Spaces:
Running
Running
| """End-to-end smoke test for the D-light upload pipeline. | |
| Stays local: drives the FastAPI app via Starlette TestClient and exercises | |
| the unit-level pipeline helpers. Skips the LLM `extract-text` body so we | |
| don't need a live NVIDIA key β the offline fallback is what we want here. | |
| """ | |
| from __future__ import annotations | |
| import io | |
| from pathlib import Path | |
| from fastapi.testclient import TestClient | |
| from app.services.proj_doc_pipeline import ( | |
| IngestArtifact, | |
| collect_text_window, | |
| extract_pages_text, | |
| stamp_index, | |
| ) | |
| TEST_PDF = Path(__file__).parent / "test.pdf" | |
| def test_pipeline_helpers_text_extraction(): | |
| """Pure pipeline layer: native text + stamp heuristic on tests/test.pdf.""" | |
| if not TEST_PDF.exists(): | |
| # No fixture PDF β skip; the assertion below is meant to be smoke. | |
| return | |
| raw = TEST_PDF.read_bytes() | |
| artifact = extract_pages_text(raw) | |
| assert artifact.sha256, "sha256 must be present" | |
| assert artifact.page_count >= 1, "at least one page expected" | |
| assert isinstance(artifact.pages, list) | |
| # Stamp index is keyed on label incl. "(ΡΡΡ. N)" suffix. | |
| stamps = stamp_index(artifact.pages) | |
| assert isinstance(stamps, dict) | |
| # Window helper must return a non-empty string for any page. | |
| if artifact.pages: | |
| window = collect_text_window( | |
| artifact.pages, around=0, span=2 | |
| ) | |
| assert window and isinstance(window, str) | |
| def test_pipeline_artifact_default_empty_text(): | |
| """Direct call against the dataclass β no IO.""" | |
| artifact = IngestArtifact( | |
| file_name="x.pdf", | |
| mime_type="application/pdf", | |
| sha256="0" * 64, | |
| page_count=0, | |
| ) | |
| assert artifact.full_text(1) == "" | |
| assert artifact.has_native_text is False | |
| def test_uploads_blueprint_endpoint_accepts_pdf(minimal_app_client: TestClient): | |
| """POST /uploads/blueprint β 200, page list non-empty (no Supabase).""" | |
| if not TEST_PDF.exists(): | |
| return | |
| client = minimal_app_client | |
| files = {"file": ("test.pdf", TEST_PDF.read_bytes(), "application/pdf")} | |
| resp = client.post("/uploads/blueprint", files=files) | |
| assert resp.status_code == 200, resp.text | |
| body = resp.json() | |
| assert body["file_name"] == "test.pdf" | |
| assert body["page_count"] >= 1 | |
| assert isinstance(body["pages"], list) | |
| assert body["stored_in_supabase"] is False # no SB creds in tests | |
| status = client.get( | |
| f"/uploads/blueprint/{body['upload_id']}" | |
| ) | |
| assert status.status_code in (200, 404), status.text | |
| # If Supabase isn't reachable we fall back to the on-disk cache β 200. | |
| if status.status_code == 200: | |
| s = status.json() | |
| assert s["upload_id"] == body["upload_id"] | |
| assert s["page_count"] == body["page_count"] | |
| def test_uploads_blueprint_rejects_oversize(minimal_app_client: TestClient): | |
| client = minimal_app_client | |
| payload = b"x" * (51 * 1024 * 1024) # 51 MB > MAX_BYTES=50MB | |
| files = { | |
| "file": ("huge.pdf", io.BytesIO(payload), "application/pdf") | |
| } | |
| resp = client.post("/uploads/blueprint", files=files) | |
| assert resp.status_code == 413 | |
| assert "too large" in resp.json()["detail"] | |
| def test_uploads_blueprint_rejects_unsupported_mime(minimal_app_client: TestClient): | |
| client = minimal_app_client | |
| files = { | |
| "file": ("odd.avi", b"abcd", "video/x-msvideo") | |
| } | |
| resp = client.post("/uploads/blueprint", files=files) | |
| assert resp.status_code == 415 | |