"""Tests für SSE-Endpoints des Specialist-Agent-Test-Harness.""" from __future__ import annotations import asyncio import json from unittest.mock import AsyncMock, patch import pytest from fastapi.testclient import TestClient from tests.fixtures.impressum_groundtruth import make_mc @pytest.fixture def app(tmp_path, monkeypatch): monkeypatch.setenv("EVIDENCE_VAULT_ROOT", str(tmp_path / "vault")) from fastapi import FastAPI from compliance.api.specialist_agent_routes import router app = FastAPI() app.include_router(router, prefix="/api/v1") return app @pytest.fixture def client(app): return TestClient(app) def test_list_agents(client): r = client.get("/api/v1/specialist-agent/agents") assert r.status_code == 200 data = r.json() agent_ids = {a["agent_id"] for a in data["agents"]} assert "impressum" in agent_ids assert "cookie_policy" in agent_ids def test_start_test_invalid_agent(client): r = client.post("/api/v1/specialist-agent/test/start", json={"agent_id": "ghost", "raw_texts": ["test"]}) assert r.status_code == 404 def test_start_test_no_input(client): r = client.post("/api/v1/specialist-agent/test/start", json={"agent_id": "impressum"}) assert r.status_code == 400 def test_start_test_with_raw_text(client): r = client.post("/api/v1/specialist-agent/test/start", json={"agent_id": "impressum", "raw_texts": ["Tesla Germany GmbH " "Berlin Email: x@y.com " "HRB 123 Charlottenburg"]}) assert r.status_code == 200 data = r.json() assert data["agent_id"] == "impressum" assert data["slot_count"] == 1 assert data["run_id"] def test_stream_unknown_run(client): r = client.get("/api/v1/specialist-agent/test/stream/ghost") assert r.status_code == 404 def test_run_result_after_text_input(client, monkeypatch): # Skip LLM async def _no_cascade(*a, **kw): return None, [] monkeypatch.setattr( "compliance.services.specialist_agents._semantic_validator.cascade", _no_cascade, ) # Agent delegiert MC-Laden ans Main Tool → _load_controls mocken. # Tesla nennt 'Management' (engl.) statt deutschem GF-Label → das # label_korrekt-MC schlaegt fehl → erwartetes Finding. async def _fake_load(doc_type, db_url, limit, business_scope=None): # pass_criteria nur mit label_korrekt-eigenen Keywords (deutsche/ # Bezeichnung/Rechtsform) — NICHT 'Geschäftsführer/Vorstand', sonst # boostet das aktive vertretungsberechtigte-Feld (Tesla: 'Management') # das MC faelschlich auf PASS. return [make_mc( "vertretungsberechtigte_label_korrekt", ["deutsche Bezeichnung Rechtsform Pflicht angeben"], )] monkeypatch.setattr( "compliance.services.rag_document_checker._load_controls", _fake_load, ) async def _no_match(*a, **kw): return set() monkeypatch.setattr( "compliance.services.mc_embedding_matcher.embedding_match", _no_match, raising=False, ) async def _no_embed(*a, **kw): return None monkeypatch.setattr( "compliance.services.mc_embedding_matcher.ensure_mc_embeddings", _no_embed, raising=False, ) r = client.post("/api/v1/specialist-agent/test/start", json={"agent_id": "impressum", "raw_texts": [ "Tesla Germany GmbH\nLudwig-Prandtl-Strasse 25\n" "12526 Berlin\nDeutschland\nEmail: x@y.com\n" "Tel: +49 89 1250 16 800\n" "Management: Elon Musk\n" "HRB 218904 B Charlottenburg", ]}) run_id = r.json()["run_id"] # Give async task time to finish (small text → fast) for _ in range(40): rr = client.get( f"/api/v1/specialist-agent/run/{run_id}/result", ) if rr.json().get("finished"): break import time; time.sleep(0.05) res = client.get(f"/api/v1/specialist-agent/run/{run_id}/result") body = res.json() assert body["finished"] assert "text1" in body["results"] out = body["results"]["text1"] field_ids = {f["field_id"] for f in out["findings"]} # Tesla pattern: German-label fehlt + USt fehlt assert "vertretungsberechtigte_label_korrekt" in field_ids def test_artifacts_listing(client, monkeypatch): async def _no_cascade(*a, **kw): return None, [] monkeypatch.setattr( "compliance.services.specialist_agents._semantic_validator.cascade", _no_cascade, ) r = client.post("/api/v1/specialist-agent/test/start", json={"agent_id": "impressum", "raw_texts": ["Tesla Germany GmbH " "Berlin Email: x@y.com " "HRB 123 Charlottenburg"]}) run_id = r.json()["run_id"] for _ in range(40): rr = client.get( f"/api/v1/specialist-agent/run/{run_id}/result", ) if rr.json().get("finished"): break import time; time.sleep(0.05) arts = client.get( f"/api/v1/specialist-agent/run/{run_id}/artifacts", ) assert arts.status_code == 200 manifest = arts.json()["manifest"] kinds = {a["kind"] for a in manifest["assets"]} assert "finding" in kinds assert "raw" in kinds