Files
hermes-agent/tests/tools/test_process_registry_owner_chain.py
2026-10-01 00:52:58 -05:00

90 lines
3.6 KiB
Python

"""RED tests for #120546: background WSL work leaves ownerless PIDs.
A delegate child spawns background processes under its RAW task id
(``sa-...``) while the registry stores the COLLAPSED container key
(``task_id``, e.g. ``"default"`` on local backends). Queries filtered on the
container key only, so the owner saw zero live processes while GPU work ran,
and kills/reaps missed them. Queries must match the ownership chain
(container key OR raw spawning owner). WSL-launched commands must also carry
a durable marker: the recorded host PID is the short-lived ``wsl.exe``
launcher, never the Linux-side workers.
"""
import time
from unittest.mock import patch
from tools.process_registry import ProcessRegistry, ProcessSession
def _owned_session(sid="proc_own1", container="default", owner="sa-1-abc123",
command="sleep 30", **kw):
return ProcessSession(
id=sid, command=command, task_id=container, owner_task_id=owner,
started_at=kw.pop("started_at", time.time()), **kw)
def test_list_surfaces_owner_spawned_process_despite_collapsed_container_key():
reg = ProcessRegistry()
reg._running["proc_own1"] = _owned_session()
entries = reg.list_sessions(task_id="sa-1-abc123")
assert [e["session_id"] for e in entries] == ["proc_own1"]
assert entries[0]["owner_task_id"] == "sa-1-abc123"
def test_list_still_matches_container_key():
reg = ProcessRegistry()
reg._running["proc_c1"] = _owned_session(
sid="proc_c1", container="default", owner="default")
assert [e["session_id"] for e in reg.list_sessions(task_id="default")] == ["proc_c1"]
def test_has_active_processes_matches_raw_owner():
reg = ProcessRegistry()
reg._running["proc_own1"] = _owned_session()
assert reg.has_active_processes("sa-1-abc123") is True
assert reg.has_active_processes("sa-9-unrelated") is False
def test_snapshot_running_ids_matches_raw_owner():
reg = ProcessRegistry()
reg._running["proc_own1"] = _owned_session()
assert reg.snapshot_running_ids("sa-1-abc123") == frozenset({"proc_own1"})
assert reg.snapshot_running_ids("sa-9-unrelated") == frozenset()
def test_kill_all_targets_owner_spawned_process():
reg = ProcessRegistry()
reg._running["proc_own1"] = _owned_session()
with patch.object(reg, "kill_process",
return_value={"status": "killed"}) as kill:
assert reg.kill_all("sa-1-abc123", source="t") == 1
kill.assert_called_once_with("proc_own1", source="t", consume_output=False)
def test_wsl_launcher_command_stamped_at_spawn():
reg = ProcessRegistry()
wsl = reg._new_session("wsl.exe -e bash -lc 'ninfer-serve --port 8080'",
"default", "sa-1-abc123", "", ".")
plain = reg._new_session("python -m pytest -x", "default", "sa-1-abc123", "", ".")
assert wsl.wsl_chain is True
assert plain.wsl_chain is False
def test_wsl_launcher_forms_detected():
reg = ProcessRegistry()
for cmd in ("wsl -e bash -c 'x'", "wsl --exec foo", "wsl -d Ubuntu -- bar",
"C:\\Windows\\System32\\wsl.exe -e foo"):
assert reg._new_session(cmd, "d", "o", "", ".").wsl_chain is True, cmd
for cmd in ("python -m wsl_tool", "echo wsl.exe", "mywsl -e x"):
assert reg._new_session(cmd, "d", "o", "", ".").wsl_chain is False, cmd
def test_list_entry_surfaces_wsl_chain_hint():
reg = ProcessRegistry()
reg._running["proc_w"] = _owned_session(
sid="proc_w", command="wsl.exe -e bash -lc 'ninfer-serve'")
reg._running["proc_w"].wsl_chain = True
(entry,) = reg.list_sessions(task_id="sa-1-abc123")
assert entry["wsl_chain"] is True
assert "wsl" in entry["wsl_note"].lower()