""" Integration test for the /compliance/agent/migration/* endpoints. Simulates a finished compliance-check run by persisting cmp_vendors + extracted_profile via the sidecar audit log, then exercises the FastAPI TestClient against banner-preview / document-preview / summary. This is the M5 BMW-scenario in miniature: realistic ePaaS-shaped vendor records (BMW INTERNAL + 2 third-party PROCESSOR) feed through to a ready-to-apply banner config and pre-filled documents. """ from __future__ import annotations import os import tempfile import pytest from fastapi.testclient import TestClient @pytest.fixture() def app_client(monkeypatch): # Isolate the sidecar SQLite so this test never races with /data prod DB tmp = tempfile.mkdtemp() monkeypatch.setenv("COMPLIANCE_AUDIT_DB", os.path.join(tmp, "audit.db")) # Build a minimal app — avoid importing the full main.py which pulls in # smtp_sender / weasyprint / pydantic-v1 modules not relevant here. from fastapi import FastAPI from compliance.api.agent_migration_routes import router app = FastAPI() app.include_router(router, prefix="/api") return TestClient(app) @pytest.fixture() def seeded_check_id(): """Persist a fake compliance check so the migration routes have data.""" from compliance.services.compliance_audit_log import record_check_payload, record_check_run cid = "bmw-test-check-001" vendors = [ { "name": "BMW AG", "category": "necessary", "recipient_type": "INTERNAL", "purpose": "Grundfunktionen + Login", "cookies": [{"name": "JSESSIONID", "expiry": "Session"}], }, { "name": "Adobe Analytics", "category": "statistics", "recipient_type": "PROCESSOR", "country": "US", "purpose": "Reichweitenmessung", "opt_out_url": "https://adobe.com/opt-out", "opt_out_ok": True, "privacy_policy_url": "https://adobe.com/privacy", "cookies": [{"name": "s_cc", "expiry": "1 Tag", "is_third_party": True}], }, { "name": "YouTube", "category": "marketing", "recipient_type": "PROCESSOR", "country": "US", "purpose": "Videos", "cookies": [{"name": "VISITOR_INFO1_LIVE", "expiry": "6 Monate", "is_third_party": True}], }, ] record_check_run( check_id=cid, tenant_id="t1", site_name="bmw.de", base_domain="bmw.de", doc_count=4, scorecard={"totals": {"pct": 75, "passed": 30, "failed": 10, "total": 40, "skipped": 0}}, ) record_check_payload(check_id=cid, vendors=vendors, profile={"companyName": "BMW AG", "headquartersStreet": "Petuelring 130", "headquartersZip": "80809", "headquartersCity": "Muenchen", "dpoEmail": "datenschutz@bmw.de"}) return cid def test_banner_preview_returns_valid_config(app_client, seeded_check_id): r = app_client.get(f"/api/compliance/agent/migration/{seeded_check_id}/banner-preview") assert r.status_code == 200, r.text body = r.json() assert body["summary"]["vendors_total"] == 3 cat_ids = {c["id"] for c in body["config"]["categories"]} assert "ESSENTIAL" in cat_ids assert "EXTERNAL_MEDIA" in cat_ids # YouTube # BMW AG (INTERNAL, cookies present) should not raise any flags assert not any(f.get("vendor") == "BMW AG" for f in body["flags"]) def test_document_preview_includes_all_three_templates(app_client, seeded_check_id): r = app_client.get(f"/api/compliance/agent/migration/{seeded_check_id}/document-preview") assert r.status_code == 200, r.text body = r.json() assert body["vendor_count"] == 3 assert set(body["templates"].keys()) == { "cookie_policy", "vvt_register", "privacy_policy", } assert "BMW AG" in body["templates"]["cookie_policy"]["initialContent"] assert "Petuelring" in body["templates"]["cookie_policy"]["initialContent"] def test_summary_returns_overview(app_client, seeded_check_id): r = app_client.get(f"/api/compliance/agent/migration/{seeded_check_id}/summary") assert r.status_code == 200, r.text body = r.json() assert body["company_name"] == "BMW AG" assert body["vendor_count"] == 3 assert body["site_name"] == "bmw.de" assert "cookie_policy" in body["available_templates"] def test_unknown_check_id_returns_404(app_client): r = app_client.get("/api/compliance/agent/migration/nope-not-there/banner-preview") assert r.status_code == 404