Spaces:
Sleeping
Sleeping
Download backend/tests/api/test_errors.py from Aynkhn/Face-Expression-Analyzer: direct link, hf CLI and curl.
- Browser
- Download file 3.38 kB
-
https://huggingface.co/spaces/Aynkhn/Face-Expression-Analyzer/resolve/main/backend/tests/api/test_errors.py
- Command line
-
hf download hf://spaces/Aynkhn/Face-Expression-Analyzer/backend/tests/api/test_errors.py
-
curl -L -o test_errors.py https://huggingface.co/spaces/Aynkhn/Face-Expression-Analyzer/resolve/main/backend/tests/api/test_errors.py
3.38 kB
| """Error-handling regression tests. | |
| The previous global handler returned ``str(exc)`` in the response body, which for a | |
| SQLAlchemy failure includes the connection URL and its password. | |
| """ | |
| from __future__ import annotations | |
| import pytest | |
| from fastapi.testclient import TestClient | |
| from app.core.config import Settings | |
| from app.db.deps import get_db | |
| from app.main import create_app | |
| LEAKY_MESSAGE = ( | |
| "(psycopg2.OperationalError) connection to server at " | |
| "postgresql://admin:hunter2@db.example.com:5432/facevision failed" | |
| ) | |
| def _app_with_exploding_db(environment: str) -> TestClient: | |
| settings = Settings( | |
| environment=environment, | |
| database_url="sqlite://", | |
| FACEVISION_INGEST_KEY="ingest", | |
| log_level="CRITICAL", | |
| ) | |
| app = create_app(settings) | |
| class ExplodingSession: | |
| def execute(self, *_args, **_kwargs): | |
| raise RuntimeError(LEAKY_MESSAGE) | |
| def close(self) -> None: | |
| pass | |
| def exploding_db(): | |
| yield ExplodingSession() | |
| app.dependency_overrides[get_db] = exploding_db | |
| return TestClient(app, raise_server_exceptions=False) | |
| class TestInternalErrorsDoNotLeak: | |
| def test_production_body_omits_the_exception_text(self): | |
| client = _app_with_exploding_db("production") | |
| response = client.get("/api/logs", headers={"X-Session-Id": "error-test-session-01"}) | |
| assert response.status_code == 500 | |
| body = response.text | |
| assert "hunter2" not in body | |
| assert "postgresql://" not in body | |
| assert "Traceback" not in body | |
| def test_production_body_carries_a_request_id(self): | |
| client = _app_with_exploding_db("production") | |
| body = client.get("/api/logs", headers={"X-Session-Id": "error-test-session-01"}).json() | |
| assert body["message"] == "Internal Server Error" | |
| assert body["request_id"] | |
| def test_development_includes_detail_for_debugging(self): | |
| client = _app_with_exploding_db("development") | |
| body = client.get("/api/logs", headers={"X-Session-Id": "error-test-session-01"}).json() | |
| assert "detail" in body | |
| class TestValidationErrors: | |
| def test_validation_failure_reports_field_errors(self, client, ingest_headers): | |
| response = client.post( | |
| "/api/logs", | |
| json={"dominant_emotion": "Nope", "duration_seconds": "abc"}, | |
| headers=ingest_headers, | |
| ) | |
| assert response.status_code == 422 | |
| body = response.json() | |
| assert body["message"] == "Validation failed" | |
| assert body["errors"] | |
| class TestRequestId: | |
| def test_successful_responses_carry_a_request_id_header(self, client): | |
| response = client.get("/api/health") | |
| assert response.headers.get("X-Request-ID") | |
| class TestSecurityHeaders: | |
| def test_isolation_headers_are_present(self, client, header, value): | |
| """next.config.ts declares these but they are inert under output: 'export'.""" | |
| assert client.get("/api/health").headers.get(header) == value | |