test: two flaky queue tests no longer race real time or the first copy's start (#6283)

This commit is contained in:
Miguel Ángel
2026-10-25 07:13:22 +00:00
committed by GitHub
parent a7273f7147
commit 4d154c6a23
3 changed files with 68 additions and 22 deletions
@@ -40,15 +40,14 @@ async function runFixture(onConnection: (socket: Socket) => void) {
});
let stderr = "";
child.stderr.on("data", (chunk) => (stderr += chunk));
const startedAt = Date.now();
const code = await new Promise<number | null>((resolve) => {
const giveUp = setTimeout(() => resolve(null), 20_000);
const giveUp = setTimeout(() => resolve(null), 110_000);
child.once("exit", (exitCode) => {
clearTimeout(giveUp);
resolve(exitCode);
});
});
return { code, stderr, port, home, elapsedMs: Date.now() - startedAt };
return { code, stderr, port, home };
}
it("exits with code 1 when the download host accepts the connection and never answers", async () => {
@@ -58,21 +57,4 @@ it("exits with code 1 when the download host accepts the connection and never an
expect(run.stderr).toContain(`The Chrome download from 127.0.0.1:${run.port} stalled`);
expect(run.stderr).toContain("Retrying (2/2)");
expect(existsSync(join(run.home, ".cache", "hyperframes", ".chrome.install.lock"))).toBe(false);
}, 30_000);
it("does not call a download that keeps sending bytes a stall", async () => {
const run = await runFixture((socket) => {
socket.once("data", () => {
socket.write("HTTP/1.1 200 OK\r\ncontent-length: 100000\r\n\r\n");
const trickle = setInterval(() => socket.write("x"), 80);
setTimeout(() => {
clearInterval(trickle);
socket.destroy();
}, 1_200);
});
});
expect(run.code).toBe(1);
expect(run.stderr).not.toContain("no data for");
expect(run.elapsedMs).toBeGreaterThan(1_000);
}, 30_000);
}, 120_000);
@@ -0,0 +1,60 @@
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { installProgressLine } from "./installProtocol.js";
const worker = vi.hoisted(() => ({
options: undefined as { signal: AbortSignal; onStdout: (chunk: string) => void } | undefined,
finish: undefined as ((paths: string) => void) | undefined,
}));
vi.mock("../utils/cancellableProcess.js", () => ({
runRenderSetupWorker: (_mode: string, _input: unknown, options: typeof worker.options) => {
worker.options = options;
return new Promise<string>((resolve, reject) => {
worker.finish = resolve;
options!.signal.addEventListener("abort", () => reject(options!.signal.reason));
});
},
}));
const { BrowserDownloadStalledError, installInChild } = await import("./installInChild.js");
const STALL_MS = 200;
const input = {
browser: "chrome-headless-shell",
buildId: "1",
cacheDir: "/x",
unpack: false,
} as const;
beforeEach(() => vi.useFakeTimers());
afterEach(() => vi.useRealTimers());
describe("installInChild stall watchdog", () => {
it("does not call a download that keeps reporting progress a stall", async () => {
const result = installInChild(input as never, {
stallMs: STALL_MS,
host: "h",
onLog: () => {},
});
for (let downloaded = 1; downloaded <= 100; downloaded++) {
await vi.advanceTimersByTimeAsync(STALL_MS - 1);
worker.options!.onStdout(installProgressLine(downloaded, 1000));
}
expect(worker.options!.signal.aborted).toBe(false);
worker.finish!("done");
await expect(result).resolves.toBe("done");
});
it("aborts with the host and window once no progress arrives for the stall window", async () => {
const result = installInChild(input as never, {
stallMs: STALL_MS,
host: "h",
onLog: () => {},
});
const rejected = expect(result).rejects.toThrow(BrowserDownloadStalledError);
worker.options!.onStdout(installProgressLine(1, 100));
await vi.advanceTimersByTimeAsync(STALL_MS);
await rejected;
await expect(result).rejects.toThrow("The Chrome download from h stalled: no data for 0.2s.");
});
});
@@ -36,6 +36,7 @@ import { openBlobStore } from "./blobStore";
// A test can hold a media copy, and run work after its blob is stored but before history records it.
const mediaCopy = vi.hoisted(() => ({
held: null as Promise<void> | null,
entered: null as (() => void) | null,
stored: null as (() => Promise<unknown>) | null,
copies: [] as string[],
fails: null as ((copy: number) => boolean) | null,
@@ -50,6 +51,7 @@ vi.mock("./blobStore", async (importOriginal) => {
...store,
put: async (path: string) => {
if (path.endsWith(".bin")) {
mediaCopy.entered?.();
await mediaCopy.held;
mediaCopy.copies.push(basename(path));
if (mediaCopy.fails?.(mediaCopy.copies.length)) throw new Error("The disk is full.");
@@ -70,7 +72,7 @@ const cleanup: Array<() => unknown> = [];
afterEach(async () => {
for (const step of cleanup.splice(0).reverse()) await step();
Object.assign(mediaCopy, { held: null, stored: null, copies: [], fails: null });
Object.assign(mediaCopy, { held: null, entered: null, stored: null, copies: [], fails: null });
});
const inside = (dir: string, path: string) => readFileSync(join(dir, path), "utf-8");
@@ -366,11 +368,13 @@ describe("openProjectHistory", () => {
it("never copies the media of a folder that replaced the project", async () => {
let release = () => {};
mediaCopy.held = new Promise<void>((resolve) => (release = resolve));
const firstCopyRunning = new Promise<void>((resolve) => (mediaCopy.entered = resolve));
const media = {
"a.bin": Buffer.alloc(2 * 1024 ** 2, 1),
"b.bin": Buffer.alloc(2 * 1024 ** 2, 2),
};
const { history, write, projectDir } = await project({ "index.html": "A", ...media });
await firstCopyRunning;
renameSync(projectDir, `${projectDir}-moved`);
cleanup.push(() => rmSync(`${projectDir}-moved`, { recursive: true, force: true }));
mkdirSync(projectDir);