"""Tests for Docker API routes.""" import pytest from unittest.mock import AsyncMock, patch, MagicMock from httpx import AsyncClient class TestDockerHostsRoutes: """Tests for Docker hosts endpoints.""" @pytest.mark.asyncio async def test_list_docker_hosts(self, client: AsyncClient, api_key_header): """Test listing Docker hosts.""" with patch('app.services.docker_service.docker_service.get_docker_hosts', new_callable=AsyncMock) as mock: mock.return_value = [ { "host_id": "host-1", "host_name": "server1", "host_ip": "192.168.1.10", "docker_enabled": True, "docker_version": "24.0.7", "docker_status": "online", "docker_last_collect_at": None, "containers_total": 5, "containers_running": 3, "images_total": 10, "volumes_total": 2, "open_alerts": 0 }, { "host_id": "host-2", "host_name": "server2", "host_ip": "192.168.1.11", "docker_enabled": False, "docker_version": None, "docker_status": None, "docker_last_collect_at": None, "containers_total": 0, "containers_running": 0, "images_total": 0, "volumes_total": 0, "open_alerts": 0 } ] response = await client.get("/api/docker/hosts", headers=api_key_header) assert response.status_code == 200 data = response.json() assert "hosts" in data assert len(data["hosts"]) == 2 assert data["hosts"][0]["host_name"] == "server1" hosts_by_id = {h["host_id"]: h for h in data["hosts"]} assert hosts_by_id["host-1"]["docker_enabled"] is True assert hosts_by_id["host-2"]["docker_enabled"] is False @pytest.mark.asyncio async def test_enable_docker_monitoring(self, client: AsyncClient, api_key_header): """Test enabling Docker monitoring on a host.""" with patch('app.services.docker_service.docker_service.enable_docker_monitoring', new_callable=AsyncMock) as mock: mock.return_value = True response = await client.post( "/api/docker/hosts/host-1/enable", headers=api_key_header, json={"enabled": True} ) assert response.status_code == 200 data = response.json() assert "message" in data @pytest.mark.asyncio async def test_collect_docker_now(self, client: AsyncClient, api_key_header): """Test forcing Docker collection on a host.""" with patch('app.services.docker_service.docker_service.collect_docker_host', new_callable=AsyncMock) as mock: mock.return_value = { "success": True, "host_id": "host-1", "host_name": "server1", "docker_version": "24.0.7", "containers_count": 5, "images_count": 10, "volumes_count": 2, "duration_ms": 1500, "error": None } response = await client.post( "/api/docker/hosts/host-1/collect", headers=api_key_header ) assert response.status_code == 200 data = response.json() assert data["success"] is True assert data["containers_count"] == 5 class TestDockerContainersRoutes: """Tests for Docker containers endpoints.""" @pytest.mark.asyncio async def test_list_containers(self, client: AsyncClient, api_key_header, db_session): """Test listing containers for a host.""" # This test would require setting up container data in the database # For now, test that the endpoint returns correctly structured data response = await client.get( "/api/docker/hosts/host-1/containers", headers=api_key_header ) assert response.status_code == 200 data = response.json() assert "containers" in data assert "total" in data assert "running" in data @pytest.mark.asyncio async def test_start_container(self, client: AsyncClient, api_key_header): """Test starting a container.""" with patch('app.services.docker_actions.docker_actions.start_container', new_callable=AsyncMock) as mock: mock.return_value = { "success": True, "message": "Container started successfully", "container_id": "abc123", "action": "start", "output": "abc123", "error": None } response = await client.post( "/api/docker/containers/host-1/abc123/start", headers=api_key_header ) assert response.status_code == 200 data = response.json() assert data["success"] is True assert data["action"] == "start" @pytest.mark.asyncio async def test_stop_container(self, client: AsyncClient, api_key_header): """Test stopping a container.""" with patch('app.services.docker_actions.docker_actions.stop_container', new_callable=AsyncMock) as mock: mock.return_value = { "success": True, "message": "Container stopped successfully", "container_id": "abc123", "action": "stop", "output": "abc123", "error": None } response = await client.post( "/api/docker/containers/host-1/abc123/stop", headers=api_key_header ) assert response.status_code == 200 data = response.json() assert data["success"] is True assert data["action"] == "stop" @pytest.mark.asyncio async def test_restart_container(self, client: AsyncClient, api_key_header): """Test restarting a container.""" with patch('app.services.docker_actions.docker_actions.restart_container', new_callable=AsyncMock) as mock: mock.return_value = { "success": True, "message": "Container restarted successfully", "container_id": "abc123", "action": "restart", "output": "abc123", "error": None } response = await client.post( "/api/docker/containers/host-1/abc123/restart", headers=api_key_header ) assert response.status_code == 200 data = response.json() assert data["success"] is True assert data["action"] == "restart" @pytest.mark.asyncio async def test_get_container_logs(self, client: AsyncClient, api_key_header): """Test getting container logs.""" with patch('app.services.docker_actions.docker_actions.get_container_logs', new_callable=AsyncMock) as mock: mock.return_value = { "container_id": "abc123", "container_name": "nginx", "logs": "2024-01-15 10:00:00 Starting nginx...\n2024-01-15 10:00:01 Ready", "lines": 2 } response = await client.get( "/api/docker/containers/host-1/abc123/logs?tail=100", headers=api_key_header ) assert response.status_code == 200 data = response.json() assert "logs" in data assert data["lines"] == 2 class TestDockerAlertsRoutes: """Tests for Docker alerts endpoints.""" @pytest.mark.asyncio async def test_list_alerts(self, client: AsyncClient, api_key_header): """Test listing Docker alerts.""" with patch('app.services.docker_alerts.docker_alerts_service.get_alerts', new_callable=AsyncMock) as mock: mock.return_value = { "alerts": [ { "id": 1, "host_id": "host-1", "host_name": "server1", "container_name": "nginx", "severity": "error", "state": "open", "message": "Container is down", "opened_at": "2024-01-15T10:00:00Z" } ], "total": 1, "open_count": 1, "acknowledged_count": 0 } response = await client.get( "/api/docker/alerts", headers=api_key_header ) assert response.status_code == 200 data = response.json() assert "alerts" in data assert data["total"] == 1 assert data["open_count"] == 1 @pytest.mark.asyncio async def test_acknowledge_alert(self, client: AsyncClient, api_key_header): """Test acknowledging an alert.""" with patch('app.services.docker_alerts.docker_alerts_service.acknowledge_alert', new_callable=AsyncMock) as mock: mock.return_value = { "id": 1, "state": "acknowledged", "acknowledged_by": "admin", "acknowledged_at": "2024-01-15T10:30:00Z" } response = await client.post( "/api/docker/alerts/1/acknowledge", headers=api_key_header, json={"note": "Investigating"} ) assert response.status_code == 200 data = response.json() assert "alert" in data @pytest.mark.asyncio async def test_close_alert(self, client: AsyncClient, api_key_header): """Test closing an alert.""" with patch('app.services.docker_alerts.docker_alerts_service.close_alert', new_callable=AsyncMock) as mock: mock.return_value = { "id": 1, "state": "closed", "closed_at": "2024-01-15T11:00:00Z" } response = await client.post( "/api/docker/alerts/1/close", headers=api_key_header ) assert response.status_code == 200 data = response.json() assert "alert" in data class TestDockerStatsRoute: """Tests for Docker stats endpoint.""" @pytest.mark.asyncio async def test_get_docker_stats(self, client: AsyncClient, api_key_header): """Test getting global Docker statistics.""" with patch('app.services.docker_alerts.docker_alerts_service.get_stats', new_callable=AsyncMock) as mock: mock.return_value = { "total_hosts": 5, "enabled_hosts": 3, "online_hosts": 2, "total_containers": 25, "running_containers": 20, "total_images": 50, "total_volumes": 10, "open_alerts": 2, "last_collection": "2024-01-15T10:00:00Z" } response = await client.get( "/api/docker/stats", headers=api_key_header ) assert response.status_code == 200 data = response.json() assert data["total_hosts"] == 5 assert data["running_containers"] == 20 assert data["open_alerts"] == 2