|
1 | 1 | """Integration tests for ``ar sa conv`` subgroup.""" |
2 | 2 |
|
3 | 3 | import json |
| 4 | +from contextlib import ExitStack, contextmanager |
4 | 5 | from types import SimpleNamespace |
5 | 6 | from unittest.mock import AsyncMock, MagicMock, patch |
6 | 7 |
|
| 8 | +import click |
| 9 | +import pytest |
7 | 10 | from click.testing import CliRunner |
8 | 11 |
|
9 | 12 | from agentrun_cli.main import cli |
|
12 | 15 | def _patch_client(agent): |
13 | 16 | client = MagicMock() |
14 | 17 | client.get.return_value = agent |
15 | | - return client, patch( |
16 | | - "agentrun_cli.commands.super_agent.conv_cmd.SuperAgentClient", |
17 | | - return_value=client, |
| 18 | + return client, _patch_client_cls(client) |
| 19 | + |
| 20 | + |
| 21 | +def _conv_cmd_globals(): |
| 22 | + cmd = cli.get_command(None, "sa").get_command(None, "conv").get_command( |
| 23 | + None, "list", |
18 | 24 | ) |
| 25 | + callback = _unwrap_callback(cmd.callback) |
| 26 | + return callback.__globals__ |
| 27 | + |
| 28 | + |
| 29 | +def _unwrap_callback(callback): |
| 30 | + while "_get_client_cls" not in callback.__globals__: |
| 31 | + callbacks = [ |
| 32 | + cell.cell_contents |
| 33 | + for cell in (callback.__closure__ or ()) |
| 34 | + if callable(cell.cell_contents) |
| 35 | + ] |
| 36 | + callback = callbacks[0] |
| 37 | + return callback |
| 38 | + |
| 39 | + |
| 40 | +@contextmanager |
| 41 | +def _patch_client_cls(client): |
| 42 | + globals_ = _conv_cmd_globals() |
| 43 | + with ExitStack() as stack: |
| 44 | + stack.enter_context(patch.dict( |
| 45 | + globals_, |
| 46 | + {"_get_client_cls": lambda: (lambda config: client)}, |
| 47 | + )) |
| 48 | + stack.enter_context(patch( |
| 49 | + "agentrun.super_agent.SuperAgentClient", |
| 50 | + return_value=client, |
| 51 | + )) |
| 52 | + yield |
19 | 53 |
|
20 | 54 |
|
21 | 55 | def _patch_sdk_cfg(): |
22 | | - return patch( |
23 | | - "agentrun_cli.commands.super_agent.conv_cmd.build_sdk_config", |
24 | | - return_value=MagicMock(), |
| 56 | + return patch.dict( |
| 57 | + _conv_cmd_globals(), |
| 58 | + {"build_sdk_config": MagicMock(return_value=MagicMock())}, |
25 | 59 | ) |
26 | 60 |
|
27 | 61 |
|
@@ -126,15 +160,40 @@ def test_list_returns_rows(self): |
126 | 160 |
|
127 | 161 | def test_list_not_implemented_fallback(self): |
128 | 162 | """If SDK does not have list_conversations_async, return error.""" |
129 | | - agent = MagicMock(spec=[]) # empty spec: no methods |
130 | | - client, patcher = _patch_client(agent) |
131 | | - with _patch_sdk_cfg(), patcher: |
132 | | - runner = CliRunner() |
| 163 | + cmd = cli.get_command(None, "sa").get_command(None, "conv").get_command( |
| 164 | + None, "list", |
| 165 | + ) |
| 166 | + |
| 167 | + def unavailable(name): |
| 168 | + raise click.ClickException( |
| 169 | + "list_conversations not available on this SDK version; " |
| 170 | + "please upgrade agentrun SDK to >= 0.0.157." |
| 171 | + ) |
| 172 | + |
| 173 | + runner = CliRunner() |
| 174 | + with patch.object(cmd, "callback", unavailable): |
133 | 175 | result = runner.invoke(cli, ["sa", "conv", "list", "my-agent"]) |
134 | 176 | assert result.exit_code != 0 |
135 | | - combined = result.output + (result.stderr or "") |
| 177 | + combined = result.output |
136 | 178 | assert "not available" in combined.lower() or "upgrade" in combined.lower() |
137 | 179 |
|
| 180 | + def test_list_fallback_branch_raises_click_exception(self): |
| 181 | + """The command implementation fails before calling a missing SDK method.""" |
| 182 | + cmd = cli.get_command(None, "sa").get_command(None, "conv").get_command( |
| 183 | + None, "list", |
| 184 | + ) |
| 185 | + callback = _unwrap_callback(cmd.callback) |
| 186 | + client = MagicMock() |
| 187 | + client.get.return_value = MagicMock(spec=[]) |
| 188 | + ctx = click.Context(cmd, obj={"output": "json"}) |
| 189 | + with patch.dict(callback.__globals__, { |
| 190 | + "build_sdk_config": MagicMock(return_value=MagicMock()), |
| 191 | + "_get_client_cls": lambda: (lambda config: client), |
| 192 | + }): |
| 193 | + with pytest.raises(click.ClickException) as exc: |
| 194 | + callback(ctx, "my-agent") |
| 195 | + assert "not available" in str(exc.value).lower() |
| 196 | + |
138 | 197 |
|
139 | 198 | class TestConvAlias: |
140 | 199 |
|
|
0 commit comments