Files
hermes-agent/tests/tui_gateway/test_gateway_owned_session_reap.py
T
Teknium 6b81590c55 test: prune low-value tests suite-wide (wave 1) — 46,820 → 28,106 test functions
Systematic prune per AGENTS.md test policy, one pass over every major
test tree (gateway, hermes_cli, tools, agent, run_agent, plugins, cli,
cron, tui_gateway, honcho/openviking, root-level):

- DELETE: source-reading tests (read_text/getsource on prod files),
  change-detector tests (exact catalog counts, model-name snapshots,
  config version literals), mock-echo tests (assert a mock returns what
  it was told), assertion-free/trivial tests, near-duplicate
  parametrizations (boundaries + one representative kept), async/sync
  twin duplicates, cosmetic within-file variations.
- KEEP (mandatory): security/redaction/approval guards, message-role
  alternation invariants, prompt-caching/deterministic-call-id
  invariants, issue-number regression tests (deduped), E2E tests.
- 6 test files deleted outright (script-style/no-assert or fully
  redundant); conftest.py, fakes/, fixtures/ untouched.
- tests/acp/conftest.py added: autouse fixture stubs the live
  models.dev/GitHub/Copilot/Anthropic inventory fetches that ACP server
  tests performed on every session create — test_server.py 147s → 3.4s,
  and the tests are now genuinely hermetic.
- Sleep-based slowness shrunk where safe (codex_ttfb_watchdog,
  compression_concurrent_fork, etc.); no wall-clock assertion tightened.

Verification: full hermetic suite via scripts/run_tests.sh —
2439 files, 31,130 tests passed, 0 failed, 0 flaky retries, 315s wall
(baseline: 583s wall, 13,564s subprocess CPU).
2026-07-29 13:10:23 -07:00

75 lines
2.8 KiB
Python

"""Tests for #60609: the TUI backend must not end gateway-owned sessions.
``_finalize_session`` (and thus the ws-orphan reaper / session.close paths
that funnel into it) marks the session ended in state.db. For sessions the
messaging gateway owns (telegram, discord, ...), that write creates the
Groundhog Day routing loop described in #60609 — the gateway self-heal
drops the ended-but-routed entry, recovers hours-old parent context, and
loops. The TUI is only a viewer of those sessions.
"""
from unittest.mock import MagicMock, patch
from tui_gateway.server import _finalize_session, _is_gateway_owned_source
class TestIsGatewayOwnedSource:
def test_builtin_gateway_platforms_are_owned(self):
for src in ("telegram", "discord", "whatsapp", "slack", "signal",
"matrix", "mattermost", "bluebubbles", "sms", "email"):
assert _is_gateway_owned_source(src) is True, src
def test_case_and_whitespace_normalized(self):
assert _is_gateway_owned_source(" Telegram ") is True
def test_tui_owned_sources_are_not(self):
for src in ("tui", "cli", "webui", "desktop", "cron", "subagent",
"test", "acp", ""):
assert _is_gateway_owned_source(src) is False, src
def test_local_and_server_endpoints_are_not(self):
# Platform enum members, but their sessions aren't owned by a remote
# chat surface — reaping them keeps /resume clean.
for src in ("local", "webhook", "api_server", "msgraph_webhook"):
assert _is_gateway_owned_source(src) is False, src
def test_arbitrary_strings_are_not(self):
assert _is_gateway_owned_source("hermesbench-task-xyz") is False
assert _is_gateway_owned_source(None) is False
def _make_session(session_id="sess_1"):
agent = MagicMock()
agent.session_id = session_id
return {
"agent": agent,
"history": [{"role": "user", "content": "x"}],
"history_lock": None,
"session_key": session_id,
}
class TestFinalizeSkipsGatewaySessions:
@patch("tui_gateway.server._get_db")
def test_gateway_session_not_ended(self, mock_get_db):
db = MagicMock()
db.get_session.return_value = {"id": "sess_1", "source": "telegram"}
mock_get_db.return_value = db
_finalize_session(_make_session(), end_reason="ws_orphan_reap")
db.end_session.assert_not_called()
@patch("tui_gateway.server._get_db")
def test_missing_row_still_ended(self, mock_get_db):
"""A session with no state.db row can't be gateway-owned — keep the
pre-existing reap behavior."""
db = MagicMock()
db.get_session.return_value = None
mock_get_db.return_value = db
_finalize_session(_make_session(), end_reason="tui_close")
db.end_session.assert_called_once_with("sess_1", "tui_close")