""" Tests pour les routes de health check. Couvre: - Métriques système - Health check global - Health check par hôte - Refresh des hôtes """ import pytest from unittest.mock import patch, AsyncMock, MagicMock from httpx import AsyncClient pytestmark = pytest.mark.unit class TestGetMetrics: """Tests pour GET /api/health.""" async def test_get_metrics(self, client: AsyncClient): """Récupère les métriques système.""" with patch("app.routes.health.db") as mock_db: mock_db.metrics = MagicMock() mock_db.metrics.dict.return_value = { "cpu_percent": 25.0, "memory_percent": 50.0, "disk_percent": 30.0 } response = await client.get("/api/health") assert response.status_code == 200 class TestGlobalHealthCheck: """Tests pour GET /api/health/global.""" async def test_global_health_no_auth(self, client: AsyncClient): """Health check global ne requiert pas d'auth.""" # Remove API key headers = dict(client.headers) headers.pop("X-API-Key", None) response = await client.get("/api/health/global") assert response.status_code == 200 data = response.json() assert data["status"] == "ok" assert "timestamp" in data async def test_global_health_returns_service_name(self, client: AsyncClient): """Retourne le nom du service.""" response = await client.get("/api/health/global") assert response.status_code == 200 data = response.json() assert data["service"] == "homelab-automation-api" class TestHostHealthCheck: """Tests pour GET /api/health/{host_name}.""" async def test_health_check_host_not_found(self, client: AsyncClient): """Erreur si hôte non trouvé.""" with patch("app.routes.health.db") as mock_db: mock_db.hosts = [] response = await client.get("/api/health/nonexistent-host") assert response.status_code == 404 @pytest.mark.asyncio async def test_health_check_host_online(self, client: AsyncClient): """Health check pour hôte en ligne.""" mock_host = MagicMock() mock_host.name = "test-host" mock_host.status = "online" mock_host.os = "linux" with patch("app.routes.health.db") as mock_db, \ patch("app.routes.health.ws_manager") as mock_ws: mock_db.hosts = [mock_host] mock_db.update_host_status = MagicMock() mock_db.logs = MagicMock() mock_db.logs.insert = MagicMock() mock_ws.broadcast = AsyncMock() response = await client.get("/api/health/test-host") assert response.status_code == 200 data = response.json() assert data["host"] == "test-host" assert data["reachable"] is True @pytest.mark.asyncio async def test_health_check_host_offline(self, client: AsyncClient): """Health check pour hôte hors ligne.""" mock_host = MagicMock() mock_host.name = "offline-host" mock_host.status = "offline" mock_host.os = "linux" with patch("app.routes.health.db") as mock_db, \ patch("app.routes.health.ws_manager") as mock_ws: mock_db.hosts = [mock_host] mock_db.update_host_status = MagicMock() mock_db.logs = MagicMock() mock_db.logs.insert = MagicMock() mock_ws.broadcast = AsyncMock() response = await client.get("/api/health/offline-host") assert response.status_code == 200 data = response.json() assert data["reachable"] is False class TestRefreshHosts: """Tests pour POST /api/health/refresh.""" @pytest.mark.asyncio async def test_refresh_hosts(self, client: AsyncClient): """Refresh des hôtes depuis l'inventaire.""" with patch("app.services.ansible_service.ansible_service") as mock_ansible, \ patch("app.services.hybrid_db.db") as mock_db, \ patch("app.services.websocket_service.ws_manager") as mock_ws: mock_ansible.invalidate_cache = MagicMock() mock_db.refresh_hosts = MagicMock(return_value=[MagicMock(), MagicMock()]) mock_ws.broadcast = AsyncMock() response = await client.post("/api/health/refresh") assert response.status_code == 200 data = response.json() assert "message" in data