from unittest.mock import MagicMock, patch import httpx import psycopg import pytest from sqlalchemy import URL from app import main class _SettingsStub: def database_url(self) -> URL: return URL.create( "postgresql+psycopg", username="app", password="database-test-password", host="db.internal", port=5432, database="rag", ) @pytest.mark.asyncio async def test_liveness_does_not_require_database_or_model_credentials() -> None: transport = httpx.ASGITransport(app=main.app) async with httpx.AsyncClient(transport=transport, base_url="http://test") as client: response = await client.get("/health/live") assert response.status_code == 200 assert response.json()["status"] == "ok" @pytest.mark.asyncio async def test_readiness_executes_select_one_and_returns_redacted_status() -> None: connection = MagicMock() connection.__enter__.return_value = connection connection.execute.return_value.fetchone.return_value = (1,) with ( patch.object(main, "get_settings", return_value=_SettingsStub()), patch.object(psycopg, "connect", return_value=connection) as connect, ): transport = httpx.ASGITransport(app=main.app) async with httpx.AsyncClient(transport=transport, base_url="http://test") as client: response = await client.get("/health/ready") assert response.status_code == 200 assert response.json() == {"status": "ready", "checks": {"database": "ok"}} connection.execute.assert_called_once_with("SELECT 1") assert connect.call_args.kwargs == {"connect_timeout": 2, "autocommit": True} assert "database-test-password" not in response.text assert "db.internal" not in response.text @pytest.mark.asyncio async def test_readiness_returns_503_without_exposing_database_error() -> None: private_error = psycopg.OperationalError( "could not connect to db.internal with database-test-password" ) with ( patch.object(main, "get_settings", return_value=_SettingsStub()), patch.object(psycopg, "connect", side_effect=private_error), ): transport = httpx.ASGITransport(app=main.app) async with httpx.AsyncClient(transport=transport, base_url="http://test") as client: response = await client.get("/health/ready") assert response.status_code == 503 assert response.json() == { "status": "not_ready", "checks": {"database": "unavailable"}, } assert "database-test-password" not in response.text assert "db.internal" not in response.text @pytest.mark.asyncio async def test_meta_exposes_model_names_but_no_credentials() -> None: transport = httpx.ASGITransport(app=main.app) async with httpx.AsyncClient(transport=transport, base_url="http://test") as client: response = await client.get("/api/v1/meta") assert response.status_code == 200 payload = response.json() assert payload["models"] == { "embedding": "text-embedding-v4", "rerank": "qwen3-rerank", "generation": "deepseek-v4-flash", } assert "key" not in str(payload).lower()