|
|
"""Integration tests for emergency chat endpoint""" |
|
|
|
|
|
import pytest |
|
|
import asyncio |
|
|
from fastapi.testclient import TestClient |
|
|
from unittest.mock import patch |
|
|
import time |
|
|
|
|
|
from src.api.routes.chat_emergency import router |
|
|
|
|
|
|
|
|
class TestEmergencyEndpointIntegration: |
|
|
"""Integration tests for emergency chat endpoint""" |
|
|
|
|
|
@pytest.fixture |
|
|
def app(self): |
|
|
"""Create FastAPI app with emergency router""" |
|
|
from fastapi import FastAPI |
|
|
app = FastAPI() |
|
|
app.include_router(router) |
|
|
return app |
|
|
|
|
|
@pytest.fixture |
|
|
def client(self, app): |
|
|
"""Create test client""" |
|
|
return TestClient(app) |
|
|
|
|
|
def test_emergency_endpoint_performance(self, client): |
|
|
"""Test emergency endpoint response time""" |
|
|
messages = [ |
|
|
"Olá!", |
|
|
"Quero investigar contratos", |
|
|
"Como funciona o sistema?", |
|
|
"Mostre gastos de 2024", |
|
|
"Analise fornecedor XYZ" |
|
|
] |
|
|
|
|
|
response_times = [] |
|
|
|
|
|
for message in messages: |
|
|
start_time = time.time() |
|
|
response = client.post( |
|
|
"/api/v1/chat/emergency", |
|
|
json={"message": message} |
|
|
) |
|
|
end_time = time.time() |
|
|
|
|
|
assert response.status_code == 200 |
|
|
response_times.append(end_time - start_time) |
|
|
|
|
|
|
|
|
assert all(t < 0.1 for t in response_times), f"Response times: {response_times}" |
|
|
|
|
|
|
|
|
avg_time = sum(response_times) / len(response_times) |
|
|
assert avg_time < 0.05, f"Average response time: {avg_time}" |
|
|
|
|
|
def test_emergency_endpoint_concurrent_requests(self, client): |
|
|
"""Test emergency endpoint under concurrent load""" |
|
|
import concurrent.futures |
|
|
|
|
|
def make_request(message): |
|
|
response = client.post( |
|
|
"/api/v1/chat/emergency", |
|
|
json={"message": message} |
|
|
) |
|
|
return response.status_code, response.json() |
|
|
|
|
|
messages = [f"Teste concorrente {i}" for i in range(20)] |
|
|
|
|
|
with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor: |
|
|
futures = [executor.submit(make_request, msg) for msg in messages] |
|
|
results = [future.result() for future in concurrent.futures.as_completed(futures)] |
|
|
|
|
|
|
|
|
assert all(status == 200 for status, _ in results) |
|
|
|
|
|
|
|
|
for _, data in results: |
|
|
assert "session_id" in data |
|
|
assert "message" in data |
|
|
assert len(data["message"]) > 0 |
|
|
|
|
|
def test_emergency_endpoint_session_continuity(self, client): |
|
|
"""Test session continuity across multiple messages""" |
|
|
session_id = "test-session-continuity" |
|
|
|
|
|
messages = [ |
|
|
"Olá!", |
|
|
"Quero investigar contratos", |
|
|
"Mostre os mais recentes" |
|
|
] |
|
|
|
|
|
for i, message in enumerate(messages): |
|
|
response = client.post( |
|
|
"/api/v1/chat/emergency", |
|
|
json={"message": message, "session_id": session_id} |
|
|
) |
|
|
|
|
|
assert response.status_code == 200 |
|
|
data = response.json() |
|
|
assert data["session_id"] == session_id |
|
|
|
|
|
|
|
|
if i == 0: |
|
|
assert data["metadata"]["intent"] == "greeting" |
|
|
elif i == 1: |
|
|
assert data["metadata"]["intent"] == "investigation" |
|
|
|
|
|
def test_emergency_endpoint_error_recovery(self, client): |
|
|
"""Test emergency endpoint handles errors gracefully""" |
|
|
|
|
|
edge_cases = [ |
|
|
{"message": "a"}, |
|
|
{"message": "?" * 100}, |
|
|
{"message": "SELECT * FROM users"}, |
|
|
{"message": "<script>alert('test')</script>"}, |
|
|
{"message": "😀" * 50}, |
|
|
] |
|
|
|
|
|
for payload in edge_cases: |
|
|
response = client.post( |
|
|
"/api/v1/chat/emergency", |
|
|
json=payload |
|
|
) |
|
|
|
|
|
assert response.status_code == 200 |
|
|
data = response.json() |
|
|
assert "message" in data |
|
|
assert len(data["message"]) > 0 |
|
|
assert "error" not in data |
|
|
|
|
|
@pytest.mark.asyncio |
|
|
async def test_emergency_endpoint_maritaca_fallback(self, client): |
|
|
"""Test fallback when Maritaca fails""" |
|
|
with patch.dict('os.environ', {'MARITACA_API_KEY': 'test-key'}): |
|
|
|
|
|
with patch('httpx.AsyncClient') as mock_client: |
|
|
mock_instance = mock_client.return_value.__aenter__.return_value |
|
|
mock_instance.post.side_effect = Exception("API Error") |
|
|
|
|
|
response = client.post( |
|
|
"/api/v1/chat/emergency", |
|
|
json={"message": "Test with failed Maritaca"} |
|
|
) |
|
|
|
|
|
assert response.status_code == 200 |
|
|
data = response.json() |
|
|
|
|
|
|
|
|
assert data["agent_id"] == "system" |
|
|
assert data["metadata"]["backend"] == "intelligent_fallback" |
|
|
assert len(data["message"]) > 0 |
|
|
|
|
|
def test_emergency_endpoint_response_variety(self, client): |
|
|
"""Test that responses vary for same intent""" |
|
|
responses = [] |
|
|
|
|
|
|
|
|
for _ in range(5): |
|
|
response = client.post( |
|
|
"/api/v1/chat/emergency", |
|
|
json={"message": "Olá!"} |
|
|
) |
|
|
|
|
|
assert response.status_code == 200 |
|
|
data = response.json() |
|
|
responses.append(data["message"]) |
|
|
|
|
|
|
|
|
unique_responses = set(responses) |
|
|
assert len(unique_responses) >= 2, "Responses should vary" |
|
|
|
|
|
def test_emergency_health_monitoring(self, client): |
|
|
"""Test health endpoint provides accurate status""" |
|
|
|
|
|
with patch.dict('os.environ', {}, clear=True): |
|
|
response = client.get("/api/v1/chat/emergency/health") |
|
|
assert response.status_code == 200 |
|
|
data = response.json() |
|
|
assert data["status"] == "operational" |
|
|
assert data["maritaca_configured"] is False |
|
|
|
|
|
|
|
|
with patch.dict('os.environ', {'MARITACA_API_KEY': 'test-key'}): |
|
|
response = client.get("/api/v1/chat/emergency/health") |
|
|
assert response.status_code == 200 |
|
|
data = response.json() |
|
|
assert data["maritaca_configured"] is True |
|
|
|
|
|
def test_emergency_endpoint_metadata_consistency(self, client): |
|
|
"""Test metadata is consistent and complete""" |
|
|
response = client.post( |
|
|
"/api/v1/chat/emergency", |
|
|
json={"message": "Test metadata"} |
|
|
) |
|
|
|
|
|
assert response.status_code == 200 |
|
|
data = response.json() |
|
|
|
|
|
|
|
|
assert "backend" in data["metadata"] |
|
|
assert "timestamp" in data["metadata"] |
|
|
assert "intent" in data["metadata"] |
|
|
|
|
|
|
|
|
from datetime import datetime |
|
|
timestamp = datetime.fromisoformat(data["metadata"]["timestamp"]) |
|
|
assert timestamp.year >= 2024 |