Files
catonline_ai/vw-agentic-rag/tests/integration/test_full_workflow.py
2025-09-26 17:15:54 +08:00

403 lines
15 KiB
Python

"""
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)