diff --git a/docs/help/testing.md b/docs/help/testing.md index 32818e20239..09dc34da1b6 100644 --- a/docs/help/testing.md +++ b/docs/help/testing.md @@ -976,6 +976,7 @@ The live-model Docker runners also bind-mount only the needed CLI auth homes (or - Onboarding wizard (TTY, full scaffolding): `pnpm test:docker:onboard` (script: `scripts/e2e/onboard-docker.sh`) - Npm tarball onboarding/channel/agent smoke: `pnpm test:docker:npm-onboard-channel-agent` installs the packed OpenClaw tarball globally in Docker, configures OpenAI via env-ref onboarding plus Telegram by default, verifies enabling the plugin installs its runtime deps on demand, runs doctor, and runs one mocked OpenAI agent turn. Reuse a prebuilt tarball with `OPENCLAW_NPM_ONBOARD_PACKAGE_TGZ=/path/to/openclaw-*.tgz`, skip the host rebuild with `OPENCLAW_NPM_ONBOARD_HOST_BUILD=0`, or switch channel with `OPENCLAW_NPM_ONBOARD_CHANNEL=discord`. - Bun global install smoke: `bash scripts/e2e/bun-global-install-smoke.sh` packs the current tree, installs it with `bun install -g` in an isolated home, and verifies `openclaw infer image providers --json` returns bundled image providers instead of hanging. Reuse a prebuilt tarball with `OPENCLAW_BUN_GLOBAL_SMOKE_PACKAGE_TGZ=/path/to/openclaw-*.tgz`, skip the host build with `OPENCLAW_BUN_GLOBAL_SMOKE_HOST_BUILD=0`, or copy `dist/` from a built Docker image with `OPENCLAW_BUN_GLOBAL_SMOKE_DIST_IMAGE=openclaw-dockerfile-smoke:local`. +- Installer Docker smoke: `bash scripts/test-install-sh-docker.sh` shares one npm cache across its root, update, direct-npm, and non-root containers. Set `OPENCLAW_INSTALL_SMOKE_NPM_CACHE_DIR=/path/to/cache` to reuse that cache across local reruns. - Gateway networking (two containers, WS auth + health): `pnpm test:docker:gateway-network` (script: `scripts/e2e/gateway-network-docker.sh`) - OpenAI Responses web_search minimal reasoning regression: `pnpm test:docker:openai-web-search-minimal` (script: `scripts/e2e/openai-web-search-minimal-docker.sh`) runs a mocked OpenAI server through Gateway, verifies `web_search` raises `reasoning.effort` from `minimal` to `low`, then forces the provider schema reject and checks the raw detail appears in Gateway logs. - MCP channel bridge (seeded Gateway + stdio bridge + raw Claude notification-frame smoke): `pnpm test:docker:mcp-channels` (script: `scripts/e2e/mcp-channels-docker.sh`) diff --git a/scripts/test-install-sh-docker.sh b/scripts/test-install-sh-docker.sh index d94cc3edb95..4dcd6d35b6b 100755 --- a/scripts/test-install-sh-docker.sh +++ b/scripts/test-install-sh-docker.sh @@ -166,12 +166,18 @@ BASELINE_TAG_URL="" FRESH_TAG_URL="" UPDATE_TAG_URL="" UPDATE_DOCKER_HOST_ARGS=() +NPM_CACHE_DIR="${OPENCLAW_INSTALL_SMOKE_NPM_CACHE_DIR:-}" +NPM_CACHE_OWNED=0 +NPM_CACHE_DOCKER_ARGS=() cleanup() { if [[ -n "$UPDATE_SERVER_PID" ]]; then kill "$UPDATE_SERVER_PID" >/dev/null 2>&1 || true wait "$UPDATE_SERVER_PID" >/dev/null 2>&1 || true fi + if [[ "$NPM_CACHE_OWNED" == "1" && -n "$NPM_CACHE_DIR" ]]; then + rm -rf "$NPM_CACHE_DIR" + fi rm -rf "$LATEST_DIR" "$UPDATE_DIR" } @@ -288,6 +294,20 @@ prepare_update_host_access() { fi } +prepare_npm_cache() { + if [[ -z "$NPM_CACHE_DIR" ]]; then + NPM_CACHE_DIR="$(mktemp -d)" + NPM_CACHE_OWNED=1 + fi + mkdir -p "$NPM_CACHE_DIR" + chmod 0777 "$NPM_CACHE_DIR" + NPM_CACHE_DOCKER_ARGS=( + -v "${NPM_CACHE_DIR}:/npm-cache" + -e npm_config_cache=/npm-cache + -e NPM_CONFIG_CACHE=/npm-cache + ) +} + start_update_server() { if [[ -z "$UPDATE_PORT" ]]; then UPDATE_PORT="$(allocate_host_port)" @@ -326,12 +346,14 @@ if [[ "$SKIP_UPDATE" == "1" ]]; then else prepare_update_tarball prepare_update_host_access + prepare_npm_cache start_update_server echo "==> Run installer smoke test (root): $FRESH_TAG_URL" docker run --rm -t \ --platform "$SMOKE_PLATFORM" \ ${UPDATE_DOCKER_HOST_ARGS[@]+"${UPDATE_DOCKER_HOST_ARGS[@]}"} \ + "${NPM_CACHE_DOCKER_ARGS[@]}" \ -v "${LATEST_DIR}:/out" \ -e OPENCLAW_INSTALL_URL="$INSTALL_URL" \ -e OPENCLAW_INSTALL_PACKAGE="$PACKAGE_NAME" \ @@ -353,6 +375,7 @@ else docker run --rm -t \ --platform "$SMOKE_PLATFORM" \ ${UPDATE_DOCKER_HOST_ARGS[@]+"${UPDATE_DOCKER_HOST_ARGS[@]}"} \ + "${NPM_CACHE_DOCKER_ARGS[@]}" \ -e OPENCLAW_INSTALL_PACKAGE="$PACKAGE_NAME" \ -e OPENCLAW_INSTALL_SMOKE_MODE=update \ -e OPENCLAW_INSTALL_UPDATE_BASELINE="$UPDATE_BASELINE_VERSION" \ @@ -371,6 +394,7 @@ else docker run --rm -t \ --platform "$SMOKE_PLATFORM" \ ${UPDATE_DOCKER_HOST_ARGS[@]+"${UPDATE_DOCKER_HOST_ARGS[@]}"} \ + "${NPM_CACHE_DOCKER_ARGS[@]}" \ -e OPENCLAW_INSTALL_PACKAGE="$PACKAGE_NAME" \ -e OPENCLAW_INSTALL_SMOKE_MODE=npm-global \ -e OPENCLAW_INSTALL_UPDATE_BASELINE="$UPDATE_BASELINE_VERSION" \ @@ -389,6 +413,7 @@ LATEST_VERSION="${LATEST_VERSION:-}" if [[ "$SKIP_NONROOT" == "1" ]]; then echo "==> Skip non-root installer smoke (OPENCLAW_INSTALL_SMOKE_SKIP_NONROOT=1)" else + prepare_npm_cache if [[ "$SKIP_NONROOT_IMAGE_BUILD" == "1" ]]; then echo "==> Reuse prebuilt non-root image: $NONROOT_IMAGE" else @@ -403,6 +428,7 @@ else echo "==> Run installer non-root test: $INSTALL_URL" docker run --rm -t \ --platform "$NONROOT_PLATFORM" \ + "${NPM_CACHE_DOCKER_ARGS[@]}" \ -e OPENCLAW_INSTALL_URL="$INSTALL_URL" \ -e OPENCLAW_INSTALL_PACKAGE="$PACKAGE_NAME" \ -e OPENCLAW_INSTALL_METHOD=npm \ @@ -427,6 +453,7 @@ echo "==> Run CLI installer non-root test (same image)" docker run --rm -t \ --platform "$NONROOT_PLATFORM" \ --entrypoint /bin/bash \ + "${NPM_CACHE_DOCKER_ARGS[@]}" \ -e OPENCLAW_INSTALL_URL="$INSTALL_URL" \ -e OPENCLAW_INSTALL_CLI_URL="$CLI_INSTALL_URL" \ -e OPENCLAW_NO_ONBOARD=1 \ diff --git a/test/scripts/test-install-sh-docker.test.ts b/test/scripts/test-install-sh-docker.test.ts index 6c8cd64e3e6..f602d10dca4 100644 --- a/test/scripts/test-install-sh-docker.test.ts +++ b/test/scripts/test-install-sh-docker.test.ts @@ -90,6 +90,9 @@ describe("install-sh smoke runner", () => { const runner = readFileSync(SMOKE_RUNNER_PATH, "utf8"); expect(script).toContain('SKIP_NPM_GLOBAL="${OPENCLAW_INSTALL_SMOKE_SKIP_NPM_GLOBAL:-0}"'); + expect(script).toContain('NPM_CACHE_DIR="${OPENCLAW_INSTALL_SMOKE_NPM_CACHE_DIR:-}"'); + expect(script).toContain("-e npm_config_cache=/npm-cache"); + expect(script).toContain('"${NPM_CACHE_DOCKER_ARGS[@]}"'); expect(script).toContain("==> Run direct npm global smoke"); expect(script).toContain("OPENCLAW_INSTALL_SMOKE_MODE=npm-global"); expect(runner).toContain("run_npm_global_smoke");