102 lines
3.4 KiB
Python
102 lines
3.4 KiB
Python
|
|
import pytest
|
||
|
|
from fastapi.testclient import TestClient
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.fixture
|
||
|
|
def client(monkeypatch: pytest.MonkeyPatch) -> TestClient:
|
||
|
|
monkeypatch.setenv("APP_ENV", "local")
|
||
|
|
monkeypatch.setenv("SECRET_PROVIDER", "fake")
|
||
|
|
monkeypatch.setenv("CERT_SECRET_NAME", "pdf-signing-cert")
|
||
|
|
monkeypatch.setenv("CERT_PASSWORD_SECRET_NAME", "pdf-signing-cert-password")
|
||
|
|
monkeypatch.setenv("SERVICE_API_KEY", "test-service-key")
|
||
|
|
monkeypatch.setenv("PDF_MAX_SIZE_BYTES", "1024")
|
||
|
|
|
||
|
|
from signing_service.application.settings.container import get_settings
|
||
|
|
|
||
|
|
get_settings.cache_clear()
|
||
|
|
from signing_service.main import create_app
|
||
|
|
|
||
|
|
return TestClient(create_app(), raise_server_exceptions=False)
|
||
|
|
|
||
|
|
|
||
|
|
def form(pdf: bytes = b"%PDF-1.4 test") -> dict[str, object]:
|
||
|
|
return {
|
||
|
|
"files": {"file": ("document.pdf", pdf, "application/pdf")},
|
||
|
|
"data": {
|
||
|
|
"certificate_secret_name": "legacy-cert",
|
||
|
|
"certificate_password_secret_name": "legacy-password",
|
||
|
|
"company_slug": "legacy-company",
|
||
|
|
},
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
def test_health_is_public(client: TestClient) -> None:
|
||
|
|
response = client.get("/health")
|
||
|
|
assert response.status_code == 200
|
||
|
|
assert response.json() == {"status": "ok"}
|
||
|
|
|
||
|
|
|
||
|
|
def test_version_is_public(client: TestClient) -> None:
|
||
|
|
assert client.get("/version").status_code == 200
|
||
|
|
|
||
|
|
|
||
|
|
def test_sign_rejects_missing_authentication(client: TestClient) -> None:
|
||
|
|
response = client.post("/documents/sign", **form())
|
||
|
|
assert response.status_code == 401
|
||
|
|
assert response.json()["error"]["code"] == "AUTHENTICATION_REQUIRED"
|
||
|
|
|
||
|
|
|
||
|
|
def test_sign_rejects_invalid_authentication(client: TestClient) -> None:
|
||
|
|
response = client.post(
|
||
|
|
"/documents/sign", headers={"Authorization": "Bearer invalid"}, **form()
|
||
|
|
)
|
||
|
|
assert response.status_code == 401
|
||
|
|
assert response.json()["error"]["code"] == "INVALID_CREDENTIALS"
|
||
|
|
|
||
|
|
|
||
|
|
def test_sign_with_valid_authentication_reaches_signing_flow(
|
||
|
|
client: TestClient,
|
||
|
|
) -> None:
|
||
|
|
response = client.post(
|
||
|
|
"/documents/sign",
|
||
|
|
headers={"Authorization": "Bearer test-service-key"},
|
||
|
|
**form(),
|
||
|
|
)
|
||
|
|
assert response.status_code == 200
|
||
|
|
assert response.headers["content-type"] == "application/pdf"
|
||
|
|
assert response.content.endswith(b"-- Signed by fake signer")
|
||
|
|
|
||
|
|
|
||
|
|
def test_invalid_pdf_is_mapped_without_internal_detail(
|
||
|
|
client: TestClient, monkeypatch: pytest.MonkeyPatch
|
||
|
|
) -> None:
|
||
|
|
from signing_service.api.routes import sign_document
|
||
|
|
from signing_service.infrastructure.pdf.pdf_validator_error import (
|
||
|
|
PDFValidationError,
|
||
|
|
)
|
||
|
|
|
||
|
|
class InvalidPdfSigner:
|
||
|
|
async def sign(self, **kwargs: object) -> bytes:
|
||
|
|
raise PDFValidationError("PFX parsing detail")
|
||
|
|
|
||
|
|
monkeypatch.setattr(sign_document, "create_pdf_signer", lambda: InvalidPdfSigner())
|
||
|
|
response = client.post(
|
||
|
|
"/documents/sign",
|
||
|
|
headers={"Authorization": "Bearer test-service-key"},
|
||
|
|
**form(b"not a PDF"),
|
||
|
|
)
|
||
|
|
assert response.status_code == 400
|
||
|
|
assert response.json() == {
|
||
|
|
"error": {"code": "INVALID_PDF", "message": "Invalid PDF document"}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
def test_pdf_size_limit_is_controlled(client: TestClient) -> None:
|
||
|
|
response = client.post(
|
||
|
|
"/documents/sign",
|
||
|
|
headers={"Authorization": "Bearer test-service-key"},
|
||
|
|
**form(b"x" * 1025),
|
||
|
|
)
|
||
|
|
assert response.status_code == 413
|
||
|
|
assert response.json()["error"]["code"] == "INVALID_REQUEST"
|