from __future__ import annotations import subprocess import sys import tempfile import unittest from pathlib import Path from fastapi.testclient import TestClient META_ROOT = Path(__file__).resolve().parents[1] RELEASE_ROOT = META_ROOT / "tools" / "release" if str(RELEASE_ROOT) not in sys.path: sys.path.insert(0, str(RELEASE_ROOT)) from server.app import create_app # noqa: E402 class ReleaseDashboardDiagnosticsTests(unittest.TestCase): def test_malformed_core_version_is_bounded_and_blocks_api_plans(self) -> None: with tempfile.TemporaryDirectory() as temp_dir: workspace = Path(temp_dir) core = workspace / "govoplan-core" core.mkdir() (core / "pyproject.toml").write_text("[project\n", encoding="utf-8") with TestClient(create_app(workspace_root=workspace)) as client: dashboard_response = client.get( "/api/dashboard", params={"public_catalog": "false"} ) selective_response = client.get( "/api/selective-plan", params={ "repos": "govoplan-core", "repo_versions": "govoplan-core:1.2.4", "public_catalog": "false", }, ) full_plan_response = client.get( "/api/plan", params={"public_catalog": "false"} ) self.assertEqual(200, dashboard_response.status_code) dashboard = dashboard_response.json() self.assertEqual("blocked", dashboard["summary"]["status"]) error = next( item for item in dashboard["collection_errors"] if item["code"] == "core_version_metadata_unreadable" ) self.assertEqual("govoplan-core/pyproject.toml", error["source"]) self.assertIn("TOMLDecodeError", error["message"]) self.assertIn("Repair govoplan-core/pyproject.toml", error["remediation"]) self.assertLess(len(error["message"]), 200) self.assertNotIn(str(workspace), error["message"]) self.assertEqual(200, selective_response.status_code) selective_plan = selective_response.json() self.assertEqual("blocked", selective_plan["status"]) self.assertFalse(selective_plan["source_preflight_ready"]) finding = next( item for item in selective_plan["gate_findings"] if item["code"] == "core_version_metadata_unreadable" ) self.assertEqual(error["remediation"], finding["remediation"]) self.assertEqual( "resolve_release_gate", selective_plan["recommended_action"]["id"] ) self.assertEqual(200, full_plan_response.status_code) full_plan = full_plan_response.json() self.assertEqual("blocked", full_plan["status"]) self.assertTrue( any( action["id"].startswith("dashboard:core_version_metadata_unreadable:") for action in full_plan["actions"] ) ) def test_malformed_manifest_is_not_silently_omitted_from_selected_plan( self, ) -> None: with tempfile.TemporaryDirectory() as temp_dir: workspace = Path(temp_dir) core = workspace / "govoplan-core" core.mkdir() (core / "pyproject.toml").write_text( '[project]\nname = "govoplan-core"\nversion = "0.1.13"\n', encoding="utf-8", ) files = workspace / "govoplan-files" manifest = files / "src" / "govoplan_files" / "backend" / "manifest.py" manifest.parent.mkdir(parents=True) (files / "pyproject.toml").write_text( '[project]\nname = "govoplan-files"\nversion = "1.2.4"\n', encoding="utf-8", ) manifest.write_text("def broken(:\n", encoding="utf-8") initialize_repository(files) with TestClient(create_app(workspace_root=workspace)) as client: dashboard_response = client.get( "/api/dashboard", params={"public_catalog": "false"} ) selective_response = client.get( "/api/selective-plan", params={ "repos": "govoplan-files", "repo_versions": "govoplan-files:1.2.4", "public_catalog": "false", }, ) self.assertEqual(200, dashboard_response.status_code) dashboard = dashboard_response.json() error = next( item for item in dashboard["collection_errors"] if item["code"] == "module_contract_unreadable" ) self.assertEqual("govoplan-files", error["repo"]) self.assertEqual( "govoplan-files/src/govoplan_files/backend/manifest.py", error["source"], ) self.assertIn("SyntaxError", error["message"]) self.assertIn("Repair the manifest", error["remediation"]) self.assertEqual(200, selective_response.status_code) plan = selective_response.json() self.assertEqual("blocked", plan["status"]) self.assertFalse(plan["source_preflight_ready"]) self.assertIn( "module_contract_unreadable", {finding["code"] for finding in plan["gate_findings"]}, ) self.assertEqual("resolve_release_gate", plan["recommended_action"]["id"]) def initialize_repository(path: Path) -> None: subprocess.run( ["git", "init", "--initial-branch=main", str(path)], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, ) subprocess.run( ["git", "-C", str(path), "add", "."], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, ) subprocess.run( [ "git", "-C", str(path), "-c", "user.name=Release Test", "-c", "user.email=release@example.invalid", "-c", "commit.gpgsign=false", "commit", "-m", "Initial fixture", ], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, ) if __name__ == "__main__": unittest.main()