PR #17660 landed a sweep of CI fixes but left three loose ends: 1. tests/cli/test_cli_loading_indicator.py::test_reload_mcp_sets_busy_state_ and_prints_status — /reload-mcp gained a prompt-cache-invalidation confirmation (commit 4d7fc0f37) that was never wired into this test. The test exercises the loading-indicator path, so pre-approve via config and go straight into _reload_mcp(). 2. tools/mcp_tool.py _make_tool_handler — the added getattr(server, '_rpc_lock', None) + 'skip the lock if missing' branch is inconsistent with four sibling call sites that still direct-access server._rpc_lock. The lock is guaranteed by MCPServerTask.__init__; falling through to an unlocked session.call_tool would silently serialize-strip RPCs if the guard ever triggered. Restore direct access. 3. tui_gateway/server.py _messages_as_conversation — the helper existed only to catch 'TypeError: include_ancestors unexpected' from mocked SessionDBs that don't actually exist. The real SessionDB.get_messages_as_conversation has accepted include_ancestors since introduction, and every test FakeDB in the repo already declares the kwarg. Remove the shim, inline the two call sites.
73 lines
2.7 KiB
Python
73 lines
2.7 KiB
Python
"""Regression tests for loading feedback on slow slash commands."""
|
|
|
|
from unittest.mock import patch
|
|
|
|
from cli import HermesCLI
|
|
|
|
|
|
class TestCLILoadingIndicator:
|
|
def _make_cli(self):
|
|
cli_obj = HermesCLI.__new__(HermesCLI)
|
|
cli_obj._app = None
|
|
cli_obj._last_invalidate = 0.0
|
|
cli_obj._command_running = False
|
|
cli_obj._command_status = ""
|
|
return cli_obj
|
|
|
|
def test_skills_command_sets_busy_state_and_prints_status(self, capsys):
|
|
cli_obj = self._make_cli()
|
|
seen = {}
|
|
|
|
def fake_handle(cmd: str):
|
|
seen["cmd"] = cmd
|
|
seen["running"] = cli_obj._command_running
|
|
seen["status"] = cli_obj._command_status
|
|
print("skills done")
|
|
|
|
with patch.object(cli_obj, "_handle_skills_command", side_effect=fake_handle), \
|
|
patch.object(cli_obj, "_invalidate") as invalidate_mock:
|
|
assert cli_obj.process_command("/skills search kubernetes")
|
|
|
|
output = capsys.readouterr().out
|
|
assert "⏳ Searching skills..." in output
|
|
assert "skills done" in output
|
|
assert seen == {
|
|
"cmd": "/skills search kubernetes",
|
|
"running": True,
|
|
"status": "Searching skills...",
|
|
}
|
|
assert cli_obj._command_running is False
|
|
assert cli_obj._command_status == ""
|
|
assert invalidate_mock.call_count == 2
|
|
|
|
def test_reload_mcp_sets_busy_state_and_prints_status(self, capsys):
|
|
cli_obj = self._make_cli()
|
|
seen = {}
|
|
|
|
def fake_reload():
|
|
seen["running"] = cli_obj._command_running
|
|
seen["status"] = cli_obj._command_status
|
|
print("reload done")
|
|
|
|
# /reload-mcp now wraps the actual reload in a prompt-cache-invalidation
|
|
# confirmation prompt (commit 4d7fc0f37). This test exercises the
|
|
# loading-indicator path, not the confirmation UX, so pre-approve the
|
|
# reload via config so the handler goes straight into _reload_mcp().
|
|
fake_cfg = {"approvals": {"mcp_reload_confirm": False}}
|
|
|
|
with patch.object(cli_obj, "_reload_mcp", side_effect=fake_reload), \
|
|
patch.object(cli_obj, "_invalidate") as invalidate_mock, \
|
|
patch("cli.load_cli_config", return_value=fake_cfg):
|
|
assert cli_obj.process_command("/reload-mcp")
|
|
|
|
output = capsys.readouterr().out
|
|
assert "⏳ Reloading MCP servers..." in output
|
|
assert "reload done" in output
|
|
assert seen == {
|
|
"running": True,
|
|
"status": "Reloading MCP servers...",
|
|
}
|
|
assert cli_obj._command_running is False
|
|
assert cli_obj._command_status == ""
|
|
assert invalidate_mock.call_count == 2
|