dcb3e27b23
- Catalog picks skip the raw-git ceremony: reviewed heading instead of the scare card, no force toggle, enable pre-checked; success toast offers 'Restart gateway' inline; missing-env warning deep-links to Tools & Keys. - plugins.manage list now carries catalog provenance (sidecar) + a backend- computed update_available; new 'update' action re-pins catalog installs to the current catalog SHA (non-catalog installs refused — CLI-owned). - Capabilities rows show tier chip + 'Update to <sha>' button; catalog picks for an already-current install are refused with a toast instead of the modal reopening. - Settings drift badge is now a button: opens the dual-target modal pre-filled (agent half only, sidecar repo+pin when present).
123 lines
3.4 KiB
Python
123 lines
3.4 KiB
Python
"""Gateway plugins.manage install action."""
|
|
|
|
from unittest.mock import patch
|
|
|
|
from tui_gateway import server
|
|
|
|
|
|
def test_plugins_manage_install_success():
|
|
payload = {
|
|
"ok": True,
|
|
"plugin_name": "hello-world",
|
|
"warnings": [],
|
|
"missing_env": [],
|
|
"after_install_path": None,
|
|
"enabled": True,
|
|
}
|
|
with patch(
|
|
"hermes_cli.plugins_cmd.dashboard_install_plugin",
|
|
return_value=payload,
|
|
) as mock_install:
|
|
resp = server.handle_request(
|
|
{
|
|
"id": "1",
|
|
"method": "plugins.manage",
|
|
"params": {
|
|
"action": "install",
|
|
"repo": "owner/hello-world",
|
|
"force": True,
|
|
"enable": False,
|
|
},
|
|
}
|
|
)
|
|
|
|
assert "result" in resp
|
|
assert resp["result"]["plugin_name"] == "hello-world"
|
|
mock_install.assert_called_once_with(
|
|
"owner/hello-world",
|
|
force=True,
|
|
enable=False,
|
|
catalog_name=None,
|
|
)
|
|
|
|
|
|
def test_plugins_manage_install_missing_identifier():
|
|
resp = server.handle_request(
|
|
{
|
|
"id": "1",
|
|
"method": "plugins.manage",
|
|
"params": {"action": "install"},
|
|
}
|
|
)
|
|
|
|
assert "error" in resp
|
|
assert "identifier" in resp["error"]["message"]
|
|
|
|
|
|
def test_plugins_manage_install_failure():
|
|
with patch(
|
|
"hermes_cli.plugins_cmd.dashboard_install_plugin",
|
|
return_value={"ok": False, "error": "Git clone failed"},
|
|
):
|
|
resp = server.handle_request(
|
|
{
|
|
"id": "1",
|
|
"method": "plugins.manage",
|
|
"params": {
|
|
"action": "install",
|
|
"identifier": "bad/repo",
|
|
},
|
|
}
|
|
)
|
|
|
|
assert "error" in resp
|
|
assert "Git clone failed" in resp["error"]["message"]
|
|
|
|
|
|
def test_plugins_manage_install_catalog_name_only():
|
|
"""A catalog pick needs no identifier — the backend resolves repo + pin."""
|
|
payload = {"ok": True, "plugin_name": "weather-plugin", "enabled": False}
|
|
with patch(
|
|
"hermes_cli.plugins_cmd.dashboard_install_plugin",
|
|
return_value=payload,
|
|
) as mock_install:
|
|
resp = server.handle_request(
|
|
{
|
|
"id": "1",
|
|
"method": "plugins.manage",
|
|
"params": {
|
|
"action": "install",
|
|
"catalog_name": "weather-plugin",
|
|
"enable": False,
|
|
},
|
|
}
|
|
)
|
|
|
|
assert "result" in resp
|
|
mock_install.assert_called_once_with(
|
|
"",
|
|
force=False,
|
|
enable=False,
|
|
catalog_name="weather-plugin",
|
|
)
|
|
|
|
|
|
def test_plugins_manage_update_requires_catalog_sidecar(tmp_path, monkeypatch):
|
|
"""Non-catalog installs are refused — their update flows stay CLI-owned."""
|
|
import hermes_cli.plugins_cmd as plugins_cmd
|
|
|
|
plugins_root = tmp_path / "plugins"
|
|
(plugins_root / "plain-git-plugin").mkdir(parents=True)
|
|
monkeypatch.setattr(plugins_cmd, "_plugins_dir", lambda: plugins_root)
|
|
|
|
resp = server.handle_request(
|
|
{
|
|
"id": "1",
|
|
"method": "plugins.manage",
|
|
"params": {"action": "update", "name": "plain-git-plugin"},
|
|
}
|
|
)
|
|
|
|
assert "error" in resp
|
|
assert "not a catalog install" in resp["error"]["message"]
|