fix(gateway): stabilize process identities

This commit is contained in:
Xubin Ren
2026-08-18 03:21:00 +08:00
parent 2b4a04fb71
commit 19ad1adfe7
3 changed files with 240 additions and 35 deletions
+70
View File
@@ -642,6 +642,24 @@ def test_lease_snapshot_prunes_a_reused_client_pid(tmp_path, monkeypatch):
}
def test_lease_snapshot_keeps_a_legacy_localized_darwin_client(tmp_path, monkeypatch):
runtime = GatewayRuntime(paths=_paths(tmp_path), platform_name="Darwin")
started_at = int(time.mktime((2026, 8, 18, 2, 17, 54, -1, -1, -1)))
identity = "42:二 8/18 02:17:54 2026"
monkeypatch.setattr(runtime, "_is_pid_running", lambda _pid: True)
monkeypatch.setattr(runtime, "_process_identity", lambda _pid: identity)
client = GatewayClientLease(runtime, kind="webui", pid=12345, token="client")
client.acquire()
client.mark_ephemeral()
identity = f"darwin:42:{started_at}:123456"
snapshot = client.snapshot()
assert snapshot.auto_stop is True
assert snapshot.clients == 1
def test_lease_snapshot_keeps_a_client_when_identity_probe_is_unavailable(
tmp_path,
monkeypatch,
@@ -791,6 +809,26 @@ def test_windows_host_identity_stays_safe_when_target_platform_is_posix(tmp_path
assert runtime.process_identity(12345) == "created-at"
def test_windows_lease_prunes_a_reused_pid_by_creation_time(tmp_path, monkeypatch):
runtime = GatewayRuntime(paths=_paths(tmp_path), platform_name="Windows")
identity = "filetime:first-process"
monkeypatch.setattr("nanobot.process_runtime._platform_name", lambda: "Windows")
monkeypatch.setattr(
"nanobot.process_runtime._windows_process_identity",
lambda _pid: identity,
)
client = GatewayClientLease(runtime, kind="tui", pid=12345, token="client")
client.acquire()
client.mark_ephemeral()
identity = "filetime:replacement-process"
snapshot = client.snapshot()
assert snapshot.auto_stop is True
assert snapshot.clients == 0
def test_status_clears_stale_state(tmp_path, monkeypatch):
runtime = GatewayRuntime(paths=_paths(tmp_path), platform_name="Linux")
runtime.paths.run_dir.mkdir(parents=True)
@@ -877,6 +915,38 @@ def test_posix_process_identity_includes_start_time_and_accepts_legacy_state(
assert runtime._record_matches_process({"identity": 42}, 12345) is True
def test_darwin_process_identity_is_locale_independent(tmp_path, monkeypatch):
runtime = GatewayRuntime(
paths=_paths(tmp_path),
platform_name="Darwin",
subprocess_run=lambda *_args, **_kwargs: pytest.fail(
"Darwin identities must not depend on localized subprocess output"
),
)
monkeypatch.setenv("LANG", "zh_CN.UTF-8")
monkeypatch.setenv("LC_ALL", "zh_CN.UTF-8")
started_at = int(time.mktime((2026, 8, 18, 2, 17, 54, -1, -1, -1)))
monkeypatch.setattr(
"nanobot.process_runtime._darwin_process_birth",
lambda _pid: (42, started_at, 123456),
)
assert runtime.process_identity(12345) == f"darwin:42:{started_at}:123456"
assert runtime._record_matches_process({"identity": 42}, 12345) is True
@pytest.mark.skipif(sys.platform != "darwin", reason="requires macOS proc_pidinfo")
def test_darwin_live_process_identity_is_stable(tmp_path):
runtime = GatewayRuntime(paths=_paths(tmp_path), platform_name="Darwin")
first = runtime.process_identity(os.getpid())
second = runtime.process_identity(os.getpid())
assert isinstance(first, str)
assert first.startswith("darwin:")
assert second == first
def test_stop_terminates_recorded_process(tmp_path, monkeypatch):
runtime = GatewayRuntime(paths=_paths(tmp_path), platform_name="Linux")
runtime.paths.run_dir.mkdir(parents=True)