homelab_automation/tests/backend/test_routes_alerts.py
Bruno Charest ecefbc8611
Some checks failed
Tests / Backend Tests (Python) (3.10) (push) Has been cancelled
Tests / Backend Tests (Python) (3.11) (push) Has been cancelled
Tests / Backend Tests (Python) (3.12) (push) Has been cancelled
Tests / Frontend Tests (JS) (push) Has been cancelled
Tests / Integration Tests (push) Has been cancelled
Tests / All Tests Passed (push) Has been cancelled
Clean up test files and debug artifacts, add node_modules to gitignore, export DashboardManager for testing, and enhance pytest configuration with comprehensive test markers and settings
2025-12-15 08:15:49 -05:00

246 lines
8.7 KiB
Python

"""
Tests pour les routes de gestion des alertes.
Couvre:
- Création d'alertes
- Liste des alertes
- Comptage non lues
- Marquage comme lues
"""
import pytest
from unittest.mock import patch, AsyncMock
from httpx import AsyncClient
pytestmark = pytest.mark.unit
class TestCreateAlert:
"""Tests pour POST /api/alerts."""
@pytest.mark.asyncio
async def test_create_alert_success(self, client: AsyncClient, db_session):
"""Création d'alerte réussie."""
with patch("app.routes.alerts.ws_manager") as mock_ws:
mock_ws.broadcast = AsyncMock()
response = await client.post(
"/api/alerts",
json={
"category": "system",
"level": "warning",
"title": "Test Alert",
"message": "This is a test alert"
}
)
assert response.status_code == 200
data = response.json()
assert data["title"] == "Test Alert"
assert data["message"] == "This is a test alert"
assert data["level"] == "warning"
@pytest.mark.asyncio
async def test_create_alert_minimal(self, client: AsyncClient, db_session):
"""Création avec champs minimaux."""
with patch("app.routes.alerts.ws_manager") as mock_ws:
mock_ws.broadcast = AsyncMock()
response = await client.post(
"/api/alerts",
json={"message": "Minimal alert"}
)
assert response.status_code == 200
data = response.json()
assert data["message"] == "Minimal alert"
assert data["category"] == "general" # default
@pytest.mark.asyncio
async def test_create_alert_broadcasts_ws(self, client: AsyncClient, db_session):
"""Création broadcast via WebSocket."""
with patch("app.routes.alerts.ws_manager") as mock_ws:
mock_ws.broadcast = AsyncMock()
await client.post(
"/api/alerts",
json={"message": "WS test alert"}
)
mock_ws.broadcast.assert_called_once()
call_args = mock_ws.broadcast.call_args[0][0]
assert call_args["type"] == "alert_created"
class TestGetAlerts:
"""Tests pour GET /api/alerts."""
async def test_list_alerts_empty(self, client: AsyncClient, db_session):
"""Liste vide quand pas d'alertes."""
response = await client.get("/api/alerts")
assert response.status_code == 200
data = response.json()
assert "alerts" in data
assert "count" in data
@pytest.mark.asyncio
async def test_list_alerts_with_data(self, client: AsyncClient, db_session):
"""Liste les alertes depuis la BD."""
with patch("app.routes.alerts.ws_manager") as mock_ws:
mock_ws.broadcast = AsyncMock()
await client.post("/api/alerts", json={"message": "Alert 1"})
await client.post("/api/alerts", json={"message": "Alert 2"})
response = await client.get("/api/alerts")
assert response.status_code == 200
data = response.json()
assert data["count"] >= 2
async def test_list_alerts_with_pagination(self, client: AsyncClient, db_session):
"""Pagination fonctionne."""
response = await client.get("/api/alerts?limit=5&offset=0")
assert response.status_code == 200
data = response.json()
assert "alerts" in data
async def test_list_alerts_unread_only(self, client: AsyncClient, db_session):
"""Filtre alertes non lues."""
response = await client.get("/api/alerts?unread_only=true")
assert response.status_code == 200
class TestUnreadCount:
"""Tests pour GET /api/alerts/unread-count."""
@pytest.mark.asyncio
async def test_unread_count(self, client: AsyncClient, db_session):
"""Comptage des alertes non lues."""
with patch("app.routes.alerts.ws_manager") as mock_ws:
mock_ws.broadcast = AsyncMock()
# Create an alert first
await client.post("/api/alerts", json={"message": "Test alert"})
response = await client.get("/api/alerts/unread-count")
assert response.status_code == 200
data = response.json()
# Response has 'unread' key instead of 'count'
assert "unread" in data or "count" in data
class TestMarkAsRead:
"""Tests pour POST /api/alerts/{alert_id}/read."""
@pytest.mark.asyncio
async def test_mark_as_read_success(self, client: AsyncClient, db_session):
"""Marquer une alerte comme lue."""
with patch("app.routes.alerts.ws_manager") as mock_ws:
mock_ws.broadcast = AsyncMock()
create_response = await client.post(
"/api/alerts",
json={"message": "Alert to mark as read"}
)
alert_id = create_response.json()["id"]
response = await client.post(f"/api/alerts/{alert_id}/read")
assert response.status_code == 200
data = response.json()
assert str(data["id"]) == str(alert_id)
assert "message" in data
@pytest.mark.asyncio
async def test_mark_as_read_not_found(self, client: AsyncClient, db_session):
"""Marquer une alerte inexistante retourne 404."""
response = await client.post("/api/alerts/nonexistent-id/read")
assert response.status_code == 404
assert "non trouvée" in response.json()["detail"]
class TestMarkAllAsRead:
"""Tests pour POST /api/alerts/mark-all-read."""
@pytest.mark.asyncio
async def test_mark_all_as_read_success(self, client: AsyncClient, db_session):
"""Marquer toutes les alertes comme lues."""
with patch("app.routes.alerts.ws_manager") as mock_ws:
mock_ws.broadcast = AsyncMock()
# Create some alerts
await client.post("/api/alerts", json={"message": "Alert 1"})
await client.post("/api/alerts", json={"message": "Alert 2"})
response = await client.post("/api/alerts/mark-all-read")
assert response.status_code == 200
data = response.json()
assert "message" in data
@pytest.mark.asyncio
async def test_mark_all_as_read_broadcasts_ws(self, client: AsyncClient, db_session):
"""Marquer tout comme lu broadcast via WebSocket."""
with patch("app.routes.alerts.ws_manager") as mock_ws:
mock_ws.broadcast = AsyncMock()
await client.post("/api/alerts", json={"message": "Alert"})
await client.post("/api/alerts/mark-all-read")
# Should have been called for create and for mark-all-read
assert mock_ws.broadcast.call_count >= 1
class TestDeleteAlert:
"""Tests pour DELETE /api/alerts/{alert_id}."""
@pytest.mark.asyncio
async def test_delete_alert_success(self, client: AsyncClient, db_session):
"""Suppression d'une alerte réussie."""
with patch("app.routes.alerts.ws_manager") as mock_ws:
mock_ws.broadcast = AsyncMock()
create_response = await client.post(
"/api/alerts",
json={"message": "Alert to delete"}
)
alert_id = create_response.json()["id"]
response = await client.delete(f"/api/alerts/{alert_id}")
assert response.status_code == 200
data = response.json()
assert str(data["id"]) == str(alert_id)
assert "supprimée" in data["message"].lower() or "message" in data
@pytest.mark.asyncio
async def test_delete_alert_not_found(self, client: AsyncClient, db_session):
"""Suppression d'une alerte inexistante retourne 404."""
response = await client.delete("/api/alerts/nonexistent-id")
assert response.status_code == 404
assert "non trouvée" in response.json()["detail"]
@pytest.mark.asyncio
async def test_delete_alert_verify_removed(self, client: AsyncClient, db_session):
"""Vérifier que l'alerte est bien supprimée."""
with patch("app.routes.alerts.ws_manager") as mock_ws:
mock_ws.broadcast = AsyncMock()
create_response = await client.post(
"/api/alerts",
json={"message": "Alert to verify deletion"}
)
alert_id = create_response.json()["id"]
# Delete
await client.delete(f"/api/alerts/{alert_id}")
# Try to mark as read - should fail
response = await client.post(f"/api/alerts/{alert_id}/read")
assert response.status_code == 404