""" Tests pour les routes ad-hoc history. """ import pytest from unittest.mock import patch, AsyncMock, MagicMock from httpx import AsyncClient pytestmark = pytest.mark.unit class TestGetAdhocHistory: """Tests pour GET /api/adhoc/history.""" @pytest.mark.asyncio async def test_get_history_empty(self, client: AsyncClient): """Historique vide.""" with patch("app.routes.adhoc.adhoc_history_service") as mock_service: mock_service.get_commands = AsyncMock(return_value=[]) response = await client.get("/api/adhoc/history") assert response.status_code == 200 data = response.json() assert "commands" in data assert "count" in data assert data["count"] == 0 @pytest.mark.asyncio async def test_get_history_with_data(self, client: AsyncClient): """Historique avec données.""" mock_cmd = MagicMock() mock_cmd.dict.return_value = { "id": "cmd-1", "command": "ping -c 1 host", "category": "network" } with patch("app.routes.adhoc.adhoc_history_service") as mock_service: mock_service.get_commands = AsyncMock(return_value=[mock_cmd]) response = await client.get("/api/adhoc/history") assert response.status_code == 200 data = response.json() assert data["count"] == 1 assert len(data["commands"]) == 1 @pytest.mark.asyncio async def test_get_history_with_category_filter(self, client: AsyncClient): """Historique filtré par catégorie.""" with patch("app.routes.adhoc.adhoc_history_service") as mock_service: mock_service.get_commands = AsyncMock(return_value=[]) response = await client.get("/api/adhoc/history?category=network") assert response.status_code == 200 mock_service.get_commands.assert_called_once() call_kwargs = mock_service.get_commands.call_args[1] assert call_kwargs["category"] == "network" @pytest.mark.asyncio async def test_get_history_with_search(self, client: AsyncClient): """Historique avec recherche.""" with patch("app.routes.adhoc.adhoc_history_service") as mock_service: mock_service.get_commands = AsyncMock(return_value=[]) response = await client.get("/api/adhoc/history?search=ping") assert response.status_code == 200 call_kwargs = mock_service.get_commands.call_args[1] assert call_kwargs["search"] == "ping" @pytest.mark.asyncio async def test_get_history_with_limit(self, client: AsyncClient): """Historique avec limite.""" with patch("app.routes.adhoc.adhoc_history_service") as mock_service: mock_service.get_commands = AsyncMock(return_value=[]) response = await client.get("/api/adhoc/history?limit=10") assert response.status_code == 200 call_kwargs = mock_service.get_commands.call_args[1] assert call_kwargs["limit"] == 10 class TestGetAdhocCategories: """Tests pour GET /api/adhoc/categories.""" @pytest.mark.asyncio async def test_get_categories_empty(self, client: AsyncClient): """Liste de catégories vide.""" with patch("app.routes.adhoc.adhoc_history_service") as mock_service: mock_service.get_categories = AsyncMock(return_value=[]) response = await client.get("/api/adhoc/categories") assert response.status_code == 200 data = response.json() assert "categories" in data assert data["categories"] == [] @pytest.mark.asyncio async def test_get_categories_with_data(self, client: AsyncClient): """Liste de catégories avec données.""" mock_cat = MagicMock() mock_cat.dict.return_value = { "name": "network", "description": "Network commands", "color": "#7c3aed", "icon": "fa-network" } with patch("app.routes.adhoc.adhoc_history_service") as mock_service: mock_service.get_categories = AsyncMock(return_value=[mock_cat]) response = await client.get("/api/adhoc/categories") assert response.status_code == 200 data = response.json() assert len(data["categories"]) == 1 class TestCreateAdhocCategory: """Tests pour POST /api/adhoc/categories.""" @pytest.mark.asyncio async def test_create_category_success(self, client: AsyncClient): """Création de catégorie réussie.""" mock_cat = MagicMock() mock_cat.dict.return_value = { "name": "new-category", "description": "Test category", "color": "#7c3aed", "icon": "fa-folder" } with patch("app.routes.adhoc.adhoc_history_service") as mock_service: mock_service.add_category = AsyncMock(return_value=mock_cat) response = await client.post( "/api/adhoc/categories?name=new-category&description=Test%20category" ) assert response.status_code == 200 data = response.json() assert "category" in data assert "message" in data class TestUpdateAdhocCategory: """Tests pour PUT /api/adhoc/categories/{category_name}.""" @pytest.mark.asyncio async def test_update_category_success(self, client: AsyncClient): """Mise à jour de catégorie réussie.""" with patch("app.routes.adhoc.adhoc_history_service") as mock_service: mock_service.update_category = AsyncMock(return_value=True) response = await client.put( "/api/adhoc/categories/old-name", json={"name": "new-name", "description": "Updated"} ) assert response.status_code == 200 data = response.json() assert data["category"] == "new-name" @pytest.mark.asyncio async def test_update_category_not_found(self, client: AsyncClient): """Catégorie non trouvée.""" with patch("app.routes.adhoc.adhoc_history_service") as mock_service: mock_service.update_category = AsyncMock(return_value=False) response = await client.put( "/api/adhoc/categories/nonexistent", json={"name": "new-name"} ) # 404 or 400 depending on error handling assert response.status_code in [400, 404] class TestDeleteAdhocCategory: """Tests pour DELETE /api/adhoc/categories/{category_name}.""" @pytest.mark.asyncio async def test_delete_category_success(self, client: AsyncClient): """Suppression de catégorie réussie.""" with patch("app.routes.adhoc.adhoc_history_service") as mock_service: mock_service.delete_category = AsyncMock(return_value=True) response = await client.delete("/api/adhoc/categories/old-category") assert response.status_code == 200 data = response.json() assert "message" in data @pytest.mark.asyncio async def test_delete_default_category_fails(self, client: AsyncClient): """Suppression de la catégorie default échoue.""" response = await client.delete("/api/adhoc/categories/default") assert response.status_code == 400 @pytest.mark.asyncio async def test_delete_category_not_found(self, client: AsyncClient): """Catégorie non trouvée.""" with patch("app.routes.adhoc.adhoc_history_service") as mock_service: mock_service.delete_category = AsyncMock(return_value=False) response = await client.delete("/api/adhoc/categories/nonexistent") assert response.status_code == 404 class TestUpdateCommandCategory: """Tests pour PUT /api/adhoc/history/{command_id}/category.""" @pytest.mark.asyncio async def test_update_command_category_success(self, client: AsyncClient): """Mise à jour de catégorie de commande réussie.""" with patch("app.routes.adhoc.adhoc_history_service") as mock_service: mock_service.update_command_category = AsyncMock(return_value=True) response = await client.put( "/api/adhoc/history/cmd-123/category?category=network" ) assert response.status_code == 200 data = response.json() assert data["command_id"] == "cmd-123" assert data["category"] == "network" @pytest.mark.asyncio async def test_update_command_category_not_found(self, client: AsyncClient): """Commande non trouvée.""" with patch("app.routes.adhoc.adhoc_history_service") as mock_service: mock_service.update_command_category = AsyncMock(return_value=False) response = await client.put( "/api/adhoc/history/nonexistent/category?category=network" ) assert response.status_code == 404 class TestDeleteAdhocCommand: """Tests pour DELETE /api/adhoc/history/{command_id}.""" @pytest.mark.asyncio async def test_delete_command_success(self, client: AsyncClient): """Suppression de commande réussie.""" with patch("app.routes.adhoc.adhoc_history_service") as mock_service: mock_service.delete_command = AsyncMock(return_value=True) response = await client.delete("/api/adhoc/history/cmd-123") assert response.status_code == 200 data = response.json() assert data["command_id"] == "cmd-123" @pytest.mark.asyncio async def test_delete_command_not_found(self, client: AsyncClient): """Commande non trouvée.""" with patch("app.routes.adhoc.adhoc_history_service") as mock_service: mock_service.delete_command = AsyncMock(return_value=False) response = await client.delete("/api/adhoc/history/nonexistent") assert response.status_code == 404