test(gateway): trim the reap-grace tests to the one invariant
Collapse TestReaperStartupGrace into a single test pinning the grace invariant: a booting gateway and an undeterminable age are spared under a positive grace while a stale orphan is still reaped. The no-grace default is already covered by the existing reaper tests.
This commit is contained in:
@@ -849,65 +849,37 @@ class TestReapUnsupervisedGatewayOrphansWindows:
|
||||
|
||||
|
||||
class TestReaperStartupGrace:
|
||||
"""``min_age_s`` spares a gateway that is still claiming its identity (#122533).
|
||||
"""``min_age_s`` spares a gateway still claiming gateway.pid/lock (#122533).
|
||||
|
||||
A gateway claims ``gateway.pid``/``gateway.lock`` only after imports and runner
|
||||
setup, so for the first seconds of its life it is visible to the argv sweep but
|
||||
not to the record-based exclusions. Reaping it writes a planned-stop marker the
|
||||
booting gateway consumes as soon as it finishes starting — a clean exit 0 with no
|
||||
supervisor to revive it, so a Desktop-launched bot goes silent until a manual
|
||||
start. The grace applies only at the Desktop boot sweep; stop/restart keep the
|
||||
immediate reap (#75936).
|
||||
A booting gateway is argv-visible before it is record-visible; reaping it writes
|
||||
a planned-stop marker it consumes on startup and exits 0 with no supervisor. An
|
||||
undeterminable age must read as too young, never widen the reap.
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def _isolate_reaper(monkeypatch, candidates, ages):
|
||||
killed = []
|
||||
def test_grace_spares_booting_and_unknown_age_but_reaps_stale_orphan(self, monkeypatch):
|
||||
booting, unknown, stale = 55501, 55502, 99998
|
||||
ages = {booting: 2.0, stale: 900.0}
|
||||
|
||||
def _age(pid):
|
||||
if pid not in ages:
|
||||
raise RuntimeError("probe failed")
|
||||
return ages[pid]
|
||||
|
||||
monkeypatch.setattr(gateway, "supports_systemd_services", lambda: False)
|
||||
monkeypatch.setattr("gateway.status.get_running_pid", lambda cleanup_stale=True: None)
|
||||
monkeypatch.setattr(
|
||||
gateway,
|
||||
"find_gateway_pids",
|
||||
lambda exclude_pids=None: [p for p in candidates if p not in (exclude_pids or set())],
|
||||
gateway, "find_gateway_pids",
|
||||
lambda exclude_pids=None: [p for p in (booting, unknown, stale) if p not in (exclude_pids or set())],
|
||||
)
|
||||
monkeypatch.setattr(gateway, "_gateway_process_age_s", lambda pid: ages[pid])
|
||||
monkeypatch.setattr(gateway.os, "kill", lambda pid, sig: killed.append(pid))
|
||||
monkeypatch.setattr("hermes_cli.dashboard_procs._process_age_seconds", _age)
|
||||
monkeypatch.setattr(gateway.os, "kill", lambda pid, sig: None)
|
||||
monkeypatch.setattr("gateway.status._pid_exists", lambda pid: False)
|
||||
monkeypatch.setattr("time.sleep", lambda _: None)
|
||||
monkeypatch.setattr("time.monotonic", lambda: 1.0)
|
||||
return killed
|
||||
|
||||
def test_grace_spares_a_booting_gateway_but_still_reaps_a_stale_orphan(self, monkeypatch):
|
||||
booting_pid, stale_orphan_pid = 55501, 99998
|
||||
self._isolate_reaper(
|
||||
monkeypatch,
|
||||
[booting_pid, stale_orphan_pid],
|
||||
{booting_pid: 2.0, stale_orphan_pid: 900.0},
|
||||
)
|
||||
marked_pids = []
|
||||
monkeypatch.setattr("gateway.status.write_planned_stop_marker", marked_pids.append)
|
||||
marked = []
|
||||
monkeypatch.setattr("gateway.status.write_planned_stop_marker", marked.append)
|
||||
|
||||
assert gateway._reap_unsupervised_gateway_orphans(min_age_s=180.0) is True
|
||||
assert marked_pids == [stale_orphan_pid]
|
||||
|
||||
def test_no_grace_keeps_reaping_a_booting_gateway(self, monkeypatch):
|
||||
booting_pid = 55501
|
||||
self._isolate_reaper(monkeypatch, [booting_pid], {booting_pid: 0.0})
|
||||
marked_pids = []
|
||||
monkeypatch.setattr("gateway.status.write_planned_stop_marker", marked_pids.append)
|
||||
|
||||
assert gateway._reap_unsupervised_gateway_orphans() is True
|
||||
assert marked_pids == [booting_pid]
|
||||
|
||||
def test_undeterminable_age_is_spared_under_a_grace(self, monkeypatch):
|
||||
"""A failed age probe must never widen a reap: unknown reads as too young."""
|
||||
booting_pid = 55501
|
||||
self._isolate_reaper(monkeypatch, [booting_pid], {booting_pid: 0.0})
|
||||
marked_pids = []
|
||||
monkeypatch.setattr("gateway.status.write_planned_stop_marker", marked_pids.append)
|
||||
|
||||
assert gateway._reap_unsupervised_gateway_orphans(min_age_s=180.0) is False
|
||||
assert marked_pids == []
|
||||
assert marked == [stale]
|
||||
|
||||
|
||||
class TestReaperCandidateIsSupervisorOwned:
|
||||
|
||||
Reference in New Issue
Block a user