hermes-agent/tests/agent/test_compression_interrupt_protection.py
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

84 lines
3.2 KiB
Python

"""Regression for #23975: context compression must survive a mid-flight
gateway interrupt.
While the compression summary LLM call is in flight, an incoming gateway
message sets the thread interrupt flag. The Codex Responses aux stream polls
that flag and used to raise InterruptedError unconditionally — aborting the
summary, which then fell back to a degraded static "summary unavailable"
marker (losing the real handoff). Compression now runs its summary call
under aux_interrupt_protection(), so the interrupt poll is masked for the
compression task only (timeouts and other aux tasks stay interruptible).
"""
from __future__ import annotations
from unittest.mock import patch
import agent.auxiliary_client as aux
class TestAuxInterruptProtection:
def test_context_manager_is_reentrant(self):
with aux.aux_interrupt_protection():
assert aux._aux_interrupt_protected() is True
with aux.aux_interrupt_protection():
assert aux._aux_interrupt_protected() is True
# inner exit must NOT clear protection while still inside outer
assert aux._aux_interrupt_protected() is True
assert aux._aux_interrupt_protected() is False
def test_restores_on_exception(self):
try:
with aux.aux_interrupt_protection():
raise ValueError("boom")
except ValueError:
pass
assert aux._aux_interrupt_protected() is False
class TestCompressionProtectsSummaryCall:
"""The compressor must wrap its summary call_llm in aux_interrupt_protection
so a mid-flight interrupt doesn't abort it (#23975)."""
def test_compressor_call_site_uses_protection(self):
# The summary call must run inside aux_interrupt_protection. We assert
# the protection flag is ACTIVE at the moment call_llm is invoked.
from agent.context_compressor import ContextCompressor
seen = {}
class _Resp:
class _Choice:
class _Msg:
content = "[CONTEXT SUMMARY]: ok"
message = _Msg()
choices = [_Choice()]
def fake_call_llm(**kwargs):
# Capture whether protection was active during the call.
seen["protected"] = aux._aux_interrupt_protected()
seen["task"] = kwargs.get("task")
return _Resp()
with patch("agent.context_compressor.get_model_context_length", return_value=100000):
c = ContextCompressor(model="test", quiet_mode=True)
msgs = [
{"role": "user", "content": "do a thing"},
{"role": "assistant", "content": "working"},
{"role": "user", "content": "more"},
{"role": "assistant", "content": "done"},
]
with patch("agent.context_compressor.call_llm", side_effect=fake_call_llm):
summary = c._generate_summary(msgs)
assert summary is not None
assert seen.get("task") == "compression"
assert seen.get("protected") is True, (
"compression summary call must run under aux_interrupt_protection"
)
# Protection must be cleared after the call returns.
assert aux._aux_interrupt_protected() is False