"""Tests for health endpoints.""" import pytest from fastapi.testclient import TestClient from unittest.mock import patch, AsyncMock from src.main import app @pytest.fixture def client(): """Create a test client.""" return TestClient(app) class TestRootEndpoint: """Test root endpoint.""" def test_root_returns_200(self, client): """Root endpoint should return 200.""" response = client.get("/") assert response.status_code == 200 def test_root_returns_service_info(self, client): """Root endpoint should return service information.""" response = client.get("/") data = response.json() assert "service" in data assert "version" in data assert "status" in data assert data["service"] == "Core Code API" assert data["status"] == "healthy" def test_root_returns_docs_link(self, client): """Root endpoint should return docs link.""" response = client.get("/") data = response.json() assert "docs" in data assert data["docs"] == "/docs" class TestHealthEndpoint: """Test /health endpoint.""" def test_health_returns_200(self, client): """Health endpoint should return 200.""" response = client.get("/health") assert response.status_code == 200 def test_health_returns_status(self, client): """Health endpoint should return status information.""" response = client.get("/health") data = response.json() assert "status" in data assert "version" in data assert data["status"] == "healthy" class TestOpenAPIEndpoint: """Test OpenAPI documentation endpoints.""" def test_openapi_spec_available(self, client): """OpenAPI spec should be available.""" response = client.get("/openapi.json") assert response.status_code == 200 data = response.json() assert "openapi" in data assert "info" in data def test_swagger_ui_available(self, client): """Swagger UI should be available.""" response = client.get("/docs") assert response.status_code == 200 class TestFullHealthCheck: """Test /health/full endpoint.""" @patch("src.shared.database.Database.health_check") @patch("src.models.ollama_client.get_ollama_client") def test_full_health_returns_503_when_unhealthy(self, mock_get_ollama, mock_db_health, client): """Full health should return 503 when Ollama unhealthy.""" mock_client = AsyncMock() mock_client.health_check.return_value = False mock_get_ollama.return_value = mock_client mock_db_health.return_value = True response = client.get("/health/full") assert response.status_code == 503 @patch("src.shared.database.Database.health_check") @patch("src.models.ollama_client.get_ollama_client") def test_full_health_returns_components_status(self, mock_get_ollama, mock_db_health, client): """Full health should return component status.""" mock_client = AsyncMock() mock_client.health_check.return_value = False mock_get_ollama.return_value = mock_client mock_db_health.return_value = True response = client.get("/health/full") data = response.json() assert "status" in data assert "components" in data assert "ollama" in data["components"] assert "database" in data["components"] assert "response_time_ms" in data @patch("src.shared.database.Database.health_check") @patch("src.models.ollama_client.get_ollama_client") def test_full_health_handles_list_models_error(self, mock_get_ollama, mock_db_health, client): """Full health should handle list_models errors.""" mock_client = AsyncMock() mock_client.health_check.return_value = True mock_client.list_models.side_effect = Exception("Connection error") mock_get_ollama.return_value = mock_client mock_db_health.return_value = True response = client.get("/health/full") data = response.json() # Should report error in component status assert "ollama" in data["components"] @patch("src.shared.database.Database.health_check") @patch("src.models.ollama_client.get_ollama_client") def test_full_health_handles_health_check_exception(self, mock_get_ollama, mock_db_health, client): """Full health should handle health check exceptions gracefully.""" mock_client = AsyncMock() # Return False instead of raising exception to test unhealthy path mock_client.health_check.return_value = False mock_get_ollama.return_value = mock_client mock_db_health.return_value = True response = client.get("/health/full") # Should return 503 for unhealthy assert response.status_code == 503 data = response.json() assert data["status"] == "unhealthy" class TestDiagnosticsEndpoint: """Test /health/diagnostics endpoint.""" @patch("src.models.ollama_client.get_ollama_client") def test_diagnostics_returns_200(self, mock_get_ollama, client): """Diagnostics should return 200.""" mock_client = AsyncMock() mock_client.health_check.return_value = True mock_get_ollama.return_value = mock_client response = client.get("/health/diagnostics") assert response.status_code == 200 @patch("src.models.ollama_client.get_ollama_client") def test_diagnostics_returns_service_info(self, mock_get_ollama, client): """Diagnostics should return service information.""" mock_client = AsyncMock() mock_client.health_check.return_value = True mock_get_ollama.return_value = mock_client response = client.get("/health/diagnostics") data = response.json() assert "service" in data assert "name" in data["service"] assert "version" in data["service"] @patch("src.models.ollama_client.get_ollama_client") def test_diagnostics_returns_components(self, mock_get_ollama, client): """Diagnostics should return component details.""" mock_client = AsyncMock() mock_client.health_check.return_value = True mock_get_ollama.return_value = mock_client response = client.get("/health/diagnostics") data = response.json() assert "components" in data assert "ollama" in data["components"] @patch("src.models.ollama_client.get_ollama_client") def test_diagnostics_returns_configuration(self, mock_get_ollama, client): """Diagnostics should return configuration info.""" mock_client = AsyncMock() mock_client.health_check.return_value = True mock_get_ollama.return_value = mock_client response = client.get("/health/diagnostics") data = response.json() assert "configuration" in data @patch("src.models.ollama_client.get_ollama_client") def test_diagnostics_returns_response_time(self, mock_get_ollama, client): """Diagnostics should return response time.""" mock_client = AsyncMock() mock_client.health_check.return_value = True mock_get_ollama.return_value = mock_client response = client.get("/health/diagnostics") data = response.json() assert "response_time_ms" in data assert isinstance(data["response_time_ms"], int) @patch("src.models.ollama_client.get_ollama_client") def test_diagnostics_handles_ollama_error(self, mock_get_ollama, client): """Diagnostics should handle Ollama connection errors.""" mock_client = AsyncMock() mock_client.health_check.side_effect = Exception("Connection refused") mock_get_ollama.return_value = mock_client response = client.get("/health/diagnostics") data = response.json() # Should still return 200 with error info assert response.status_code == 200 assert "error" in data["components"]["ollama"]