diff --git a/sanctions/src/main.py b/sanctions/src/main.py index bf498d8..0f8023d 100644 --- a/sanctions/src/main.py +++ b/sanctions/src/main.py @@ -239,13 +239,20 @@ async def screen(req: ScreenRequest): """Screen a name against OpenSanctions lists via yente.""" try: results = await _query_yente(req.name, req.threshold) - except httpx.ConnectError: + except httpx.ConnectError as e: raise HTTPException( status_code=503, detail=f"yente service not reachable at {YENTE_URL}.", - ) + ) from e + except httpx.TimeoutException as e: + raise HTTPException( + status_code=504, + detail=f"yente request timed out at {YENTE_URL}.", + ) from e + except httpx.RequestError as e: + raise HTTPException(status_code=503, detail=f"yente request failed: {e}") from e except httpx.HTTPStatusError as e: - raise HTTPException(status_code=502, detail=f"yente error: {e}") + raise HTTPException(status_code=502, detail=f"yente error: {e}") from e matches = [ ScreenMatch( diff --git a/sanctions/tests/test_main.py b/sanctions/tests/test_main.py index 7a386d8..a6abc55 100644 --- a/sanctions/tests/test_main.py +++ b/sanctions/tests/test_main.py @@ -5,6 +5,7 @@ from unittest.mock import AsyncMock, patch +import httpx import pytest from fastapi.testclient import TestClient @@ -77,6 +78,23 @@ async def test_screen_no_matches(): assert data["matches"] == [] +def test_screen_timeout_returns_gateway_timeout(): + """Timeouts von yente werden als 504 statt als 500 zurueckgegeben.""" + with patch( + "sanctions.src.main._query_yente", + new=AsyncMock(side_effect=httpx.ReadTimeout("timed out")), + ): + response = client.post( + "/api/screen", + json={"name": "Max Mustermann"}, + ) + + assert response.status_code == 504 + assert response.json() == { + "detail": "yente request timed out at http://localhost:8100." + } + + def test_screen_missing_body(): """Fehlender Body → 422 Validation Error.""" response = client.post("/api/screen", json={})