"""Tests ciblés sur l'intégration agent du contrat finalize enrichi.""" from __future__ import annotations import sys import types from pathlib import Path from unittest.mock import MagicMock, patch _ROOT = str(Path(__file__).resolve().parents[2]) if _ROOT not in sys.path: sys.path.insert(0, _ROOT) class _ImmediateThread: def __init__(self, target=None, args=(), kwargs=None, daemon=None): self._target = target self._args = args self._kwargs = kwargs or {} def start(self): if self._target is not None: self._target(*self._args, **self._kwargs) class _DummyServerClient: _stream_base = "http://server.test:5005" def __init__(self): self.on_connection_change = None def set_on_connection_change(self, callback): self.on_connection_change = callback def _auth_headers(self): return {"Authorization": "Bearer test-token"} def _install_pystray_stub(): pystray_stub = types.ModuleType("pystray") class _DummyMenu: SEPARATOR = object() def __init__(self, *args, **kwargs): self.args = args self.kwargs = kwargs class _DummyIcon: def __init__(self, *args, **kwargs): self.args = args self.kwargs = kwargs def run(self): return None def stop(self): return None def update_menu(self): return None pystray_stub.MenuItem = lambda *args, **kwargs: (args, kwargs) pystray_stub.Menu = _DummyMenu pystray_stub.Icon = _DummyIcon sys.modules["pystray"] = pystray_stub def _build_tray(): _install_pystray_stub() from agent_v0.agent_v1.ui.smart_tray import SmartTrayV1 tray = SmartTrayV1( on_start_callback=lambda _name: None, on_stop_callback=lambda: None, server_client=_DummyServerClient(), ) tray._notifier = MagicMock() return tray def test_offer_finalize_replay_requires_user_consent(): _install_pystray_stub() from agent_v0.agent_v1.ui import smart_tray as smart_tray_mod tray = _build_tray() tray._launch_replay_request = MagicMock() with patch.object(smart_tray_mod.threading, "Thread", _ImmediateThread), \ patch.object(smart_tray_mod, "_ask_consent", return_value=False): tray.offer_finalize_replay( { "endpoint": "/api/v1/traces/stream/replay-session", "session_id": "sess_offer_001", "machine_id": "pc-offer", }, "Bloc-notes", ) tray._notifier.notify.assert_called_once() tray._launch_replay_request.assert_not_called() def test_launch_replay_request_calls_replay_session_endpoint(): _install_pystray_stub() from agent_v0.agent_v1.ui import smart_tray as smart_tray_mod tray = _build_tray() with patch.object(smart_tray_mod.threading, "Thread", _ImmediateThread), \ patch("requests.post") as mock_post: mock_post.return_value = MagicMock(ok=True) tray._launch_replay_request( { "endpoint": "/api/v1/traces/stream/replay-session", "session_id": "sess_offer_002", "machine_id": "pc-replay", }, "Bloc-notes", ) mock_post.assert_called_once() _, kwargs = mock_post.call_args assert kwargs["params"] == { "session_id": "sess_offer_002", "machine_id": "pc-replay", } assert kwargs["headers"] == {"Authorization": "Bearer test-token"} assert kwargs["allow_redirects"] is False def test_agent_finalize_result_delegates_to_tray_offer(): from agent_v0.agent_v1.finalize_contract import dispatch_finalize_result ui = MagicMock() dispatch_finalize_result( ui, { "replay_ready": True, "replay_request": { "endpoint": "/api/v1/traces/stream/replay-session", "session_id": "sess_offer_003", "machine_id": "pc-main", }, }, "Saisie dossier", ) ui.offer_finalize_replay.assert_called_once_with( { "endpoint": "/api/v1/traces/stream/replay-session", "session_id": "sess_offer_003", "machine_id": "pc-main", }, "Saisie dossier", ) def test_agent_finalize_result_ignores_already_started_replay(): from agent_v0.agent_v1.finalize_contract import dispatch_finalize_result ui = MagicMock() dispatch_finalize_result( ui, { "replay_ready": True, "replay_request": { "endpoint": "/api/v1/traces/stream/replay-session", "session_id": "sess_offer_004", "machine_id": "pc-main", }, "replay_launch": { "status": "started", "replay": {"replay_id": "replay_sess_1234"}, }, }, "Saisie dossier", ) ui.offer_finalize_replay.assert_not_called()