mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-21 10:16:44 +00:00
* fix(e2e): bound cross-OS installer fetches * test(e2e): prove Windows installer timeout Co-authored-by: Alix-007 <li.long15@xydigit.com> * test(e2e): track installer proof temp dirs Co-authored-by: Alix-007 <li.long15@xydigit.com> * fix(e2e): buffer POSIX installer downloads Co-authored-by: Alix-007 <li.long15@xydigit.com> --------- Co-authored-by: Peter Steinberger <steipete@gmail.com>
223 lines
7.0 KiB
TypeScript
223 lines
7.0 KiB
TypeScript
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
import { createServer } from "node:http";
|
|
import { join } from "node:path";
|
|
import { afterEach, describe, expect, it } from "vitest";
|
|
import {
|
|
buildInstallerSmokeScript,
|
|
runCommand,
|
|
} from "../../scripts/lib/cross-os-release-checks/index.ts";
|
|
import { useAutoCleanupTempDirTracker } from "../helpers/temp-dir.ts";
|
|
|
|
const tempDirs = useAutoCleanupTempDirTracker(afterEach);
|
|
|
|
function powerShellSingleQuote(value: string) {
|
|
return value.replace(/'/gu, "''");
|
|
}
|
|
|
|
async function runPowerShell(params: {
|
|
script: string;
|
|
cwd: string;
|
|
env: NodeJS.ProcessEnv;
|
|
logPath: string;
|
|
}) {
|
|
return runCommand(
|
|
"powershell.exe",
|
|
[
|
|
"-NoLogo",
|
|
"-NoProfile",
|
|
"-NonInteractive",
|
|
"-ExecutionPolicy",
|
|
"Bypass",
|
|
"-Command",
|
|
params.script,
|
|
],
|
|
{
|
|
check: false,
|
|
cwd: params.cwd,
|
|
env: params.env,
|
|
logPath: params.logPath,
|
|
timeoutMs: 10_000,
|
|
},
|
|
);
|
|
}
|
|
|
|
async function runPosixShell(params: {
|
|
script: string;
|
|
cwd: string;
|
|
env: NodeJS.ProcessEnv;
|
|
logPath: string;
|
|
}) {
|
|
return runCommand("/bin/bash", ["-lc", params.script], {
|
|
check: false,
|
|
cwd: params.cwd,
|
|
env: params.env,
|
|
logPath: params.logPath,
|
|
timeoutMs: 10_000,
|
|
});
|
|
}
|
|
|
|
function installerTempFiles(dir: string) {
|
|
return readdirSync(dir).filter((entry) => entry.startsWith("openclaw-installer-"));
|
|
}
|
|
|
|
describe("cross-OS installer fetch", () => {
|
|
it.runIf(process.platform !== "win32")(
|
|
"buffers POSIX installers before execution and cleans up timed-out downloads",
|
|
async () => {
|
|
const dir = tempDirs.make("openclaw-cross-os-installer-");
|
|
const healthyMarker = join(dir, "healthy.txt");
|
|
const stalledMarker = join(dir, "stalled.txt");
|
|
const server = createServer((request, response) => {
|
|
response.writeHead(200, { "content-type": "text/plain; charset=utf-8" });
|
|
if (request.url === "/healthy") {
|
|
response.end('printf "%s" "$1|$2|$3" > "$OPENCLAW_PROOF_HEALTHY_MARKER"\n');
|
|
return;
|
|
}
|
|
response.write('printf executed > "$OPENCLAW_PROOF_STALL_MARKER"\n');
|
|
});
|
|
|
|
try {
|
|
await new Promise<void>((resolvePromise, rejectPromise) => {
|
|
server.once("error", rejectPromise);
|
|
server.listen(0, "127.0.0.1", resolvePromise);
|
|
});
|
|
const address = server.address();
|
|
if (!address || typeof address === "string") {
|
|
throw new Error("POSIX installer proof server did not bind to a TCP port.");
|
|
}
|
|
const baseUrl = `http://127.0.0.1:${address.port}`;
|
|
const env = {
|
|
...process.env,
|
|
TMPDIR: dir,
|
|
OPENCLAW_PROOF_HEALTHY_MARKER: healthyMarker,
|
|
OPENCLAW_PROOF_STALL_MARKER: stalledMarker,
|
|
};
|
|
const timeouts = { connectTimeoutSeconds: 2, requestTimeoutSeconds: 1 };
|
|
|
|
const healthy = await runPosixShell({
|
|
script: buildInstallerSmokeScript(
|
|
{
|
|
installerUrl: `${baseUrl}/healthy`,
|
|
installTarget: "proof-target",
|
|
platform: "linux",
|
|
},
|
|
timeouts,
|
|
),
|
|
cwd: dir,
|
|
env,
|
|
logPath: join(dir, "healthy.log"),
|
|
});
|
|
|
|
expect(healthy.exitCode).toBe(0);
|
|
expect(readFileSync(healthyMarker, "utf8")).toBe("--version|proof-target|--no-onboard");
|
|
expect(installerTempFiles(dir)).toEqual([]);
|
|
|
|
const stalled = await runPosixShell({
|
|
script: buildInstallerSmokeScript(
|
|
{
|
|
installerUrl: `${baseUrl}/stalled`,
|
|
installTarget: "proof-target",
|
|
platform: "linux",
|
|
},
|
|
timeouts,
|
|
),
|
|
cwd: dir,
|
|
env,
|
|
logPath: join(dir, "stalled.log"),
|
|
});
|
|
|
|
expect(stalled.exitCode).toBe(28);
|
|
expect(existsSync(stalledMarker)).toBe(false);
|
|
expect(installerTempFiles(dir)).toEqual([]);
|
|
} finally {
|
|
server.closeAllConnections();
|
|
await new Promise<void>((resolvePromise) => {
|
|
server.close(() => resolvePromise());
|
|
});
|
|
}
|
|
},
|
|
15_000,
|
|
);
|
|
|
|
it.runIf(process.platform === "win32")(
|
|
"times out stalled bodies without executing partial scripts or leaking temp files",
|
|
async () => {
|
|
const dir = tempDirs.make("openclaw-cross-os-installer-");
|
|
const healthyMarker = join(dir, "healthy.txt");
|
|
const stalledMarker = join(dir, "stalled.txt");
|
|
const server = createServer((request, response) => {
|
|
response.writeHead(200, { "content-type": "text/plain; charset=utf-8" });
|
|
if (request.url === "/healthy") {
|
|
response.end(
|
|
[
|
|
"param([string] $Tag, [switch] $NoOnboard)",
|
|
`[System.IO.File]::WriteAllText('${powerShellSingleQuote(healthyMarker)}', "tag=$Tag noOnboard=$($NoOnboard.IsPresent)")`,
|
|
].join("\n"),
|
|
);
|
|
return;
|
|
}
|
|
response.write(
|
|
`[System.IO.File]::WriteAllText('${powerShellSingleQuote(stalledMarker)}', 'executed')\n`,
|
|
);
|
|
});
|
|
|
|
try {
|
|
await new Promise<void>((resolvePromise, rejectPromise) => {
|
|
server.once("error", rejectPromise);
|
|
server.listen(0, "127.0.0.1", resolvePromise);
|
|
});
|
|
const address = server.address();
|
|
if (!address || typeof address === "string") {
|
|
throw new Error("Windows installer proof server did not bind to a TCP port.");
|
|
}
|
|
const baseUrl = `http://127.0.0.1:${address.port}`;
|
|
const env = { ...process.env, TEMP: dir, TMP: dir };
|
|
const timeouts = { connectTimeoutSeconds: 2, requestTimeoutSeconds: 1 };
|
|
|
|
const healthy = await runPowerShell({
|
|
script: buildInstallerSmokeScript(
|
|
{
|
|
installerUrl: `${baseUrl}/healthy`,
|
|
installTarget: "proof-target",
|
|
platform: "win32",
|
|
},
|
|
timeouts,
|
|
),
|
|
cwd: dir,
|
|
env,
|
|
logPath: join(dir, "healthy.log"),
|
|
});
|
|
|
|
expect(healthy.exitCode).toBe(0);
|
|
expect(readFileSync(healthyMarker, "utf8")).toBe("tag=proof-target noOnboard=True");
|
|
expect(installerTempFiles(dir)).toEqual([]);
|
|
|
|
const stalled = await runPowerShell({
|
|
script: buildInstallerSmokeScript(
|
|
{
|
|
installerUrl: `${baseUrl}/stalled`,
|
|
installTarget: "proof-target",
|
|
platform: "win32",
|
|
},
|
|
timeouts,
|
|
),
|
|
cwd: dir,
|
|
env,
|
|
logPath: join(dir, "stalled.log"),
|
|
});
|
|
|
|
expect(stalled.exitCode).not.toBe(0);
|
|
expect(`${stalled.stdout}\n${stalled.stderr}`).toContain("exit 28");
|
|
expect(existsSync(stalledMarker)).toBe(false);
|
|
expect(installerTempFiles(dir)).toEqual([]);
|
|
} finally {
|
|
server.closeAllConnections();
|
|
await new Promise<void>((resolvePromise) => {
|
|
server.close(() => resolvePromise());
|
|
});
|
|
}
|
|
},
|
|
15_000,
|
|
);
|
|
});
|