From cd60935f953ff3fcaa65a8ac95828f0e4d8b2bc2 Mon Sep 17 00:00:00 2001 From: jwinterm Date: Mon, 6 Jul 2026 03:41:26 -0400 Subject: [PATCH] Show route metadata in fixture checks --- ampbrowser/cli.py | 2 ++ ampbrowser/fixtures.py | 15 +++++++++++++++ docs/fixture-manifests.md | 3 +++ tests/test_fixtures.py | 3 +++ 4 files changed, 23 insertions(+) diff --git a/ampbrowser/cli.py b/ampbrowser/cli.py index 50f35b0..39b0ea0 100644 --- a/ampbrowser/cli.py +++ b/ampbrowser/cli.py @@ -185,6 +185,8 @@ def _cmd_fixture(args) -> int: "AMPBROWSER_FIXTURE " f"site={check.site_id} " f"protocol={check.protocol} " + f"route_match={check.route_match} " + f"fixture_path={check.fixture_path} " f"url={check.url} " f"expected_transport={check.expected_transport} " f"actual_transport={check.actual_transport} " diff --git a/ampbrowser/fixtures.py b/ampbrowser/fixtures.py index 4cc2637..8b4f948 100644 --- a/ampbrowser/fixtures.py +++ b/ampbrowser/fixtures.py @@ -16,6 +16,8 @@ SUPPORTED_SCHEMAS = {"ampg.fixture-manifest.v1"} class FixtureCheck: site_id: str protocol: str + route_match: str + fixture_path: str url: str expected_transport: str actual_transport: str @@ -77,6 +79,7 @@ def _check_fixture(site_id: str, fixture: Any, path: Path) -> FixtureCheck: expected_transport = _string(checks, "transport") expected_profile = _string(checks, "profile") interaction = _interaction_policy(fixture) + route_metadata = _route_metadata(fixture) route = route_url(url) failures: list[str] = [] @@ -98,6 +101,8 @@ def _check_fixture(site_id: str, fixture: Any, path: Path) -> FixtureCheck: return FixtureCheck( site_id=site_id, protocol=protocol, + route_match=route_metadata["match"], + fixture_path=route_metadata["fixture_path"], url=route.normalized, expected_transport=expected_transport, actual_transport=route.transport, @@ -140,6 +145,16 @@ def _interaction_policy(fixture: dict[str, Any]) -> dict[str, Any]: } +def _route_metadata(fixture: dict[str, Any]) -> dict[str, str]: + raw = fixture.get("route", {}) + if not isinstance(raw, dict): + raise ValueError(f"{fixture.get('protocol', 'fixture')}: route must be a table") + return { + "match": _optional_string(raw, "match", "/"), + "fixture_path": _optional_string(raw, "fixture_path", "/"), + } + + def _optional_string(data: dict[str, Any], key: str, default: str) -> str: value = data.get(key, default) if not isinstance(value, str) or not value: diff --git a/docs/fixture-manifests.md b/docs/fixture-manifests.md index b3e4bc3..030fbac 100644 --- a/docs/fixture-manifests.md +++ b/docs/fixture-manifests.md @@ -6,6 +6,9 @@ AMPB can check AMPG fixture manifests without contacting any network. The check that each generated fixture URL routes to the expected AMPB transport and profile, and that its declared interaction policy fits that transport. +Route-expanded fixtures may include `route.match` and `route.fixture_path`, which identify +the route group that produced the fixture. + ## Command ```sh diff --git a/tests/test_fixtures.py b/tests/test_fixtures.py index f147a74..166a530 100644 --- a/tests/test_fixtures.py +++ b/tests/test_fixtures.py @@ -31,6 +31,7 @@ class FixtureCheckTest(unittest.TestCase): { "protocol": "ipfs", "url": "ipfs://bafyexample", + "route": {"match": "/snapshot/*", "fixture_path": "/snapshot/"}, "checks": {"transport": "ipfs", "profile": "ipfs"}, "interaction": {"tier": "static"}, }, @@ -44,6 +45,8 @@ class FixtureCheckTest(unittest.TestCase): self.assertTrue(result.ok) self.assertEqual(3, len(result.checks)) + self.assertEqual("/snapshot/*", result.checks[2].route_match) + self.assertEqual("/snapshot/", result.checks[2].fixture_path) def test_reports_route_mismatch(self) -> None: with tempfile.TemporaryDirectory() as tmp: