import httpx import pytest from pathlib import Path from app.config import Settings from app.api.routes import get_project_repository from app.main import app from app.repositories.memory import InMemoryProjectRepository from app.runtime_settings import EncryptedSettingsStore, get_runtime_store @pytest.fixture def transport(tmp_path: Path) -> httpx.ASGITransport: store = EncryptedSettingsStore( Settings( _env_file=None, runtime_settings_dir=str(tmp_path), database_url="postgresql://user:secret@postgres:5432/app", redis_url="redis://:secret@redis:6379/0", ) ) repository = InMemoryProjectRepository() app.dependency_overrides[get_runtime_store] = lambda: store app.dependency_overrides[get_project_repository] = lambda: repository return httpx.ASGITransport(app=app) @pytest.mark.asyncio async def test_health(transport: httpx.ASGITransport) -> None: async with httpx.AsyncClient(transport=transport, base_url="http://test") as client: response = await client.get("/v1/health") assert response.status_code == 200 assert response.json()["status"] == "ok" @pytest.mark.asyncio async def test_demo_project_contract(transport: httpx.ASGITransport) -> None: async with httpx.AsyncClient(transport=transport, base_url="http://test") as client: response = await client.get("/v1/projects/demo-apartment") assert response.status_code == 200 body = response.json() assert body["stage"] == "plan_review" assert body["plan"]["cad_layer_count"] == 43 @pytest.mark.asyncio async def test_settings_contract_never_returns_secret_values(transport: httpx.ASGITransport) -> None: async with httpx.AsyncClient(transport=transport, base_url="http://test") as client: response = await client.get("/v1/settings") assert response.status_code == 200 body = response.json() assert len(body["categories"]) == 6 assert "ai_api_key" not in body["values"] assert body["readiness"]["ready"] is False @pytest.mark.asyncio async def test_workflow_command_is_blocked_until_required_settings_are_ready( transport: httpx.ASGITransport, ) -> None: async with httpx.AsyncClient(transport=transport, base_url="http://test") as client: response = await client.post( "/v1/projects/demo-apartment/commands", json={"command": "confirm_plan", "expected_revision": 3, "payload": {}}, ) assert response.status_code == 503 assert response.json()["detail"]["code"] == "SETTINGS_INCOMPLETE"