diff --git a/scripts/e2e/browser-cdp-snapshot-docker.sh b/scripts/e2e/browser-cdp-snapshot-docker.sh index 62bc9174c6e..07e0c4b6721 100755 --- a/scripts/e2e/browser-cdp-snapshot-docker.sh +++ b/scripts/e2e/browser-cdp-snapshot-docker.sh @@ -5,7 +5,16 @@ ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" source "$ROOT_DIR/scripts/lib/docker-e2e-image.sh" BASE_IMAGE="$(docker_e2e_resolve_image "openclaw-browser-cdp-base-e2e" OPENCLAW_BROWSER_CDP_BASE_E2E_IMAGE)" -IMAGE_NAME="$(docker_e2e_resolve_image "openclaw-browser-cdp-snapshot-e2e" OPENCLAW_BROWSER_CDP_SNAPSHOT_E2E_IMAGE)" +if [ -n "${OPENCLAW_BROWSER_CDP_SNAPSHOT_E2E_IMAGE:-}" ]; then + IMAGE_NAME="$OPENCLAW_BROWSER_CDP_SNAPSHOT_E2E_IMAGE" + DERIVED_SHARED_IMAGE="0" +elif [ -n "${OPENCLAW_DOCKER_E2E_IMAGE:-}" ]; then + IMAGE_NAME="openclaw-browser-cdp-snapshot-e2e:${OPENCLAW_DOCKER_ALL_LANE_NAME:-shared}" + DERIVED_SHARED_IMAGE="1" +else + IMAGE_NAME="openclaw-browser-cdp-snapshot-e2e" + DERIVED_SHARED_IMAGE="0" +fi SKIP_BUILD="${OPENCLAW_BROWSER_CDP_SNAPSHOT_E2E_SKIP_BUILD:-0}" PORT="18789" CDP_PORT="19222" @@ -19,7 +28,9 @@ cleanup() { } trap cleanup EXIT -if [ "${OPENCLAW_SKIP_DOCKER_BUILD:-0}" = "1" ] || [ "$SKIP_BUILD" = "1" ]; then +# Targeted Docker runs reuse the shared functional image as the base, but this +# lane still needs a derived image with Chromium installed. +if [ "$SKIP_BUILD" = "1" ] || { [ "$DERIVED_SHARED_IMAGE" = "0" ] && [ "${OPENCLAW_SKIP_DOCKER_BUILD:-0}" = "1" ]; }; then echo "Reusing Docker image: $IMAGE_NAME" docker_e2e_docker_cmd image inspect "$IMAGE_NAME" >/dev/null else @@ -82,7 +93,7 @@ if ! docker_e2e_wait_container_bash "$CONTAINER_NAME" 180 0.5 " fi echo "Running browser CDP snapshot smoke..." -docker_e2e_docker_cmd exec "$CONTAINER_NAME" bash -lc " +if ! docker_e2e_docker_cmd exec "$CONTAINER_NAME" bash -lc " set -euo pipefail source /tmp/openclaw-test-state-env source scripts/lib/openclaw-e2e-instance.sh @@ -93,6 +104,10 @@ grep -q 'OK live-snapshot' /tmp/browser-cdp-doctor.txt node \"\$entry\" browser \"\${base_args[@]}\" --browser-profile docker-cdp open http://127.0.0.1:$FIXTURE_PORT/ >/tmp/browser-cdp-open.txt node \"\$entry\" browser \"\${base_args[@]}\" --browser-profile docker-cdp snapshot --interactive --urls --out /tmp/browser-cdp-snapshot.txt >/tmp/browser-cdp-snapshot.out node scripts/e2e/lib/browser-cdp-snapshot/assert-snapshot.mjs /tmp/browser-cdp-snapshot.txt -" +"; then + echo "Browser CDP snapshot smoke failed" + docker_e2e_tail_container_file_if_running "$CONTAINER_NAME" "/tmp/browser-cdp-doctor.txt /tmp/browser-cdp-open.txt /tmp/browser-cdp-snapshot.out /tmp/browser-cdp-snapshot.txt /tmp/browser-cdp-chromium.log /tmp/browser-cdp-gateway.log /tmp/browser-cdp-fixture.log" 200 + exit 1 +fi echo "Browser CDP snapshot Docker E2E passed." diff --git a/test/scripts/docker-build-helper.test.ts b/test/scripts/docker-build-helper.test.ts index 7d46b35a296..965f9de0553 100644 --- a/test/scripts/docker-build-helper.test.ts +++ b/test/scripts/docker-build-helper.test.ts @@ -759,6 +759,94 @@ grep -q '^pull openclaw-reuse-image$' "$TMPDIR/docker-seen" } }); + it("derives the browser CDP image from the shared functional image", () => { + const workDir = mkdtempSync(join(tmpdir(), "openclaw-browser-cdp-shared-image-")); + + try { + const rootDir = process.cwd(); + mkdirSync(join(workDir, "bin")); + writeFileSync( + join(workDir, "bin", "docker"), + `#!/usr/bin/env bash +printf "%s\\n" "$*" >>"$TMPDIR/docker-seen" +case "$1 $2" in + "image inspect") + exit 0 + ;; + "inspect -f") + printf "true\\n" + exit 0 + ;; + "rm -f") + exit 0 + ;; + "run "*) + printf "container-id\\n" + exit 0 + ;; + "exec "*) + exit 0 + ;; +esac +case "$1" in + build) + exit 0 + ;; +esac +exit 9 +`, + ); + writeFileSync( + join(workDir, "bin", "node"), + `#!/usr/bin/env bash +printf "echo state\\n" +`, + ); + writeFileSync( + join(workDir, "bin", "timeout"), + `#!/usr/bin/env bash +case "\${1:-}" in + --kill-after=1s | --kill-after=30s) + shift 2 + ;; + *) + shift + ;; +esac +exec "$@" +`, + ); + chmodSync(join(workDir, "bin", "docker"), 0o755); + chmodSync(join(workDir, "bin", "node"), 0o755); + chmodSync(join(workDir, "bin", "timeout"), 0o755); + + const script = ` +set -euo pipefail +ROOT_DIR=${shellQuote(rootDir)} +TMPDIR=${shellQuote(workDir)} +export ROOT_DIR TMPDIR +export PATH="$TMPDIR/bin:$PATH" +export OPENCLAW_SKIP_DOCKER_BUILD=1 +export OPENCLAW_DOCKER_E2E_IMAGE=shared-functional +export OPENCLAW_DOCKER_ALL_LANE_NAME=browser-cdp-snapshot + +bash "$ROOT_DIR/scripts/e2e/browser-cdp-snapshot-docker.sh" + +grep -q '^image inspect shared-functional$' "$TMPDIR/docker-seen" +grep -Fq 'build -t openclaw-browser-cdp-snapshot-e2e:browser-cdp-snapshot' "$TMPDIR/docker-seen" +grep -Fq ' openclaw-browser-cdp-snapshot-e2e:browser-cdp-snapshot ' "$TMPDIR/docker-seen" +if grep -Fq ' shared-functional ' "$TMPDIR/docker-seen"; then + echo "browser CDP lane reused the shared image without Chromium" >&2 + exit 1 +fi +`; + + execFileSync("bash", ["-lc", script], { encoding: "utf8" }); + } finally { + rmSync(workDir, { recursive: true, force: true }); + } + }); + it("fails Docker commands fast when timeout is unavailable", () => { const workDir = mkdtempSync(join(tmpdir(), "openclaw-docker-timeout-required-"));