Files
hermes-agent/tests/hermes_cli/test_relay_plugin_cutover.py
ethernet 53e6f001c7 refactor(pm): consolidate runtime ownership and updater completion
Run historical updater completion in a fresh interpreter so cached imports
cannot revive retired dependency installers. Share Git and ZIP completion,
carry receipt and recovery state, and preserve child exit status.

Route plugin admission, binary acquisition, desktop launch and build paths
through PM. Replace redundant helpers and tests with real worker, package,
publication and launch checks. Keep the shipped compatibility surface fixed.

Targeted Python and desktop checks pass. Native update journeys and fresh
production image qualification remain pending. This is a checkpoint before
those acceptance runs.
2026-09-12 16:30:35 -04:00

137 lines
4.4 KiB
Python

"""Regression tests for migration from the removed Hermes Relay plugin."""
from __future__ import annotations
import os
from unittest.mock import patch
import pytest
import hermes_yaml as yaml
from hermes_cli.config import migrate_config
from hermes_cli.doctor_config import collect_relay_plugin_cutover_findings
from hermes_cli.relay_plugin_cutover import RELAY_PLUGINS_CONFIG_ENV
def test_v38_migration_removes_only_legacy_relay_plugin_keys(tmp_path):
config_path = tmp_path / "config.yaml"
config_path.write_text(
yaml.safe_dump(
{
"_config_version": 37,
"plugins": {
"enabled": [
"keep-me",
"observability/nemo_relay",
"nemo_relay",
]
},
},
sort_keys=False,
),
encoding="utf-8",
)
with patch.dict(os.environ, {"HERMES_HOME": str(tmp_path)}):
results = migrate_config(interactive=False, quiet=True)
raw = yaml.safe_load(config_path.read_text(encoding="utf-8"))
# Behavior contract, not a snapshot: the run must land at (at least) the
# v38 relay-cutover step; later migrations legitimately advance the
# version further, and pinning the literal broke on every bump.
assert raw["_config_version"] >= 38
assert raw["plugins"]["enabled"] == ["keep-me"]
assert any(
"observability/nemo_relay" in warning
and RELAY_PLUGINS_CONFIG_ENV in warning
for warning in results["warnings"]
)
def test_doctor_reports_stale_relay_plugin_key():
findings = dict(
collect_relay_plugin_cutover_findings(
{"plugins": {"enabled": ["observability/nemo_relay"]}},
{},
)
)
replacement = findings["plugins.enabled: observability/nemo_relay"]
assert "remove it" in replacement
assert RELAY_PLUGINS_CONFIG_ENV in replacement
def test_doctor_reports_legacy_exporter_env_without_new_config(monkeypatch):
monkeypatch.delenv(RELAY_PLUGINS_CONFIG_ENV, raising=False)
findings = dict(
collect_relay_plugin_cutover_findings(
{},
{
"HERMES_NEMO_RELAY_ATIF_ENABLED": "true",
"HERMES_NEMO_RELAY_ATIF_EXPORT_TIMEOUT_S": "30",
},
)
)
assert "now ignored" in findings["HERMES_NEMO_RELAY_ATIF_ENABLED"]
assert RELAY_PLUGINS_CONFIG_ENV in findings["HERMES_NEMO_RELAY_ATIF_ENABLED"]
assert "now ignored" in findings["HERMES_NEMO_RELAY_ATIF_EXPORT_TIMEOUT_S"]
assert (
RELAY_PLUGINS_CONFIG_ENV
in findings["HERMES_NEMO_RELAY_ATIF_EXPORT_TIMEOUT_S"]
)
@pytest.mark.parametrize("name", ["nemo_relay", "observability/nemo_relay"])
def test_enable_rejects_removed_relay_plugin_without_discovery(name, capsys):
with (
patch("hermes_cli.plugins_cmd._resolve_plugin_key_and_source") as resolve,
patch("hermes_cli.plugins_cmd._set_plugin_enabled") as save_enabled,
):
from hermes_cli.plugins_cmd import cmd_enable
with pytest.raises(SystemExit) as exc_info:
cmd_enable(name, allow_tool_override=False)
assert exc_info.value.code == 1
resolve.assert_not_called()
save_enabled.assert_not_called()
output = capsys.readouterr().out
assert name in output
assert RELAY_PLUGINS_CONFIG_ENV in output
def test_enable_rejects_alias_resolving_to_removed_relay_plugin(capsys):
with (
patch(
"hermes_cli.plugins_cmd._resolve_plugin_key_and_source",
return_value=("observability/nemo_relay", "user"),
),
patch("hermes_cli.plugins_cmd._set_plugin_enabled") as save_enabled,
):
from hermes_cli.plugins_cmd import cmd_enable
with pytest.raises(SystemExit) as exc_info:
cmd_enable("relay-copy", allow_tool_override=False)
assert exc_info.value.code == 1
save_enabled.assert_not_called()
output = capsys.readouterr().out
assert "observability/nemo_relay" in output
assert RELAY_PLUGINS_CONFIG_ENV in output
def test_doctor_does_not_warn_for_legacy_env_after_new_config_is_selected(
monkeypatch,
):
monkeypatch.delenv(RELAY_PLUGINS_CONFIG_ENV, raising=False)
findings = collect_relay_plugin_cutover_findings(
{},
{
RELAY_PLUGINS_CONFIG_ENV: "/tmp/plugins.toml",
"HERMES_NEMO_RELAY_ATIF_ENABLED": "true",
},
)
assert findings == []