Skip to content

Commit 11eeba9

Browse files
authored
perf: speed up crabbox wrapper tests (#99969)
1 parent fc4f8dd commit 11eeba9

1 file changed

Lines changed: 56 additions & 21 deletions

File tree

test/scripts/crabbox-wrapper.test.ts

Lines changed: 56 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ import { afterAll, beforeAll, describe, expect, it } from "vitest";
1919
const tempDirs: string[] = [];
2020
const repoRoot = process.cwd();
2121
const fakeCrabboxBinDirs = new Map<string, string>();
22+
const fakeGitBinDirs = new Map<string, string>();
23+
const timingPreloads = new Map<string, string>();
2224
const GIT_COMMON_DIR_KEY = "rev-parse\u0000--git-common-dir";
2325
const GIT_CONFIG_SPARSE_KEY = "config\u0000--bool\u0000core.sparseCheckout";
2426
const GIT_SPARSE_LIST_KEY = "sparse-checkout\u0000list";
@@ -213,6 +215,38 @@ function makeSlowVersionCrabbox(helpText: string): string {
213215
return binDir;
214216
}
215217

218+
function testTimingPreload(options: { clockScale?: number; spawnTimeoutMs?: number }): string {
219+
const key = JSON.stringify(options);
220+
let preloadPath = timingPreloads.get(key);
221+
if (!preloadPath) {
222+
const dir = mkdtempSync(path.join(tmpdir(), "openclaw-crabbox-timing-"));
223+
tempDirs.push(dir);
224+
preloadPath = path.join(dir, "preload.cjs");
225+
const script: string[] = [];
226+
if (options.clockScale !== undefined) {
227+
script.push(
228+
"const realNow = Date.now.bind(Date);",
229+
"const startedAt = realNow();",
230+
`Date.now = () => startedAt + (realNow() - startedAt) * ${options.clockScale};`,
231+
);
232+
}
233+
if (options.spawnTimeoutMs !== undefined) {
234+
script.push(
235+
'const childProcess = require("node:child_process");',
236+
'const { syncBuiltinESMExports } = require("node:module");',
237+
"const realSpawnSync = childProcess.spawnSync;",
238+
"childProcess.spawnSync = (command, args, spawnOptions) =>",
239+
" realSpawnSync(command, args,",
240+
` spawnOptions?.timeout ? { ...spawnOptions, timeout: Math.min(spawnOptions.timeout, ${options.spawnTimeoutMs}) } : spawnOptions);`,
241+
"syncBuiltinESMExports();",
242+
);
243+
}
244+
writeFileSync(preloadPath, `${script.join("\n")}\n`, "utf8");
245+
timingPreloads.set(key, preloadPath);
246+
}
247+
return preloadPath;
248+
}
249+
216250
function windowsNodeCmdShim(target: string): string {
217251
return [
218252
"@ECHO off",
@@ -243,6 +277,11 @@ function shellSingleQuote(value: string): string {
243277
function makeFakeGit(
244278
responses: Record<string, { status?: number; stdout?: string; stderr?: string }>,
245279
): string {
280+
const key = JSON.stringify(responses);
281+
const cached = fakeGitBinDirs.get(key);
282+
if (cached) {
283+
return cached;
284+
}
246285
const binDir = mkdtempSync(path.join(tmpdir(), "openclaw-fake-git-"));
247286
tempDirs.push(binDir);
248287
const gitPath = path.join(binDir, "git");
@@ -277,6 +316,7 @@ function makeFakeGit(
277316
].join("\n");
278317
writeFileSync(gitPath, `${script}\n`, "utf8");
279318
chmodSync(gitPath, 0o755);
319+
fakeGitBinDirs.set(key, binDir);
280320
return binDir;
281321
}
282322

@@ -299,6 +339,7 @@ function makeFakeGit(
299339
writeFileSync(gitPath, `${script}\n`, "utf8");
300340
writeFileSync(`${gitPath}.cmd`, windowsNodeCmdShim("git"), "utf8");
301341
chmodSync(gitPath, 0o755);
342+
fakeGitBinDirs.set(key, binDir);
302343
return binDir;
303344
}
304345

@@ -311,7 +352,12 @@ function shellArgListCondition(args: string[]): string {
311352
}
312353

313354
function runWrapper(helpText: string, args: string[], options: WrapperOptions = {}) {
314-
return spawnSync(process.execPath, ["scripts/crabbox-wrapper.mjs", ...args], {
355+
const nodeArgs = [
356+
...(options.nodePreload ? ["--require", options.nodePreload] : []),
357+
"scripts/crabbox-wrapper.mjs",
358+
...args,
359+
];
360+
return spawnSync(process.execPath, nodeArgs, {
315361
cwd: repoRoot,
316362
encoding: "utf8",
317363
input: options.input,
@@ -327,10 +373,16 @@ type WrapperOptions = {
327373
extraPathEntries?: string[];
328374
gitResponses?: Record<string, { status?: number; stdout?: string; stderr?: string }>;
329375
input?: string;
376+
nodePreload?: string;
330377
};
331378

332379
function spawnWrapper(helpText: string, args: string[], options: WrapperOptions = {}) {
333-
return spawn(process.execPath, ["scripts/crabbox-wrapper.mjs", ...args], {
380+
const nodeArgs = [
381+
...(options.nodePreload ? ["--require", options.nodePreload] : []),
382+
"scripts/crabbox-wrapper.mjs",
383+
...args,
384+
];
385+
return spawn(process.execPath, nodeArgs, {
334386
cwd: repoRoot,
335387
env: wrapperEnv(helpText, options),
336388
stdio: ["ignore", "pipe", "pipe"],
@@ -442,6 +494,7 @@ async function runSignalCleanupProof(sendSignals: (pid: number) => Promise<void>
442494
env: {
443495
OPENCLAW_FAKE_CRABBOX_DESCENDANT_PID_PATH: descendantPidPath,
444496
},
497+
nodePreload: testTimingPreload({ clockScale: 20 }),
445498
},
446499
);
447500

@@ -3060,6 +3113,7 @@ describe.concurrent("scripts/crabbox-wrapper", () => {
30603113
const helpText = "provider: hetzner, aws, local-container, blacksmith-testbox, or cloudflare\n";
30613114
const result = runWrapper(helpText, ["--version"], {
30623115
extraPathEntries: [makeSlowVersionCrabbox(helpText)],
3116+
nodePreload: testTimingPreload({ spawnTimeoutMs: 25 }),
30633117
});
30643118

30653119
expect(result.error).toBeUndefined();
@@ -3185,25 +3239,6 @@ describe.concurrent("scripts/crabbox-wrapper", () => {
31853239
);
31863240
});
31873241

3188-
it("rebuilds stale remote Git metadata before sparse changed gates", () => {
3189-
const result = runWrapper(
3190-
"provider: hetzner, aws, local-container, blacksmith-testbox, or cloudflare\n",
3191-
["run", "--provider", "aws", "--", "corepack", "pnpm", "check:changed"],
3192-
{
3193-
gitResponses: {
3194-
[GIT_CONFIG_SPARSE_KEY]: { stdout: "true\n" },
3195-
[GIT_STATUS_PORCELAIN_KEY]: { stdout: "" },
3196-
[GIT_MERGE_BASE_MAIN_HEAD_KEY]: { stdout: "abc123\n" },
3197-
},
3198-
},
3199-
);
3200-
3201-
const output = parseFakeCrabboxOutput(result);
3202-
const remoteCommand = normalizeShellLineEndings(output.args.at(-1) ?? "");
3203-
expect(result.status).toBe(0);
3204-
expectChangedGateGitBootstrap(remoteCommand);
3205-
});
3206-
32073242
it("bootstraps Git metadata for non-sparse changed gates on remote raw syncs", () => {
32083243
const result = runWrapper(
32093244
"provider: hetzner, aws, local-container, blacksmith-testbox, or cloudflare\n",

0 commit comments

Comments
 (0)