from __future__ import annotations from dataclasses import dataclass from datetime import UTC, datetime, timedelta from pathlib import Path from govoplan_core.core.operations import ( OperationalCheck, OperationalCheckProviderRegistration, ) from govoplan_ops.backend.api.v1 import routes @dataclass class _Manifest: operational_check_providers: tuple[OperationalCheckProviderRegistration, ...] class _Registry: def __init__(self, *registrations: OperationalCheckProviderRegistration): self._manifest = _Manifest(tuple(registrations)) def manifests(self): return (self._manifest,) def test_module_operational_checks_cache_and_force() -> None: routes._module_check_cache.clear() calls = 0 def provider() -> OperationalCheck: nonlocal calls calls += 1 return OperationalCheck("example.roundtrip", "Example", "ok", "Passed") registration = OperationalCheckProviderRegistration( module_id="example", check_id="example.roundtrip", provider=provider, ) registry = _Registry(registration) assert routes._module_operational_checks(registry, force=False)[0]["state"] == "ok" assert routes._module_operational_checks(registry, force=False)[0]["state"] == "ok" assert calls == 1 routes._module_operational_checks(registry, force=True) assert calls == 2 def test_module_operational_check_failure_is_isolated() -> None: routes._module_check_cache.clear() def provider() -> OperationalCheck: raise RuntimeError("secret detail") result = routes._module_operational_checks( _Registry( OperationalCheckProviderRegistration( module_id="example", check_id="example.failed", provider=provider, ) ), force=True, )[0] assert result["state"] == "error" assert "secret detail" not in result["detail"] def test_shared_runtime_cluster_missing_replicas_blocks_readiness() -> None: check = routes._runtime_cluster_check( { "available": True, "state_profile": "shared", "nodes": [ {"role": "api", "state": "active", "stale": False}, {"role": "worker", "state": "active", "stale": True}, ], "expected": {"api": 2, "worker": 1}, "active": {"api": 1, "worker": 0}, "recovery": {"requires_attention": 1}, } ) assert check["state"] == "error" assert check["readiness_critical"] is True assert check["metrics"]["recovery_required"] == 1 def test_shared_runtime_cluster_skew_or_unserved_queue_blocks_readiness() -> None: check = routes._runtime_cluster_check( { "available": True, "state_profile": "shared", "nodes": [], "expected": {"api": 2, "worker": 2}, "active": {"api": 2, "worker": 2}, "composition": {"skewed": True}, "software_versions": {"skewed": False}, "queues": {"missing": ["calendar"]}, "recovery": {"requires_attention": 0}, } ) assert check["state"] == "error" assert check["readiness_critical"] is True assert check["metrics"]["composition_skewed"] is True assert check["metrics"]["missing_queues"] == 1 def test_database_capacity_check_enforces_shared_rendered_budget( monkeypatch, ) -> None: monkeypatch.setattr(routes.core_settings, "state_profile", "shared") monkeypatch.setattr(routes.core_settings, "database_connection_limit", 100) monkeypatch.setattr(routes.core_settings, "database_connection_reserve", 10) monkeypatch.setattr(routes.core_settings, "database_connection_available", 90) monkeypatch.setattr(routes.core_settings, "database_connection_peak", 70) healthy = routes._database_capacity_check() assert healthy["state"] == "ok" assert healthy["metrics"]["peak"] == 70 monkeypatch.setattr(routes.core_settings, "database_connection_peak", 91) overrun = routes._database_capacity_check() assert overrun["state"] == "error" assert overrun["readiness_critical"] is True def test_recovery_metrics_separate_failure_unknown_and_active_work() -> None: metrics = routes._recovery_metrics( [ {"status": "running"}, {"status": "failed"}, {"status": "outcome_unknown"}, {"status": "recovery_required"}, {"status": "manual_intervention"}, ] ) assert metrics == { "failed": 2, "outcome_unknown": 1, "recovery_required": 1, "active": 1, "requires_attention": 4, } def test_local_storage_capacity_reports_bounded_filesystem_metrics( tmp_path: Path, ) -> None: metrics = routes._local_storage_capacity(tmp_path) assert metrics["backend"] == "local" assert metrics["capacity_observable"] is True assert metrics["capacity_total_bytes"] > 0 assert 0 <= metrics["capacity_used_percent"] <= 100 def test_deployer_backup_receipt_reports_verified_and_expired_state( monkeypatch, ) -> None: now = datetime.now(UTC) values = { "GOVOPLAN_BACKUP_EVIDENCE_STATE": "verified", "GOVOPLAN_BACKUP_EVIDENCE_ID": "evidence-1", "GOVOPLAN_BACKUP_RECOVERY_POINT_ID": "recovery-1", "GOVOPLAN_BACKUP_RESTORE_DRILL_ID": "drill-1", "GOVOPLAN_BACKUP_EVIDENCE_SHA256": "a" * 64, "GOVOPLAN_BACKUP_RELEASE_MANIFEST_SHA256": "b" * 64, "GOVOPLAN_BACKUP_CAPTURED_AT": (now - timedelta(hours=2)).isoformat(), "GOVOPLAN_BACKUP_EXPIRES_AT": (now + timedelta(hours=2)).isoformat(), "GOVOPLAN_BACKUP_RESTORE_STARTED_AT": ( now - timedelta(hours=1, minutes=5) ).isoformat(), "GOVOPLAN_BACKUP_RESTORE_COMPLETED_AT": (now - timedelta(hours=1)).isoformat(), "GOVOPLAN_BACKUP_VERIFIED_AT": (now - timedelta(minutes=30)).isoformat(), "GOVOPLAN_BACKUP_MEASURED_RPO_SECONDS": "120", "GOVOPLAN_BACKUP_MEASURED_RTO_SECONDS": "300", "GOVOPLAN_BACKUP_COMPONENT_COUNT": "4", } for key, value in values.items(): monkeypatch.setenv(key, value) verified = routes._backup_restore_check() assert verified["state"] == "ok" assert verified["metrics"]["recovery_point_id"] == "recovery-1" assert verified["metrics"]["measured_rto_seconds"] == 300 monkeypatch.setenv( "GOVOPLAN_BACKUP_EXPIRES_AT", (now - timedelta(minutes=1)).isoformat(), ) expired = routes._backup_restore_check() assert expired["state"] == "warning" assert expired["metrics"]["evidence_state"] == "expired" def test_deployer_backup_receipt_fails_closed_without_exposing_private_evidence( monkeypatch, ) -> None: monkeypatch.setenv("GOVOPLAN_BACKUP_EVIDENCE_STATE", "invalid") invalid = routes._backup_restore_check() assert invalid["state"] == "warning" assert invalid["metrics"] == { "evidence_state": "invalid", "restore_drill_ok": False, } assert "artifact" not in invalid["detail"].lower() assert "key" not in invalid["detail"].lower()