Spaces:
Running
Running
File size: 4,167 Bytes
efff1ff | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | """HTTP-layer tests: validation, error mapping, and response shape.
Uses FastAPI's TestClient with the real pipeline where inference is needed, so
these exercise the actual serving path rather than a stub.
"""
from __future__ import annotations
import base64
import pytest
from fastapi.testclient import TestClient
from docxextract.api import app
@pytest.fixture(scope="module")
def client():
with TestClient(app) as c:
yield c
def test_health(client):
response = client.get("/health")
assert response.status_code == 200
body = response.json()
assert body["status"] in ("ok", "degraded")
assert "model_ready" in body
def test_config(client):
body = client.get("/v1/config").json()
assert body["max_keys"] > 0
assert 0.0 <= body["confidence_threshold"] <= 1.0
def test_extract_rejects_unsupported_media(client):
response = client.post(
"/v1/extract",
files={"file": ("notes.txt", b"just text", "text/plain")},
data={"keys": "Total"},
)
assert response.status_code in (415, 422)
def test_extract_rejects_empty_keys(client, sample_pdf):
response = client.post(
"/v1/extract",
files={"file": ("invoice.pdf", sample_pdf, "application/pdf")},
data={"keys": " , , "},
)
assert response.status_code == 422
def test_extract_rejects_too_many_keys(client, sample_pdf):
response = client.post(
"/v1/extract",
files={"file": ("invoice.pdf", sample_pdf, "application/pdf")},
data={"keys": ",".join(f"key{i}" for i in range(500))},
)
assert response.status_code == 422
def test_extract_rejects_corrupt_pdf(client):
response = client.post(
"/v1/extract",
files={"file": ("broken.pdf", b"%PDF-1.7\ngarbage garbage",
"application/pdf")},
data={"keys": "Total"},
)
assert response.status_code in (422, 500)
def test_extract_success_shape(client, sample_pdf):
keys = ["INVOICE NO", "Total Amount"]
response = client.post(
"/v1/extract",
files={"file": ("invoice.pdf", sample_pdf, "application/pdf")},
data={"keys": ",".join(keys)},
)
assert response.status_code == 200
body = response.json()
assert [f["key"] for f in body["fields"]] == keys
for field in body["fields"]:
assert field["status"] in ("extracted", "low_confidence", "not_found",
"error")
assert 0.0 <= field["confidence"] <= 1.0
assert body["document"]["word_count"] > 0
assert body["latency_ms"] >= 0
assert response.headers.get("X-Request-ID")
def test_duplicate_keys_collapse(client, sample_pdf):
response = client.post(
"/v1/extract",
files={"file": ("invoice.pdf", sample_pdf, "application/pdf")},
data={"keys": "Total Amount,Total Amount"},
)
body = response.json()
assert len(body["fields"]) == 1
def test_json_endpoint(client, sample_pdf):
response = client.post("/v1/extract/json", json={
"keys": ["INVOICE NO"],
"document_base64": base64.b64encode(sample_pdf).decode(),
})
assert response.status_code == 200
assert response.json()["fields"][0]["key"] == "INVOICE NO"
def test_json_endpoint_rejects_bad_base64(client):
response = client.post("/v1/extract/json", json={
"keys": ["Total"], "document_base64": "!!!not-base64!!!"})
assert response.status_code == 422
def test_json_endpoint_requires_keys(client, sample_pdf):
response = client.post("/v1/extract/json", json={
"keys": [], "document_base64": base64.b64encode(sample_pdf).decode()})
assert response.status_code == 422
def test_confidence_threshold_is_respected(client, sample_pdf):
"""A threshold of 1.0 must suppress every extraction."""
response = client.post(
"/v1/extract",
files={"file": ("invoice.pdf", sample_pdf, "application/pdf")},
data={"keys": "INVOICE NO,Total Amount", "confidence_threshold": "1.0"},
)
body = response.json()
assert body["confidence_threshold"] == 1.0
assert all(f["status"] != "extracted" for f in body["fields"])
|