Spaces:
Sleeping
Sleeping
| """RAG API tests — real RagService (in-memory vector store + fake embedder).""" | |
| import hashlib | |
| import numpy as np | |
| import pytest | |
| pytest.importorskip("fastapi") | |
| pytest.importorskip("httpx") | |
| from fastapi.testclient import TestClient # noqa: E402 | |
| from backend.app import create_app # noqa: E402 | |
| from backend.core.config import Settings # noqa: E402 | |
| from backend.rag.embeddings import RagEmbedder # noqa: E402 | |
| from backend.rag.service import RagService # noqa: E402 | |
| from backend.rag.store import InMemoryVectorStore # noqa: E402 | |
| from backend.repositories import tickets as repo # noqa: E402 | |
| DIM = 384 | |
| STOP = set( | |
| "represent this sentence for searching relevant passages the a an is are was " | |
| "were and or to of my that i it in on again please".split() | |
| ) | |
| def fake_embed(texts): | |
| out = np.zeros((len(texts), DIM), dtype="float32") | |
| for i, text in enumerate(texts): | |
| for word in str(text).lower().split(): | |
| if word in STOP: | |
| continue | |
| out[i, int(hashlib.md5(word.encode()).hexdigest(), 16) % DIM] += 1.0 | |
| return out | |
| def _db_result(ticket_id: str, text: str) -> dict: | |
| return { | |
| "ticket_id": ticket_id, | |
| "route": "HUMAN_REVIEW", | |
| "department": "Technical_Support", | |
| "priority": "critical", | |
| "priority_confidence": 0.8, | |
| "confidence": 0.74, | |
| "review": True, | |
| "tags": "incident (1.00)", | |
| "latency": 12.0, | |
| "is_duplicate": False, | |
| "duplicate_score": 0.2, | |
| "duplicate_text": None, | |
| "duplicate_matched_id": None, | |
| "duplicate_threshold": 0.76, | |
| "explanation": "x", | |
| "explanation_struct": {"routing": {}, "duplicate": None, "priority": {}}, | |
| "original_text": text, | |
| "routing_text": text, | |
| "detected_language": "en", | |
| "translation_applied": False, | |
| "routing": {"recommended_department": "Technical_Support", "margin": 0.1, "entropy": 1.6, "top_tag_votes": []}, | |
| } | |
| def client(db_factory): | |
| with db_factory() as session: | |
| repo.save_analysis( | |
| session, _db_result("prod0001", "production server down unreachable outage") | |
| ) | |
| settings = Settings(rag_embedding_dim=DIM, vector_store_mode="memory") | |
| rag = RagService( | |
| settings, | |
| embedder=RagEmbedder(settings, embed_fn=fake_embed), | |
| store=InMemoryVectorStore(settings), | |
| ) | |
| rag.ingest( | |
| [ | |
| {"ticket_id": "h1", "text": "production server down unreachable outage incident", "department": "Technical_Support", "priority": "high"}, | |
| {"ticket_id": "h2", "text": "billing charged twice subscription refund", "department": "Billing_And_Payments", "priority": "medium"}, | |
| ] | |
| ) | |
| app = create_app(pipeline=object(), session_factory=db_factory, rag=rag) | |
| return TestClient(app) | |
| def test_rag_health(client): | |
| body = client.get("/rag/health").json() | |
| assert body["collections"]["historical_tickets"] == 2 | |
| assert body["embedding_dim"] == DIM | |
| def test_rag_search_returns_cited_results(client): | |
| r = client.post("/rag/search", json={"query": "production server down"}) | |
| assert r.status_code == 200 | |
| results = r.json() | |
| assert results | |
| assert results[0]["ticket_id"] == "h1" | |
| assert results[0]["text"] # citation text present | |
| assert results[0]["score"] >= results[-1]["score"] | |
| def test_rag_search_department_filter(client): | |
| r = client.post( | |
| "/rag/search", | |
| json={ | |
| "query": "charged subscription refund", | |
| "department": "Billing_And_Payments", | |
| "top_k": 5, | |
| }, | |
| ) | |
| assert r.status_code == 200 | |
| body = r.json() | |
| assert body and all(x["department"] == "Billing_And_Payments" for x in body) | |
| def test_similar_tickets_endpoint(client): | |
| r = client.get("/tickets/prod0001/similar") | |
| assert r.status_code == 200 | |
| results = r.json() | |
| assert any(x["ticket_id"] == "h1" for x in results) | |
| assert all(x["ticket_id"] != "prod0001" for x in results) | |
| def test_similar_tickets_404(client): | |
| assert client.get("/tickets/ghost/similar").status_code == 404 | |
| def test_review_override_feeds_rag_feedback_records(client): | |
| # The feedback loop (Phase 11): an override ingests the human-verified | |
| # routing into the RAG feedback_records collection. | |
| before = client.get("/rag/health").json()["collections"].get("feedback_records", 0) | |
| r = client.post( | |
| "/tickets/prod0001/review", | |
| json={ | |
| "action": "overridden", | |
| "final_department": "IT_Support", | |
| "correction_reason": "wrong_department", | |
| }, | |
| ) | |
| assert r.status_code == 200 | |
| after = client.get("/rag/health").json()["collections"]["feedback_records"] | |
| assert after == before + 1 | |
| def test_get_rag_dependency_raises_503_when_absent(): | |
| import types | |
| from fastapi import HTTPException | |
| from backend.api.deps import get_rag | |
| request = types.SimpleNamespace( | |
| app=types.SimpleNamespace(state=types.SimpleNamespace()) | |
| ) | |
| with pytest.raises(HTTPException) as excinfo: | |
| get_rag(request) | |
| assert excinfo.value.status_code == 503 | |