POST /v1/lead-scoring/score now evaluates in the request, applies an overall AI deadline, and stores the completed run only after scoring. Idempotency is kept by (app_id, account_id, request_id) with a body fingerprint. Removes the webhook outbox, scheduler/recovery loop, app lead_scoring permission, credential audit events, seed_demo and generate_secret scripts, and the tests that covered them. Trims tests to behavior of the new flow.
48 lines
1.6 KiB
Python
48 lines
1.6 KiB
Python
from types import SimpleNamespace
|
|
|
|
import pytest
|
|
from fastapi.testclient import TestClient
|
|
from sqlalchemy.exc import OperationalError
|
|
|
|
from ai_platform.bootstrap.app import create_app
|
|
from ai_platform.bootstrap.wiring import get_app_credential_use_cases, get_scoring_use_cases
|
|
from ai_platform.infrastructure.config.settings import Settings
|
|
|
|
|
|
@pytest.mark.parametrize("boundary", ["auth", "scoring"])
|
|
@pytest.mark.parametrize(
|
|
"error",
|
|
[
|
|
OperationalError(
|
|
"private-sql", {"credential": "private-key"}, Exception("private-storage-error")
|
|
),
|
|
ConnectionRefusedError("private-storage-error"),
|
|
],
|
|
)
|
|
def test_database_unavailability_returns_safe_503(valid_run_payload, boundary, error):
|
|
app = create_app(Settings())
|
|
|
|
async def authenticate(_raw):
|
|
return "omni-local"
|
|
|
|
async def credential_cases():
|
|
if boundary == "auth":
|
|
raise error
|
|
return SimpleNamespace(authenticate=authenticate)
|
|
|
|
async def scoring_cases():
|
|
raise error
|
|
|
|
app.dependency_overrides[get_app_credential_use_cases] = credential_cases
|
|
app.dependency_overrides[get_scoring_use_cases] = scoring_cases
|
|
# Dependencies are isolated; this test makes no DB connections or startup mutations.
|
|
client = TestClient(app)
|
|
headers = {
|
|
"Authorization": "Bearer private-key",
|
|
"Idempotency-Key": valid_run_payload["request_id"],
|
|
}
|
|
response = client.post("/v1/lead-scoring/score", headers=headers, json=valid_run_payload)
|
|
assert response.status_code == 503
|
|
assert response.json() == {"detail": "Database unavailable"}
|
|
assert "private" not in response.text
|