

















@@ -1,5 +1,13 @@
11import { execFileSync } from "node:child_process";
2-import { mkdtempSync, mkdirSync, readdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
2+import {
3+chmodSync,
4+mkdtempSync,
5+mkdirSync,
6+readdirSync,
7+readFileSync,
8+rmSync,
9+writeFileSync,
10+} from "node:fs";
311import { tmpdir } from "node:os";
412import { join } from "node:path";
513import { describe, expect, it } from "vitest";
@@ -244,6 +252,239 @@ grep -q '^pull openclaw-reuse-image$' "$TMPDIR/docker-seen"
244252}
245253});
246254255+it("fails Docker commands fast when timeout is unavailable", () => {
256+const workDir = mkdtempSync(join(tmpdir(), "openclaw-docker-timeout-required-"));
257+258+try {
259+mkdirSync(join(workDir, "bin"));
260+const rootDir = process.cwd();
261+const script = `
262+set -euo pipefail
263+ROOT_DIR=${shellQuote(rootDir)}
264+TMPDIR=${shellQuote(workDir)}
265+export ROOT_DIR TMPDIR
266+export PATH="$TMPDIR/bin"
267+export DOCKER_COMMAND_TIMEOUT=7s
268+269+docker() {
270+ printf "%s\\n" "$*" >"$TMPDIR/docker-seen"
271+}
272+export -f docker
273+274+source "$ROOT_DIR/scripts/lib/docker-e2e-container.sh"
275+276+set +e
277+docker_e2e_docker_cmd ps 2>"$TMPDIR/stderr"
278+status="$?"
279+set -e
280+281+stderr="$(<"$TMPDIR/stderr")"
282+[[ "$status" = "127" ]]
283+[[ "$stderr" = *"timeout command not found; cannot bound Docker command after 7s"* ]]
284+[[ ! -e "$TMPDIR/docker-seen" ]]
285+`;
286+287+execFileSync("bash", ["-lc", script], { encoding: "utf8" });
288+} finally {
289+rmSync(workDir, { recursive: true, force: true });
290+}
291+});
292+293+it("uses plain timeout when kill-after is unsupported", () => {
294+const workDir = mkdtempSync(join(tmpdir(), "openclaw-docker-plain-timeout-"));
295+296+try {
297+const binDir = join(workDir, "bin");
298+mkdirSync(binDir);
299+writeFileSync(
300+join(binDir, "timeout"),
301+`#!/bin/bash
302+set -euo pipefail
303+if [[ "$1" = "--kill-after=1s" ]]; then
304+ exit 1
305+fi
306+printf 'plain:%s|%s\\n' "$1" "\${*:2}" >>"$TMPDIR/timeout-seen"
307+shift
308+"$@"
309+`,
310+);
311+chmodSync(join(binDir, "timeout"), 0o755);
312+const rootDir = process.cwd();
313+const script = `
314+set -euo pipefail
315+ROOT_DIR=${shellQuote(rootDir)}
316+TMPDIR=${shellQuote(workDir)}
317+export ROOT_DIR TMPDIR
318+export PATH="$TMPDIR/bin:$PATH"
319+export DOCKER_COMMAND_TIMEOUT=9s
320+321+docker() {
322+ printf "%s\\n" "$*" >>"$TMPDIR/docker-seen"
323+}
324+export -f docker
325+326+source "$ROOT_DIR/scripts/lib/docker-e2e-container.sh"
327+328+docker_e2e_docker_cmd image inspect demo
329+330+grep -q '^plain:9s|docker image inspect demo$' "$TMPDIR/timeout-seen"
331+grep -q '^image inspect demo$' "$TMPDIR/docker-seen"
332+`;
333+334+execFileSync("bash", ["-lc", script], { encoding: "utf8" });
335+} finally {
336+rmSync(workDir, { recursive: true, force: true });
337+}
338+});
339+340+it("uses gtimeout when timeout is unavailable", () => {
341+const workDir = mkdtempSync(join(tmpdir(), "openclaw-docker-gtimeout-"));
342+343+try {
344+const binDir = join(workDir, "bin");
345+mkdirSync(binDir);
346+writeFileSync(
347+join(binDir, "gtimeout"),
348+`#!/bin/bash
349+set -euo pipefail
350+if [[ "$1" = "--kill-after=1s" ]]; then
351+ exit 0
352+fi
353+printf 'gtimeout:%s %s|%s\\n' "$1" "$2" "\${*:3}" >>"$TMPDIR/timeout-seen"
354+shift 2
355+"$@"
356+`,
357+);
358+chmodSync(join(binDir, "gtimeout"), 0o755);
359+const rootDir = process.cwd();
360+const script = `
361+set -euo pipefail
362+ROOT_DIR=${shellQuote(rootDir)}
363+TMPDIR=${shellQuote(workDir)}
364+export ROOT_DIR TMPDIR
365+export PATH="$TMPDIR/bin"
366+export OPENCLAW_DOCKER_E2E_RUN_TIMEOUT=13s
367+368+docker() {
369+ printf "%s\\n" "$*" >>"$TMPDIR/docker-seen"
370+}
371+export -f docker
372+373+source "$ROOT_DIR/scripts/lib/docker-e2e-container.sh"
374+375+docker_e2e_docker_run_cmd run demo
376+377+[[ "$(<"$TMPDIR/timeout-seen")" = "gtimeout:--kill-after=30s 13s|docker run demo" ]]
378+[[ "$(<"$TMPDIR/docker-seen")" = "run demo" ]]
379+`;
380+381+execFileSync("bash", ["-lc", script], { encoding: "utf8" });
382+} finally {
383+rmSync(workDir, { recursive: true, force: true });
384+}
385+});
386+387+it("keeps package-backed Docker runs bounded without the shared timeout helper", () => {
388+const workDir = mkdtempSync(join(tmpdir(), "openclaw-docker-package-timeout-required-"));
389+390+try {
391+mkdirSync(join(workDir, "bin"));
392+const rootDir = process.cwd();
393+const script = `
394+set -euo pipefail
395+ROOT_DIR=${shellQuote(rootDir)}
396+TMPDIR=${shellQuote(workDir)}
397+export ROOT_DIR TMPDIR
398+export PATH="$TMPDIR/bin"
399+export OPENCLAW_DOCKER_E2E_RUN_TIMEOUT=11s
400+401+dirname() {
402+ /usr/bin/dirname "$@"
403+}
404+405+docker_e2e_docker_cmd() {
406+ return 0
407+}
408+409+docker() {
410+ printf "%s\\n" "$*" >"$TMPDIR/docker-seen"
411+}
412+export -f docker_e2e_docker_cmd docker
413+414+source "$ROOT_DIR/scripts/lib/docker-e2e-package.sh"
415+416+set +e
417+docker_e2e_docker_run_cmd run demo 2>"$TMPDIR/stderr"
418+status="$?"
419+set -e
420+421+stderr="$(<"$TMPDIR/stderr")"
422+[[ "$status" = "127" ]]
423+[[ "$stderr" = *"timeout command not found; cannot bound Docker run after 11s"* ]]
424+[[ ! -e "$TMPDIR/docker-seen" ]]
425+`;
426+427+execFileSync("bash", ["-lc", script], { encoding: "utf8" });
428+} finally {
429+rmSync(workDir, { recursive: true, force: true });
430+}
431+});
432+433+it("uses gtimeout for package-backed Docker runs without the shared timeout helper", () => {
434+const workDir = mkdtempSync(join(tmpdir(), "openclaw-docker-package-gtimeout-"));
435+436+try {
437+const binDir = join(workDir, "bin");
438+mkdirSync(binDir);
439+writeFileSync(
440+join(binDir, "gtimeout"),
441+`#!/bin/bash
442+set -euo pipefail
443+if [[ "$1" = "--kill-after=1s" ]]; then
444+ exit 0
445+fi
446+printf 'gtimeout:%s %s|%s\\n' "$1" "$2" "\${*:3}" >>"$TMPDIR/timeout-seen"
447+shift 2
448+"$@"
449+`,
450+);
451+chmodSync(join(binDir, "gtimeout"), 0o755);
452+const rootDir = process.cwd();
453+const script = `
454+set -euo pipefail
455+ROOT_DIR=${shellQuote(rootDir)}
456+TMPDIR=${shellQuote(workDir)}
457+export ROOT_DIR TMPDIR
458+export PATH="$TMPDIR/bin"
459+export OPENCLAW_DOCKER_E2E_RUN_TIMEOUT=15s
460+461+dirname() {
462+ /usr/bin/dirname "$@"
463+}
464+465+docker_e2e_docker_cmd() {
466+ return 0
467+}
468+469+docker() {
470+ printf "%s\\n" "$*" >>"$TMPDIR/docker-seen"
471+}
472+export -f docker_e2e_docker_cmd docker
473+474+source "$ROOT_DIR/scripts/lib/docker-e2e-package.sh"
475+476+docker_e2e_docker_run_cmd run demo
477+478+[[ "$(<"$TMPDIR/timeout-seen")" = "gtimeout:--kill-after=30s 15s|docker run demo" ]]
479+[[ "$(<"$TMPDIR/docker-seen")" = "run demo" ]]
480+`;
481+482+execFileSync("bash", ["-lc", script], { encoding: "utf8" });
483+} finally {
484+rmSync(workDir, { recursive: true, force: true });
485+}
486+});
487+247488it("removes functional Docker build package inputs after the build", () => {
248489const workDir = mkdtempSync(join(tmpdir(), "openclaw-docker-build-cleanup-"));
249490此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。