mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-31 19:16:29 +00:00
Second, deeper pass over tools/gateway/hermes_cli plus first pass over the trees wave 1 missed (acp, acp_adapter, skills, computer_use, docker, dashboard, conformance, monitoring, secret_sources, hermes_state, providers). Same rubric as wave 1 (AGENTS.md test policy); security, alternation/caching invariants, issue-number regressions, and E2E kept. Real test-quality fixes found and rooted out along the way: - tests/tools/test_command_guards.py made real auxiliary-LLM HTTPS calls (DEFAULT_CONFIG smart-approval leaked in) — pinned approval mode=manual via autouse fixture: 17.4s → 0.4s. - test_model_switch_custom_providers.py / test_user_providers_model_switch.py silently probed live provider catalogs (~2s/test) — stubbed cached_provider_model_ids/provider_model_ids/fetch_api_models. - test_telegram_noise_filter.py: 15-platform copy-paste matrix over shared gateway.run logic → 3 representative platforms (55s → 3.9s). - test_gateway_shutdown.py: stop()'s 5s interrupt-deadline loop spun on MagicMock agents — interrupt.side_effect now clears _running_agents (22s → 1.0s). - test_gateway_inactivity_timeout.py poll-harness timings shrunk 3-5x (24s → 1.1s); test_mcp_stability.py backoff/SIGTERM-grace sleeps patched (15.4s → 2.5s); test_async_delegation.py negative-drain wait 5s → 0.5s. - test_telegram_init_deadline.py: loop-block margin restored to 1.0s with rationale comment — the watchdog-dump assertion needs the loop blocked well past deadline+grace under parallel load (flaked once in the 40-worker verification run at a 0.2s margin). Verification: full hermetic suite via scripts/run_tests.sh — 2,438 files, 21,718 tests passed, 0 failed, 293.9s wall. Suite totals vs original baseline: 46,820 → 19,757 test functions (−57.8%), wall 583.5s → 293.9s (−50%), subprocess CPU 13,564s → 11,623s.
119 lines
3.6 KiB
Python
119 lines
3.6 KiB
Python
import asyncio
|
|
import time
|
|
|
|
|
|
class _FakeProc:
|
|
def __init__(self, lines=None, returncode=0):
|
|
self.stdout = iter(lines or [])
|
|
self._returncode = returncode
|
|
self.terminated = False
|
|
self.killed = False
|
|
self.pid = 12345
|
|
|
|
def poll(self):
|
|
return None if not self.terminated and not self.killed else self._returncode
|
|
|
|
def wait(self, timeout=None):
|
|
return self._returncode
|
|
|
|
def terminate(self):
|
|
self.terminated = True
|
|
|
|
def kill(self):
|
|
self.killed = True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_apply_whatsapp_onboarding_saves_pairing_policy(monkeypatch):
|
|
from hermes_cli import web_server as ws
|
|
|
|
saved = {}
|
|
removed = []
|
|
enabled = []
|
|
|
|
monkeypatch.setattr(ws, "save_env_value", lambda key, value: saved.setdefault(key, value))
|
|
monkeypatch.setattr(ws, "remove_env_value", lambda key: removed.append(key))
|
|
monkeypatch.setattr(ws, "_write_platform_enabled", lambda platform, value: enabled.append((platform, value)))
|
|
monkeypatch.setattr(
|
|
ws,
|
|
"_restart_gateway_after_whatsapp_onboarding",
|
|
lambda profile=None: {"restart_started": True, "restart_pid": 12345},
|
|
)
|
|
|
|
record = ws._WhatsAppOnboardingSession(
|
|
proc=None,
|
|
mode="bot",
|
|
allowed_users="",
|
|
session_path="/tmp/session",
|
|
expires_at="2099-01-01T00:00:00Z",
|
|
expires_at_ts=time.time() + 600,
|
|
status="connected",
|
|
)
|
|
ws._whatsapp_onboarding_sessions.clear()
|
|
ws._whatsapp_onboarding_sessions["pairing"] = record
|
|
|
|
result = asyncio.run(
|
|
ws.apply_whatsapp_onboarding(
|
|
"pairing",
|
|
ws.WhatsAppOnboardingApply(mode="bot", allowed_users=""),
|
|
)
|
|
)
|
|
|
|
assert result["ok"] is True
|
|
assert saved["WHATSAPP_MODE"] == "bot"
|
|
assert saved["WHATSAPP_DM_POLICY"] == "pairing"
|
|
assert saved["WHATSAPP_ENABLED"] == "true"
|
|
assert "WHATSAPP_ALLOWED_USERS" not in removed
|
|
assert enabled == [("whatsapp", True)]
|
|
assert "pairing" not in ws._whatsapp_onboarding_sessions
|
|
|
|
|
|
def test_start_whatsapp_onboarding_existing_creds_returns_linked_account(monkeypatch, tmp_path):
|
|
from hermes_cli import web_server as ws
|
|
|
|
session_dir = tmp_path / "session"
|
|
session_dir.mkdir()
|
|
(session_dir / "creds.json").write_text(
|
|
'{"me":{"id":"15551234567:1@s.whatsapp.net","name":"Hermes Bot"}}',
|
|
encoding="utf-8",
|
|
)
|
|
|
|
old_proc = _FakeProc(returncode=1)
|
|
old_record = ws._WhatsAppOnboardingSession(
|
|
proc=old_proc,
|
|
mode="bot",
|
|
allowed_users="",
|
|
session_path=str(session_dir),
|
|
expires_at="2099-01-01T00:00:00Z",
|
|
expires_at_ts=time.time() + 600,
|
|
)
|
|
ws._whatsapp_onboarding_sessions.clear()
|
|
ws._whatsapp_onboarding_sessions["old"] = old_record
|
|
monkeypatch.setattr(ws, "_whatsapp_session_path", lambda: session_dir)
|
|
monkeypatch.setattr(ws.secrets, "token_urlsafe", lambda size: "existing-creds")
|
|
|
|
result = asyncio.run(
|
|
ws.start_whatsapp_onboarding(
|
|
ws.WhatsAppOnboardingStart(mode="self-chat", allowed_users="")
|
|
)
|
|
)
|
|
|
|
assert result["pairing_id"] == "existing-creds"
|
|
assert result["status"] == "connected"
|
|
assert result["qr_payload"] is None
|
|
assert result["account_id"] == "15551234567:1@s.whatsapp.net"
|
|
assert result["account_name"] == "Hermes Bot"
|
|
assert result["account_phone"] == "15551234567"
|
|
assert old_record.status == "cancelled"
|
|
assert old_proc.terminated is True
|
|
assert ws._whatsapp_onboarding_sessions["existing-creds"].account_phone == "15551234567"
|
|
ws._whatsapp_onboarding_sessions.clear()
|
|
|
|
|
|
|
|
|