Files
hermes-agent/tests/tools/test_browser_process_tree.py

60 lines
2.0 KiB
Python

"""Browser cleanup fallback contracts, retained after retiring the npx warmer."""
import os
import signal
from unittest.mock import MagicMock, patch
import pytest
from tools.browser_tool_lifecycle import _legacy_kill_process_tree
@pytest.mark.platforms("posix")
def test_posix_kills_process_group_term_then_kill(monkeypatch):
proc = MagicMock(pid=999)
monkeypatch.setattr(os, "getpgid", lambda pid: 999)
calls = []
monkeypatch.setattr(os, "killpg", lambda pgid, sig: calls.append((pgid, sig)))
_legacy_kill_process_tree(proc)
assert calls == [(999, signal.SIGTERM), (999, signal.SIGKILL)]
@pytest.mark.platforms("posix")
def test_posix_missing_process_returns_silently(monkeypatch):
def missing(pid):
raise ProcessLookupError()
monkeypatch.setattr(os, "getpgid", missing)
_legacy_kill_process_tree(MagicMock(pid=999))
@pytest.mark.platforms("posix")
@pytest.mark.parametrize("kill_error", [None, OSError("already reaped")])
def test_missing_killpg_falls_back_to_proc_kill(monkeypatch, kill_error):
proc = MagicMock(pid=999)
proc.kill.side_effect = kill_error
monkeypatch.delattr(os, "killpg", raising=False)
_legacy_kill_process_tree(proc)
proc.kill.assert_called_once()
@pytest.mark.platforms("posix")
def test_permission_denied_does_not_attempt_sigkill(monkeypatch):
monkeypatch.setattr(os, "getpgid", lambda pid: 999)
calls = []
def denied(pgid, sig):
calls.append((pgid, sig))
raise PermissionError()
monkeypatch.setattr(os, "killpg", denied)
_legacy_kill_process_tree(MagicMock(pid=999))
assert calls == [(999, signal.SIGTERM)]
@pytest.mark.platforms("windows")
@pytest.mark.parametrize("error", [None, OSError("taskkill missing")])
def test_windows_taskkill_targets_tree_and_is_best_effort(error):
with patch("subprocess.run", side_effect=error) as run:
_legacy_kill_process_tree(MagicMock(pid=4321))
assert run.call_args.args[0] == ["taskkill", "/PID", "4321", "/T", "/F"]