From 5c1ecda0ca5f831fc4ef99dbddc550e4ab204ea9 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Tue, 26 May 2026 21:49:02 +0200 Subject: [PATCH] fix(e2e): support plain timeout wrappers --- scripts/lib/openclaw-e2e-instance.sh | 6 +- test/scripts/openclaw-e2e-instance.test.ts | 64 ++++++++++++++++++++++ 2 files changed, 69 insertions(+), 1 deletion(-) diff --git a/scripts/lib/openclaw-e2e-instance.sh b/scripts/lib/openclaw-e2e-instance.sh index f5307069edc..5dbb53030b7 100644 --- a/scripts/lib/openclaw-e2e-instance.sh +++ b/scripts/lib/openclaw-e2e-instance.sh @@ -56,7 +56,11 @@ openclaw_e2e_maybe_timeout() { "$@" return fi - "$timeout_bin" --kill-after=30s "$timeout_value" "$@" + if "$timeout_bin" --kill-after=1s 1s true >/dev/null 2>&1; then + "$timeout_bin" --kill-after=30s "$timeout_value" "$@" + else + "$timeout_bin" "$timeout_value" "$@" + fi } openclaw_e2e_install_package() { local log_file="$1" diff --git a/test/scripts/openclaw-e2e-instance.test.ts b/test/scripts/openclaw-e2e-instance.test.ts index b58daf3c9b9..522a0dc3f0c 100644 --- a/test/scripts/openclaw-e2e-instance.test.ts +++ b/test/scripts/openclaw-e2e-instance.test.ts @@ -116,6 +116,70 @@ describe("scripts/lib/openclaw-e2e-instance.sh", () => { } }); + it("falls back to plain timeout when kill-after is unavailable", () => { + const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-e2e-instance-plain-timeout-")); + try { + const timeoutArgsPath = path.join(tempDir, "timeout-args.txt"); + const npmArgsPath = path.join(tempDir, "npm-args.txt"); + const logPath = path.join(tempDir, "install.log"); + const packagePath = path.join(tempDir, "openclaw.tgz"); + fs.writeFileSync(packagePath, ""); + fs.writeFileSync( + path.join(tempDir, "timeout"), + [ + "#!/usr/bin/env bash", + "set -euo pipefail", + 'if [ "${1:-}" = "--kill-after=1s" ]; then', + " exit 1", + "fi", + 'printf "%s\\n" "$*" >"$OPENCLAW_TEST_TIMEOUT_ARGS"', + 'while [ "$#" -gt 0 ] && [ "$1" != "npm" ]; do shift; done', + 'exec "$@"', + "", + ].join("\n"), + ); + fs.writeFileSync( + path.join(tempDir, "npm"), + ["#!/bin/sh", "set -eu", 'printf "%s\\n" "$*" >"$OPENCLAW_TEST_NPM_ARGS"', ""].join("\n"), + ); + fs.chmodSync(path.join(tempDir, "timeout"), 0o755); + fs.chmodSync(path.join(tempDir, "npm"), 0o755); + + const result = spawnSync( + "/bin/bash", + [ + "-c", + [ + "set -euo pipefail", + `source ${shellQuote(helperPath)}`, + `openclaw_e2e_install_package ${shellQuote(logPath)} ${shellQuote("fixture package")}`, + ].join("; "), + ], + { + encoding: "utf8", + env: { + ...process.env, + PATH: `${tempDir}:${process.env.PATH ?? ""}`, + OPENCLAW_CURRENT_PACKAGE_TGZ: packagePath, + OPENCLAW_E2E_NPM_INSTALL_TIMEOUT: "42s", + OPENCLAW_TEST_TIMEOUT_ARGS: timeoutArgsPath, + OPENCLAW_TEST_NPM_ARGS: npmArgsPath, + }, + }, + ); + + expect(result.status).toBe(0); + expect(fs.readFileSync(timeoutArgsPath, "utf8").trim()).toBe( + `42s npm install -g ${packagePath} --no-fund --no-audit`, + ); + expect(fs.readFileSync(npmArgsPath, "utf8").trim()).toBe( + `install -g ${packagePath} --no-fund --no-audit`, + ); + } finally { + fs.rmSync(tempDir, { force: true, recursive: true }); + } + }); + it("runs package installs without a wrapper when timeout is unavailable", () => { const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-e2e-instance-no-timeout-")); try {