"""Teste US-001 (PRD 5.6): handler global de excepții -> 500 structurat (3 niveluri) + log.""" from __future__ import annotations import os import tempfile import pytest from fastapi.testclient import TestClient @pytest.fixture() def client(monkeypatch): tmp = tempfile.mkdtemp() monkeypatch.setenv("AUTOPASS_DB_PATH", os.path.join(tmp, "eh.db")) monkeypatch.setenv("AUTOPASS_LOG_DIR", os.path.join(tmp, "logs")) from app.config import get_settings get_settings.cache_clear() from app.main import app # raise_server_exceptions=False: lasam handlerul sa produca raspunsul 500, nu sa propage with TestClient(app, raise_server_exceptions=False) as c: yield c get_settings.cache_clear() def _force_500(monkeypatch): """Forteaza o excepție interna pe /healthz (queue_depth arunca).""" import app.main as m def boom(*a, **k): raise RuntimeError("parola=secreta123 explodeaza intern") monkeypatch.setattr(m, "queue_depth", boom) def test_exceptie_neasteptata_da_500_structurat(client, monkeypatch): _force_500(monkeypatch) r = client.get("/healthz") assert r.status_code == 500 body = r.json() assert body["cod"] == "EROARE_INTERNA" # 3 niveluri (PRD 5.4): problema + fix assert body["problema"] assert body["fix"] assert "request_id" in body def test_raspuns_contine_request_id_fara_traceback(client, monkeypatch): _force_500(monkeypatch) r = client.get("/healthz", headers={"X-Request-ID": "rid-eroare"}) body = r.json() assert body["request_id"] == "rid-eroare" assert r.headers.get("X-Request-ID") == "rid-eroare" raw = r.text # Fara traceback / mesaj brut de excepție assert "Traceback" not in raw assert "RuntimeError" not in raw assert "explodeaza intern" not in raw def test_creds_nu_apar_in_raspuns(client, monkeypatch): _force_500(monkeypatch) r = client.get("/healthz") assert "secreta123" not in r.text def test_traceback_in_jurnal_redactat(client, monkeypatch): _force_500(monkeypatch) client.get("/healthz") # Evenimentul exista in app_events, cu cod EROARE_INTERNA si fara parola in clar from app.db import get_connection conn = get_connection() try: row = conn.execute( "SELECT cod, context_json FROM app_events WHERE tip='eroare_interna' ORDER BY id DESC LIMIT 1" ).fetchone() finally: conn.close() assert row is not None assert row["cod"] == "EROARE_INTERNA" # parola redactata in traceback-ul logat assert "secreta123" not in (row["context_json"] or "") def test_handlerele_existente_neatinse(client): """422 ramane 422 structurat (nu prins de handlerul generic).""" r = client.post("/v1/prezentari", json={"prezentari": []}) assert r.status_code == 422 # 404 ramane 404 r2 = client.get("/v1/prezentari/999999") assert r2.status_code in (200, 404)