""" Full Workflow Integration Tests These tests validate complete end-to-end workflows by connecting to a running service. They test realistic user scenarios and complex interactions. """ import pytest import asyncio import httpx import time import os from typing import List, Dict, Any # Configuration for remote service connection DEFAULT_SERVICE_URL = "http://127.0.0.1:8000" SERVICE_URL = os.getenv("AGENTIC_RAG_SERVICE_URL", DEFAULT_SERVICE_URL) @pytest.fixture(scope="session") def service_url() -> str: """Get the service URL for testing""" return SERVICE_URL class TestCompleteWorkflows: """Test complete user workflows""" @pytest.mark.asyncio async def test_standards_research_workflow(self, service_url: str): """Test a complete standards research workflow""" session_id = f"standards_workflow_{int(time.time())}" # Simulate a user researching ISO 26262 conversation_flow = [ "What is ISO 26262 and what does it cover?", "What are the ASIL levels in ISO 26262?", "Can you explain ASIL D requirements in detail?", "How does ISO 26262 relate to vehicle cybersecurity?" ] async with httpx.AsyncClient(timeout=60.0) as client: for i, question in enumerate(conversation_flow): request_data = { "session_id": session_id, "messages": [{"role": "user", "content": question}] } response = await client.post( f"{service_url}/api/ai-sdk/chat", json=request_data, headers={"Content-Type": "application/json"} ) assert response.status_code == 200 # Read the streaming response content = "" async for chunk in response.aiter_text(): content += chunk if len(content) > 200: # Get substantial response break # Verify we get meaningful content assert len(content) > 50 print(f"Question {i+1} response length: {len(content)} chars") # Small delay between questions await asyncio.sleep(0.5) @pytest.mark.asyncio async def test_manufacturing_safety_workflow(self, service_url: str): """Test manufacturing safety standards workflow""" session_id = f"manufacturing_workflow_{int(time.time())}" conversation_flow = [ "What are the key safety standards for manufacturing equipment?", "How do ISO 13849 and IEC 62061 compare?", "What is the process for safety risk assessment in manufacturing?" ] async with httpx.AsyncClient(timeout=60.0) as client: responses = [] for question in conversation_flow: request_data = { "session_id": session_id, "messages": [{"role": "user", "content": question}] } response = await client.post( f"{service_url}/api/chat", json=request_data, headers={"Content-Type": "application/json"} ) assert response.status_code == 200 # Collect response content content = "" async for chunk in response.aiter_text(): content += chunk if len(content) > 300: break responses.append(content) await asyncio.sleep(0.5) # Verify we got responses for all questions assert len(responses) == len(conversation_flow) for response_content in responses: assert len(response_content) > 30 @pytest.mark.asyncio async def test_session_context_continuity(self, service_url: str): """Test that session context is maintained across requests""" session_id = f"context_test_{int(time.time())}" async with httpx.AsyncClient(timeout=60.0) as client: # First message - establish context request1 = { "session_id": session_id, "messages": [{"role": "user", "content": "I'm working on a safety system for automotive braking. What standard should I follow?"}] } response1 = await client.post( f"{service_url}/api/chat", json=request1, headers={"Content-Type": "application/json"} ) assert response1.status_code == 200 # Wait for processing await asyncio.sleep(2) # Follow-up question that depends on context request2 = { "session_id": session_id, "messages": [{"role": "user", "content": "What are the specific testing requirements for this standard?"}] } response2 = await client.post( f"{service_url}/api/chat", json=request2, headers={"Content-Type": "application/json"} ) assert response2.status_code == 200 # Verify both responses are meaningful content1 = "" async for chunk in response1.aiter_text(): content1 += chunk if len(content1) > 100: break content2 = "" async for chunk in response2.aiter_text(): content2 += chunk if len(content2) > 100: break assert len(content1) > 50 assert len(content2) > 50 class TestErrorRecoveryWorkflows: """Test error recovery and edge case workflows""" @pytest.mark.asyncio async def test_session_recovery_after_error(self, service_url: str): """Test that sessions can recover after encountering errors""" session_id = f"error_recovery_{int(time.time())}" async with httpx.AsyncClient(timeout=60.0) as client: # Valid request valid_request = { "session_id": session_id, "messages": [{"role": "user", "content": "What is ISO 9001?"}] } response = await client.post( f"{service_url}/api/chat", json=valid_request, headers={"Content-Type": "application/json"} ) assert response.status_code == 200 # Try an invalid request that might cause issues invalid_request = { "session_id": session_id, "messages": [{"role": "user", "content": ""}] # Empty content } try: await client.post( f"{service_url}/api/chat", json=invalid_request, headers={"Content-Type": "application/json"} ) except Exception: pass # Expected to potentially fail await asyncio.sleep(1) # Another valid request to test recovery recovery_request = { "session_id": session_id, "messages": [{"role": "user", "content": "Can you summarize what we discussed?"}] } recovery_response = await client.post( f"{service_url}/api/chat", json=recovery_request, headers={"Content-Type": "application/json"} ) # Session should still work assert recovery_response.status_code == 200 @pytest.mark.asyncio async def test_concurrent_sessions(self, service_url: str): """Test multiple concurrent sessions""" base_time = int(time.time()) sessions = [f"concurrent_{base_time}_{i}" for i in range(3)] async def test_session(session_id: str, question: str): """Test a single session""" async with httpx.AsyncClient(timeout=60.0) as client: request = { "session_id": session_id, "messages": [{"role": "user", "content": question}] } response = await client.post( f"{service_url}/api/chat", json=request, headers={"Content-Type": "application/json"} ) assert response.status_code == 200 return session_id # Run concurrent sessions questions = [ "What is ISO 27001?", "What is NIST Cybersecurity Framework?", "What is GDPR compliance?" ] tasks = [ test_session(session_id, question) for session_id, question in zip(sessions, questions) ] results = await asyncio.gather(*tasks, return_exceptions=True) # All sessions should complete successfully assert len(results) == 3 for result in results: assert not isinstance(result, Exception) class TestPerformanceWorkflows: """Test performance-related workflows""" @pytest.mark.asyncio async def test_rapid_fire_requests(self, service_url: str): """Test rapid consecutive requests in same session""" session_id = f"rapid_fire_{int(time.time())}" questions = [ "Hello", "What is ISO 14001?", "Thank you", "Goodbye" ] async with httpx.AsyncClient(timeout=60.0) as client: for i, question in enumerate(questions): request = { "session_id": session_id, "messages": [{"role": "user", "content": question}] } response = await client.post( f"{service_url}/api/chat", json=request, headers={"Content-Type": "application/json"} ) assert response.status_code == 200 print(f"Rapid request {i+1} completed") # Very short delay await asyncio.sleep(0.1) @pytest.mark.asyncio async def test_large_context_workflow(self, service_url: str): """Test workflow with gradually increasing context""" session_id = f"large_context_{int(time.time())}" async with httpx.AsyncClient(timeout=60.0) as client: # Build up context over multiple turns conversation = [ "I need to understand automotive safety standards", "Specifically, tell me about ISO 26262 functional safety", "What are the different ASIL levels and their requirements?", "How do I implement ASIL D for a braking system?", "What testing and validation is required for ASIL D?", "Can you provide a summary of everything we've discussed?" ] for i, message in enumerate(conversation): request = { "session_id": session_id, "messages": [{"role": "user", "content": message}] } response = await client.post( f"{service_url}/api/chat", json=request, headers={"Content-Type": "application/json"} ) assert response.status_code == 200 print(f"Context turn {i+1} completed") # Allow time for processing await asyncio.sleep(1) class TestRealWorldScenarios: """Test realistic user scenarios""" @pytest.mark.asyncio async def test_compliance_officer_scenario(self, service_url: str): """Simulate a compliance officer's typical workflow""" session_id = f"compliance_officer_{int(time.time())}" # Typical compliance questions scenario_questions = [ "I need to ensure our new product meets regulatory requirements. What standards apply to automotive safety systems?", "Our system is classified as ASIL C. What does this mean for our development process?", "What documentation do we need to prepare for safety assessment?", "How often do we need to review and update our safety processes?" ] async with httpx.AsyncClient(timeout=90.0) as client: for i, question in enumerate(scenario_questions): request = { "session_id": session_id, "messages": [{"role": "user", "content": question}] } response = await client.post( f"{service_url}/api/ai-sdk/chat", json=request, headers={"Content-Type": "application/json"} ) assert response.status_code == 200 # Allow realistic time between questions await asyncio.sleep(2) print(f"Compliance scenario step {i+1} completed") @pytest.mark.asyncio async def test_engineer_research_scenario(self, service_url: str): """Simulate an engineer researching technical details""" session_id = f"engineer_research_{int(time.time())}" research_flow = [ "I'm designing a safety-critical system. What's the difference between ISO 26262 and IEC 61508?", "For automotive applications, which standard takes precedence?", "What are the specific requirements for software development under ISO 26262?", "Can you explain the V-model development process required by the standard?" ] async with httpx.AsyncClient(timeout=90.0) as client: for question in research_flow: request = { "session_id": session_id, "messages": [{"role": "user", "content": question}] } response = await client.post( f"{service_url}/api/chat", json=request, headers={"Content-Type": "application/json"} ) assert response.status_code == 200 # Read some response to verify it's working content = "" async for chunk in response.aiter_text(): content += chunk if len(content) > 150: break assert len(content) > 50 await asyncio.sleep(1.5)