148 lines
5.5 KiB
Python
148 lines
5.5 KiB
Python
"""스모크 테스트. `pip install fastapi httpx pytest` 후 실행."""
|
|
from __future__ import annotations
|
|
|
|
from fastapi.testclient import TestClient
|
|
|
|
from app.main import app
|
|
|
|
|
|
def test_health():
|
|
with TestClient(app) as client:
|
|
resp = client.get("/v1/health")
|
|
assert resp.status_code == 200
|
|
body = resp.json()
|
|
assert body["status"] == "ok"
|
|
assert body["corpus_size"] >= 0
|
|
|
|
|
|
def test_detect_no_auth_required():
|
|
"""인증 제거 - 키 없이도 200 응답."""
|
|
with TestClient(app) as client:
|
|
resp = client.post(
|
|
"/v1/plagiarism/detect",
|
|
json={"doc_id": "x", "text": "테스트 본문"},
|
|
)
|
|
assert resp.status_code == 200
|
|
|
|
|
|
def test_detect_returns_schema():
|
|
with TestClient(app) as client:
|
|
resp = client.post(
|
|
"/v1/plagiarism/detect",
|
|
json={
|
|
"doc_id": "t-1",
|
|
"text": "어린왕자는 작은 별에서 온 소년이다. 그는 여우를 만나 길들임을 배운다.",
|
|
},
|
|
)
|
|
assert resp.status_code == 200
|
|
body = resp.json()
|
|
assert body["doc_id"] == "t-1"
|
|
assert "matches" in body
|
|
assert "extracted_elements" in body
|
|
assert "engine_version" in body
|
|
|
|
|
|
def test_copyright_review_returns_only_mobile_tab_fields():
|
|
with TestClient(app) as client:
|
|
resp = client.post(
|
|
"/v1/plagiarism/review",
|
|
json={"doc_id": "mobile-1", "text": "창밖으로 보이는 숲은 오늘따라 푸르게 보였다."},
|
|
)
|
|
assert resp.status_code == 200
|
|
body = resp.json()
|
|
assert set(body) == {
|
|
"doc_id", "copyright", "similar_sentences",
|
|
"ai_generation_suspicion", "legal_judgment", "analyzed_at",
|
|
}
|
|
assert 0 <= body["copyright"]["originality_percent"] <= 100
|
|
assert body["copyright"]["description"]
|
|
assert body["similar_sentences"]["label"].endswith("건")
|
|
assert body["ai_generation_suspicion"]["label"] in {
|
|
"낮음", "중간", "높음", "확인 불가",
|
|
}
|
|
assert "matches" not in body
|
|
assert "extracted_elements" not in body
|
|
assert "score_semantics" not in body
|
|
|
|
|
|
def test_batch_flow():
|
|
with TestClient(app) as client:
|
|
resp = client.post(
|
|
"/v1/plagiarism/batch",
|
|
json={
|
|
"items": [
|
|
{"doc_id": "b-1", "text": "앤 셜리는 초록 지붕 집에 입양된 소녀다."},
|
|
]
|
|
},
|
|
)
|
|
assert resp.status_code == 202
|
|
job_id = resp.json()["job_id"]
|
|
status = client.get(f"/v1/plagiarism/batch/{job_id}")
|
|
assert status.status_code == 200
|
|
|
|
|
|
def test_detect_exposes_score_semantics():
|
|
"""#9 — 점수/임계값의 의미가 응답에 명시되어야 한다."""
|
|
with TestClient(app) as client:
|
|
resp = client.post(
|
|
"/v1/plagiarism/detect",
|
|
json={"doc_id": "s-1", "text": "어린왕자는 작은 별에서 온 소년이다."},
|
|
)
|
|
assert resp.status_code == 200
|
|
sem = resp.json()["score_semantics"]
|
|
assert sem["threshold_source"] == "server_default"
|
|
assert sem["threshold_calibrated"] is False
|
|
assert sem["provisional"] is True, "캘리브레이션 전에는 잠정값으로 노출"
|
|
assert 0.0 <= sem["union_coverage"] <= 1.0
|
|
assert sem["query_chars"] > 0
|
|
assert "침해 확률이 아닙니다" in sem["note"]
|
|
|
|
|
|
def test_detect_reports_request_threshold_override():
|
|
with TestClient(app) as client:
|
|
resp = client.post(
|
|
"/v1/plagiarism/detect",
|
|
json={"doc_id": "s-2", "text": "앤 셜리는 초록 지붕 집에 입양된 소녀다.",
|
|
"options": {"threshold": 0.4}},
|
|
)
|
|
sem = resp.json()["score_semantics"]
|
|
assert sem["threshold_source"] == "request_override"
|
|
assert sem["threshold_used"] == 0.4
|
|
|
|
|
|
def test_detect_accepts_legal_context():
|
|
"""#10 — 사람이 확인한 사실을 전달하면 missing_factors 에서 빠진다."""
|
|
with TestClient(app) as client:
|
|
base = client.post(
|
|
"/v1/plagiarism/detect",
|
|
json={"doc_id": "l-1", "text": "홍길동은 활빈당을 만들어 재물을 나누었다."},
|
|
).json()["legal_risk"]
|
|
assert base["access_evidence"] == "not_provided"
|
|
assert len(base["missing_factors"]) == 3
|
|
|
|
supplied = client.post(
|
|
"/v1/plagiarism/detect",
|
|
json={
|
|
"doc_id": "l-2", "text": "홍길동은 활빈당을 만들어 재물을 나누었다.",
|
|
"legal_context": {
|
|
"work_type": "literary", "access_evidence": True,
|
|
"protected_expression_reviewed": True, "rights_verified": True,
|
|
},
|
|
},
|
|
).json()["legal_risk"]
|
|
assert supplied["access_evidence"] == "provided"
|
|
assert supplied["protected_expression"] == "reviewed"
|
|
assert supplied["missing_factors"] == []
|
|
|
|
|
|
def test_matches_carry_match_reasons():
|
|
with TestClient(app) as client:
|
|
resp = client.post(
|
|
"/v1/plagiarism/detect",
|
|
json={"doc_id": "r-1", "text": "어린왕자는 작은 별에서 온 소년이다. 그는 여우를 만난다.",
|
|
"options": {"threshold": 0.01}},
|
|
)
|
|
for match in resp.json()["matches"]:
|
|
assert match["match_reasons"], "채택 이유가 비어 있으면 안 된다"
|
|
assert set(match["match_reasons"]) <= {"score_threshold", "exact_span", "coverage"}
|