"""Tests für Cookie-Policy-Agent v3 (Sprint 1.12 Phase 2).""" from __future__ import annotations import asyncio import pytest from compliance.services.specialist_agents import ( REGISTRY, AgentInput, CookiePolicyAgent, Severity, ) FULL_POLICY = """Cookie-Richtlinie Stand: 1. Juni 2026 Wir verwenden auf unserer Website verschiedene Cookies. Diese werden in folgende Kategorien eingeteilt: 1. Essentielle Cookies (unbedingt erforderlich) Zweck: grundlegende Funktion der Website. Rechtsgrundlage: § 25 Abs. 2 TDDDG Laufzeit: Session 2. Funktionale Cookies — Zweck: Präferenzen speichern. Laufzeit: 30 Tage 3. Analytics-Cookies — Drittanbieter: Google LLC, USA Cookies: _ga, _gid · Laufzeit: 24 Monate Drittland: USA — Standardvertragsklauseln + DPF 4. Marketing — Drittanbieter: Meta Platforms Inc. Cookies: _fbp, _fbc · Laufzeit: 90 Tage Cookie-Einstellungen jederzeit ändern. Browser-Einstellungen: Chrome, Firefox, Safari, Edge. Kontakt: datenschutz@example.com Datenschutzbeauftragter: Max Mustermann """ def _run(coro): return asyncio.get_event_loop().run_until_complete(coro) @pytest.fixture def mock_v3_pipeline(monkeypatch): """Mockt run_v3_pipeline für deterministische Tests offline.""" async def _fake(text, scope): results = [ {"control_id": "COOKIE-MC-001", "passed": True, "severity": "MEDIUM", "label": "Cookie-Kategorien benannt", "regulation": "TDDDG", "article": "§ 25", "hint": "", "matched_text": "essentiell", "source": "kw"}, {"control_id": "COOKIE-MC-002", "passed": False, "severity": "HIGH", "label": "Versionsdatum / Stand der Policy", "regulation": "DSGVO", "article": "Art. 5", "hint": "Bitte 'Stand: TT.MM.JJJJ' angeben", "matched_text": "", "source": ""}, ] telemetry = { "layer_0_field_hits": 4, "layer_0_field_ids": ["categories_named", "purpose_described", "retention_duration", "version_date"], "layer_1_pass": 1, "layer_0_boost_overrides": 0, "total_mcs": 2, } return results, telemetry monkeypatch.setattr( "compliance.services.specialist_agents.cookie_policy.agent.run_v3_pipeline", _fake, ) async def _no_validator(*a, **kw): return {} monkeypatch.setattr( "compliance.services.specialist_agents.cookie_policy.agent.validate_present", _no_validator, ) def test_agent_is_registered(): a = REGISTRY.get("cookie_policy") assert a is not None assert a.doc_type == "cookie" assert a.agent_version == "3.0" def test_short_text_skipped(mock_v3_pipeline): agent = CookiePolicyAgent() out = _run(agent.evaluate(AgentInput(doc_type="cookie", text="x"))) assert all(c.status == "skipped" for c in out.mc_coverage) assert not out.findings def test_agent_uses_db_mcs(mock_v3_pipeline): agent = CookiePolicyAgent() out = _run(agent.evaluate(AgentInput(doc_type="cookie", text=FULL_POLICY))) db_findings = [f for f in out.findings if f.check_id.startswith("DBMC-")] assert len(db_findings) == 1 assert db_findings[0].check_id == "DBMC-COOKIE-MC-002" assert db_findings[0].severity == Severity.HIGH.value def test_agent_emits_boost_coverage(mock_v3_pipeline): agent = CookiePolicyAgent() out = _run(agent.evaluate(AgentInput(doc_type="cookie", text=FULL_POLICY))) # 2 DB-MCs + 12 Pattern-Boost-Slots = 14 coverage entries minimum assert out.mc_total >= 14 boost_ok = [c for c in out.mc_coverage if c.mc_id.startswith("CP-MC-") and c.status == "ok"] assert len(boost_ok) == 4 def test_agent_notes_telemetry(mock_v3_pipeline): agent = CookiePolicyAgent() out = _run(agent.evaluate(AgentInput(doc_type="cookie", text=FULL_POLICY))) assert "v3-pipeline" in out.notes assert "Pattern-Boosts" in out.notes def test_cmp_vendor_cross_check_emits_finding(mock_v3_pipeline): """KB-Layer: CMP-Vendoren-Cross-Check bleibt erhalten in v3.""" agent = CookiePolicyAgent() out = _run(agent.evaluate(AgentInput( doc_type="cookie", text=FULL_POLICY, context={"cmp_vendors": [ {"name": "Hotjar"}, # nicht in Policy {"name": "Google LLC"}, # in Policy ]}, ))) field_ids = {f.field_id for f in out.findings} assert "vendor_consistency" in field_ids f = next(f for f in out.findings if f.field_id == "vendor_consistency") assert "Hotjar" in f.evidence