Build and Push / build (release) Successful in 1m28s
- Dashboard domain with Quick Links CRUD + reorder endpoints - Dashboard widgets management endpoints - Database migrations for quick_links and dashboard_widgets tables - Static file controller for Organizr widgets - Default local user when OIDC is disabled - Domain-based architecture refactor (src/domains/, src/shared/) - Test suite updated for new structure (285 tests passing) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
223 lines
7.9 KiB
Python
223 lines
7.9 KiB
Python
"""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"]
|