test(workspaces): make lock contention deterministic

This commit is contained in:
2026-08-25 21:39:35 +02:00
parent 4499869c75
commit 66f9fa2821
+29 -5
View File
@@ -323,16 +323,40 @@ test("parallel contenders recover a stale lock file without overlapping critical
const second = new WorkspaceRepositoryLock(locks); const second = new WorkspaceRepositoryLock(locks);
let active = 0; let active = 0;
let maximum = 0; let maximum = 0;
const critical = async () => { let firstEntered!: () => void;
const entered = new Promise<void>((resolve) => { firstEntered = resolve; });
let releaseFirst!: () => void;
const held = new Promise<void>((resolve) => { releaseFirst = resolve; });
const firstRun = first.run(async () => {
active += 1;
maximum = Math.max(maximum, active);
firstEntered();
await held;
active -= 1;
});
await entered;
const secondRun = second.run(async () => {
active += 1; active += 1;
maximum = Math.max(maximum, active); maximum = Math.max(maximum, active);
await new Promise((resolve) => setTimeout(resolve, 25)); await new Promise((resolve) => setTimeout(resolve, 25));
active -= 1; active -= 1;
}; });
const results = await Promise.allSettled([first.run(critical), second.run(critical)]); let timeout!: ReturnType<typeof setTimeout>;
const contender = await Promise.race([
secondRun.then(
() => ({ status: "fulfilled" as const }),
() => ({ status: "rejected" as const }),
),
new Promise<{ status: "timed-out" }>((resolve) => {
timeout = setTimeout(() => resolve({ status: "timed-out" }), 2_000);
}),
]);
clearTimeout(timeout);
releaseFirst();
await firstRun;
await secondRun.catch(() => undefined);
expect(results.filter((result) => result.status === "fulfilled")).toHaveLength(1); expect(contender.status).toBe("rejected");
expect(results.filter((result) => result.status === "rejected")).toHaveLength(1);
expect(maximum).toBe(1); expect(maximum).toBe(1);
}); });