Initial commit: import from sinmb79/Gov-chat-bot
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
"""
|
||||
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
|
||||
Reference in New Issue
Block a user