OverviewFilesCommitsIssuesDocsReleasesPeers

kodi-jacktook commits / 43a2332

Test the real Stream, so it cannot drift from the one in production
test_list_stremio_movie_builds_enriched_play_media_payload has been failing on main. It stood in for a Stream with `type("Stream", (), {...})()` -- an ad-hoc object carrying four attributes and none of the model's behaviour. That held until the fork plumbed behaviorHints.proxyHeaders through playback. Production began calling stream.get_proxy_headers(); the stub had no such method; the test failed with AttributeError against code that was working correctly in the field. So the failure said nothing about the product, which is the worst state for a test to be in -- it trains you to ignore it, and a real regression here would have looked exactly the same. Fixed by building a real Stream via Stream.from_dict, the way addon_client does. A stand-in that shares no code with the thing it stands for cannot notice when that thing changes; one built from the model has no choice. Also adds the case that was missing entirely, and whose absence is why the stub went stale unnoticed: a stream WITH proxyHeaders reaching the playback payload. That is the reason this fork exists -- hotlink-gated CDNs 403 every segment without the Referer the addon advertised -- and nothing at this level covered it. Both tests were checked against a deliberately broken build: removing the `playback_data["proxyHeaders"] = ...` line fails both, so they are guarding the line and not merely passing near it. No version bump: tests only, no change to shipped behaviour. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
43a2332a709e26afd05c7406ee1a1b7a33cdc13b
by plankatron <fleeky@gmail.com> · 2026-09-05T01:27:26.000Z

Changed files (1) +73 -15

plugin.video.jacktook/tests/unit/test_stremio_regressions.py +73 -15
……@@ -3,7 +3,7 @@ from unittest.mock import MagicMock
33
44from lib import search
55from lib.api.stremio.addon_manager import AddonManager
6from lib.api.stremio.models import Meta, MetaPreview
6from lib.api.stremio.models import Meta, MetaPreview, Stream
77from lib.clients.stremio import addon_client, addon_selection, catalog_menus, helpers
88from lib.clients.stremio.catalog_menus import CATALOG_PAGE_SIZE
99from lib.clients.stremio.constants import (
……@@ -1272,26 +1272,35 @@ def test_add_meta_items_resolves_tmdb_id_from_imdb_for_context_menu(monkeypatch)
12721272 assert menu_labels.count("Open Settings") == 1
12731273
12741274
1275def _catalog_stream(**overrides):
1276 """A REAL Stream, the way addon_client builds one.
1277
1278 This used to be `type("Stream", (), {...})()` -- an ad-hoc object carrying
1279 four attributes and none of the model's behaviour. It drifted the moment the
1280 fork plumbed behaviorHints.proxyHeaders through playback: production called
1281 `stream.get_proxy_headers()`, the stub had no such method, and the test
1282 failed with AttributeError on code that was working correctly in the field.
1283
1284 Building the real model means the test cannot pass while the production
1285 object it stands for has moved on.
1286 """
1287 data = {
1288 "title": "Movie Stream",
1289 "description": "Stream plot",
1290 "url": "https://video",
1291 "infoHash": "",
1292 }
1293 data.update(overrides)
1294 return Stream.from_dict(data)
1295
1296
12751297def test_list_stremio_movie_builds_enriched_play_media_payload(monkeypatch):
12761298 captured = {}
12771299
12781300 monkeypatch.setattr(
12791301 catalog_menus,
12801302 "catalogs_get_cache",
1281 lambda *args, **kwargs: {
1282 "streams": [
1283 type(
1284 "Stream",
1285 (),
1286 {
1287 "title": "Movie Stream",
1288 "description": "Stream plot",
1289 "url": "https://video",
1290 "infoHash": "",
1291 },
1292 )()
1293 ]
1294 },
1303 lambda *args, **kwargs: {"streams": [_catalog_stream()]},
12951304 )
12961305 monkeypatch.setattr(catalog_menus, "notification", lambda *args, **kwargs: None)
12971306 monkeypatch.setattr(catalog_menus, "end_of_directory", lambda *args, **kwargs: None)
……@@ -1334,5 +1343,54 @@ def test_list_stremio_movie_builds_enriched_play_media_payload(monkeypatch):
13341343 "catalog_type": "movie",
13351344 "meta_id": "custom:movie",
13361345 "url": "https://video",
1346 # Present and empty: a direct stream always carries the key, so a
1347 # regression that stopped plumbing headers shows up as a missing key
1348 # rather than as an empty dict that looks the same as "none needed".
1349 "proxyHeaders": {},
13371350 "type": catalog_menus.IndexerType.DIRECT,
13381351 }
1352
1353
1354def test_list_stremio_movie_carries_proxy_headers_to_playback(monkeypatch):
1355 """The reason this fork exists.
1356
1357 Hotlink-gated CDNs 403 every segment without the Referer the addon
1358 advertised, so behaviorHints.proxyHeaders has to survive all the way into
1359 the playback payload. Nothing at this level covered it, which is how the
1360 stub above went stale without anyone noticing.
1361 """
1362 captured = {}
1363 stream = _catalog_stream(
1364 behaviorHints={
1365 "notWebReady": True,
1366 # Stremio nests these under `request`; the model flattens them.
1367 "proxyHeaders": {"request": {"Referer": "https://vidcore.net/",
1368 "User-Agent": "Mozilla/5.0"}},
1369 }
1370 )
1371 monkeypatch.setattr(catalog_menus, "catalogs_get_cache",
1372 lambda *args, **kwargs: {"streams": [stream]})
1373 monkeypatch.setattr(catalog_menus, "notification", lambda *args, **kwargs: None)
1374 monkeypatch.setattr(catalog_menus, "end_of_directory", lambda *args, **kwargs: None)
1375 monkeypatch.setattr(catalog_menus, "make_list_item", lambda label="", path="": MagicMock())
1376 monkeypatch.setattr(catalog_menus, "addDirectoryItem", lambda *args, **kwargs: None)
1377
1378 def _build_url(action, **kwargs):
1379 captured["data"] = json.loads(kwargs["data"])
1380 return "plugin://test"
1381
1382 monkeypatch.setattr(catalog_menus, "build_url", _build_url)
1383
1384 catalog_menus.list_stremio_movie(
1385 {
1386 "addon_url": "https://example.com/addon",
1387 "catalog_type": "movie",
1388 "meta_id": "custom:movie",
1389 "ids": json.dumps({"tmdb_id": "100"}),
1390 }
1391 )
1392
1393 assert captured["data"]["proxyHeaders"] == {
1394 "Referer": "https://vidcore.net/",
1395 "User-Agent": "Mozilla/5.0",
1396 }