110 lines
3.1 KiB
Python
110 lines
3.1 KiB
Python
"""
|
|
POST /engine/query 엔드포인트 테스트 (웹 시뮬레이터).
|
|
"""
|
|
import pytest
|
|
from unittest.mock import AsyncMock, patch
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_engine_query_returns_correct_structure(client):
|
|
"""POST /engine/query → 필수 필드 포함 응답."""
|
|
response = await client.post(
|
|
"/engine/query",
|
|
json={
|
|
"tenant": "test-tenant",
|
|
"utterance": "여권 발급 방법 알려주세요",
|
|
"user_key": "test-user-key",
|
|
},
|
|
)
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert "answer" in data
|
|
assert "tier" in data
|
|
assert "source" in data
|
|
assert "citations" in data
|
|
assert "request_id" in data
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_engine_query_tier_d_when_no_faq(client):
|
|
"""FAQ 없으면 Tier D 폴백 반환."""
|
|
response = await client.post(
|
|
"/engine/query",
|
|
json={
|
|
"tenant": "test-tenant",
|
|
"utterance": "알 수 없는 질문",
|
|
"user_key": "user-1",
|
|
},
|
|
)
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["tier"] == "D"
|
|
assert data["source"] == "fallback"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_engine_query_idempotency_deduplication(client):
|
|
"""같은 request_id로 두 번 요청 → 동일 응답 (캐시 HIT)."""
|
|
payload = {
|
|
"tenant": "test-tenant",
|
|
"utterance": "중복 요청 테스트",
|
|
"user_key": "user-1",
|
|
"request_id": "dup-req-001",
|
|
}
|
|
|
|
# Mock Redis for idempotency
|
|
mock_redis = AsyncMock()
|
|
cached_result = {
|
|
"answer": "캐시된 응답",
|
|
"tier": "D",
|
|
"source": "fallback",
|
|
"citations": [],
|
|
"request_id": "dup-req-001",
|
|
"elapsed_ms": 10,
|
|
"is_timeout": False,
|
|
}
|
|
import json
|
|
mock_redis.get = AsyncMock(return_value=json.dumps(cached_result).encode())
|
|
mock_redis.setex = AsyncMock()
|
|
|
|
# app.state에 직접 설정 (lifespan 미실행 상태)
|
|
client.app.state.redis = mock_redis
|
|
try:
|
|
resp1 = await client.post("/engine/query", json=payload)
|
|
finally:
|
|
client.app.state.redis = None
|
|
|
|
assert resp1.status_code == 200
|
|
assert resp1.json()["answer"] == "캐시된 응답"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_engine_query_request_id_auto_generated(client):
|
|
"""request_id 미전송 시 자동 생성."""
|
|
response = await client.post(
|
|
"/engine/query",
|
|
json={
|
|
"tenant": "test-tenant",
|
|
"utterance": "테스트",
|
|
"user_key": "user-1",
|
|
},
|
|
)
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["request_id"] is not None
|
|
assert len(data["request_id"]) > 0
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_engine_query_channel_default_web(client):
|
|
"""channel 미전송 시 기본값 web 사용 — 응답은 정상."""
|
|
response = await client.post(
|
|
"/engine/query",
|
|
json={
|
|
"tenant": "test-tenant",
|
|
"utterance": "테스트",
|
|
"user_key": "user-1",
|
|
},
|
|
)
|
|
assert response.status_code == 200
|