test(workspaces): make lock contention deterministic
This commit is contained in:
@@ -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);
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user