


























@@ -110,6 +110,9 @@ describe("docker build helper", () => {
110110expect(helper).toContain("docker buildx build --load");
111111expect(helper).toContain("docker_build_transient_failure()");
112112expect(helper).toContain("OPENCLAW_DOCKER_BUILD_RETRIES");
113+expect(helper).toContain("OPENCLAW_DOCKER_BUILD_TIMEOUT");
114+expect(helper).toContain('docker_build_run_command "$timeout_value" "${command[@]}"');
115+expect(helper).toContain("OPENCLAW_DOCKER_BUILD_REQUIRE_TIMEOUT");
113116expect(helper).toContain("frontend grpc server closed unexpectedly");
114117});
115118@@ -182,6 +185,182 @@ describe("docker build helper", () => {
182185);
183186});
184187188+it("wraps centralized Docker builds with the timeout helper", () => {
189+const workDir = mkdtempSync(join(tmpdir(), "openclaw-docker-build-timeout-"));
190+191+try {
192+const binDir = join(workDir, "bin");
193+mkdirSync(binDir);
194+writeFileSync(
195+join(binDir, "timeout"),
196+`#!/bin/bash
197+set -euo pipefail
198+if [[ "$1" = "--kill-after=1s" ]]; then
199+ exit 0
200+fi
201+printf '%s %s|%s\\n' "$1" "$2" "\${*:3}" >>"$TMPDIR/timeout-seen"
202+shift 2
203+"$@"
204+`,
205+);
206+chmodSync(join(binDir, "timeout"), 0o755);
207+writeFileSync(
208+join(binDir, "docker"),
209+`#!/bin/sh
210+printf "%s\\n" "$*" >>"$TMPDIR/docker-seen"
211+`,
212+);
213+chmodSync(join(binDir, "docker"), 0o755);
214+const rootDir = process.cwd();
215+const script = `
216+set -euo pipefail
217+ROOT_DIR=${shellQuote(rootDir)}
218+TMPDIR=${shellQuote(workDir)}
219+export ROOT_DIR TMPDIR
220+export PATH="$TMPDIR/bin:$PATH"
221+export OPENCLAW_DOCKER_BUILD_TIMEOUT=17s
222+223+source "$ROOT_DIR/scripts/lib/docker-build.sh"
224+225+docker_build_run e2e-build -t demo-image .
226+227+grep -q '^--kill-after=30s 17s|env DOCKER_BUILDKIT=1 docker build -t demo-image .$' "$TMPDIR/timeout-seen"
228+grep -q '^build -t demo-image .$' "$TMPDIR/docker-seen"
229+`;
230+231+execFileSync("bash", ["-lc", script], { encoding: "utf8" });
232+} finally {
233+rmSync(workDir, { recursive: true, force: true });
234+}
235+});
236+237+it("fails centralized Docker builds fast when timeout is unavailable", () => {
238+const workDir = mkdtempSync(join(tmpdir(), "openclaw-docker-build-timeout-required-"));
239+240+try {
241+mkdirSync(join(workDir, "bin"));
242+const rootDir = process.cwd();
243+const script = `
244+set -euo pipefail
245+ROOT_DIR=${shellQuote(rootDir)}
246+TMPDIR=${shellQuote(workDir)}
247+export ROOT_DIR TMPDIR
248+export PATH="$TMPDIR/bin"
249+export OPENCLAW_DOCKER_BUILD_TIMEOUT=19s
250+251+dirname() {
252+ /usr/bin/dirname "$@"
253+}
254+255+grep() {
256+ /usr/bin/grep "$@"
257+}
258+259+cat() {
260+ /bin/cat "$@"
261+}
262+263+rm() {
264+ /bin/rm "$@"
265+}
266+267+mktemp() {
268+ /usr/bin/mktemp "$@"
269+}
270+271+docker() {
272+ printf "%s\\n" "$*" >"$TMPDIR/docker-seen"
273+}
274+export -f dirname grep cat rm mktemp docker
275+276+source "$ROOT_DIR/scripts/lib/docker-build.sh"
277+278+set +e
279+docker_build_run e2e-build -t demo-image . >"$TMPDIR/stdout" 2>"$TMPDIR/stderr"
280+status="$?"
281+set -e
282+283+stdout="$(<"$TMPDIR/stdout")"
284+[[ "$status" = "1" ]]
285+[[ "$stdout" = *"timeout command not found; cannot bound Docker command after 19s"* ]]
286+[[ ! -e "$TMPDIR/docker-seen" ]]
287+`;
288+289+execFileSync("bash", ["-lc", script], { encoding: "utf8" });
290+} finally {
291+rmSync(workDir, { recursive: true, force: true });
292+}
293+});
294+295+it("keeps setup-style Docker builds compatible when timeout is unavailable", () => {
296+const workDir = mkdtempSync(join(tmpdir(), "openclaw-docker-build-timeout-optional-"));
297+298+try {
299+const binDir = join(workDir, "bin");
300+mkdirSync(binDir);
301+writeFileSync(
302+join(binDir, "env"),
303+`#!/bin/sh
304+while [ "$#" -gt 0 ]; do
305+ case "$1" in
306+ *=*)
307+ shift
308+ ;;
309+ *)
310+ break
311+ ;;
312+ esac
313+done
314+exec "$@"
315+`,
316+);
317+chmodSync(join(binDir, "env"), 0o755);
318+writeFileSync(
319+join(binDir, "docker"),
320+`#!/bin/sh
321+printf "%s\\n" "$*" >"$TMPDIR/docker-seen"
322+`,
323+);
324+chmodSync(join(binDir, "docker"), 0o755);
325+const rootDir = process.cwd();
326+const script = `
327+set -euo pipefail
328+ROOT_DIR=${shellQuote(rootDir)}
329+TMPDIR=${shellQuote(workDir)}
330+export ROOT_DIR TMPDIR
331+export PATH="$TMPDIR/bin"
332+export OPENCLAW_DOCKER_BUILD_TIMEOUT=23s
333+334+dirname() {
335+ /usr/bin/dirname "$@"
336+}
337+338+grep() {
339+ /usr/bin/grep "$@"
340+}
341+342+rm() {
343+ /bin/rm "$@"
344+}
345+346+mktemp() {
347+ /usr/bin/mktemp "$@"
348+}
349+export -f dirname grep rm mktemp
350+351+source "$ROOT_DIR/scripts/lib/docker-build.sh"
352+353+docker_build_exec -t setup-image .
354+355+[[ "$(<"$TMPDIR/docker-seen")" = "build -t setup-image ." ]]
356+`;
357+358+execFileSync("bash", ["-lc", script], { encoding: "utf8" });
359+} finally {
360+rmSync(workDir, { recursive: true, force: true });
361+}
362+});
363+185364it("keeps reused Docker image probes behind the timeout-aware helper", () => {
186365const workDir = mkdtempSync(join(tmpdir(), "openclaw-docker-image-reuse-timeout-"));
187366此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。