Files
openclaw/test/scripts/ci-live-command-retry.test.ts
T
Dallin RomneyandGitHub 8c77936e50 fix(release): propagate frozen-target guard and retry live timeouts (#108418)
* fix(release): preserve frozen package acceptance opt-in

* fix(release): retry transient live terminal timeouts

* fix(release): keep package dispatch input budget

* refactor(release): name frozen-target compatibility mode

* revert: keep frozen-target guard naming
2026-07-15 13:06:24 -07:00

107 lines
4.0 KiB
TypeScript

// CI live command retry tests cover transient provider failure classification.
import { spawnSync } from "node:child_process";
import { chmodSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import path from "node:path";
import { afterEach, describe, expect, it } from "vitest";
const SCRIPT_PATH = path.resolve("scripts/ci-live-command-retry.sh");
const tempDirs: string[] = [];
function writeCommand(
prefix: string,
lines: string[],
): { commandPath: string; counterPath: string } {
const dir = mkdtempSync(path.join(tmpdir(), prefix));
tempDirs.push(dir);
const commandPath = path.join(dir, "command.sh");
const counterPath = path.join(dir, "attempts.txt");
writeFileSync(commandPath, ["#!/bin/bash", "set -euo pipefail", ...lines, ""].join("\n"));
chmodSync(commandPath, 0o755);
return { commandPath, counterPath };
}
function runRetryHelper(commandPath: string, counterPath: string) {
const env = { ...process.env };
delete env.OPENCLAW_LIVE_COMMAND_RETRY_PATTERN;
delete env.OPENCLAW_LIVE_COMMAND_RATE_LIMIT_PATTERN;
return spawnSync("/bin/bash", [SCRIPT_PATH], {
cwd: process.cwd(),
encoding: "utf8",
env: {
...env,
OPENCLAW_LIVE_COMMAND: `/bin/bash ${JSON.stringify(commandPath)}`,
OPENCLAW_LIVE_COMMAND_ATTEMPTS: "2",
OPENCLAW_LIVE_COMMAND_RETRY_DELAY_SECONDS: "0",
OPENCLAW_LIVE_COMMAND_RATE_LIMIT_RETRY_DELAY_SECONDS: "0",
OPENCLAW_RETRY_TEST_COUNTER: counterPath,
},
});
}
afterEach(() => {
while (tempDirs.length > 0) {
rmSync(tempDirs.pop()!, { force: true, recursive: true });
}
});
describe("scripts/ci-live-command-retry.sh", () => {
it("retries a provider-internal RPC timeout", () => {
const { commandPath, counterPath } = writeCommand("openclaw-ci-live-rpc-timeout-", [
'attempts="$(cat "$OPENCLAW_RETRY_TEST_COUNTER" 2>/dev/null || printf 0)"',
'attempts="$((attempts + 1))"',
'printf "%s" "$attempts" > "$OPENCLAW_RETRY_TEST_COUNTER"',
'if [[ "$attempts" -eq 1 ]]; then',
' echo "MiniMax image generation API error (1000): rpc timeout: timeout=1m0s" >&2',
" exit 42",
"fi",
]);
const result = runRetryHelper(commandPath, counterPath);
expect(result.status).toBe(0);
expect(readFileSync(counterPath, "utf8")).toBe("2");
expect(result.stderr).toContain(
"Live command failed with a retryable provider/network error; retrying (1/2)",
);
});
it.each([
["provider HTTP 500", "xAI image edit failed (HTTP 500): Please try again later"],
["live test timeout", "Error: Test timed out in 45000ms."],
["live terminal timeout", "Error: terminal timeout after 300000ms"],
])("retries a transient %s", (_label, message) => {
const { commandPath, counterPath } = writeCommand("openclaw-ci-live-transient-", [
'attempts="$(cat "$OPENCLAW_RETRY_TEST_COUNTER" 2>/dev/null || printf 0)"',
'attempts="$((attempts + 1))"',
'printf "%s" "$attempts" > "$OPENCLAW_RETRY_TEST_COUNTER"',
'if [[ "$attempts" -eq 1 ]]; then',
` echo ${JSON.stringify(message)} >&2`,
" exit 42",
"fi",
]);
const result = runRetryHelper(commandPath, counterPath);
expect(result.status).toBe(0);
expect(readFileSync(counterPath, "utf8")).toBe("2");
expect(result.stderr).toContain("retrying (1/2)");
});
it("does not retry a MiniMax authentication failure", () => {
const { commandPath, counterPath } = writeCommand("openclaw-ci-live-auth-failure-", [
'attempts="$(cat "$OPENCLAW_RETRY_TEST_COUNTER" 2>/dev/null || printf 0)"',
'attempts="$((attempts + 1))"',
'printf "%s" "$attempts" > "$OPENCLAW_RETRY_TEST_COUNTER"',
'echo "MiniMax image generation API error (1004): authentication failed" >&2',
"exit 42",
]);
const result = runRetryHelper(commandPath, counterPath);
expect(result.status).toBe(42);
expect(readFileSync(counterPath, "utf8")).toBe("1");
expect(result.stderr).not.toContain("retrying");
});
});