Files
openclaw/test/scripts/e2e-shell-tempfiles.test.ts
2026-06-04 20:49:50 -04:00

174 lines
5.6 KiB
TypeScript

// E2E Shell Tempfiles tests cover e2e shell tempfiles script behavior.
import { spawnSync } from "node:child_process";
import { mkdir, mkdtemp, readdir, readFile, rm, writeFile } from "node:fs/promises";
import { tmpdir } from "node:os";
import path from "node:path";
import { describe, expect, it } from "vitest";
async function listShellScripts(dir: string): Promise<string[]> {
const entries = await readdir(dir, { withFileTypes: true });
const scripts: string[] = [];
for (const entry of entries.toSorted((a, b) => a.name.localeCompare(b.name))) {
const entryPath = path.join(dir, entry.name);
if (entry.isDirectory()) {
scripts.push(...(await listShellScripts(entryPath)));
} else if (entry.isFile() && entry.name.endsWith(".sh")) {
scripts.push(entryPath);
}
}
return scripts;
}
describe("e2e shell tempfile hygiene", () => {
it("does not allocate FIFO paths with mktemp -u", async () => {
const offenders: string[] = [];
for (const scriptPath of await listShellScripts("scripts/e2e")) {
const contents = await readFile(path.resolve(scriptPath), "utf8");
if (contents.includes("mktemp -u")) {
offenders.push(scriptPath);
}
}
expect(offenders).toEqual([]);
});
it("preserves wizard exit status when reporting failures", async () => {
const tempRoot = await mkdtemp(path.join(tmpdir(), "openclaw-onboard-status-test-"));
const fixturePath = path.join(tempRoot, "wizard-status.sh");
await writeFile(
fixturePath,
`#!/usr/bin/env bash
set -euo pipefail
export OPENCLAW_ONBOARD_SCENARIO_SOURCE_ONLY=1
export OPENCLAW_ONBOARD_E2E_TMPDIR=${JSON.stringify(tempRoot)}
OPENCLAW_ENTRY=node
openclaw_test_state_create() { :; }
source scripts/e2e/lib/onboard/scenario.sh
openclaw_e2e_run_script_with_pty() {
local _command="$1"
local log_path="$2"
printf 'fake wizard log\\n' >"$log_path"
exit 7
}
send_noop() { :; }
run_wizard_cmd failing-wizard fake-state "node fake-wizard" send_noop false
`,
);
try {
const result = spawnSync("bash", [fixturePath], {
cwd: process.cwd(),
encoding: "utf8",
});
const output = `${result.stdout}\n${result.stderr}`;
expect(result.status).toBe(7);
expect(output).toContain("Wizard exited with status 7");
expect(output).toContain("fake wizard log");
} finally {
await rm(tempRoot, { force: true, recursive: true });
}
});
it("checks local onboarding logs for systemd noise", async () => {
const contents = await readFile("scripts/e2e/lib/onboard/scenario.sh", "utf8");
expect(contents).toContain(
'ONBOARD_TMP_DIR="$(mktemp -d "$ONBOARD_TMP_ROOT/openclaw-onboard.XXXXXX")"',
);
expect(contents).toContain('OPENCLAW_E2E_LOG_DIR="$ONBOARD_TMP_DIR/logs"');
expect(contents).toContain('GATEWAY_LOG_PATH="$ONBOARD_TMP_DIR/gateway-e2e.log"');
expect(contents).not.toContain("/tmp/gateway-e2e.log");
expect(contents).toContain('validate_local_basic_log "$OPENCLAW_E2E_LAST_LOG_PATH"');
expect(contents).not.toContain(
"validate_local_basic_log /tmp/openclaw-onboard-local-basic.log",
);
expect(contents).toContain(
'openclaw_e2e_assert_log_not_contains "$log_path" "systemctl --user unavailable"',
);
});
it("probes onboarding gateway readiness through the isolated scratch log", async () => {
const tempRoot = await mkdtemp(path.join(tmpdir(), "openclaw-onboard-gateway-log-"));
const fixturePath = path.join(tempRoot, "gateway-log.sh");
await writeFile(
fixturePath,
`#!/usr/bin/env bash
set -euo pipefail
export OPENCLAW_ONBOARD_SCENARIO_SOURCE_ONLY=1
export OPENCLAW_ONBOARD_E2E_TMPDIR=${JSON.stringify(tempRoot)}
OPENCLAW_ENTRY=node
source scripts/e2e/lib/onboard/scenario.sh
openclaw_e2e_probe_tcp() { return 1; }
sleep 30 &
GATEWAY_PID="$!"
printf 'listening on ws://127.0.0.1:18789\\n' >"$GATEWAY_LOG_PATH"
wait_for_gateway
case "$GATEWAY_LOG_PATH" in
"$ONBOARD_TMP_DIR"/*) ;;
*) echo "gateway log escaped scratch root: $GATEWAY_LOG_PATH" >&2; exit 1 ;;
esac
cleanup_onboard_artifacts
test ! -e "$ONBOARD_TMP_DIR"
`,
);
try {
const result = spawnSync("bash", [fixturePath], {
cwd: process.cwd(),
encoding: "utf8",
});
expect(result.status, `${result.stdout}\n${result.stderr}`).toBe(0);
} finally {
await rm(tempRoot, { force: true, recursive: true });
}
});
it("removes fallback ClawHub skill install HOME on failure", async () => {
const tempRoot = await mkdtemp(path.join(tmpdir(), "openclaw-clawhub-home-test-"));
const fakeBin = path.join(tempRoot, "bin");
const scratchRoot = path.join(tempRoot, "scratch");
await mkdir(fakeBin, { recursive: true });
await mkdir(scratchRoot, { recursive: true });
await writeFile(
path.join(fakeBin, "pnpm"),
`#!/usr/bin/env bash
exit 42
`,
{ mode: 0o755 },
);
try {
const result = spawnSync("bash", ["scripts/e2e/lib/skills/clawhub-install-proof.sh"], {
cwd: process.cwd(),
encoding: "utf8",
env: {
...process.env,
OPENCLAW_CURRENT_PACKAGE_TGZ: "",
OPENCLAW_TEST_STATE_SCRIPT_B64: "",
PATH: `${fakeBin}:${process.env.PATH ?? ""}`,
TMPDIR: scratchRoot,
},
});
expect(result.status, `${result.stdout}\n${result.stderr}`).toBe(42);
const scratchEntries = await readdir(scratchRoot);
expect(
scratchEntries.filter((entry) => entry.startsWith("openclaw-skill-install-home.")),
).toEqual([]);
} finally {
await rm(tempRoot, { force: true, recursive: true });
}
});
});