131 lines
3.9 KiB
Python
131 lines
3.9 KiB
Python
import os
|
|
import io
|
|
import uuid
|
|
from datetime import date
|
|
|
|
import pytest
|
|
from fastapi.testclient import TestClient
|
|
|
|
# Ensure required env vars for app import/config
|
|
os.environ.setdefault("SECRET_KEY", "x" * 32)
|
|
os.environ.setdefault("DATABASE_URL", "sqlite:////tmp/delphi_test.sqlite")
|
|
|
|
from app.main import app # noqa: E402
|
|
from app.auth.security import get_current_user # noqa: E402
|
|
from tests.helpers import assert_http_error, assert_validation_error # noqa: E402
|
|
|
|
|
|
class _User:
|
|
def __init__(self):
|
|
self.id = 1
|
|
self.username = "uploader"
|
|
self.is_admin = True
|
|
self.is_active = True
|
|
|
|
|
|
@pytest.fixture()
|
|
def client():
|
|
app.dependency_overrides[get_current_user] = lambda: _User()
|
|
try:
|
|
yield TestClient(app)
|
|
finally:
|
|
app.dependency_overrides.pop(get_current_user, None)
|
|
|
|
|
|
def _create_customer_and_file(client: TestClient):
|
|
customer_id = f"UP-{uuid.uuid4().hex[:8]}"
|
|
resp = client.post(
|
|
"/api/customers/",
|
|
json={"id": customer_id, "last": "Upload", "email": "u@example.com"},
|
|
)
|
|
assert resp.status_code == 200
|
|
|
|
file_no = f"U-{uuid.uuid4().hex[:6]}"
|
|
file_payload = {
|
|
"file_no": file_no,
|
|
"id": customer_id,
|
|
"regarding": "Upload doc test",
|
|
"empl_num": "E01",
|
|
"file_type": "CIVIL",
|
|
"opened": date.today().isoformat(),
|
|
"status": "ACTIVE",
|
|
"rate_per_hour": 100.0,
|
|
}
|
|
resp = client.post("/api/files/", json=file_payload)
|
|
assert resp.status_code == 200
|
|
return file_no
|
|
|
|
|
|
def test_upload_invalid_file_type_returns_400_envelope_and_correlation_header(client: TestClient):
|
|
file_no = _create_customer_and_file(client)
|
|
|
|
files = {
|
|
"file": ("bad.txt", b"hello", "text/plain"),
|
|
}
|
|
resp = client.post(f"/api/documents/upload/{file_no}", files=files)
|
|
|
|
assert_http_error(resp, 400, "Invalid file type")
|
|
|
|
|
|
def test_upload_oversize_file_returns_400_envelope_and_correlation_header(client: TestClient):
|
|
file_no = _create_customer_and_file(client)
|
|
|
|
# 10MB + 1 byte
|
|
big_bytes = b"x" * (10 * 1024 * 1024 + 1)
|
|
files = {
|
|
"file": ("large.pdf", big_bytes, "application/pdf"),
|
|
}
|
|
resp = client.post(f"/api/documents/upload/{file_no}", files=files)
|
|
|
|
assert_http_error(resp, 400, "File too large")
|
|
|
|
|
|
def test_upload_uses_incoming_correlation_id_when_provided(client: TestClient):
|
|
file_no = _create_customer_and_file(client)
|
|
|
|
cid = f"cid-{uuid.uuid4().hex[:8]}"
|
|
files = {
|
|
"file": ("bad.txt", b"hello", "text/plain"),
|
|
}
|
|
resp = client.post(
|
|
f"/api/documents/upload/{file_no}",
|
|
files=files,
|
|
headers={"X-Correlation-ID": cid},
|
|
)
|
|
|
|
# Envelope shape and message
|
|
assert_http_error(resp, 400, "Invalid file type")
|
|
# Echoes our provided correlation id
|
|
body = resp.json()
|
|
assert resp.headers.get("X-Correlation-ID") == cid
|
|
assert body.get("correlation_id") == cid
|
|
|
|
|
|
def test_upload_without_file_returns_400_no_file_uploaded(client: TestClient):
|
|
file_no = _create_customer_and_file(client)
|
|
|
|
# Provide an empty filename to trigger the explicit 400 in route logic
|
|
files = {
|
|
# Use a valid filename but zero-byte payload to hit the 400 "No file uploaded" branch
|
|
"file": ("empty.pdf", io.BytesIO(b""), "application/pdf"),
|
|
}
|
|
resp = client.post(f"/api/documents/upload/{file_no}", files=files)
|
|
|
|
assert_http_error(resp, 400, "No file uploaded")
|
|
|
|
|
|
def test_upload_missing_file_field_returns_422_validation_envelope(client: TestClient):
|
|
file_no = _create_customer_and_file(client)
|
|
|
|
# Submit without the required `file` field
|
|
resp = client.post(
|
|
f"/api/documents/upload/{file_no}",
|
|
data={"description": "missing file"},
|
|
headers={"X-Correlation-ID": f"cid-{uuid.uuid4().hex[:8]}"},
|
|
)
|
|
|
|
# Ensure 422 envelope and correlation header; details should mention `file`
|
|
assert_validation_error(resp, "file")
|
|
|
|
|