Files
anonymisation/tests/unit/test_gui_v6_diagnostics.py
2026-06-30 10:39:25 +02:00

111 lines
4.3 KiB
Python

import json
from types import SimpleNamespace
from gui_v6 import diagnostics
def _doc(**kw):
base = dict(ordinal=0, status="success", error_type=None, error_code=None, duration_ms=12)
base.update(kw)
return SimpleNamespace(**base)
def test_new_run_id_is_hex():
rid = diagnostics.new_run_id()
assert isinstance(rid, str) and len(rid) >= 16
def test_items_from_summary_whitelist_only():
summary = SimpleNamespace(documents=[
_doc(ordinal=0, status="success"),
_doc(ordinal=1, status="failed", error_type="ValueError", error_code="processing_error"),
])
items = diagnostics.items_from_summary(summary)
assert items[1]["error_type"] == "ValueError"
assert set(items[0]) <= {"ordinal", "status", "error_type", "error_code", "duration_ms"}
def test_build_payload_counts_and_no_pii_leak():
# On INJECTE de la PII via des clés interdites + un faux message d'erreur :
raw_docs = [
{"ordinal": 0, "status": "success", "duration_ms": 5,
"filename": "LETTRE Dupont 1980.pdf", "path": "/home/dom/secret.pdf"},
{"ordinal": 1, "status": "failed", "error_type": "ValueError",
"error_code": "processing_error", "error_message": "patient Dupont Jean"},
]
payload = diagnostics.build_diagnostics_payload(
run_id="r" * 16, app_name="gui_v6", app_version="6.0.0-g1",
license_ref="LIC-1", machine_id="m" * 12, duration_ms=999, items=raw_docs,
)
assert payload["document_count"] == 2
assert payload["succeeded_count"] == 1 and payload["failed_count"] == 1
blob = json.dumps(payload).lower()
for forbidden in ("filename", "path", "secret", "dupont", "lettre", "error_message", "patient"):
assert forbidden not in blob, f"fuite RGPD : {forbidden}"
for item in payload["items"]:
assert set(item) <= {"ordinal", "status", "error_type", "error_code", "duration_ms"}
class _FakeResp:
def __init__(self, status_code):
self.status_code = status_code
class _FakeSession:
def __init__(self, status_code=200, raise_exc=None):
self.status_code = status_code
self.raise_exc = raise_exc
self.calls = []
def post(self, url, json=None, timeout=None):
self.calls.append((url, json, timeout))
if self.raise_exc:
raise self.raise_exc
return _FakeResp(self.status_code)
def test_client_report_ok_on_2xx():
sess = _FakeSession(status_code=200)
client = diagnostics.DiagnosticsClient("https://app.aivanov.eu/", session=sess)
assert client.report({"run_id": "r"}) is True
assert sess.calls[0][0] == "https://app.aivanov.eu/api/v1/diagnostics/report"
def test_client_report_false_on_network_error_without_raising():
sess = _FakeSession(raise_exc=RuntimeError("no network"))
client = diagnostics.DiagnosticsClient("https://app.aivanov.eu", session=sess)
assert client.report({"run_id": "r"}) is False # ne lève pas
def test_report_run_diagnostics_no_send_without_license(tmp_path):
sess = _FakeSession()
ok = diagnostics.report_run_diagnostics(
SimpleNamespace(documents=[]), base_url="https://app.aivanov.eu",
license_ref=None, machine_id="m" * 12, session=sess,
spool_path=tmp_path / "spool.jsonl",
)
assert ok is False and sess.calls == []
def test_report_run_diagnostics_network_down_spools(tmp_path):
sess = _FakeSession(raise_exc=RuntimeError("down"))
spool = tmp_path / "spool.jsonl"
summary = SimpleNamespace(documents=[_doc(ordinal=0, status="failed",
error_type="ValueError", error_code="processing_error")])
ok = diagnostics.report_run_diagnostics(
summary, base_url="https://app.aivanov.eu", license_ref="LIC-1",
machine_id="m" * 12, session=sess, spool_path=spool,
)
assert ok is False and spool.exists()
line = json.loads(spool.read_text(encoding="utf-8").splitlines()[0])
assert line["failed_count"] == 1
def test_flush_spool_sends_and_clears(tmp_path):
spool = tmp_path / "spool.jsonl"
diagnostics.spool_payload(spool, {"run_id": "r1"})
diagnostics.spool_payload(spool, {"run_id": "r2"})
sent = diagnostics.flush_spool(spool, diagnostics.DiagnosticsClient(
"https://app.aivanov.eu", session=_FakeSession(status_code=200)))
assert sent == 2 and not spool.exists()