fix(ci): make Windows unit tests deterministic

This commit is contained in:
Peter Steinberger
2026-02-15 03:46:43 +00:00
parent cb54a532f0
commit a47b08d551
2 changed files with 8 additions and 45 deletions

View File

@@ -99,9 +99,10 @@ async function execLaunchctl(
args: string[],
): Promise<{ stdout: string; stderr: string; code: number }> {
try {
const { stdout, stderr } = await execFileAsync("launchctl", args, {
encoding: "utf8",
});
const isWindows = process.platform === "win32";
const file = isWindows ? (process.env.ComSpec ?? "cmd.exe") : "launchctl";
const fileArgs = isWindows ? ["/d", "/s", "/c", "launchctl", ...args] : args;
const { stdout, stderr } = await execFileAsync(file, fileArgs, { encoding: "utf8" });
return {
stdout: String(stdout ?? ""),
stderr: String(stderr ?? ""),

View File

@@ -62,36 +62,6 @@ function makeProcStat(pid: number, startTime: number) {
return `${pid} (node) ${fields.join(" ")}`;
}
type PromiseSettlement<T> =
| { status: "resolved"; value: T }
| { status: "rejected"; reason: unknown };
async function settleWithFakeTimers<T>(
promise: Promise<T>,
params: { stepMs: number; maxSteps: number },
) {
const wrapped: Promise<PromiseSettlement<T>> = promise.then(
(value) => ({ status: "resolved", value }),
(reason) => ({ status: "rejected", reason }),
);
for (let step = 0; step < params.maxSteps; step += 1) {
const settled = await Promise.race([wrapped, Promise.resolve(null)]);
if (settled) {
return settled;
}
await vi.advanceTimersByTimeAsync(params.stepMs);
}
const final = await Promise.race([wrapped, Promise.resolve(null)]);
if (final) {
return final;
}
throw new Error(
`promise did not settle after ${params.maxSteps} steps of ${params.stepMs}ms fake time`,
);
}
describe("gateway lock", () => {
beforeAll(async () => {
fixtureRoot = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gateway-lock-"));
@@ -106,7 +76,7 @@ describe("gateway lock", () => {
});
it("blocks concurrent acquisition until release", async () => {
vi.useFakeTimers();
vi.useRealTimers();
const { env, cleanup } = await makeEnv();
const lock = await acquireGatewayLock({
env,
@@ -122,11 +92,7 @@ describe("gateway lock", () => {
timeoutMs: 80,
pollIntervalMs: 5,
});
const settlement = await settleWithFakeTimers(pending, { stepMs: 5, maxSteps: 40 });
expect(settlement.status).toBe("rejected");
expect((settlement as { status: "rejected"; reason: unknown }).reason).toBeInstanceOf(
GatewayLockError,
);
await expect(pending).rejects.toBeInstanceOf(GatewayLockError);
await lock?.release();
const lock2 = await acquireGatewayLock({
@@ -175,7 +141,7 @@ describe("gateway lock", () => {
});
it("keeps lock on linux when proc access fails unless stale", async () => {
vi.useFakeTimers();
vi.useRealTimers();
const { env, cleanup } = await makeEnv();
const { lockPath, configPath } = resolveLockPath(env);
const payload = {
@@ -202,11 +168,7 @@ describe("gateway lock", () => {
staleMs: 10_000,
platform: "linux",
});
const settlement = await settleWithFakeTimers(pending, { stepMs: 5, maxSteps: 30 });
expect(settlement.status).toBe("rejected");
expect((settlement as { status: "rejected"; reason: unknown }).reason).toBeInstanceOf(
GatewayLockError,
);
await expect(pending).rejects.toBeInstanceOf(GatewayLockError);
spy.mockRestore();