Files
web-page-backend/saju-lab/tests/test_routes.py

230 lines
9.0 KiB
Python

import pytest
from unittest.mock import patch, AsyncMock
from fastapi.testclient import TestClient
from app.main import app
from app import db as db_module
@pytest.fixture(autouse=True)
def fresh_db(monkeypatch, tmp_path):
db_file = tmp_path / "test_saju.db"
monkeypatch.setattr(db_module, "DB_PATH", str(db_file))
db_module.init_db()
yield
try:
if db_file.exists():
db_file.unlink()
except PermissionError:
pass
def _interpret_result(interp_json=None):
if interp_json is None:
interp_json = {"items": [], "summary": "...", "advice": "...", "warning": None, "confidence": "medium"}
return {
"interpretation_json": interp_json,
"model": "claude-sonnet-4-6",
"tokens_in": 200, "tokens_out": 400, "cost_usd": 0.01,
"latency_ms": 1200, "reroll_count": 0,
}
def test_health():
with TestClient(app) as c:
r = c.get("/health")
assert r.status_code == 200
assert r.json() == {"ok": True}
def test_saju_interpret_endpoint(monkeypatch):
"""saju interpret이 pipeline mock으로 동작 + 신규 필드 검증."""
async def fake_interpret(*args, **kwargs):
return _interpret_result()
from app.routers import saju as saju_router
monkeypatch.setattr(saju_router.pipeline, "interpret_saju", fake_interpret)
with TestClient(app) as c:
r = c.post("/api/saju/interpret", json={
"year": 1990, "month": 5, "day": 15, "hour": 14,
"gender": "male", "calendar_type": "solar"
})
assert r.status_code == 200, r.text
data = r.json()
assert "saju" in data
assert "analysis" in data
assert "daeun" in data
assert "reading_id" in data
assert data["reading_id"] > 0
# 신규 필드
assert "fortune_scores" in data
for k in ("wealth", "romance", "social", "career", "overall"):
assert k in data["fortune_scores"]
assert 0 <= data["fortune_scores"][k] <= 100
assert "lucky" in data
for k in ("color", "number", "direction", "good_signs", "warnings"):
assert k in data["lucky"]
assert "monthly_flow" in data
assert len(data["monthly_flow"]) == 12
def test_saju_list_get_cycle(monkeypatch):
async def fake_interpret(*args, **kwargs):
return _interpret_result()
from app.routers import saju as saju_router
monkeypatch.setattr(saju_router.pipeline, "interpret_saju", fake_interpret)
with TestClient(app) as c:
# save
rid = c.post("/api/saju/interpret", json={
"year": 1990, "month": 5, "day": 15, "hour": 14,
"gender": "male", "calendar_type": "solar"
}).json()["reading_id"]
# list
assert c.get("/api/saju/readings").json()["total"] == 1
# get
r = c.get(f"/api/saju/readings/{rid}")
assert r.status_code == 200
assert r.json()["birth_year"] == 1990
def test_saju_patch_and_delete(monkeypatch):
async def fake_interpret(*args, **kwargs):
return _interpret_result()
from app.routers import saju as saju_router
monkeypatch.setattr(saju_router.pipeline, "interpret_saju", fake_interpret)
with TestClient(app) as c:
rid = c.post("/api/saju/interpret", json={
"year": 1990, "month": 5, "day": 15, "hour": 14,
"gender": "male", "calendar_type": "solar"
}).json()["reading_id"]
r = c.patch(f"/api/saju/readings/{rid}", json={"favorite": True, "memo": "메모"})
assert r.status_code == 200
row = c.get(f"/api/saju/readings/{rid}").json()
assert row["favorite"] == 1
assert row["memo"] == "메모"
r = c.delete(f"/api/saju/readings/{rid}")
assert r.status_code == 200
assert c.get(f"/api/saju/readings/{rid}").status_code == 404
def test_saju_get_404():
with TestClient(app) as c:
assert c.get("/api/saju/readings/9999").status_code == 404
def test_saju_current_fortune(monkeypatch):
async def fake_interpret(*args, **kwargs):
return _interpret_result()
from app.routers import saju as saju_router
monkeypatch.setattr(saju_router.pipeline, "interpret_saju", fake_interpret)
with TestClient(app) as c:
rid = c.post("/api/saju/interpret", json={
"year": 1990, "month": 5, "day": 15, "hour": 14,
"gender": "male", "calendar_type": "solar"
}).json()["reading_id"]
r = c.get(f"/api/saju/current-fortune?reading_id={rid}")
assert r.status_code == 200
data = r.json()
assert "seun" in data
assert data["seun"]["stem"]
def test_compat_interpret(monkeypatch):
async def fake_compat(*args, **kwargs):
return {
"interpretation_json": {"summary": "...", "strengths": [
{"title": "A", "explanation": "B", "evidence": "C"},
{"title": "A2", "explanation": "B2", "evidence": "C2"},
], "challenges": [
{"title": "D", "explanation": "E", "evidence": "F"},
{"title": "D2", "explanation": "E2", "evidence": "F2"},
], "advice": "...", "warning": None, "confidence": "high"},
"model": "claude-sonnet-4-6",
"tokens_in": 300, "tokens_out": 500, "cost_usd": 0.015,
"latency_ms": 1500, "reroll_count": 0,
}
from app.routers import compat as compat_router
monkeypatch.setattr(compat_router.pipeline, "interpret_compat", fake_compat)
with TestClient(app) as c:
r = c.post("/api/saju/compat/interpret", json={
"person_a": {"year": 1990, "month": 5, "day": 15, "hour": 14, "gender": "male", "calendar_type": "solar"},
"person_b": {"year": 1992, "month": 8, "day": 8, "hour": 18, "gender": "female", "calendar_type": "solar"},
})
assert r.status_code == 200, r.text
data = r.json()
assert "score" in data
assert "saju_a" in data
assert "saju_b" in data
def test_compat_list_get_cycle(monkeypatch):
async def fake_compat(*args, **kwargs):
return {
"interpretation_json": {"summary": "...", "strengths": [
{"title": "a", "explanation": "b", "evidence": "c"},
{"title": "a", "explanation": "b", "evidence": "c"},
], "challenges": [
{"title": "d", "explanation": "e", "evidence": "f"},
{"title": "d", "explanation": "e", "evidence": "f"},
], "advice": "", "warning": None, "confidence": "medium"},
"model": "x", "tokens_in": 0, "tokens_out": 0, "cost_usd": 0.0,
"latency_ms": 0, "reroll_count": 0,
}
from app.routers import compat as compat_router
monkeypatch.setattr(compat_router.pipeline, "interpret_compat", fake_compat)
with TestClient(app) as c:
rid = c.post("/api/saju/compat/interpret", json={
"person_a": {"year": 1990, "month": 5, "day": 15, "hour": 14, "gender": "male", "calendar_type": "solar"},
"person_b": {"year": 1992, "month": 8, "day": 8, "hour": 18, "gender": "female", "calendar_type": "solar"},
}).json()["reading_id"]
assert c.get("/api/saju/compat/readings").json()["total"] == 1
r = c.get(f"/api/saju/compat/readings/{rid}")
assert r.status_code == 200
assert r.json()["score"] >= 0
def test_compat_patch_and_delete(monkeypatch):
async def fake_compat(*args, **kwargs):
return {
"interpretation_json": {"summary": "...", "strengths": [
{"title": "a", "explanation": "b", "evidence": "c"},
{"title": "a", "explanation": "b", "evidence": "c"},
], "challenges": [
{"title": "d", "explanation": "e", "evidence": "f"},
{"title": "d", "explanation": "e", "evidence": "f"},
], "advice": "", "warning": None, "confidence": "medium"},
"model": "x", "tokens_in": 0, "tokens_out": 0, "cost_usd": 0.0,
"latency_ms": 0, "reroll_count": 0,
}
from app.routers import compat as compat_router
monkeypatch.setattr(compat_router.pipeline, "interpret_compat", fake_compat)
with TestClient(app) as c:
rid = c.post("/api/saju/compat/interpret", json={
"person_a": {"year": 1990, "month": 5, "day": 15, "hour": 14, "gender": "male", "calendar_type": "solar"},
"person_b": {"year": 1992, "month": 8, "day": 8, "hour": 18, "gender": "female", "calendar_type": "solar"},
}).json()["reading_id"]
r = c.patch(f"/api/saju/compat/readings/{rid}", json={"favorite": True, "memo": "좋은 궁합"})
assert r.status_code == 200
row = c.get(f"/api/saju/compat/readings/{rid}").json()
assert row["favorite"] == 1
r = c.delete(f"/api/saju/compat/readings/{rid}")
assert r.status_code == 200
assert c.get(f"/api/saju/compat/readings/{rid}").status_code == 404
def test_compat_get_404():
with TestClient(app) as c:
assert c.get("/api/saju/compat/readings/9999").status_code == 404