Mahrufa's picture
Open external links in new tabs
68705e9
Raw History Blame Contribute Delete
7.06 kB
import json
import pytest
from fastapi.testclient import TestClient
from clinical_rag_eval import api as api_module
app = api_module.app
@pytest.fixture(autouse=True)
def clear_api_key(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.delenv("API_KEY", raising=False)
def test_root_endpoint() -> None:
with TestClient(app) as client:
response = client.get("/")
assert response.status_code == 200
assert "text/html" in response.headers["content-type"]
assert "Evidence-first Clinical RAG Evaluation Framework" in response.text
assert "API Docs" in response.text
assert "/docs" in response.text
assert (
'href="https://github.com/mahrufa-binta-ali/clinical-rag-evaluation-framework" '
'target="_blank" rel="noopener noreferrer"'
) in response.text
assert (
'href="https://huggingface.co/spaces/Mahrufa/clinical-rag-evaluation-framework" '
'target="_blank" rel="noopener noreferrer"'
) in response.text
def test_demo_endpoint() -> None:
with TestClient(app) as client:
response = client.get("/demo")
assert response.status_code == 200
assert "text/html" in response.headers["content-type"]
assert "Evidence Retrieval Playground" in response.text
assert "Why evidence first?" in response.text
assert "Try Built-in Evidence Retrieval" in response.text
assert "Upload and Index a PDF" in response.text
assert "Search Uploaded Documents" in response.text
assert "Developer API" in response.text
assert (
'href="https://github.com/mahrufa-binta-ali/clinical-rag-evaluation-framework" '
'target="_blank" rel="noopener noreferrer"'
) in response.text
def test_demo_config_returns_api_key_requirement(
monkeypatch: pytest.MonkeyPatch,
) -> None:
monkeypatch.setenv("API_KEY", "change-me")
with TestClient(app) as client:
response = client.get("/demo-config")
assert response.status_code == 200
assert response.json() == {"api_key_required": True}
def test_demo_query_returns_builtin_results() -> None:
with TestClient(app) as client:
response = client.post(
"/demo-query",
json={
"question": "Why is evidence retrieval important in healthcare AI?",
"top_k": 3,
},
)
assert response.status_code == 200
body = response.json()
assert body["mode"] == "built-in demo corpus"
assert len(body["results"]) >= 1
assert body["results"][0]["rank"] == 1
assert "evidence_summary" in body
assert body["evidence_summary"]["answer_generation"] == "disabled"
def test_health_endpoint() -> None:
with TestClient(app) as client:
response = client.get("/health")
assert response.status_code == 200
assert response.json() == {
"status": "ok",
"project": "Clinical RAG Evaluation Framework",
}
def test_upload_rejects_non_pdf_file() -> None:
with TestClient(app) as client:
response = client.post(
"/upload",
files={"file": ("notes.txt", b"not a pdf", "text/plain")},
)
assert response.status_code == 400
assert response.json()["detail"] == "Only .pdf files are allowed."
def test_upload_and_index_rejects_non_pdf_file() -> None:
with TestClient(app) as client:
response = client.post(
"/upload-and-index",
files={"file": ("notes.txt", b"not a pdf", "text/plain")},
)
assert response.status_code == 400
assert response.json()["detail"] == "Only .pdf files are allowed."
def test_health_endpoint_works_without_api_key_when_api_key_is_set(
monkeypatch: pytest.MonkeyPatch,
) -> None:
monkeypatch.setenv("API_KEY", "change-me")
with TestClient(app) as client:
response = client.get("/health")
assert response.status_code == 200
assert response.json()["status"] == "ok"
def test_query_requires_api_key_when_configured(
monkeypatch: pytest.MonkeyPatch,
) -> None:
monkeypatch.setenv("API_KEY", "change-me")
with TestClient(app) as client:
response = client.post("/query", json={"question": "What is RAG?"})
assert response.status_code == 401
assert response.json()["detail"] == "Missing or invalid API key."
def test_upload_requires_api_key_when_configured(
monkeypatch: pytest.MonkeyPatch,
) -> None:
monkeypatch.setenv("API_KEY", "change-me")
with TestClient(app) as client:
response = client.post(
"/upload",
files={"file": ("notes.pdf", b"%PDF-1.4", "application/pdf")},
)
assert response.status_code == 401
assert response.json()["detail"] == "Missing or invalid API key."
def test_protected_upload_accepts_correct_api_key(
monkeypatch: pytest.MonkeyPatch,
) -> None:
monkeypatch.setenv("API_KEY", "change-me")
with TestClient(app) as client:
response = client.post(
"/upload",
headers={"X-API-Key": "change-me"},
files={"file": ("notes.txt", b"not a pdf", "text/plain")},
)
assert response.status_code == 400
assert response.json()["detail"] == "Only .pdf files are allowed."
def read_audit_events(audit_log_path) -> list[dict]:
return [
json.loads(line)
for line in audit_log_path.read_text(encoding="utf-8").splitlines()
]
def test_audit_log_file_is_created_after_health_check(
monkeypatch: pytest.MonkeyPatch,
tmp_path,
) -> None:
audit_log_path = tmp_path / "audit.log"
monkeypatch.setattr(api_module, "AUDIT_LOG_FILE", audit_log_path)
with TestClient(app) as client:
response = client.get("/health")
assert response.status_code == 200
assert audit_log_path.exists()
events = read_audit_events(audit_log_path)
assert any(event["event"] == "api_startup" for event in events)
health_events = [
event for event in events if event["event"] == "health_check_request"
]
assert health_events
assert health_events[-1]["endpoint"] == "/health"
assert health_events[-1]["status"] == "ok"
assert "client_ip" in health_events[-1]
def test_unauthorized_request_writes_audit_event(
monkeypatch: pytest.MonkeyPatch,
tmp_path,
) -> None:
audit_log_path = tmp_path / "audit.log"
monkeypatch.setattr(api_module, "AUDIT_LOG_FILE", audit_log_path)
monkeypatch.setenv("API_KEY", "change-me")
with TestClient(app) as client:
response = client.post("/query", json={"question": "What is RAG?"})
assert response.status_code == 401
events = read_audit_events(audit_log_path)
unauthorized_events = [
event for event in events if event["event"] == "unauthorized_request"
]
assert unauthorized_events
event = unauthorized_events[-1]
assert event["endpoint"] == "/query"
assert event["status"] == "unauthorized"
assert event["error_message"] == "Missing or invalid API key."
assert "change-me" not in audit_log_path.read_text(encoding="utf-8")