| """ |
| Functional tests — GET /jobs/{request_id}/status |
| ================================================== |
| Tests for the job-status polling endpoint. |
| |
| Key behaviours: |
| • 404 for a request_id that is not in Supabase |
| • 500/404 for a malformed (non-UUID) request_id |
| • Response contract when a real job exists (structural) |
| • Status field is constrained to known values |
| """ |
| import pytest |
| import requests |
| from tests.conftest import BASE_URL, TIMEOUT, NONEXISTENT_REQUEST_ID |
|
|
| ENDPOINT_TPL = f"{BASE_URL}/jobs/{{request_id}}/status" |
|
|
| VALID_STATUSES = { |
| "pending", "processing", "downloading", "generating", |
| "zipping", "uploading", "completed", "completed_no_gdrive", |
| "completed_gdrive_failed", "failed", "error", |
| } |
|
|
|
|
| class TestJobStatusEndpoint: |
| """GET /jobs/{request_id}/status""" |
|
|
| def test_unknown_uuid_returns_non_200(self, http): |
| url = ENDPOINT_TPL.format(request_id=NONEXISTENT_REQUEST_ID) |
| r = http.get(url, timeout=TIMEOUT) |
| |
| assert r.status_code in (404, 500), ( |
| f"Expected 404/500 for unknown request_id, got {r.status_code}" |
| ) |
|
|
| def test_unknown_uuid_response_is_json(self, http): |
| url = ENDPOINT_TPL.format(request_id=NONEXISTENT_REQUEST_ID) |
| r = http.get(url, timeout=TIMEOUT) |
| assert "application/json" in r.headers.get("Content-Type", "") |
|
|
| def test_unknown_uuid_has_detail(self, http): |
| url = ENDPOINT_TPL.format(request_id=NONEXISTENT_REQUEST_ID) |
| r = http.get(url, timeout=TIMEOUT) |
| body = r.json() |
| assert "detail" in body, f"Error response must contain 'detail'. Got: {body}" |
|
|
| def test_garbage_request_id_returns_error(self, http): |
| """A completely non-UUID string should still return a meaningful error.""" |
| url = ENDPOINT_TPL.format(request_id="not-a-real-id") |
| r = http.get(url, timeout=TIMEOUT) |
| assert r.status_code in (404, 500) |
|
|
| def test_endpoint_is_get_only(self, http): |
| url = ENDPOINT_TPL.format(request_id=NONEXISTENT_REQUEST_ID) |
| r = http.post(url, json={}, timeout=TIMEOUT) |
| assert r.status_code == 405, ( |
| f"POST to a GET-only endpoint should be 405, got {r.status_code}" |
| ) |
|
|
| def test_status_field_in_known_values_if_200(self, http): |
| """ |
| If we ever get a 200 (e.g., a real job in the DB), the status must |
| be one of the known values documented in the API. |
| """ |
| url = ENDPOINT_TPL.format(request_id=NONEXISTENT_REQUEST_ID) |
| r = http.get(url, timeout=TIMEOUT) |
| if r.status_code == 200: |
| body = r.json() |
| assert body.get("status") in VALID_STATUSES, ( |
| f"Unexpected status value: {body.get('status')}" |
| ) |
|
|
| def test_200_response_contract_if_present(self, http): |
| """ |
| If a 200 is returned, the body must contain the required fields. |
| """ |
| url = ENDPOINT_TPL.format(request_id=NONEXISTENT_REQUEST_ID) |
| r = http.get(url, timeout=TIMEOUT) |
| if r.status_code == 200: |
| body = r.json() |
| for field in ("request_id", "status", "created_at", "updated_at"): |
| assert field in body, f"Missing required field '{field}' in {body}" |
|
|