""" Tests for FastAPI endpoints """ import pytest from fastapi.testclient import TestClient from main import app, sessions @pytest.fixture def client(): """Create a test client""" return TestClient(app) @pytest.fixture(autouse=True) def clear_sessions(): """Clear sessions before each test""" sessions.clear() yield sessions.clear() class TestSessionEndpoints: """Test session-related endpoints""" def test_create_session(self, client): """Test creating a new session""" response = client.post("/sessions/?name=TestSession") assert response.status_code == 200 data = response.json() assert data["name"] == "TestSession" assert "id" in data assert data["characters"] == {} assert data["current_scene"] == "" assert data["scene_history"] == [] assert data["public_messages"] == [] def test_create_session_generates_unique_ids(self, client): """Test that each session gets a unique ID""" response1 = client.post("/sessions/?name=Session1") response2 = client.post("/sessions/?name=Session2") assert response1.status_code == 200 assert response2.status_code == 200 id1 = response1.json()["id"] id2 = response2.json()["id"] assert id1 != id2 def test_get_session(self, client): """Test retrieving a session""" # Create session create_response = client.post("/sessions/?name=TestSession") session_id = create_response.json()["id"] # Get session get_response = client.get(f"/sessions/{session_id}") assert get_response.status_code == 200 data = get_response.json() assert data["id"] == session_id assert data["name"] == "TestSession" def test_get_nonexistent_session(self, client): """Test getting a session that doesn't exist""" response = client.get("/sessions/fake-id-12345") assert response.status_code == 404 assert "not found" in response.json()["detail"].lower() class TestCharacterEndpoints: """Test character-related endpoints""" def test_add_character_minimal(self, client): """Test adding a character with minimal info""" # Create session session_response = client.post("/sessions/?name=TestSession") session_id = session_response.json()["id"] # Add character response = client.post( f"/sessions/{session_id}/characters/", params={ "name": "Gandalf", "description": "A wise wizard" } ) assert response.status_code == 200 data = response.json() assert data["name"] == "Gandalf" assert data["description"] == "A wise wizard" assert data["personality"] == "" assert data["llm_model"] == "gpt-3.5-turbo" assert "id" in data def test_add_character_full(self, client): """Test adding a character with all fields""" # Create session session_response = client.post("/sessions/?name=TestSession") session_id = session_response.json()["id"] # Add character response = client.post( f"/sessions/{session_id}/characters/", params={ "name": "Aragorn", "description": "A ranger", "personality": "Brave and noble", "llm_model": "gpt-4" } ) assert response.status_code == 200 data = response.json() assert data["name"] == "Aragorn" assert data["personality"] == "Brave and noble" assert data["llm_model"] == "gpt-4" def test_add_character_to_nonexistent_session(self, client): """Test adding a character to a session that doesn't exist""" response = client.post( "/sessions/fake-id/characters/", params={ "name": "Test", "description": "Test" } ) assert response.status_code == 404 def test_add_multiple_characters(self, client): """Test adding multiple characters to a session""" # Create session session_response = client.post("/sessions/?name=TestSession") session_id = session_response.json()["id"] # Add first character char1_response = client.post( f"/sessions/{session_id}/characters/", params={"name": "Frodo", "description": "A hobbit"} ) # Add second character char2_response = client.post( f"/sessions/{session_id}/characters/", params={"name": "Sam", "description": "Loyal friend"} ) assert char1_response.status_code == 200 assert char2_response.status_code == 200 # Verify different IDs char1_id = char1_response.json()["id"] char2_id = char2_response.json()["id"] assert char1_id != char2_id # Verify both in session session = client.get(f"/sessions/{session_id}").json() assert len(session["characters"]) == 2 assert char1_id in session["characters"] assert char2_id in session["characters"] def test_get_character_conversation(self, client): """Test getting a character's conversation history""" # Create session and character session_response = client.post("/sessions/?name=TestSession") session_id = session_response.json()["id"] char_response = client.post( f"/sessions/{session_id}/characters/", params={"name": "Test", "description": "Test"} ) char_id = char_response.json()["id"] # Get conversation conv_response = client.get( f"/sessions/{session_id}/characters/{char_id}/conversation" ) assert conv_response.status_code == 200 data = conv_response.json() assert "character" in data assert "conversation" in data assert "pending_response" in data assert data["character"]["name"] == "Test" assert data["conversation"] == [] assert data["pending_response"] is False class TestModelsEndpoint: """Test LLM models endpoint""" def test_get_models(self, client): """Test getting available models""" response = client.get("/models") assert response.status_code == 200 data = response.json() assert "openai" in data assert "openrouter" in data assert isinstance(data["openai"], list) assert isinstance(data["openrouter"], list) def test_models_include_required_fields(self, client): """Test that model objects have required fields""" response = client.get("/models") data = response.json() # Check OpenAI models if available if len(data["openai"]) > 0: model = data["openai"][0] assert "id" in model assert "name" in model assert "provider" in model assert model["provider"] == "OpenAI" # Check OpenRouter models if available if len(data["openrouter"]) > 0: model = data["openrouter"][0] assert "id" in model assert "name" in model assert "provider" in model class TestPendingMessages: """Test pending messages endpoint""" def test_get_pending_messages_empty(self, client): """Test getting pending messages when there are none""" # Create session session_response = client.post("/sessions/?name=TestSession") session_id = session_response.json()["id"] response = client.get(f"/sessions/{session_id}/pending_messages") assert response.status_code == 200 assert response.json() == {} def test_get_pending_messages_nonexistent_session(self, client): """Test getting pending messages for nonexistent session""" response = client.get("/sessions/fake-id/pending_messages") assert response.status_code == 404 class TestSessionState: """Test session state integrity""" def test_session_persists_in_memory(self, client): """Test that session state persists across requests""" # Create session create_response = client.post("/sessions/?name=TestSession") session_id = create_response.json()["id"] # Add character char_response = client.post( f"/sessions/{session_id}/characters/", params={"name": "Gandalf", "description": "Wizard"} ) char_id = char_response.json()["id"] # Get session again get_response = client.get(f"/sessions/{session_id}") session_data = get_response.json() # Verify character is still there assert char_id in session_data["characters"] assert session_data["characters"][char_id]["name"] == "Gandalf" def test_public_messages_in_session(self, client): """Test that public_messages field exists in session""" response = client.post("/sessions/?name=TestSession") data = response.json() assert "public_messages" in data assert isinstance(data["public_messages"], list) assert len(data["public_messages"]) == 0 class TestMessageVisibilityAPI: """Test API handling of different message visibilities""" def test_session_includes_public_messages_field(self, client): """Test that sessions include public_messages field""" # Create session response = client.post("/sessions/?name=TestSession") session_data = response.json() assert "public_messages" in session_data assert session_data["public_messages"] == [] def test_character_has_conversation_history(self, client): """Test that characters have conversation_history field""" # Create session and character session_response = client.post("/sessions/?name=TestSession") session_id = session_response.json()["id"] char_response = client.post( f"/sessions/{session_id}/characters/", params={"name": "Test", "description": "Test"} ) char_data = char_response.json() assert "conversation_history" in char_data assert char_data["conversation_history"] == []