fix(test): bound startup build helpers

This commit is contained in:
Vincent Koc
2026-05-28 14:25:06 +02:00
parent aab5410bd5
commit bda3531560
9 changed files with 157 additions and 6 deletions

View File

@@ -8,6 +8,20 @@ import { fileURLToPath, pathToFileURL } from "node:url";
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
const entryCandidates = ["dist/entry.js", "dist/entry.mjs"];
const startupMetadataPath = "dist/cli-startup-metadata.json";
const DEFAULT_BUILD_TIMEOUT_MS = 10 * 60 * 1000;
function positiveEnvInt(name, env, fallback) {
const raw = env[name]?.trim();
if (raw === undefined || raw === "" || !/^[0-9]+$/.test(raw)) {
return fallback;
}
const value = Number.parseInt(raw, 10);
return Number.isSafeInteger(value) && value > 0 ? value : fallback;
}
export function resolveCliStartupBuildTimeoutMs(env = process.env) {
return positiveEnvInt("OPENCLAW_CLI_STARTUP_BUILD_TIMEOUT_MS", env, DEFAULT_BUILD_TIMEOUT_MS);
}
export function hasCliStartupBuild(params = {}) {
const rootDir = params.rootDir ?? repoRoot;
@@ -32,7 +46,9 @@ export function ensureCliStartupBuild(params = {}) {
const result = spawn(nodeExecPath, [buildScript, "cliStartup"], {
cwd: rootDir,
env: params.env ?? process.env,
killSignal: params.killSignal ?? "SIGKILL",
stdio: params.stdio ?? "inherit",
timeout: params.timeoutMs ?? resolveCliStartupBuildTimeoutMs(params.env ?? process.env),
});
if (result.error) {
throw result.error;

View File

@@ -10,6 +10,24 @@ import {
} from "./lib/bundled-plugin-build-entries.mjs";
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
const DEFAULT_BUILD_TIMEOUT_MS = 10 * 60 * 1000;
function positiveEnvInt(name, env, fallback) {
const raw = env[name]?.trim();
if (raw === undefined || raw === "" || !/^[0-9]+$/.test(raw)) {
return fallback;
}
const value = Number.parseInt(raw, 10);
return Number.isSafeInteger(value) && value > 0 ? value : fallback;
}
export function resolveExtensionMemoryBuildTimeoutMs(env = process.env) {
return positiveEnvInt(
"OPENCLAW_EXTENSION_MEMORY_BUILD_TIMEOUT_MS",
env,
DEFAULT_BUILD_TIMEOUT_MS,
);
}
function collectExpectedExtensionMemoryEntryIds(rootDir, env) {
try {
@@ -80,7 +98,9 @@ export function ensureExtensionMemoryBuild(params = {}) {
const result = spawn(nodeExecPath, [buildScript, "cliStartup"], {
cwd: rootDir,
env: params.env ?? process.env,
killSignal: params.killSignal ?? "SIGKILL",
stdio: params.stdio ?? "inherit",
timeout: params.timeoutMs ?? resolveExtensionMemoryBuildTimeoutMs(params.env ?? process.env),
});
if (result.error) {
throw result.error;

View File

@@ -302,8 +302,8 @@ export function utcCalendarDayDistance(left: Date, right: Date): number {
}
function positiveEnvInt(name: string, env: NodeJS.ProcessEnv, fallback: number): number {
const raw = env[name];
if (raw === undefined || raw === "") {
const raw = env[name]?.trim();
if (raw === undefined || raw === "" || !/^[0-9]+$/u.test(raw)) {
return fallback;
}
const value = Number.parseInt(raw, 10);

View File

@@ -93,8 +93,8 @@ function ensurePreparedArtifacts(): void {
}
function positiveEnvInt(name: string, env: NodeJS.ProcessEnv, fallback: number): number {
const raw = env[name];
if (raw === undefined || raw === "") {
const raw = env[name]?.trim();
if (raw === undefined || raw === "" || !/^[0-9]+$/u.test(raw)) {
return fallback;
}
const value = Number.parseInt(raw, 10);

View File

@@ -175,8 +175,8 @@ const PACKED_PLUGIN_SDK_TYPESCRIPT_SMOKE_FIXTURE = resolve(
);
function positiveEnvInt(name: string, fallback: number): number {
const raw = process.env[name];
if (raw === undefined || raw === "") {
const raw = process.env[name]?.trim();
if (raw === undefined || raw === "" || !/^[0-9]+$/u.test(raw)) {
return fallback;
}
const value = Number.parseInt(raw, 10);

View File

@@ -471,6 +471,14 @@ describe("resolveNpmReleaseCheckCommandTimeoutMs", () => {
}),
).toBe(10 * 60 * 1000);
});
it("falls back when the environment timeout has a numeric prefix", () => {
expect(
resolveNpmReleaseCheckCommandTimeoutMs({
OPENCLAW_NPM_RELEASE_CHECK_COMMAND_TIMEOUT_MS: "10m",
}),
).toBe(10 * 60 * 1000);
});
});
describe("parseNpmPackJsonOutput", () => {

View File

@@ -64,4 +64,10 @@ describe("resolvePrepackCommandTimeoutMs", () => {
30 * 60 * 1000,
);
});
it("falls back when the environment timeout has a numeric prefix", () => {
expect(resolvePrepackCommandTimeoutMs({ OPENCLAW_PREPACK_COMMAND_TIMEOUT_MS: "10m" })).toBe(
30 * 60 * 1000,
);
});
});

View File

@@ -5,6 +5,7 @@ import { afterEach, describe, expect, it } from "vitest";
import {
ensureCliStartupBuild,
hasCliStartupBuild,
resolveCliStartupBuildTimeoutMs,
} from "../../scripts/ensure-cli-startup-build.mjs";
const tempRoots: string[] = [];
@@ -80,7 +81,9 @@ describe("ensure-cli-startup-build", () => {
args: [path.join(root, "scripts", "build-all.mjs"), "cliStartup"],
options: expect.objectContaining({
cwd: root,
killSignal: "SIGKILL",
stdio: "pipe",
timeout: 10 * 60 * 1000,
}),
},
]);
@@ -107,12 +110,37 @@ describe("ensure-cli-startup-build", () => {
args: [path.join(root, "scripts", "build-all.mjs"), "cliStartup"],
options: expect.objectContaining({
cwd: root,
killSignal: "SIGKILL",
stdio: "pipe",
timeout: 10 * 60 * 1000,
}),
},
]);
});
it("uses the configured cliStartup build timeout", () => {
const root = makeTempRoot();
const calls: unknown[] = [];
ensureCliStartupBuild({
rootDir: root,
env: { OPENCLAW_CLI_STARTUP_BUILD_TIMEOUT_MS: "1234" },
spawnSync: (command, args, options) => {
calls.push({ command, args, options });
return { status: 0 };
},
stdio: "pipe",
});
expect(calls).toEqual([
expect.objectContaining({
options: expect.objectContaining({
timeout: 1234,
}),
}),
]);
});
it("fails when the cliStartup build profile fails", () => {
const root = makeTempRoot();
@@ -137,3 +165,23 @@ describe("ensure-cli-startup-build", () => {
).toThrow("spawn denied");
});
});
describe("resolveCliStartupBuildTimeoutMs", () => {
it("uses a positive environment timeout", () => {
expect(resolveCliStartupBuildTimeoutMs({ OPENCLAW_CLI_STARTUP_BUILD_TIMEOUT_MS: "4321" })).toBe(
4321,
);
});
it("falls back when the environment timeout is invalid", () => {
expect(resolveCliStartupBuildTimeoutMs({ OPENCLAW_CLI_STARTUP_BUILD_TIMEOUT_MS: "nope" })).toBe(
10 * 60 * 1000,
);
});
it("falls back when the environment timeout has a numeric prefix", () => {
expect(resolveCliStartupBuildTimeoutMs({ OPENCLAW_CLI_STARTUP_BUILD_TIMEOUT_MS: "10m" })).toBe(
10 * 60 * 1000,
);
});
});

View File

@@ -5,6 +5,7 @@ import { afterEach, describe, expect, it } from "vitest";
import {
ensureExtensionMemoryBuild,
hasBuiltExtensionMemoryEntries,
resolveExtensionMemoryBuildTimeoutMs,
} from "../../scripts/ensure-extension-memory-build.mjs";
const tempRoots: string[] = [];
@@ -97,12 +98,38 @@ describe("ensure-extension-memory-build", () => {
args: [path.join(root, "scripts", "build-all.mjs"), "cliStartup"],
options: expect.objectContaining({
cwd: root,
killSignal: "SIGKILL",
stdio: "pipe",
timeout: 10 * 60 * 1000,
}),
},
]);
});
it("uses the configured extension memory build timeout", () => {
const root = makeTempRoot();
const calls: unknown[] = [];
ensureExtensionMemoryBuild({
rootDir: root,
env: { OPENCLAW_EXTENSION_MEMORY_BUILD_TIMEOUT_MS: "1234" },
requiredExtensionIds: ["discord"],
spawnSync: (command, args, options) => {
calls.push({ command, args, options });
return { status: 0 };
},
stdio: "pipe",
});
expect(calls).toEqual([
expect.objectContaining({
options: expect.objectContaining({
timeout: 1234,
}),
}),
]);
});
it("fails when the cliStartup build profile fails", () => {
const root = makeTempRoot();
@@ -115,3 +142,29 @@ describe("ensure-extension-memory-build", () => {
).toThrow("cliStartup build profile failed with exit code 1");
});
});
describe("resolveExtensionMemoryBuildTimeoutMs", () => {
it("uses a positive environment timeout", () => {
expect(
resolveExtensionMemoryBuildTimeoutMs({
OPENCLAW_EXTENSION_MEMORY_BUILD_TIMEOUT_MS: "4321",
}),
).toBe(4321);
});
it("falls back when the environment timeout is invalid", () => {
expect(
resolveExtensionMemoryBuildTimeoutMs({
OPENCLAW_EXTENSION_MEMORY_BUILD_TIMEOUT_MS: "nope",
}),
).toBe(10 * 60 * 1000);
});
it("falls back when the environment timeout has a numeric prefix", () => {
expect(
resolveExtensionMemoryBuildTimeoutMs({
OPENCLAW_EXTENSION_MEMORY_BUILD_TIMEOUT_MS: "10m",
}),
).toBe(10 * 60 * 1000);
});
});