"""Pin the psutil-free process helpers. psutil is an optional extra, so on a base install these are the only way `ncp stop` / `nexus status` can see or stop a service. Windows previously had no fallback at all: pid_is_ours returned False, kill_port returned False, and the terminate branch was POSIX-only, so stop was a no-op there. Probing must also stay side-effect free. That is easy to get wrong on Windows, where os.kill(pid, sig) is TerminateProcess for every sig except 0 and the two console-control events - os.kill(pid, 15) kills instead of asking. """ from __future__ import annotations import subprocess import sys import time import pytest from synapse import proc_util def _spawn(): return subprocess.Popen( [sys.executable, "-c", "import time; time.sleep(30)"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, ) def _wait_gone(proc, timeout=10.0) -> bool: deadline = time.monotonic() + timeout while time.monotonic() < deadline: if proc.poll() is not None: return True time.sleep(0.05) return False @pytest.fixture def victim(): proc = _spawn() try: yield proc finally: if proc.poll() is None: proc.kill() proc.wait(timeout=10) def test_pid_alive_does_not_kill_the_process(victim): """Probing must be side-effect free, however it is implemented.""" for _ in range(5): assert proc_util.pid_alive(victim.pid) is True time.sleep(0.3) assert victim.poll() is None, "pid_alive() terminated the process it probed" def test_pid_alive_is_false_for_a_dead_pid(victim): victim.kill() victim.wait(timeout=10) assert proc_util.pid_alive(victim.pid) is False @pytest.mark.parametrize("pid", [None, 0, -1, "not-a-pid"]) def test_pid_alive_rejects_junk(pid): assert proc_util.pid_alive(pid) is False def test_terminate_pid_actually_stops_it(victim): assert proc_util.terminate_pid(victim.pid) is True assert _wait_gone(victim), "terminate_pid() did not stop the process" assert proc_util.pid_alive(victim.pid) is False def test_terminate_pid_is_false_when_already_gone(victim): victim.kill() victim.wait(timeout=10) assert proc_util.terminate_pid(victim.pid) is False def test_pid_cmdline_identifies_the_process(victim): cmd = proc_util.pid_cmdline(victim.pid) if not cmd: pytest.skip("no command-line source on this host") assert "time.sleep" in cmd or "python" in cmd.lower() def test_iter_processes_includes_this_interpreter(): import os entries = proc_util.iter_processes() if not entries: pytest.skip("no process enumeration available on this host") assert os.getpid() in {pid for pid, _ in entries}