test: add real-world release fixtures (EASY bucket)
Captures 5 canonical releases from /mnt/testipool/downloads as parametrized fixtures under tests/fixtures/releases/easy/. Each fixture declares the release name, expected ParsedRelease fields, original tree, and the future routing (library / torrents / seed_hardlinks) for the upcoming organize_media refactor. Today only the 'parsed' section is asserted; tree is materialized into a tmp_path to catch typos. Routing is captured ahead of the planner work — it becomes verifiable once organize_media lands. Cases: back_in_action (movie), slow_horses_single_ep (TV single), foundation_season_pack (S02 + .nfo noise), long_walk_with_noise (movie + KONTRAST.TOP.txt), sinners_yts (YTS bracket-heavy + Subs/ dir). Also tracks CHANGELOG.md under [Unreleased] / Added.
This commit is contained in:
Vendored
+60
@@ -0,0 +1,60 @@
|
||||
"""Fixture discovery and materialization helpers for release fixtures.
|
||||
|
||||
Each fixture is a directory under ``tests/fixtures/releases/<bucket>/<case>/``
|
||||
containing one ``expected.yaml`` file. See ``releases/README.md`` for the
|
||||
schema.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
|
||||
import yaml
|
||||
|
||||
FIXTURES_ROOT = Path(__file__).parent
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ReleaseFixture:
|
||||
"""A loaded fixture, ready to be materialized into a temp dir."""
|
||||
|
||||
name: str # "<bucket>/<case>", e.g. "easy/back_in_action"
|
||||
path: Path # directory containing expected.yaml
|
||||
data: dict # parsed YAML contents
|
||||
|
||||
@property
|
||||
def release_name(self) -> str:
|
||||
return self.data["release_name"]
|
||||
|
||||
@property
|
||||
def expected_parsed(self) -> dict:
|
||||
return self.data.get("parsed", {})
|
||||
|
||||
@property
|
||||
def tree(self) -> list[str]:
|
||||
return self.data.get("tree", [])
|
||||
|
||||
@property
|
||||
def routing(self) -> dict:
|
||||
return self.data.get("routing", {})
|
||||
|
||||
def materialize(self, root: Path) -> None:
|
||||
"""Create the fixture's ``tree`` as empty files/dirs under ``root``."""
|
||||
for entry in self.tree:
|
||||
target = root / entry
|
||||
if entry.endswith("/"):
|
||||
target.mkdir(parents=True, exist_ok=True)
|
||||
else:
|
||||
target.parent.mkdir(parents=True, exist_ok=True)
|
||||
target.touch()
|
||||
|
||||
|
||||
def discover_fixtures() -> list[ReleaseFixture]:
|
||||
"""Find all ``expected.yaml`` files under FIXTURES_ROOT."""
|
||||
fixtures = []
|
||||
for yaml_path in sorted(FIXTURES_ROOT.glob("*/*/expected.yaml")):
|
||||
data = yaml.safe_load(yaml_path.read_text())
|
||||
name = f"{yaml_path.parent.parent.name}/{yaml_path.parent.name}"
|
||||
fixtures.append(ReleaseFixture(name=name, path=yaml_path.parent, data=data))
|
||||
return fixtures
|
||||
Reference in New Issue
Block a user