From 06b4e3885e8b7bd1f2fb7aed6816fc4194154811 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Tue, 21 Apr 2026 16:44:41 +0100 Subject: [PATCH] test: stabilize stale-pid ancestor override (cherry picked from commit 4e25479cb25f2c478ae72093c8ca37619f6b5ec7) --- src/infra/restart-stale-pids.test.ts | 15 +++++---------- src/infra/restart-stale-pids.ts | 10 +++++++++- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/infra/restart-stale-pids.test.ts b/src/infra/restart-stale-pids.test.ts index 9d8d1b429d7..0ba01d77a60 100644 --- a/src/infra/restart-stale-pids.test.ts +++ b/src/infra/restart-stale-pids.test.ts @@ -185,24 +185,19 @@ describe.skipIf(isWindows)("restart-stale-pids", () => { afterEach(() => { __testing.setSleepSyncOverride(null); __testing.setDateNowOverride(null); + __testing.setParentPidOverride(null); vi.restoreAllMocks(); }); - // Temporarily rewrites `process.ppid` for a block of test code. Used by the + // Temporarily overrides the parent PID for a block of test code. Used by the // ancestor-exclusion tests to drive the real `getSelfAndAncestorPidsSync` - // walk without installing a runtime-reachable override on the module. Node - // always exposes `process.ppid` as an own property so the captured - // descriptor is non-null in practice; the `if (orig)` guard is defensive - // against a broken environment, not a reachable branch. + // walk without depending on runtime-specific `process.ppid` descriptors. function withStubbedPpid(ppid: number, fn: () => T): T { - const orig = Object.getOwnPropertyDescriptor(process, "ppid"); - Object.defineProperty(process, "ppid", { value: ppid, configurable: true }); + __testing.setParentPidOverride(() => ppid); try { return fn(); } finally { - if (orig) { - Object.defineProperty(process, "ppid", orig); - } + __testing.setParentPidOverride(null); } } diff --git a/src/infra/restart-stale-pids.ts b/src/infra/restart-stale-pids.ts index 5693c23742c..e8485d8c7cd 100644 --- a/src/infra/restart-stale-pids.ts +++ b/src/infra/restart-stale-pids.ts @@ -45,6 +45,7 @@ const MAX_ANCESTOR_WALK_DEPTH = 32; const restartLog = createSubsystemLogger("restart"); let sleepSyncOverride: ((ms: number) => void) | null = null; let dateNowOverride: (() => number) | null = null; +let parentPidOverride: (() => number) | null = null; function getTimeMs(): number { return dateNowOverride ? dateNowOverride() : Date.now(); @@ -70,6 +71,10 @@ function sleepSync(ms: number): void { } } +function getParentPid(): number { + return parentPidOverride ? parentPidOverride() : process.ppid; +} + /** * Read a single ancestor PID from `/proc//status` on Linux. * Returns null on any failure (non-Linux platform, restricted /proc, race @@ -135,7 +140,7 @@ function readParentPidFromProc(pid: number): number | null { */ function getSelfAndAncestorPidsSync(): Set { const pids = new Set([process.pid]); - const immediateParent = process.ppid; + const immediateParent = getParentPid(); if (!Number.isFinite(immediateParent) || immediateParent <= 0) { return pids; } @@ -553,6 +558,9 @@ export const __testing = { setDateNowOverride(fn: (() => number) | null) { dateNowOverride = fn; }, + setParentPidOverride(fn: (() => number) | null) { + parentPidOverride = fn; + }, /** Invoke sleepSync directly (bypasses the override) for unit-testing the real Atomics path. */ callSleepSyncRaw: sleepSync, };