From 431b997c780004d5460ebcebff9bdd3642219b33 Mon Sep 17 00:00:00 2001 From: luvs01 Date: Fri, 28 Aug 2026 11:03:28 +0900 Subject: [PATCH] fix(test): scope run lock to user home --- scripts/test-run-lock.ts | 12 ++++++++---- scripts/test.ts | 4 ++-- tests/preload.ts | 2 +- tests/test-runner.test.ts | 8 +++++++- 4 files changed, 18 insertions(+), 8 deletions(-) diff --git a/scripts/test-run-lock.ts b/scripts/test-run-lock.ts index d1c65487d5..81a85debd6 100644 --- a/scripts/test-run-lock.ts +++ b/scripts/test-run-lock.ts @@ -8,12 +8,11 @@ import { statSync, writeFileSync, } from "node:fs"; -import { tmpdir } from "node:os"; +import { homedir } from "node:os"; import { join } from "node:path"; export const TEST_RUN_ID_ENV = "OCX_TEST_RUN_ID"; export const TEST_RUN_NO_QUEUE_ENV = "OCX_TEST_NO_QUEUE"; -const DEFAULT_LOCK_PATH = join(tmpdir(), "opencodex-bun-test.lock"); const OWNER_FILE = "owner.json"; const MEMBERS_DIR = "members"; const INCOMPLETE_OWNER_GRACE_MS = 10_000; @@ -48,6 +47,11 @@ export interface BareTestRunIdentity { runId: string; } +/** Keep the shared lock in a directory controlled by the current OS user. */ +export function resolveDefaultTestRunLockPath(home = homedir()): string { + return join(home, ".opencodex-bun-test.lock"); +} + /** * Give one bare Bun invocation a stable identity without conflating sibling commands. * @@ -151,7 +155,7 @@ function ownsLock(lockPath: string, owner: TestRunLockOwner): boolean { } /** - * Acquire the machine-wide OpenCodex Bun-test lock. + * Acquire the user-wide OpenCodex Bun-test lock. * * `mkdir` is the cross-platform atomic primitive. The owner PID makes a lock left by * SIGKILL recoverable, while the run ID lets every worker belonging to one bare @@ -165,7 +169,7 @@ export async function acquireTestRunLock(options: AcquireTestRunLockOptions): Pr return { acquired: false, owner: null, release() {} }; } - const lockPath = options.lockPath ?? DEFAULT_LOCK_PATH; + const lockPath = options.lockPath ?? resolveDefaultTestRunLockPath(); const ownerPid = options.ownerPid ?? process.pid; const pollMs = Math.max(1, options.pollMs ?? 5_000); const maxWaitMs = Math.max(pollMs, options.maxWaitMs ?? 45 * 60 * 1000); diff --git a/scripts/test.ts b/scripts/test.ts index 29357a681a..f36746329c 100644 --- a/scripts/test.ts +++ b/scripts/test.ts @@ -297,10 +297,10 @@ if (import.meta.main) { const lock = await acquireTestRunLock({ runId, onWait: owner => console.warn( - `[test] another Bun test run${owner ? ` (pid ${owner.pid})` : ""} holds the machine lock; waiting. ` + `[test] another Bun test run${owner ? ` (pid ${owner.pid})` : ""} holds the user lock; waiting. ` + "Set OCX_TEST_NO_QUEUE=1 only for intentional overlap.", ), - onAcquiredAfterWait: elapsedMs => console.warn(`[test] acquired the machine lock after ${Math.round(elapsedMs / 1000)}s.`), + onAcquiredAfterWait: elapsedMs => console.warn(`[test] acquired the user lock after ${Math.round(elapsedMs / 1000)}s.`), }); const startedAt = Date.now(); try { diff --git a/tests/preload.ts b/tests/preload.ts index 37b2233df0..dd04c5c33c 100644 --- a/tests/preload.ts +++ b/tests/preload.ts @@ -34,7 +34,7 @@ await acquireTestRunLock({ runId, ownerPid: bareIdentity.ownerPid, onWait: owner => console.warn( - `[test] bare Bun worker ${process.pid} is waiting for test run${owner ? ` pid ${owner.pid}` : ""} to release the machine lock.`, + `[test] bare Bun worker ${process.pid} is waiting for test run${owner ? ` pid ${owner.pid}` : ""} to release the user lock.`, ), }); diff --git a/tests/test-runner.test.ts b/tests/test-runner.test.ts index 9589bc59d8..629a47a376 100644 --- a/tests/test-runner.test.ts +++ b/tests/test-runner.test.ts @@ -10,6 +10,7 @@ import { } from "../scripts/test"; import { acquireTestRunLock, + resolveDefaultTestRunLockPath, resolveBareTestRunIdentity, TEST_RUN_NO_QUEUE_ENV, } from "../scripts/test-run-lock"; @@ -208,7 +209,12 @@ describe("bun test argv", () => { }); }); -describe("bun test machine lock", () => { +describe("bun test user lock", () => { + test("keeps the default lock out of the shared temporary directory", () => { + expect(resolveDefaultTestRunLockPath(join("home", "alice"))) + .toBe(join("home", "alice", ".opencodex-bun-test.lock")); + }); + test("independent bare runners do not inherit a shared long-lived parent identity", () => { expect(resolveBareTestRunIdentity({ pid: 101, ppid: 50 })).toEqual({ ownerPid: 101,