"""Tests for analysis sessions endpoints.""" import pytest from unittest.mock import AsyncMock import httpx from app.models.analysis import SessionResponse, SessionList, SessionCreate class TestAnalysisEndpoints: """Tests for /api/v1/analysis/sessions endpoints.""" def test_create_session_success(self, client, mock_db_client): """Test creating a new analysis session.""" mock_session = SessionResponse( session_id="session-123", user_id="test-user-123", environment="ift", api_mode="bench", request=[], response={}, annotations={}, created_at="2024-01-01T00:00:00Z", updated_at="2024-01-01T00:00:00Z" ) mock_db_client.save_session = AsyncMock(return_value=mock_session) session_data = { "environment": "ift", "api_mode": "bench", "request": [], "response": {"answers": []}, "annotations": {} } response = client.post("/api/v1/analysis/sessions", json=session_data) assert response.status_code == 201 data = response.json() assert data["session_id"] == "session-123" assert data["environment"] == "ift" assert data["api_mode"] == "bench" mock_db_client.save_session.assert_called_once() def test_create_session_invalid_data(self, client, mock_db_client): """Test creating session with invalid data.""" error_response = httpx.Response(400, json={"detail": "Invalid format"}) mock_db_client.save_session = AsyncMock( side_effect=httpx.HTTPStatusError("Bad request", request=None, response=error_response) ) session_data = { "environment": "invalid", "api_mode": "bench", "request": [], "response": {}, "annotations": {} } response = client.post("/api/v1/analysis/sessions", json=session_data) assert response.status_code in [400, 422] def test_get_sessions_success(self, client, mock_db_client): """Test getting list of sessions.""" from app.models.analysis import SessionListItem mock_sessions = SessionList( sessions=[ SessionListItem( session_id="session-1", environment="ift", created_at="2024-01-01T00:00:00Z" ), SessionListItem( session_id="session-2", environment="psi", created_at="2024-01-02T00:00:00Z" ) ], total=2 ) mock_db_client.get_sessions = AsyncMock(return_value=mock_sessions) response = client.get("/api/v1/analysis/sessions?limit=50&offset=0") assert response.status_code == 200 data = response.json() assert data["total"] == 2 assert len(data["sessions"]) == 2 assert data["sessions"][0]["session_id"] == "session-1" assert data["sessions"][1]["session_id"] == "session-2" mock_db_client.get_sessions.assert_called_once_with( "test-user-123", None, 50, 0 ) def test_get_sessions_with_filter(self, client, mock_db_client): """Test getting sessions with environment filter.""" mock_sessions = SessionList(sessions=[], total=0) mock_db_client.get_sessions = AsyncMock(return_value=mock_sessions) response = client.get("/api/v1/analysis/sessions?environment=ift&limit=10&offset=5") assert response.status_code == 200 mock_db_client.get_sessions.assert_called_once_with( "test-user-123", "ift", 10, 5 ) def test_get_sessions_pagination(self, client, mock_db_client): """Test sessions pagination limits.""" mock_sessions = SessionList(sessions=[], total=0) mock_db_client.get_sessions = AsyncMock(return_value=mock_sessions) response = client.get("/api/v1/analysis/sessions") assert response.status_code == 200 mock_db_client.get_sessions.assert_called_with( "test-user-123", None, 50, 0 ) response = client.get("/api/v1/analysis/sessions?limit=250") assert response.status_code == 422 def test_get_session_by_id_success(self, client, mock_db_client): """Test getting specific session by ID.""" mock_session = SessionResponse( session_id="session-123", user_id="test-user-123", environment="ift", api_mode="bench", request=[{"body": "Q1", "with_docs": True}], response={"answers": ["A1"]}, annotations={"note": "test"}, created_at="2024-01-01T00:00:00Z", updated_at="2024-01-01T00:00:00Z" ) mock_db_client.get_session = AsyncMock(return_value=mock_session) response = client.get("/api/v1/analysis/sessions/session-123") assert response.status_code == 200 data = response.json() assert data["session_id"] == "session-123" assert data["annotations"]["note"] == "test" mock_db_client.get_session.assert_called_once_with("test-user-123", "session-123") def test_get_session_not_found(self, client, mock_db_client): """Test getting non-existent session.""" error_response = httpx.Response(404, json={"detail": "Not found"}) mock_db_client.get_session = AsyncMock( side_effect=httpx.HTTPStatusError("Not found", request=None, response=error_response) ) response = client.get("/api/v1/analysis/sessions/nonexistent") assert response.status_code == 404 def test_delete_session_success(self, client, mock_db_client): """Test deleting a session.""" mock_db_client.delete_session = AsyncMock(return_value=None) response = client.delete("/api/v1/analysis/sessions/session-123") assert response.status_code == 204 assert response.content == b"" mock_db_client.delete_session.assert_called_once_with("test-user-123", "session-123") def test_delete_session_not_found(self, client, mock_db_client): """Test deleting non-existent session.""" error_response = httpx.Response(404, json={"detail": "Not found"}) mock_db_client.delete_session = AsyncMock( side_effect=httpx.HTTPStatusError("Not found", request=None, response=error_response) ) response = client.delete("/api/v1/analysis/sessions/nonexistent") assert response.status_code == 404 def test_analysis_endpoints_require_auth(self, unauthenticated_client): """Test that all analysis endpoints require authentication.""" response = unauthenticated_client.post("/api/v1/analysis/sessions", json={}) assert response.status_code == 401 response = unauthenticated_client.get("/api/v1/analysis/sessions") assert response.status_code == 401 response = unauthenticated_client.get("/api/v1/analysis/sessions/test") assert response.status_code == 401 response = unauthenticated_client.delete("/api/v1/analysis/sessions/test") assert response.status_code == 401 def test_create_session_user_not_found(self, client, mock_db_client): """Test creating session when user not found in DB API.""" error_response = httpx.Response(404, json={"detail": "User not found"}) mock_db_client.save_session = AsyncMock( side_effect=httpx.HTTPStatusError("Not found", request=None, response=error_response) ) session_data = { "environment": "ift", "api_mode": "bench", "request": [], "response": {}, "annotations": {} } response = client.post("/api/v1/analysis/sessions", json=session_data) assert response.status_code == 404 assert "user not found" in response.json()["detail"].lower() def test_create_session_db_api_error(self, client, mock_db_client): """Test creating session when DB API returns 502.""" error_response = httpx.Response(503, json={"detail": "Service unavailable"}) mock_db_client.save_session = AsyncMock( side_effect=httpx.HTTPStatusError("Service error", request=None, response=error_response) ) session_data = { "environment": "ift", "api_mode": "bench", "request": [], "response": {}, "annotations": {} } response = client.post("/api/v1/analysis/sessions", json=session_data) assert response.status_code == 502 def test_create_session_unexpected_error(self, client, mock_db_client): """Test creating session with unexpected error.""" mock_db_client.save_session = AsyncMock( side_effect=Exception("Unexpected database error") ) session_data = { "environment": "ift", "api_mode": "bench", "request": [], "response": {}, "annotations": {} } response = client.post("/api/v1/analysis/sessions", json=session_data) assert response.status_code == 500 def test_get_sessions_user_not_found(self, client, mock_db_client): """Test getting sessions when user not found.""" error_response = httpx.Response(404, json={"detail": "User not found"}) mock_db_client.get_sessions = AsyncMock( side_effect=httpx.HTTPStatusError("Not found", request=None, response=error_response) ) response = client.get("/api/v1/analysis/sessions") assert response.status_code == 404 def test_get_sessions_db_api_error(self, client, mock_db_client): """Test getting sessions when DB API fails.""" error_response = httpx.Response(503, json={"detail": "Service error"}) mock_db_client.get_sessions = AsyncMock( side_effect=httpx.HTTPStatusError("Service error", request=None, response=error_response) ) response = client.get("/api/v1/analysis/sessions") assert response.status_code == 502 def test_get_sessions_unexpected_error(self, client, mock_db_client): """Test getting sessions with unexpected error.""" mock_db_client.get_sessions = AsyncMock( side_effect=Exception("Database connection lost") ) response = client.get("/api/v1/analysis/sessions") assert response.status_code == 500 def test_get_session_by_id_db_api_error(self, client, mock_db_client): """Test getting session when DB API returns 502.""" error_response = httpx.Response(500, json={"error": "Server error"}) mock_db_client.get_session = AsyncMock( side_effect=httpx.HTTPStatusError("Server error", request=None, response=error_response) ) response = client.get("/api/v1/analysis/sessions/session-123") assert response.status_code == 502 assert "failed to retrieve session" in response.json()["detail"].lower() def test_get_session_by_id_unexpected_error(self, client, mock_db_client): """Test getting session with unexpected error.""" mock_db_client.get_session = AsyncMock(side_effect=Exception("Database crash")) response = client.get("/api/v1/analysis/sessions/session-123") assert response.status_code == 500 assert "internal server error" in response.json()["detail"].lower() def test_delete_session_db_api_error(self, client, mock_db_client): """Test deleting session when DB API returns 502.""" error_response = httpx.Response(500, json={"error": "Server error"}) mock_db_client.delete_session = AsyncMock( side_effect=httpx.HTTPStatusError("Server error", request=None, response=error_response) ) response = client.delete("/api/v1/analysis/sessions/session-123") assert response.status_code == 502 assert "failed to delete session" in response.json()["detail"].lower() def test_delete_session_unexpected_error(self, client, mock_db_client): """Test deleting session with unexpected error.""" mock_db_client.delete_session = AsyncMock(side_effect=Exception("Database crash")) response = client.delete("/api/v1/analysis/sessions/session-123") assert response.status_code == 500 assert "internal server error" in response.json()["detail"].lower()