merge(R2): DialogResolver MVP P0 (worktree a86565d0)

This commit is contained in:
Dom
2026-05-24 17:53:35 +02:00
7 changed files with 995 additions and 0 deletions

View File

@@ -0,0 +1,141 @@
"""Tests intégration HTTP de POST /api/v1/dialog/resolve — R2 MVP P0.
Vérifie :
- flag OFF par défaut → 503.
- flag ON + match catalogue → 200 + payload conforme.
- flag ON + pas de match → 200 + matched=False + policy=pause.
"""
from __future__ import annotations
import sys
from pathlib import Path
import pytest
_ROOT = str(Path(__file__).resolve().parents[2])
if _ROOT not in sys.path:
sys.path.insert(0, _ROOT)
pytestmark = pytest.mark.integration
_TEST_API_TOKEN = "test_dialog_resolver_endpoint_token"
@pytest.fixture
def client(monkeypatch):
"""TestClient FastAPI avec token. Le flag RPA_DIALOG_RESOLVER_ENABLED
est géré par chaque test (par défaut absent → 503)."""
monkeypatch.setenv("RPA_API_TOKEN", _TEST_API_TOKEN)
from fastapi.testclient import TestClient
from agent_v0.server_v1 import api_stream
monkeypatch.setattr(api_stream, "API_TOKEN", _TEST_API_TOKEN)
return TestClient(api_stream.app, raise_server_exceptions=False)
def _auth_headers():
return {"Authorization": f"Bearer {_TEST_API_TOKEN}"}
class TestDialogResolveEndpointFlag:
"""Flag OFF par défaut — protection anti-régression."""
def test_disabled_by_default_returns_503(self, client, monkeypatch):
# flag explicitement absent → 503 attendu.
monkeypatch.delenv("RPA_DIALOG_RESOLVER_ENABLED", raising=False)
resp = client.post(
"/api/v1/dialog/resolve",
json={"current_title": "Confirmer l'enregistrement", "evidence_texts": []},
headers=_auth_headers(),
)
assert resp.status_code == 503
assert "RPA_DIALOG_RESOLVER_ENABLED" in resp.text
class TestDialogResolveEndpointEnabled:
"""Flag ON : l'endpoint retourne une résolution conforme."""
@pytest.fixture(autouse=True)
def _enable_flag(self, monkeypatch):
monkeypatch.setenv("RPA_DIALOG_RESOLVER_ENABLED", "true")
def test_match_confirm_save_overwrite(self, client):
resp = client.post(
"/api/v1/dialog/resolve",
json={
"current_title": "Confirmer l'enregistrement",
"evidence_texts": [],
"machine_id": "pc-alpha",
},
headers=_auth_headers(),
)
assert resp.status_code == 200
body = resp.json()
assert body["matched"] is True
assert body["dialog_id"] == "confirm-save-overwrite"
assert body["policy"] == "auto"
assert body["action"] is not None
assert body["action"]["button_label"] == "Oui"
def test_match_notepad_with_evidence(self, client):
resp = client.post(
"/api/v1/dialog/resolve",
json={
"current_title": "Bloc-notes",
"evidence_texts": ["Ne pas enregistrer"],
"machine_id": "pc-alpha",
},
headers=_auth_headers(),
)
assert resp.status_code == 200
body = resp.json()
assert body["matched"] is True
assert body["dialog_id"] == "notepad-unsaved-changes"
assert body["policy"] == "auto"
def test_no_match_returns_pause(self, client):
resp = client.post(
"/api/v1/dialog/resolve",
json={
"current_title": "Fenêtre inconnue XYZ",
"evidence_texts": [],
"machine_id": "pc-alpha",
},
headers=_auth_headers(),
)
assert resp.status_code == 200
body = resp.json()
assert body["matched"] is False
assert body["dialog_id"] == ""
assert body["policy"] == "pause"
assert body["action"] is None
def test_match_windows_uac_returns_pause(self, client):
resp = client.post(
"/api/v1/dialog/resolve",
json={
"current_title": "Contrôle de compte d'utilisateur",
"evidence_texts": ["Voulez-vous autoriser cette application"],
"machine_id": "pc-alpha",
},
headers=_auth_headers(),
)
assert resp.status_code == 200
body = resp.json()
assert body["matched"] is True
assert body["dialog_id"] == "windows-uac"
assert body["policy"] == "pause"
assert body["action"] is None
def test_requires_auth(self, client):
resp = client.post(
"/api/v1/dialog/resolve",
json={"current_title": "Confirmer l'enregistrement", "evidence_texts": []},
# pas de header → 401.
)
assert resp.status_code == 401