""" Tests for the /api/v1/imap endpoints. Covers connection testing, report fetching (foreground and background), and status. """ from unittest.mock import MagicMock, patch from fastapi.testclient import TestClient class TestImapTestConnection: """Tests for POST /api/v1/imap/test-connection""" def test_successful_connection(self, authed_client: TestClient): mock_client = MagicMock() mock_client.test_connection.return_value = ( True, "Connection successful", { "message_count": 5, "unread_count": 2, "dmarc_count": 1, "available_mailboxes": ["INBOX", "Sent"], "server": "imap.example.com", "port": 993, }, ) with patch("app.api.api_v1.endpoints.imap.IMAPClient", return_value=mock_client): response = authed_client.post( "/api/v1/imap/test-connection", json={ "server": "imap.example.com", "port": 993, "username": "user@example.com", "password": "secret", "ssl": True, }, ) assert response.status_code == 200 data = response.json() assert data["success"] is True assert data["message_count"] == 5 assert data["unread_count"] == 2 assert "INBOX" in data["available_mailboxes"] def test_failed_connection(self, authed_client: TestClient): mock_client = MagicMock() mock_client.test_connection.return_value = (False, "Connection failed", {}) with patch("app.api.api_v1.endpoints.imap.IMAPClient", return_value=mock_client): response = authed_client.post( "/api/v1/imap/test-connection", json={"server": "bad.example.com", "port": 993}, ) assert response.status_code == 200 data = response.json() assert data["success"] is False assert data["message_count"] == 0 def test_requires_auth(self, client: TestClient): """Without auth, the endpoint should return 401.""" response = client.post( "/api/v1/imap/test-connection", json={"server": "imap.example.com", "port": 993}, ) assert response.status_code == 401 class TestImapFetchReports: """Tests for POST /api/v1/imap/fetch-reports""" def test_fetch_foreground_success(self, authed_client: TestClient): mock_client = MagicMock() mock_client.fetch_reports.return_value = { "success": True, "processed": 3, "reports_found": 2, "new_domains": ["example.com"], "errors": [], } with patch("app.api.api_v1.endpoints.imap.IMAPClient", return_value=mock_client): response = authed_client.post("/api/v1/imap/fetch-reports?days=7") assert response.status_code == 200 data = response.json() assert data["success"] is True assert data["processed_emails"] == 3 assert data["reports_found"] == 2 def test_fetch_days_too_low(self, authed_client: TestClient): response = authed_client.post("/api/v1/imap/fetch-reports?days=0") assert response.status_code == 400 def test_fetch_days_too_high(self, authed_client: TestClient): response = authed_client.post("/api/v1/imap/fetch-reports?days=400") assert response.status_code == 400 def test_fetch_background_for_long_range(self, authed_client: TestClient): """Days > 14 should queue a background task.""" mock_client = MagicMock() with patch("app.api.api_v1.endpoints.imap.IMAPClient", return_value=mock_client): response = authed_client.post("/api/v1/imap/fetch-reports?days=30") assert response.status_code == 200 data = response.json() assert data["success"] is True assert "background" in data["message"].lower() def test_fetch_with_errors_in_result(self, authed_client: TestClient): mock_client = MagicMock() mock_client.fetch_reports.return_value = { "success": True, "processed": 1, "reports_found": 0, "new_domains": [], "errors": ["Could not parse email 1"], } with patch("app.api.api_v1.endpoints.imap.IMAPClient", return_value=mock_client): response = authed_client.post("/api/v1/imap/fetch-reports?days=3") assert response.status_code == 200 data = response.json() assert data["errors"] is not None def test_fetch_exception_returns_500(self, authed_client: TestClient): mock_client = MagicMock() mock_client.fetch_reports.side_effect = RuntimeError("unexpected") with patch("app.api.api_v1.endpoints.imap.IMAPClient", return_value=mock_client): response = authed_client.post("/api/v1/imap/fetch-reports?days=5") assert response.status_code == 500 def test_requires_auth(self, client: TestClient): response = client.post("/api/v1/imap/fetch-reports?days=7") assert response.status_code == 401 class TestImapStatus: """Tests for GET /api/v1/imap/status""" def test_status_returns_200(self, authed_client: TestClient): response = authed_client.get("/api/v1/imap/status") assert response.status_code == 200 def test_status_response_structure(self, authed_client: TestClient): response = authed_client.get("/api/v1/imap/status") data = response.json() assert "is_running" in data assert "timestamp" in data def test_requires_auth(self, client: TestClient): response = client.get("/api/v1/imap/status") assert response.status_code == 401