"""실시간 내담자 공급자 준비상태의 API health 계약.""" from __future__ import annotations import unittest from types import SimpleNamespace from unittest.mock import AsyncMock, patch from . import main from .upload_storage import UploadWriteFreezeStatus class EngineHealthContractTest(unittest.IsolatedAsyncioTestCase): async def test_health_requires_and_exposes_lifespan_database_proof(self) -> None: target_sha256 = "a" * 64 manifest = SimpleNamespace( manifest_sha256="b" * 64, database_target_sha256=target_sha256, preserved_object_count=93, preserved_total_size_bytes=52973, preserved_decode_valid_count=3, preserved_decode_invalid_count=90, required_decode_invalid_object_count=0, required_decode_invalid_reference_count=0, preserved_object_set_sha256="c" * 64, required_object_count=8, reference_set_sha256="d" * 64, ) runtime_proof = SimpleNamespace( database_target_sha256=target_sha256, current_references=SimpleNamespace( object_count=8, reference_count=8, reference_set_sha256="e" * 64, decode_invalid_object_count=6, decode_invalid_reference_count=6, ), ) with ( patch.object(main, "upload_manifest_proof", manifest), patch.object(main, "healthcheck", AsyncMock(return_value=True)), patch.object( main.engine_client, "health_detail", AsyncMock(return_value={"ok": True}), ), patch.object( main.app.state, "upload_database_proof", runtime_proof, create=True, ), ): response = await main.health() self.assertEqual("ok", response["status"]) self.assertTrue(response["upload_manifest"]["runtime_database_validated"]) self.assertEqual(8, response["upload_manifest"]["current_object_count"]) self.assertEqual( 52973, response["upload_manifest"]["preserved_total_size_bytes"], ) self.assertEqual(8, response["upload_manifest"]["current_reference_count"]) self.assertTrue(response["upload_manifest"]["forensic_fallback_active"]) self.assertEqual( 6, response["upload_manifest"]["current_decode_invalid_reference_count"], ) self.assertEqual( "e" * 64, response["upload_manifest"]["current_reference_set_sha256"], ) async def test_health_is_degraded_for_invalid_active_upload_freeze(self) -> None: engine_detail = {"ok": True, "detail": "ready"} invalid_freeze = UploadWriteFreezeStatus( capable=True, active=True, valid=False, in_flight=0, path_sha256="a" * 64, token_sha256=None, ) with ( patch.object(main, "healthcheck", AsyncMock(return_value=True)), patch.object( main.engine_client, "health_detail", AsyncMock(return_value=engine_detail), ), patch.object( main.upload_write_freeze_gate, "status", return_value=invalid_freeze, ), ): response = await main.health() self.assertEqual("degraded", response["status"]) self.assertFalse(response["upload_write_freeze"]["valid"]) async def test_health_stays_ok_for_valid_active_maintenance_freeze(self) -> None: engine_detail = {"ok": True, "detail": "ready"} valid_freeze = UploadWriteFreezeStatus( capable=True, active=True, valid=True, in_flight=0, path_sha256="a" * 64, token_sha256="b" * 64, ) with ( patch.object(main, "healthcheck", AsyncMock(return_value=True)), patch.object( main.engine_client, "health_detail", AsyncMock(return_value=engine_detail), ), patch.object( main.upload_write_freeze_gate, "status", return_value=valid_freeze, ), ): response = await main.health() self.assertEqual("ok", response["status"]) self.assertTrue(response["upload_write_freeze"]["active"]) async def test_health_is_degraded_when_live_client_lane_is_unready(self) -> None: engine_detail = { "ok": False, "detail": "실시간 내담자 공급자 claude_cli: login required", "default_engine": { "provider": "agy_cli", "ok": True, "detail": "ready", }, "live_client_engine": { "provider": "claude_cli", "ok": False, "detail": "login required", }, } with ( patch.object(main, "healthcheck", AsyncMock(return_value=True)), patch.object( main.engine_client, "health_detail", AsyncMock(return_value=engine_detail), ), patch.object(main.engine_client, "engine_mode", "agy_cli"), patch.object(main.engine_client, "live_client_provider", "claude_cli"), ): response = await main.health() self.assertEqual(response["status"], "degraded") self.assertFalse(response["engine"]) self.assertEqual(response["engine_mode"], "agy_cli") self.assertEqual(response["live_client_provider"], "claude_cli") self.assertEqual( response["live_client_engine"], engine_detail["live_client_engine"], ) if __name__ == "__main__": unittest.main()