from __future__ import annotations from fastapi.testclient import TestClient from server.gateway.app import create_app from server.state.seed import seed_world from tests.auth_provider import install_test_auth class _Store: def __init__(self) -> None: self.data = seed_world() self.data["scheduleVersions"] = [{ "id": 501, "versionNo": "ATTR-501", "status": "DRAFT", "createdAt": "2026-08-17T00:00:00Z", }] for conflict in self.data.get("conflicts") or []: conflict["versionId"] = 501 self.world_key = "personal-1001" self.tenant_uuid = "tenant-attribution-api" def next_id(self, _kind: str) -> int: return 1 def save(self) -> None: return None def test_attribution_api_is_track_and_version_bound(monkeypatch): import server.gateway.app as gateway install_test_auth(monkeypatch, "tenant-attribution-api") store = _Store() monkeypatch.setattr(gateway, "get_store", lambda: store) client = TestClient(create_app()) assert client.post( "/api/auth/login", json={"username": "planner", "password": "test"}, ).status_code == 200 response = client.get("/api/attribution?track=fixed") assert response.status_code == 200, response.text body = response.json() assert body["schemaVersion"] == "schedule-attribution.v1" assert body["track"] == "fixed" assert body["versionId"] == store.data["scheduleVersions"][-1]["id"] assert all(row["isShadowPriceProxy"] is True for row in body["masterControl"]) assert all("conflictId" in row for row in body["attributions"]) assert all(row.get("iisId", "").startswith("IIS-") for row in body["iis"]) assert all(isinstance(row.get("evidence"), dict) for row in body["attributions"]) assert client.get("/api/attribution?track=unknown").status_code == 400 assert client.get("/api/attribution?track=fixed&versionId=999999").status_code == 404 store.data["flexScheduleVersions"] = [] assert client.get("/api/attribution?track=flex").status_code == 404