diff options
Diffstat (limited to 'packages/meshbay-hub/tests/test_search_video_merge.py')
| -rw-r--r-- | packages/meshbay-hub/tests/test_search_video_merge.py | 185 |
1 files changed, 0 insertions, 185 deletions
diff --git a/packages/meshbay-hub/tests/test_search_video_merge.py b/packages/meshbay-hub/tests/test_search_video_merge.py deleted file mode 100644 index e9ab258..0000000 --- a/packages/meshbay-hub/tests/test_search_video_merge.py +++ /dev/null @@ -1,185 +0,0 @@ -""" -The reported symptom, end to end: one library shared by two groups. - -`test_search_source_merge.py` holds the merging rules in isolation. This holds -the thing an operator actually saw — a node hosting two groups that were given -the same video directory, and a Search view showing every film as two poster -cards and every episode twice inside a show. - -Three pieces have to agree for that to come out right, and each lives in a -different file: - - * `groupVideoEntries` (video-app.js) turns entries into films and shows; - * `videoUnits` (search-page.js) turns those into merge units; - * `mergeUnitEntries` (source-merge.js) folds them on the content hash. - -All three are read out of their real sources here rather than restated. The -pipeline is assembled the way `search-page.js` assembles it, and then the -result is passed through `groupVideoEntries` a second time — which is what -`VideoApp` does with it — so what this counts is what the grid renders. - -See docs/refactoring-search.md. -""" - -import json -import re -import shutil -import subprocess -from pathlib import Path - -import pytest - -STATIC = Path(__file__).resolve().parents[1] / "src" / "meshbay_hub" / "static" -VIDEO_APP = STATIC / "video-app.js" -SEARCH_PAGE = STATIC / "search-page.js" -MERGE = STATIC / "source-merge.js" - -pytestmark = pytest.mark.skipif( - shutil.which("node") is None or not MERGE.exists(), - reason="node or the SPA sources are not available") - -EXPORT = re.compile(r"^export \{[^}]*\};?\s*$", re.M) - - -def _block(path, header): - """One top-level `function name(...) {` ... `}` read out of a module.""" - src = path.read_text() - m = re.search(r"^" + re.escape(header) + r".*?^\}", src, re.M | re.S) - assert m, ( - f"{header} is no longer where this test reads it from in {path.name} — " - "the Search view's de-duplication is untested until this is fixed") - return m.group(0) - - -@pytest.fixture(scope="module") -def pipeline(): - root = re.search(r"^const SEARCH_VIDEO_ROOT = .*?;$", SEARCH_PAGE.read_text(), re.M) - assert root, "SEARCH_VIDEO_ROOT moved — videoUnits cannot be lifted" - return "\n".join([ - EXPORT.sub("", MERGE.read_text()), - _block(VIDEO_APP, "function underVideoRoot(entry, videoRoot) {"), - _block(VIDEO_APP, "function buildSeasons(episodes) {"), - _block(VIDEO_APP, "function groupVideoEntries(entries, videoRoot) {"), - root.group(0), - _block(SEARCH_PAGE, "function videoUnits(entries) {"), - ]) - - -def _grid(tmp_path, pipeline, entries, salt="reader", local=()): - """What the poster grid ends up with, after the merge and VideoApp's own - regrouping.""" - body = f""" - const raw = {json.dumps(entries)}; - const local = new Set({json.dumps(list(local))}); - const merged = mergeUnitEntries(videoUnits(raw), {{ - salt: {json.dumps(salt)}, - isLocal: (g) => local.has(g), - }}); - const {{ movies, shows }} = groupVideoEntries(merged, SEARCH_VIDEO_ROOT); - console.log(JSON.stringify({{ - movies: movies.map((e) => ({{ - id: e.id, title: e.display_title || e.name, groupId: e.groupId, - sources: e._sources.length, - }})), - shows: shows.map((s) => ({{ - title: s.title, - groups: [...new Set(s.episodes.map((e) => e.groupId))].sort(), - seasons: s.seasons.map((x) => ({{ - season: x.season, - episodes: x.episodes.map((e) => `S${{e.season}}E${{e.episode}}`), - }})), - }})), - }})); - """ - script = tmp_path / "case.js" - script.write_text(f"{pipeline}\n{body}\n") - out = subprocess.run( - ["node", str(script)], capture_output=True, text=True, timeout=30) - assert out.returncode == 0, out.stderr - return json.loads(out.stdout) - - -# The shape of one shared library: a film, and a two-season show. Invented -# titles — the real one this was found against is nobody's business here. -def _library(group): - """`path` is already prefixed the way search-page.js prefixes it.""" - def entry(file_id, name, **kw): - return { - "id": file_id, "name": name, "type": "video", - "path": "__search__/shows", "size": 1, - "groupId": group, "groupName": group.upper(), "groupOwner": "someone", - "_tRef": f"t:{group}", "_gRef": f"g:{group}", "_connGen": 1, - **kw, - } - files = [entry("film1", "a-film.mkv", display_title="Some Film")] - for season in (1, 2): - for ep in (1, 2, 3): - files.append(entry( - f"s{season}e{ep}", f"show.s0{season}e0{ep}.mkv", - display_title="Some Saga", season=season, episode=ep)) - return files - - -def test_a_shared_library_is_listed_once(tmp_path, pipeline): - """ - The bug as reported: two groups, one directory, everything twice. - """ - both = _library("demo35") + _library("media") - grid = _grid(tmp_path, pipeline, both) - - assert [m["title"] for m in grid["movies"]] == ["Some Film"] - assert grid["movies"][0]["sources"] == 2 - - assert len(grid["shows"]) == 1 - show = grid["shows"][0] - assert [s["season"] for s in show["seasons"]] == [1, 2] - for season in show["seasons"]: - assert season["episodes"] == [ - f"S{season['season']}E{n}" for n in (1, 2, 3)], ( - "an episode is listed more than once — this is the reported bug, " - "in the season list under the synopsis") - - -def test_a_show_streams_from_one_source(tmp_path, pipeline): - """A season split across two nodes would open two connections and two - metadata lookups for one show.""" - both = _library("demo35") + _library("media") - show = _grid(tmp_path, pipeline, both)["shows"][0] - assert len(show["groups"]) == 1 - - -def test_the_operators_own_node_serves_it(tmp_path, pipeline): - """Both groups are on the operator's node in the reported case; when only - one is, that one is the source.""" - both = _library("remote") + _library("mine") - grid = _grid(tmp_path, pipeline, both, local=["mine"]) - assert grid["movies"][0]["groupId"] == "mine" - assert grid["shows"][0]["groups"] == ["mine"] - - -def test_one_group_is_unchanged(tmp_path, pipeline): - """The overwhelmingly common case: nothing to merge, nothing different.""" - grid = _grid(tmp_path, pipeline, _library("solo")) - assert [m["title"] for m in grid["movies"]] == ["Some Film"] - assert grid["movies"][0]["sources"] == 1 - assert grid["movies"][0]["groupId"] == "solo" - show = grid["shows"][0] - assert show["groups"] == ["solo"] - assert sum(len(s["episodes"]) for s in show["seasons"]) == 6 - - -def test_an_episode_only_one_group_has_is_kept(tmp_path, pipeline): - """ - Merging must never subtract. A group holding one extra episode contributes - it, whichever source the show settled on. - """ - extra = _library("media") - extra.append({ - "id": "s2e4", "name": "show.s02e04.mkv", "type": "video", - "path": "__search__/shows", "size": 1, - "groupId": "media", "groupName": "MEDIA", "groupOwner": "someone", - "display_title": "Some Saga", "season": 2, "episode": 4, - }) - grid = _grid(tmp_path, pipeline, _library("demo35") + extra) - season2 = [s for s in grid["shows"][0]["seasons"] if s["season"] == 2][0] - assert season2["episodes"] == ["S2E1", "S2E2", "S2E3", "S2E4"] |