Spaces:
Runtime error
Runtime error
File size: 18,221 Bytes
330b6e4 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 | """
Integration tests for language switching and chat history persistence.
Tests the complete integration between language context, chat history, and session management.
"""
import pytest
import time
from unittest.mock import patch, MagicMock
from chat_agent.services.chat_agent import ChatAgent
from chat_agent.services.session_manager import SessionManager
from chat_agent.services.language_context import LanguageContextManager
from chat_agent.services.chat_history import ChatHistoryManager
from chat_agent.services.groq_client import GroqClient
class TestLanguageSwitchingIntegration:
"""Integration tests for language switching functionality."""
@pytest.fixture
def mock_groq_client(self):
"""Mock Groq client with language-specific responses."""
with patch('chat_agent.services.groq_client.GroqClient') as mock:
mock_instance = MagicMock()
def mock_generate_response(prompt, chat_history=None, language_context=None, **kwargs):
# Return language-specific responses
if language_context and 'python' in language_context.lower():
return "This is a Python-specific response about programming concepts."
elif language_context and 'javascript' in language_context.lower():
return "This is a JavaScript-specific response about web development."
elif language_context and 'java' in language_context.lower():
return "This is a Java-specific response about object-oriented programming."
else:
return "This is a general programming response."
mock_instance.generate_response.side_effect = mock_generate_response
mock.return_value = mock_instance
yield mock_instance
@pytest.fixture
def integrated_system(self, mock_groq_client):
"""Create fully integrated chat system."""
session_manager = SessionManager()
language_context_manager = LanguageContextManager()
chat_history_manager = ChatHistoryManager()
chat_agent = ChatAgent(
groq_client=mock_groq_client,
session_manager=session_manager,
language_context_manager=language_context_manager,
chat_history_manager=chat_history_manager
)
return {
'chat_agent': chat_agent,
'session_manager': session_manager,
'language_context_manager': language_context_manager,
'chat_history_manager': chat_history_manager,
'groq_client': mock_groq_client
}
def test_language_switching_preserves_history(self, integrated_system):
"""Test that language switching preserves chat history."""
user_id = "test-user-lang-switch"
system = integrated_system
# Create session with Python
session = system['session_manager'].create_session(user_id, language="python")
session_id = session['session_id']
# Send Python message
python_message = "How do I create a list in Python?"
python_response = system['chat_agent'].process_message(
session_id=session_id,
message=python_message,
language="python"
)
# Verify Python response
assert "Python" in python_response
# Check history after Python message
history_after_python = system['chat_history_manager'].get_recent_history(session_id)
assert len(history_after_python) == 2
assert history_after_python[0]['content'] == python_message
assert history_after_python[0]['language'] == 'python'
assert history_after_python[1]['language'] == 'python'
# Switch to JavaScript
system['chat_agent'].switch_language(session_id, "javascript")
# Verify language context changed
current_language = system['language_context_manager'].get_language(session_id)
assert current_language == "javascript"
# Send JavaScript message
js_message = "How do I create an array in JavaScript?"
js_response = system['chat_agent'].process_message(
session_id=session_id,
message=js_message,
language="javascript"
)
# Verify JavaScript response
assert "JavaScript" in js_response
# Check complete history
complete_history = system['chat_history_manager'].get_recent_history(session_id, limit=10)
assert len(complete_history) == 4
# Verify history contains both languages
python_messages = [msg for msg in complete_history if msg['language'] == 'python']
js_messages = [msg for msg in complete_history if msg['language'] == 'javascript']
assert len(python_messages) == 2 # User message + response
assert len(js_messages) == 2 # User message + response
# Verify message order is preserved
assert complete_history[0]['content'] == python_message
assert complete_history[1]['content'] == python_response
assert complete_history[2]['content'] == js_message
assert complete_history[3]['content'] == js_response
def test_multiple_language_switches_in_conversation(self, integrated_system):
"""Test multiple language switches within a single conversation."""
user_id = "test-user-multi-switch"
system = integrated_system
# Create session
session = system['session_manager'].create_session(user_id, language="python")
session_id = session['session_id']
# Conversation flow: Python -> JavaScript -> Java -> Python
conversation_flow = [
("python", "What is a Python dictionary?"),
("javascript", "How do I create an object in JavaScript?"),
("java", "Explain Java classes"),
("python", "What is list comprehension in Python?")
]
for language, message in conversation_flow:
# Switch language
system['chat_agent'].switch_language(session_id, language)
# Verify language context
current_lang = system['language_context_manager'].get_language(session_id)
assert current_lang == language
# Send message
response = system['chat_agent'].process_message(
session_id=session_id,
message=message,
language=language
)
# Verify response is language-specific
assert language.title() in response or language.lower() in response.lower()
# Verify complete conversation history
complete_history = system['chat_history_manager'].get_full_history(session_id)
assert len(complete_history) == 8 # 4 user messages + 4 responses
# Verify language distribution
language_counts = {}
for msg in complete_history:
lang = msg['language']
language_counts[lang] = language_counts.get(lang, 0) + 1
assert language_counts['python'] == 4 # 2 messages + 2 responses
assert language_counts['javascript'] == 2 # 1 message + 1 response
assert language_counts['java'] == 2 # 1 message + 1 response
def test_language_context_affects_llm_prompts(self, integrated_system):
"""Test that language context properly affects LLM prompts."""
user_id = "test-user-context-prompts"
system = integrated_system
# Create session
session = system['session_manager'].create_session(user_id, language="python")
session_id = session['session_id']
# Send message in Python context
message = "How do I handle errors?"
system['chat_agent'].process_message(
session_id=session_id,
message=message,
language="python"
)
# Verify Groq client was called with Python context
call_args = system['groq_client'].generate_response.call_args
assert call_args is not None
# Check that language context was passed
if len(call_args) > 1: # positional args
language_context = call_args[1] if len(call_args) > 1 else None
else: # keyword args
language_context = call_args.kwargs.get('language_context')
# Switch to JavaScript and send same message
system['chat_agent'].switch_language(session_id, "javascript")
system['chat_agent'].process_message(
session_id=session_id,
message=message,
language="javascript"
)
# Verify second call had different context
second_call_args = system['groq_client'].generate_response.call_args
assert second_call_args is not None
def test_chat_history_persistence_across_language_switches(self, integrated_system):
"""Test that chat history persists correctly across language switches."""
user_id = "test-user-history-persistence"
system = integrated_system
# Create session
session = system['session_manager'].create_session(user_id, language="python")
session_id = session['session_id']
# Build conversation with language switches
messages_and_languages = [
("python", "What is a variable?"),
("python", "How do I create a function?"),
("javascript", "What is a closure?"),
("javascript", "How do I use async/await?"),
("java", "What is inheritance?")
]
for language, message in messages_and_languages:
system['chat_agent'].switch_language(session_id, language)
system['chat_agent'].process_message(
session_id=session_id,
message=message,
language=language
)
# Test different history retrieval methods
# 1. Recent history (last 6 messages)
recent_history = system['chat_history_manager'].get_recent_history(session_id, limit=6)
assert len(recent_history) == 6
# Should include last 3 conversations (user + assistant messages)
expected_languages = ["javascript", "javascript", "java", "java"]
actual_languages = [msg['language'] for msg in recent_history[-4:]]
assert actual_languages == expected_languages
# 2. Full history
full_history = system['chat_history_manager'].get_full_history(session_id)
assert len(full_history) == 10 # 5 user messages + 5 responses
# 3. Language-specific filtering (if implemented)
python_messages = [msg for msg in full_history if msg['language'] == 'python']
js_messages = [msg for msg in full_history if msg['language'] == 'javascript']
java_messages = [msg for msg in full_history if msg['language'] == 'java']
assert len(python_messages) == 4 # 2 user + 2 assistant
assert len(js_messages) == 4 # 2 user + 2 assistant
assert len(java_messages) == 2 # 1 user + 1 assistant
def test_session_language_state_persistence(self, integrated_system):
"""Test that session language state persists correctly."""
user_id = "test-user-session-state"
system = integrated_system
# Create session with default language
session = system['session_manager'].create_session(user_id, language="python")
session_id = session['session_id']
# Verify initial language
initial_language = system['language_context_manager'].get_language(session_id)
assert initial_language == "python"
# Switch languages multiple times
languages = ["javascript", "java", "python", "cpp"]
for language in languages:
system['chat_agent'].switch_language(session_id, language)
# Verify immediate state change
current_language = system['language_context_manager'].get_language(session_id)
assert current_language == language
# Send a message to ensure state is used
response = system['chat_agent'].process_message(
session_id=session_id,
message=f"Test message in {language}",
language=language
)
assert response is not None
# Verify final state
final_language = system['language_context_manager'].get_language(session_id)
assert final_language == "cpp"
# Simulate session retrieval (as if from database)
retrieved_session = system['session_manager'].get_session(session_id)
assert retrieved_session is not None
# Language context should still be accessible
persistent_language = system['language_context_manager'].get_language(session_id)
assert persistent_language == "cpp"
def test_concurrent_language_switches(self, integrated_system):
"""Test concurrent language switches across multiple sessions."""
user_ids = ["concurrent-user-1", "concurrent-user-2", "concurrent-user-3"]
system = integrated_system
# Create multiple sessions
sessions = []
for user_id in user_ids:
session = system['session_manager'].create_session(user_id, language="python")
sessions.append(session)
# Perform concurrent language switches
import threading
def switch_and_chat(session_id, target_language, message):
system['chat_agent'].switch_language(session_id, target_language)
response = system['chat_agent'].process_message(
session_id=session_id,
message=message,
language=target_language
)
return response
# Create threads for concurrent operations
threads = []
results = {}
operations = [
(sessions[0]['session_id'], "javascript", "JS question"),
(sessions[1]['session_id'], "java", "Java question"),
(sessions[2]['session_id'], "python", "Python question")
]
for session_id, language, message in operations:
thread = threading.Thread(
target=lambda sid=session_id, lang=language, msg=message:
results.update({sid: switch_and_chat(sid, lang, msg)})
)
threads.append(thread)
thread.start()
# Wait for all threads to complete
for thread in threads:
thread.join()
# Verify all operations completed successfully
assert len(results) == 3
# Verify each session has correct language context
for i, (session_id, expected_language, _) in enumerate(operations):
current_language = system['language_context_manager'].get_language(session_id)
assert current_language == expected_language
# Verify response was generated
assert session_id in results
assert results[session_id] is not None
def test_language_switching_with_chat_context(self, integrated_system):
"""Test that language switching maintains proper chat context for LLM."""
user_id = "test-user-context-maintenance"
system = integrated_system
# Create session
session = system['session_manager'].create_session(user_id, language="python")
session_id = session['session_id']
# Start conversation in Python
system['chat_agent'].process_message(
session_id=session_id,
message="I'm learning about data structures",
language="python"
)
system['chat_agent'].process_message(
session_id=session_id,
message="Can you explain Python lists?",
language="python"
)
# Switch to JavaScript but ask follow-up question
system['chat_agent'].switch_language(session_id, "javascript")
response = system['chat_agent'].process_message(
session_id=session_id,
message="What's the equivalent in JavaScript?",
language="javascript"
)
# Verify that the LLM received chat history as context
# The mock should have been called with chat history
call_args = system['groq_client'].generate_response.call_args
assert call_args is not None
# Check that chat history was provided
if len(call_args) > 0:
# History should be in the call arguments
chat_history = None
if len(call_args) > 1:
chat_history = call_args[1] if isinstance(call_args[1], list) else None
# Or in keyword arguments
if not chat_history:
chat_history = call_args.kwargs.get('chat_history')
# Verify context was maintained
history = system['chat_history_manager'].get_recent_history(session_id, limit=5)
assert len(history) >= 4 # Previous conversation + current message
# Verify response acknowledges context
assert response is not None
assert "JavaScript" in response
if __name__ == '__main__':
pytest.main([__file__, '-v']) |