import unittest from fastapi.testclient import TestClient from api.app import app from env.grader import TASK_REGISTRY class ApiContractTests(unittest.TestCase): @classmethod def setUpClass(cls): cls.client = TestClient(app) def test_reset_accepts_empty_post(self): response = self.client.post("/reset") self.assertEqual(response.status_code, 200) self.assertEqual(response.headers["content-type"].split(";")[0], "application/json") self.assertIn("tasks", response.json()) def test_reset_accepts_query_parameters_on_post(self): response = self.client.post("/reset?task_name=triage&seed=31") self.assertEqual(response.status_code, 200) payload = response.json() self.assertEqual(len(payload["tasks"]), len(TASK_REGISTRY["triage"])) self.assertEqual(payload["tasks"][0]["name"], TASK_REGISTRY["triage"][0]["name"]) def test_reset_accepts_urlencoded_form_payload(self): response = self.client.post("/reset", data={"task_name": "medium", "seed": "42"}) self.assertEqual(response.status_code, 200) payload = response.json() self.assertEqual(payload["tasks"][0]["name"], TASK_REGISTRY["medium"][0]["name"]) def test_reset_accepts_raw_json_without_json_content_type(self): response = self.client.post( "/reset", content='{"task_name":"hard","seed":19}', headers={"content-type": "text/plain"}, ) self.assertEqual(response.status_code, 200) payload = response.json() self.assertEqual(payload["tasks"][0]["name"], TASK_REGISTRY["hard"][0]["name"]) def test_validate_lists_submission_endpoints(self): response = self.client.get("/validate") self.assertEqual(response.status_code, 200) payload = response.json() self.assertEqual(payload["status"], "ok") self.assertIn("/reset", payload["endpoints"]) self.assertEqual(payload["docker"]["app_import"], "api.app:app") if __name__ == "__main__": unittest.main()