papermate / tests /test_api_contract.py
Phuc-HugigFace's picture
@
3fa4cc8
Raw
History Blame Contribute Delete
3.68 kB
import io
import unittest
from unittest.mock import AsyncMock, patch
from fastapi.testclient import TestClient
from backend.main import app
class ApiContractTests(unittest.TestCase):
def setUp(self):
self.client = TestClient(app)
def test_submit_rejects_non_pdf(self):
response = self.client.post(
"/api/submit",
files={"file": ("note.txt", b"hello", "text/plain")},
data={"email": "user@example.com"},
)
self.assertEqual(response.status_code, 400)
self.assertIn("Only PDF files", response.json()["detail"])
def test_review_lookup_404_for_unknown_key(self):
with patch("backend.main.job_store.get_job", new=AsyncMock(return_value=None)):
response = self.client.get("/api/review/missing-key")
self.assertEqual(response.status_code, 404)
self.assertIn("Review not found", response.json()["detail"])
def test_review_lookup_returns_existing_job_shape(self):
job = {
"access_key": "known-key",
"email": "user@example.com",
"status": "completed",
"created_at": "2026-01-01T00:00:00+00:00",
"completed_at": "2026-01-01T00:05:00+00:00",
"paper_filename": "paper.pdf",
"review": {"overall_assessment": 3.5, "paper_summary": "Solid."},
"has_parsed_markdown": True,
"error": None,
}
with patch("backend.main.job_store.get_job", new=AsyncMock(return_value=job)):
response = self.client.get("/api/review/known-key")
self.assertEqual(response.status_code, 200)
body = response.json()
self.assertEqual(body["access_key"], "known-key")
self.assertEqual(body["review"]["overall_assessment"], 3.5)
# Retrieval links are attached for the original PDF and parsed markdown.
self.assertEqual(body["pdf_url"], "/api/review/known-key/pdf")
self.assertEqual(body["markdown_url"], "/api/review/known-key/markdown")
def test_submit_returns_access_key_with_valid_pdf(self):
fake_job = {
"access_key": "new-secret",
"status": "pending",
}
with patch("backend.main.job_store.create_job", new=AsyncMock(return_value=fake_job)), \
patch("backend.main.send_access_key_email"), \
patch("backend.main._run_pipeline", new=AsyncMock()):
response = self.client.post(
"/api/submit",
files={"file": ("paper.pdf", io.BytesIO(b"%PDF-1.4 sample"), "application/pdf")},
data={"email": "user@example.com"},
)
self.assertEqual(response.status_code, 200)
body = response.json()
self.assertEqual(body["access_key"], "new-secret")
self.assertNotIn("submission_key", body)
self.assertIn("submitted", body["message"].lower())
def test_feedback_is_saved_in_feedback_table_contract(self):
job = {"access_key": "known-key", "status": "completed"}
save_feedback = AsyncMock(return_value={"id": 1})
with patch("backend.main.job_store.get_job", new=AsyncMock(return_value=job)), \
patch("backend.main.job_store.save_feedback", new=save_feedback):
response = self.client.post(
"/api/feedback/known-key",
json={
"helpfulness": "high",
"has_critical_error": False,
"has_suggestions": True,
"comments": "Good signal",
},
)
self.assertEqual(response.status_code, 200)
save_feedback.assert_awaited_once()