Spaces:
Runtime error
Runtime error
| """ | |
| Integration tests for ChatAgent service. | |
| Tests the complete message processing flow including session management, | |
| language context switching, chat history, and LLM integration. | |
| """ | |
| import pytest | |
| import os | |
| from unittest.mock import Mock, patch, MagicMock | |
| from datetime import datetime, timedelta | |
| import redis | |
| from chat_agent.services.chat_agent import ChatAgent, ChatAgentError, create_chat_agent | |
| from chat_agent.services.groq_client import GroqClient, ChatMessage, LanguageContext | |
| from chat_agent.services.language_context import LanguageContextManager | |
| from chat_agent.services.session_manager import SessionManager, SessionNotFoundError | |
| from chat_agent.services.chat_history import ChatHistoryManager | |
| from chat_agent.models.chat_session import ChatSession | |
| from chat_agent.models.message import Message | |
| from chat_agent.models.base import db | |
| def mock_redis(): | |
| """Mock Redis client for testing.""" | |
| return Mock(spec=redis.Redis) | |
| def mock_groq_client(): | |
| """Mock Groq client for testing.""" | |
| client = Mock(spec=GroqClient) | |
| client.generate_response.return_value = "Test response from LLM" | |
| client.stream_response.return_value = iter(["Test ", "streaming ", "response"]) | |
| client.get_model_info.return_value = { | |
| "model": "mixtral-8x7b-32768", | |
| "temperature": 0.7, | |
| "max_tokens": 2048 | |
| } | |
| return client | |
| def language_context_manager(): | |
| """Create language context manager for testing.""" | |
| return LanguageContextManager() | |
| def mock_session_manager(): | |
| """Mock session manager for testing.""" | |
| manager = Mock(spec=SessionManager) | |
| # Create a mock session | |
| mock_session = Mock(spec=ChatSession) | |
| mock_session.id = "test-session-id" | |
| mock_session.user_id = "test-user-id" | |
| mock_session.language = "python" | |
| mock_session.created_at = datetime.utcnow() | |
| mock_session.last_active = datetime.utcnow() | |
| mock_session.message_count = 0 | |
| mock_session.is_active = True | |
| mock_session.session_metadata = {} | |
| manager.get_session.return_value = mock_session | |
| manager.update_session_activity.return_value = None | |
| manager.increment_message_count.return_value = None | |
| manager.set_session_language.return_value = None | |
| return manager | |
| def mock_chat_history_manager(): | |
| """Mock chat history manager for testing.""" | |
| manager = Mock(spec=ChatHistoryManager) | |
| # Create mock messages | |
| mock_user_message = Mock(spec=Message) | |
| mock_user_message.id = "user-msg-id" | |
| mock_user_message.session_id = "test-session-id" | |
| mock_user_message.role = "user" | |
| mock_user_message.content = "Test user message" | |
| mock_user_message.language = "python" | |
| mock_user_message.timestamp = datetime.utcnow() | |
| mock_user_message.message_metadata = {} | |
| mock_assistant_message = Mock(spec=Message) | |
| mock_assistant_message.id = "assistant-msg-id" | |
| mock_assistant_message.session_id = "test-session-id" | |
| mock_assistant_message.role = "assistant" | |
| mock_assistant_message.content = "Test assistant response" | |
| mock_assistant_message.language = "python" | |
| mock_assistant_message.timestamp = datetime.utcnow() | |
| mock_assistant_message.message_metadata = {} | |
| manager.store_message.side_effect = [mock_user_message, mock_assistant_message] | |
| manager.get_recent_history.return_value = [mock_user_message] | |
| manager.get_message_count.return_value = 2 | |
| manager.get_cache_stats.return_value = { | |
| 'session_id': 'test-session-id', | |
| 'cached_messages': 2, | |
| 'cache_ttl': 3600, | |
| 'max_cache_size': 20 | |
| } | |
| return manager | |
| st.fixture | |
| def chat_agent(mock_groq_client, language_context_manager, mock_session_manager, mock_chat_history_manager): | |
| """Create ChatAgent instance for testing.""" | |
| return ChatAgent( | |
| groq_client=mock_groq_client, | |
| language_context_manager=language_context_manager, | |
| session_manager=mock_session_manager, | |
| chat_history_manager=mock_chat_history_manager | |
| ) | |
| class TestChatAgentMessageProcessing: | |
| """Test complete message processing workflow.""" | |
| def test_process_message_success(self, chat_agent, mock_groq_client, mock_session_manager, mock_chat_history_manager): | |
| """Test successful message processing flow.""" | |
| # Arrange | |
| session_id = "test-session-id" | |
| message = "How do I create a list in Python?" | |
| # Act | |
| result = chat_agent.process_message(session_id, message) | |
| # Assert | |
| assert result['response'] == "Test response from LLM" | |
| assert result['language'] == "python" | |
| assert result['session_id'] == session_id | |
| assert 'message_id' in result | |
| assert 'timestamp' in result | |
| assert 'metadata' in result | |
| # Verify service calls | |
| mock_session_manager.get_session.assert_called_once_with(session_id) | |
| mock_session_manager.update_session_activity.assert_called_once_with(session_id) | |
| mock_session_manager.increment_message_count.assert_called_once_with(session_id) | |
| # Verify message storage (user message, then assistant message) | |
| assert mock_chat_history_manager.store_message.call_count == 2 | |
| # Verify LLM call | |
| mock_groq_client.generate_response.assert_called_once() | |
| def test_process_message_with_language_override(self, chat_agent, mock_groq_client, mock_session_manager): | |
| """Test message processing with language override.""" | |
| # Arrange | |
| session_id = "test-session-id" | |
| message = "How do I create an array in JavaScript?" | |
| language = "javascript" | |
| # Act | |
| result = chat_agent.process_message(session_id, message, language) | |
| # Assert | |
| assert result['language'] == "javascript" | |
| mock_session_manager.set_session_language.assert_called_once_with(session_id, language) | |
| def test_process_message_invalid_session(self, chat_agent, mock_session_manager): | |
| """Test message processing with invalid session.""" | |
| # Arrange | |
| mock_session_manager.get_session.side_effect = SessionNotFoundError("Session not found") | |
| # Act & Assert | |
| with pytest.raises(ChatAgentError, match="Session error"): | |
| chat_agent.process_message("invalid-session", "test message") | |
| def test_process_message_invalid_language(self, chat_agent, mock_session_manager): | |
| """Test message processing with invalid language falls back to session default.""" | |
| # Arrange | |
| session_id = "test-session-id" | |
| message = "Test message" | |
| invalid_language = "invalid-lang" | |
| # Act | |
| result = chat_agent.process_message(session_id, message, invalid_language) | |
| # Assert - should fall back to session default (python) | |
| assert result['language'] == "python" | |
| class TestChatAgentLanguageSwitching: | |
| """Test language switching functionality.""" | |
| def test_switch_language_success(self, chat_agent, mock_session_manager, mock_chat_history_manager): | |
| """Test successful language switching.""" | |
| # Arrange | |
| session_id = "test-session-id" | |
| new_language = "javascript" | |
| # Act | |
| result = chat_agent.switch_language(session_id, new_language) | |
| # Assert | |
| assert result['success'] is True | |
| assert result['new_language'] == new_language | |
| assert result['previous_language'] == "python" | |
| assert result['session_id'] == session_id | |
| assert 'message' in result | |
| assert 'timestamp' in result | |
| # Verify service calls | |
| mock_session_manager.get_session.assert_called_once_with(session_id) | |
| mock_session_manager.set_session_language.assert_called_once_with(session_id, new_language) | |
| # Verify switch message is stored | |
| mock_chat_history_manager.store_message.assert_called_once() | |
| store_call = mock_chat_history_manager.store_message.call_args | |
| assert store_call[1]['role'] == 'assistant' | |
| assert store_call[1]['language'] == new_language | |
| assert 'language_switch' in store_call[1]['message_metadata']['type'] | |
| def test_switch_language_invalid_language(self, chat_agent): | |
| """Test language switching with invalid language.""" | |
| # Arrange | |
| session_id = "test-session-id" | |
| invalid_language = "invalid-lang" | |
| # Act & Assert | |
| with pytest.raises(ChatAgentError, match="Unsupported language"): | |
| chat_agent.switch_language(session_id, invalid_language) | |
| def test_switch_language_invalid_session(self, chat_agent, mock_session_manager): | |
| """Test language switching with invalid session.""" | |
| # Arrange | |
| mock_session_manager.get_session.side_effect = SessionNotFoundError("Session not found") | |
| # Act & Assert | |
| with pytest.raises(ChatAgentError, match="Session error"): | |
| chat_agent.switch_language("invalid-session", "javascript") | |
| cla | |
| ss TestChatAgentStreaming: | |
| """Test streaming response functionality.""" | |
| def test_stream_response_success(self, chat_agent, mock_groq_client, mock_session_manager, mock_chat_history_manager): | |
| """Test successful streaming response.""" | |
| # Arrange | |
| session_id = "test-session-id" | |
| message = "Explain Python functions" | |
| # Act | |
| stream_results = list(chat_agent.stream_response(session_id, message)) | |
| # Assert | |
| assert len(stream_results) >= 5 # start + 3 chunks + complete | |
| # Check start event | |
| start_event = stream_results[0] | |
| assert start_event['type'] == 'start' | |
| assert start_event['session_id'] == session_id | |
| assert start_event['language'] == 'python' | |
| # Check chunk events | |
| chunk_events = [event for event in stream_results if event['type'] == 'chunk'] | |
| assert len(chunk_events) == 3 | |
| assert chunk_events[0]['content'] == "Test " | |
| assert chunk_events[1]['content'] == "streaming " | |
| assert chunk_events[2]['content'] == "response" | |
| # Check complete event | |
| complete_event = stream_results[-1] | |
| assert complete_event['type'] == 'complete' | |
| assert complete_event['session_id'] == session_id | |
| assert complete_event['total_chunks'] == 3 | |
| assert 'processing_time' in complete_event | |
| # Verify service calls | |
| mock_session_manager.get_session.assert_called_once_with(session_id) | |
| mock_session_manager.increment_message_count.assert_called_once_with(session_id) | |
| # Verify message storage | |
| assert mock_chat_history_manager.store_message.call_count == 2 | |
| def test_stream_response_error(self, chat_agent, mock_session_manager): | |
| """Test streaming response with session error.""" | |
| # Arrange | |
| mock_session_manager.get_session.side_effect = SessionNotFoundError("Session not found") | |
| # Act | |
| stream_results = list(chat_agent.stream_response("invalid-session", "test message")) | |
| # Assert | |
| assert len(stream_results) == 1 | |
| error_event = stream_results[0] | |
| assert error_event['type'] == 'error' | |
| assert 'Session error' in error_event['error'] | |
| class TestChatAgentHistory: | |
| """Test chat history retrieval functionality.""" | |
| def test_get_chat_history_success(self, chat_agent, mock_session_manager, mock_chat_history_manager): | |
| """Test successful chat history retrieval.""" | |
| # Arrange | |
| session_id = "test-session-id" | |
| limit = 5 | |
| # Act | |
| history = chat_agent.get_chat_history(session_id, limit) | |
| # Assert | |
| assert isinstance(history, list) | |
| assert len(history) == 1 # Based on mock setup | |
| message = history[0] | |
| assert 'id' in message | |
| assert 'role' in message | |
| assert 'content' in message | |
| assert 'language' in message | |
| assert 'timestamp' in message | |
| assert 'metadata' in message | |
| # Verify service calls | |
| mock_session_manager.get_session.assert_called_once_with(session_id) | |
| mock_chat_history_manager.get_recent_history.assert_called_once_with(session_id, limit) | |
| def test_get_chat_history_invalid_session(self, chat_agent, mock_session_manager): | |
| """Test chat history retrieval with invalid session.""" | |
| # Arrange | |
| mock_session_manager.get_session.side_effect = SessionNotFoundError("Session not found") | |
| # Act & Assert | |
| with pytest.raises(ChatAgentError, match="Session error"): | |
| chat_agent.get_chat_history("invalid-session") | |
| class TestChatAgentSessionInfo: | |
| """Test session information retrieval.""" | |
| def test_get_session_info_success(self, chat_agent, mock_session_manager, mock_chat_history_manager, language_context_manager): | |
| """Test successful session info retrieval.""" | |
| # Arrange | |
| session_id = "test-session-id" | |
| # Act | |
| info = chat_agent.get_session_info(session_id) | |
| # Assert | |
| assert 'session' in info | |
| assert 'language_context' in info | |
| assert 'statistics' in info | |
| assert 'supported_languages' in info | |
| # Check session info | |
| session_info = info['session'] | |
| assert session_info['id'] == session_id | |
| assert session_info['language'] == 'python' | |
| assert session_info['is_active'] is True | |
| # Check statistics | |
| stats = info['statistics'] | |
| assert 'total_messages' in stats | |
| assert 'session_message_count' in stats | |
| assert 'cache_stats' in stats | |
| # Check supported languages | |
| assert isinstance(info['supported_languages'], list) | |
| assert 'python' in info['supported_languages'] | |
| assert 'javascript' in info['supported_languages'] | |
| # Verify service calls | |
| mock_session_manager.get_session.assert_called_once_with(session_id) | |
| mock_chat_history_manager.get_message_count.assert_called_once_with(session_id) | |
| mock_chat_history_manager.get_cache_stats.assert_called_once_with(session_id) | |
| class TestChatAgentFactory: | |
| """Test ChatAgent factory function.""" | |
| def test_create_chat_agent(self, mock_groq_client, language_context_manager, mock_session_manager, mock_chat_history_manager): | |
| """Test ChatAgent factory function.""" | |
| # Act | |
| agent = create_chat_agent( | |
| mock_groq_client, | |
| language_context_manager, | |
| mock_session_manager, | |
| mock_chat_history_manager | |
| ) | |
| # Assert | |
| assert isinstance(agent, ChatAgent) | |
| assert agent.groq_client == mock_groq_client | |
| assert agent.language_context_manager == language_context_manager | |
| assert agent.session_manager == mock_session_manager | |
| assert agent.chat_history_manager == mock_chat_history_manager | |
| class TestChatAgentIntegrationFlow: | |
| """Test complete integration flows.""" | |
| def test_complete_conversation_flow(self, chat_agent, mock_groq_client, mock_session_manager, mock_chat_history_manager): | |
| """Test a complete conversation flow with multiple messages.""" | |
| session_id = "test-session-id" | |
| # First message | |
| result1 = chat_agent.process_message(session_id, "What is Python?") | |
| assert result1['language'] == 'python' | |
| # Switch language | |
| switch_result = chat_agent.switch_language(session_id, "javascript") | |
| assert switch_result['success'] is True | |
| assert switch_result['new_language'] == 'javascript' | |
| # Second message in new language | |
| result2 = chat_agent.process_message(session_id, "What is JavaScript?") | |
| assert result2['language'] == 'javascript' | |
| # Get session info | |
| info = chat_agent.get_session_info(session_id) | |
| assert info['session']['language'] == 'javascript' | |
| # Verify all service interactions occurred | |
| assert mock_session_manager.get_session.call_count >= 3 | |
| assert mock_session_manager.set_session_language.call_count >= 1 | |
| assert mock_chat_history_manager.store_message.call_count >= 5 # 2 conversations + 1 switch message | |
| def test_streaming_with_language_switch(self, chat_agent, mock_session_manager, mock_chat_history_manager): | |
| """Test streaming response after language switch.""" | |
| session_id = "test-session-id" | |
| # Switch language first | |
| chat_agent.switch_language(session_id, "java") | |
| # Stream response in new language | |
| stream_results = list(chat_agent.stream_response(session_id, "Explain Java classes", "java")) | |
| # Verify language context is maintained | |
| start_event = stream_results[0] | |
| assert start_event['language'] == 'java' | |
| # Verify session language was set | |
| mock_session_manager.set_session_language.assert_called_with(session_id, "java") |