ITARS_Ver-2.0 / tests /test_api.py
Eklavya Singh Rathore
Initial release: ITARS platform v1.0
92ab5d8
Raw
History Blame Contribute Delete
7.01 kB
"""API contract tests using an injected fake pipeline (no heavy ML deps)."""
import pytest
pytest.importorskip("fastapi")
pytest.importorskip("httpx")
from fastapi.testclient import TestClient # noqa: E402
from backend.app import create_app # noqa: E402
class _Engine:
index_size = 44160
duplicate_threshold = 0.7623
class _Artifacts:
tag_list = list(range(28))
dept_prototypes = {f"D{i}": object() for i in range(10)}
class FakePipeline:
"""Returns canned results; includes NaN priority_confidence to test sanitizing."""
def __init__(self):
self.artifacts = _Artifacts()
self.duplicate_engine = _Engine()
self.routing_sbert = object()
def process_ticket(self, text, register=True, translate=True):
return {
"ticket_id": "abc12345",
"status": "NOT DUPLICATE",
"route": "AUTO_ROUTE",
"department": "Technical_Support",
"priority": "high",
"priority_confidence": float("nan"),
"confidence": 0.96,
"review": False,
"tags": "network_issue (0.93)",
"message": "ok",
"latency": 12.3,
"is_duplicate": False,
"duplicate_score": 0.21,
"duplicate_text": None,
"explanation": "Ticket processed.",
"original_text": text,
"detected_language": "en",
"translated_text": text,
"translation_applied": False,
"routing": {
"top_tag_votes": [
{"tag": "network_issue", "score": 0.93, "department": "Technical_Support"}
],
"margin": 0.2,
"entropy": 1.6,
"priority_confidence": float("nan"),
},
"explanation_struct": {
"routing": {
"plain": "Auto-routed to Technical Support because network_issue maps there.",
"evidence": {
"department": "Technical_Support",
"tag_votes": [
{
"tag": "network_issue",
"score": 0.93,
"department": "Technical_Support",
}
],
"gate_rule": "margin_pass",
},
"forensics": {"margin": 0.2, "entropy": 1.6},
},
"duplicate": None,
"priority": {
"plain": "Predicted high priority; urgency cues: down.",
"evidence": {"priority": "high", "urgency_words": ["down"]},
"forensics": {"handcrafted_features": {"urgency_count": 1}},
},
},
}
def route_only(self, text):
return {
"mode": "AUTO_ROUTE",
"department": "Technical_Support",
"recommended_department": "Technical_Support",
"priority": "high",
"priority_confidence": float("nan"),
"hybrid_confidence": 0.96,
"review": False,
"margin": 0.2,
"entropy": 1.6,
"top_tag_votes": [
{"tag": "network_issue", "score": 0.93, "department": "Technical_Support"}
],
"note": "Stage 2 pass",
}
def check_duplicate(self, text):
return {
"is_duplicate": True,
"duplicate_score": 0.88,
"matched_text": "production servers down",
"matched_id": "f2bbf3c1",
"threshold": 0.7623,
}
class FakeTranslation:
def translate(self, text, detected_lang=None):
return {
"original_text": text,
"detected_language": "es",
"translated_text": "the production server is down",
"translation_applied": True,
"model": "Helsinki-NLP/opus-mt-ROMANCE-en",
"error": None,
}
@pytest.fixture
def client(db_factory):
return TestClient(
create_app(
pipeline=FakePipeline(),
translation=FakeTranslation(),
session_factory=db_factory,
)
)
def test_health(client):
r = client.get("/health")
assert r.status_code == 200
body = r.json()
assert body["status"] == "ok"
assert body["tags"] == 28
assert body["departments"] == 10
assert body["encoders_loaded"] is True
def test_analyze_ticket(client):
r = client.post("/analyze-ticket", json={"text": "server down", "register": False})
assert r.status_code == 200
body = r.json()
assert body["route"] == "AUTO_ROUTE"
assert body["department"] == "Technical_Support"
assert body["priority_confidence"] is None # NaN sanitized
assert body["routing"]["priority_confidence"] is None # nested NaN sanitized
assert len(body["tag_votes"]) == 1
assert body["original_text"] == "server down"
assert body["translation_applied"] is False
# Layered explainability surfaces on every ticket.
assert body["explanation_layers"]["routing"]["evidence"]["gate_rule"] == "margin_pass"
assert body["explanation_layers"]["duplicate"] is None
assert "down" in body["explanation_layers"]["priority"]["evidence"]["urgency_words"]
def test_analyze_ticket_empty_text_422(client):
r = client.post("/analyze-ticket", json={"text": ""})
assert r.status_code == 422
def test_route(client):
r = client.post("/route", json={"text": "server down"})
assert r.status_code == 200
assert r.json()["mode"] == "AUTO_ROUTE"
def test_duplicate_check(client):
r = client.post("/duplicate-check", json={"text": "production servers down"})
assert r.status_code == 200
body = r.json()
assert body["is_duplicate"] is True
assert body["matched_id"] == "f2bbf3c1"
def test_translate(client):
r = client.post("/translate", json={"text": "el servidor esta caido"})
assert r.status_code == 200
body = r.json()
assert body["detected_language"] == "es"
assert body["translated_text"] == "the production server is down"
assert body["original_text"] == "el servidor esta caido"
def test_translate_unsupported_target(client):
r = client.post("/translate", json={"text": "hola", "target_lang": "fr"})
assert r.status_code == 400
def test_metrics_increment(client):
client.post("/analyze-ticket", json={"text": "server down", "register": False})
r = client.get("/metrics")
assert r.status_code == 200
body = r.json()
assert body["requests_total"] >= 1
assert body["route_mode_counts"].get("AUTO_ROUTE", 0) >= 1
def test_openapi_renders(client):
r = client.get("/openapi.json")
assert r.status_code == 200
paths = r.json()["paths"]
for endpoint in ["/analyze-ticket", "/route", "/duplicate-check", "/translate", "/health", "/metrics"]:
assert endpoint in paths