From e6a12b9a7c45fd0fa3d6e28e03eb31b9d9c7815a Mon Sep 17 00:00:00 2001 From: 1445043649 <> Date: Sun, 28 Jun 2026 20:01:29 +0800 Subject: [PATCH] test(gateway): strengthen dual-mount coverage to a v1-twin invariant (Stage 1 PR5) Co-Authored-By: Claude Opus 4.8 (1M context) --- backend/tests/test_api_deprecation_header.py | 13 +++++++++++++ backend/tests/test_api_v1_dual_mount.py | 13 +++++++++---- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/backend/tests/test_api_deprecation_header.py b/backend/tests/test_api_deprecation_header.py index eb68caf6..44af5ee8 100644 --- a/backend/tests/test_api_deprecation_header.py +++ b/backend/tests/test_api_deprecation_header.py @@ -25,6 +25,10 @@ def _make_app(): async def lg(): return {"ok": True} + @app.get("/api/assistants/info") + async def assistants(): + return {"ok": True} + return app @@ -44,3 +48,12 @@ def test_langgraph_path_no_header(): client = TestClient(_make_app()) r = client.get("/api/langgraph/info") assert "X-API-Deprecated" not in r.headers + + +def test_assistants_compat_path_gets_deprecation_header(): + # assistants_compat is an un-versioned LangGraph-platform stub; it + # intentionally carries the deprecation header (it is /api/, not + # /api/v1 or /api/langgraph). Documented here to prevent confusion. + client = TestClient(_make_app()) + r = client.get("/api/assistants/info") + assert r.headers.get("X-API-Deprecated") == "2027-01-01" diff --git a/backend/tests/test_api_v1_dual_mount.py b/backend/tests/test_api_v1_dual_mount.py index 7f14878c..d0a010d4 100644 --- a/backend/tests/test_api_v1_dual_mount.py +++ b/backend/tests/test_api_v1_dual_mount.py @@ -25,11 +25,16 @@ def test_runs_dual_mounted(): assert "/api/v1/runs/stream" in paths -def test_threads_dual_mounted(): +def test_every_legacy_api_path_has_v1_twin(): + """Strong invariant: every unversioned /api/* path (except the + intentionally-excluded surfaces) must also exist under /api/v1/*. + Catches any single legacy router losing its v1 mount.""" paths = _paths() - # at least one threads sub-path must exist on both surfaces - assert any(p.startswith("/api/threads/") for p in paths) - assert any(p.startswith("/api/v1/threads/") for p in paths) + excluded_prefixes = ("/api/v1/", "/api/langgraph/", "/api/assistants") + legacy = {p for p in paths if p.startswith("/api/") and not p.startswith(excluded_prefixes)} + assert legacy, "expected some unversioned /api/* paths" + missing = sorted(p for p in legacy if ("/api/v1/" + p[len("/api/") :]) not in paths) + assert missing == [], f"legacy /api paths without an /api/v1 twin: {missing}" def test_uploads_dual_mounted():