| """Tests for acp_adapter.permissions — ACP approval bridging.""" |
|
|
| import asyncio |
| from concurrent.futures import Future |
| from unittest.mock import MagicMock, patch |
|
|
| import pytest |
|
|
| from acp.schema import ( |
| AllowedOutcome, |
| DeniedOutcome, |
| RequestPermissionResponse, |
| ) |
| from acp_adapter.permissions import make_approval_callback |
|
|
|
|
| def _make_response(outcome): |
| """Helper to build a RequestPermissionResponse with the given outcome.""" |
| return RequestPermissionResponse(outcome=outcome) |
|
|
|
|
| def _setup_callback(outcome, timeout=60.0): |
| """ |
| Create a callback wired to a mock request_permission coroutine |
| that resolves to the given outcome. |
| |
| Returns: |
| (callback, mock_request_permission_fn) |
| """ |
| loop = MagicMock(spec=asyncio.AbstractEventLoop) |
| mock_rp = MagicMock(name="request_permission") |
|
|
| response = _make_response(outcome) |
|
|
| |
| |
| future = MagicMock(spec=Future) |
| future.result.return_value = response |
|
|
| with patch("acp_adapter.permissions.asyncio.run_coroutine_threadsafe", return_value=future): |
| cb = make_approval_callback(mock_rp, loop, session_id="s1", timeout=timeout) |
| result = cb("rm -rf /", "dangerous command") |
|
|
| return result |
|
|
|
|
| class TestApprovalMapping: |
| def test_approval_allow_once_maps_correctly(self): |
| outcome = AllowedOutcome(option_id="allow_once", outcome="selected") |
| result = _setup_callback(outcome) |
| assert result == "once" |
|
|
| def test_approval_allow_always_maps_correctly(self): |
| outcome = AllowedOutcome(option_id="allow_always", outcome="selected") |
| result = _setup_callback(outcome) |
| assert result == "always" |
|
|
| def test_approval_deny_maps_correctly(self): |
| outcome = DeniedOutcome(outcome="cancelled") |
| result = _setup_callback(outcome) |
| assert result == "deny" |
|
|
| def test_approval_timeout_returns_deny(self): |
| """When the future times out, the callback should return 'deny'.""" |
| loop = MagicMock(spec=asyncio.AbstractEventLoop) |
| mock_rp = MagicMock(name="request_permission") |
|
|
| future = MagicMock(spec=Future) |
| future.result.side_effect = TimeoutError("timed out") |
|
|
| with patch("acp_adapter.permissions.asyncio.run_coroutine_threadsafe", return_value=future): |
| cb = make_approval_callback(mock_rp, loop, session_id="s1", timeout=0.01) |
| result = cb("rm -rf /", "dangerous") |
|
|
| assert result == "deny" |
|
|