From 14808371a6ffa34addbff0c9feac864231610107 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Thu, 23 Apr 2026 16:35:31 +0100 Subject: [PATCH] test: improve macos parallels update smoke --- .../skills/openclaw-parallels-smoke/SKILL.md | 4 + scripts/e2e/parallels-macos-smoke.sh | 6 + scripts/e2e/parallels-npm-update-smoke.sh | 213 ++++++++++++------ 3 files changed, 153 insertions(+), 70 deletions(-) diff --git a/.agents/skills/openclaw-parallels-smoke/SKILL.md b/.agents/skills/openclaw-parallels-smoke/SKILL.md index c358c169e1c..5775017f65d 100644 --- a/.agents/skills/openclaw-parallels-smoke/SKILL.md +++ b/.agents/skills/openclaw-parallels-smoke/SKILL.md @@ -45,6 +45,9 @@ Use this skill for Parallels guest workflows and smoke interpretation. Do not lo ## npm install then update - Preferred entrypoint: `pnpm test:parallels:npm-update` +- For a macOS-only published release update check, use: + - `timeout --foreground 75m pnpm test:parallels:npm-update -- --platform macos --package-spec openclaw@ --update-target --json` + This keeps the same-guest `openclaw update --tag ...` coverage and uses the shared macOS current-user/sudo fallback without starting Windows/Linux lanes. - Required coverage: every release/update regression run must include both lanes: - fresh snapshot -> install requested package/baseline -> smoke - same guest baseline -> run the guest's installed `openclaw update ...` command -> smoke again @@ -75,6 +78,7 @@ Use this skill for Parallels guest workflows and smoke interpretation. Do not lo ## macOS flow - Preferred entrypoint: `pnpm test:parallels:macos` +- `parallels-macos-smoke.sh --mode fresh --target-package-spec openclaw@` is an install smoke only. For published old-version -> new-version update coverage on macOS, prefer the npm-update wrapper with `--platform macos`; `parallels-macos-smoke.sh --mode upgrade --target-package-spec ...` installs the target package and does not exercise the baseline CLI's updater. - Default upgrade coverage on macOS should now include: fresh snapshot -> site installer pinned to the latest stable tag -> `openclaw update --channel dev` on the guest. Treat this as part of the default Tahoe regression plan, not an optional side quest. - `parallels-macos-smoke.sh --mode upgrade` should run that release-to-dev lane by default. Keep the older host-tgz upgrade path only when the caller explicitly passes `--target-package-spec`. - Because the default upgrade lane no longer needs a host tgz, skip `npm pack` + host HTTP server startup for `--mode upgrade` unless `--target-package-spec` is set. Keep the pack/server path for `fresh` and `both`. diff --git a/scripts/e2e/parallels-macos-smoke.sh b/scripts/e2e/parallels-macos-smoke.sh index 4f8d1d8b221..c825e53c646 100644 --- a/scripts/e2e/parallels-macos-smoke.sh +++ b/scripts/e2e/parallels-macos-smoke.sh @@ -1921,6 +1921,9 @@ run_fresh_main_lane() { phase_run "fresh.install-main" "$(install_main_timeout)" install_main_tgz "$host_ip" "openclaw-main-fresh.tgz" FRESH_MAIN_VERSION="$(extract_last_version "$(phase_log_path fresh.install-main)")" phase_run "fresh.verify-main-version" "$TIMEOUT_VERIFY_S" verify_target_version + if [[ -z "$FRESH_MAIN_VERSION" ]]; then + FRESH_MAIN_VERSION="$(extract_last_version "$(phase_log_path fresh.verify-main-version)")" + fi phase_run "fresh.verify-bundle-permissions" "$TIMEOUT_PERMISSION_S" verify_bundle_permissions phase_run "fresh.onboard-ref" "$TIMEOUT_ONBOARD_S" run_ref_onboard phase_run "fresh.gateway-start" "$TIMEOUT_GATEWAY_S" start_manual_gateway_if_needed @@ -1958,6 +1961,9 @@ run_upgrade_lane() { phase_run "upgrade.install-main" "$(install_main_timeout)" install_main_tgz "$host_ip" "openclaw-main-upgrade.tgz" UPGRADE_MAIN_VERSION="$(extract_last_version "$(phase_log_path upgrade.install-main)")" phase_run "upgrade.verify-main-version" "$TIMEOUT_VERIFY_S" verify_target_version + if [[ -z "$UPGRADE_MAIN_VERSION" ]]; then + UPGRADE_MAIN_VERSION="$(extract_last_version "$(phase_log_path upgrade.verify-main-version)")" + fi phase_run "upgrade.verify-bundle-permissions" "$TIMEOUT_PERMISSION_S" verify_bundle_permissions else phase_run "upgrade.update-dev" "$TIMEOUT_UPDATE_DEV_S" run_dev_channel_update diff --git a/scripts/e2e/parallels-npm-update-smoke.sh b/scripts/e2e/parallels-npm-update-smoke.sh index 991b95b32eb..ade6dc19da6 100755 --- a/scripts/e2e/parallels-npm-update-smoke.sh +++ b/scripts/e2e/parallels-npm-update-smoke.sh @@ -16,6 +16,7 @@ MODEL_ID="" PYTHON_BIN="${PYTHON_BIN:-}" PACKAGE_SPEC="" UPDATE_TARGET="" +RUN_PLATFORMS="all" JSON_OUTPUT=0 RUN_DIR="$(mktemp -d /tmp/openclaw-parallels-npm-update.XXXXXX)" MAIN_TGZ_DIR="$(mktemp -d)" @@ -115,6 +116,8 @@ Options: --update-target Target passed to guest 'openclaw update --tag'. Default: host-served tgz packed from current checkout. Examples: latest, beta, 2026.4.10, http://host/openclaw.tgz + --platform Comma-separated platforms to run: all, macos, windows, linux. + Default: all --provider Provider auth/model lane. Default: openai --api-key-env Host env var name for provider API key. @@ -138,6 +141,10 @@ while [[ $# -gt 0 ]]; do UPDATE_TARGET="$2" shift 2 ;; + --platform|--only) + RUN_PLATFORMS="$2" + shift 2 + ;; --provider) PROVIDER="$2" shift 2 @@ -160,6 +167,41 @@ while [[ $# -gt 0 ]]; do esac done +platform_enabled() { + local platform="$1" + [[ "$RUN_PLATFORMS" == "all" ]] && return 0 + case ",$RUN_PLATFORMS," in + *,"$platform",*) return 0 ;; + *) return 1 ;; + esac +} + +validate_platforms() { + local normalized entry valid_any + local -a entries + normalized="${RUN_PLATFORMS// /}" + [[ -n "$normalized" ]] || die "--platform must not be empty" + RUN_PLATFORMS="$normalized" + if [[ "$RUN_PLATFORMS" == "all" ]]; then + return + fi + valid_any=0 + IFS=',' read -ra entries <<<"$RUN_PLATFORMS" + for entry in "${entries[@]}"; do + case "$entry" in + macos|windows|linux) + valid_any=1 + ;; + *) + die "invalid --platform entry: $entry" + ;; + esac + done + [[ "$valid_any" -eq 1 ]] || die "--platform must include at least one platform" +} + +validate_platforms + case "$PROVIDER" in openai) AUTH_CHOICE="openai-api-key" @@ -1533,50 +1575,65 @@ if [[ -z "$PACKAGE_SPEC" ]]; then fi resolve_current_head -RESOLVED_LINUX_VM="$(resolve_linux_vm_name)" -if [[ "$RESOLVED_LINUX_VM" != "$LINUX_VM" ]]; then - warn "requested VM $LINUX_VM not found; using $RESOLVED_LINUX_VM" - LINUX_VM="$RESOLVED_LINUX_VM" +if platform_enabled linux; then + RESOLVED_LINUX_VM="$(resolve_linux_vm_name)" + if [[ "$RESOLVED_LINUX_VM" != "$LINUX_VM" ]]; then + warn "requested VM $LINUX_VM not found; using $RESOLVED_LINUX_VM" + LINUX_VM="$RESOLVED_LINUX_VM" + fi fi say "Run fresh npm baseline: $PACKAGE_SPEC" +say "Platforms: $RUN_PLATFORMS" say "Run dir: $RUN_DIR" -bash "$ROOT_DIR/scripts/e2e/parallels-macos-smoke.sh" \ - --mode fresh \ - --provider "$PROVIDER" \ - --api-key-env "$API_KEY_ENV" \ - --target-package-spec "$PACKAGE_SPEC" \ - --json >"$RUN_DIR/macos-fresh.log" 2>&1 & -macos_fresh_pid=$! +fresh_monitor_args=() +if platform_enabled macos; then + bash "$ROOT_DIR/scripts/e2e/parallels-macos-smoke.sh" \ + --mode fresh \ + --provider "$PROVIDER" \ + --api-key-env "$API_KEY_ENV" \ + --target-package-spec "$PACKAGE_SPEC" \ + --json >"$RUN_DIR/macos-fresh.log" 2>&1 & + macos_fresh_pid=$! + fresh_monitor_args+=("macOS" "$macos_fresh_pid" "$RUN_DIR/macos-fresh.log") +fi -bash "$ROOT_DIR/scripts/e2e/parallels-windows-smoke.sh" \ - --mode fresh \ - --provider "$PROVIDER" \ - --api-key-env "$API_KEY_ENV" \ - --target-package-spec "$PACKAGE_SPEC" \ - --json >"$RUN_DIR/windows-fresh.log" 2>&1 & -windows_fresh_pid=$! +if platform_enabled windows; then + bash "$ROOT_DIR/scripts/e2e/parallels-windows-smoke.sh" \ + --mode fresh \ + --provider "$PROVIDER" \ + --api-key-env "$API_KEY_ENV" \ + --target-package-spec "$PACKAGE_SPEC" \ + --json >"$RUN_DIR/windows-fresh.log" 2>&1 & + windows_fresh_pid=$! + fresh_monitor_args+=("Windows" "$windows_fresh_pid" "$RUN_DIR/windows-fresh.log") +fi -bash "$ROOT_DIR/scripts/e2e/parallels-linux-smoke.sh" \ - --mode fresh \ - --provider "$PROVIDER" \ - --api-key-env "$API_KEY_ENV" \ - --target-package-spec "$PACKAGE_SPEC" \ - --json >"$RUN_DIR/linux-fresh.log" 2>&1 & -linux_fresh_pid=$! +if platform_enabled linux; then + bash "$ROOT_DIR/scripts/e2e/parallels-linux-smoke.sh" \ + --mode fresh \ + --provider "$PROVIDER" \ + --api-key-env "$API_KEY_ENV" \ + --target-package-spec "$PACKAGE_SPEC" \ + --json >"$RUN_DIR/linux-fresh.log" 2>&1 & + linux_fresh_pid=$! + fresh_monitor_args+=("Linux" "$linux_fresh_pid" "$RUN_DIR/linux-fresh.log") +fi -monitor_jobs_progress "fresh" \ - "macOS" "$macos_fresh_pid" "$RUN_DIR/macos-fresh.log" \ - "Windows" "$windows_fresh_pid" "$RUN_DIR/windows-fresh.log" \ - "Linux" "$linux_fresh_pid" "$RUN_DIR/linux-fresh.log" +monitor_jobs_progress "fresh" "${fresh_monitor_args[@]}" -wait_job "macOS fresh" "$macos_fresh_pid" "$RUN_DIR/macos-fresh.log" && MACOS_FRESH_STATUS="pass" || MACOS_FRESH_STATUS="fail" -wait_job "Windows fresh" "$windows_fresh_pid" "$RUN_DIR/windows-fresh.log" && WINDOWS_FRESH_STATUS="pass" || WINDOWS_FRESH_STATUS="fail" -wait_job "Linux fresh" "$linux_fresh_pid" "$RUN_DIR/linux-fresh.log" && LINUX_FRESH_STATUS="pass" || LINUX_FRESH_STATUS="fail" - -[[ "$MACOS_FRESH_STATUS" == "pass" ]] || die "macOS fresh baseline failed" -[[ "$WINDOWS_FRESH_STATUS" == "pass" ]] || die "Windows fresh baseline failed" -[[ "$LINUX_FRESH_STATUS" == "pass" ]] || die "Linux fresh baseline failed" +if platform_enabled macos; then + wait_job "macOS fresh" "$macos_fresh_pid" "$RUN_DIR/macos-fresh.log" && MACOS_FRESH_STATUS="pass" || MACOS_FRESH_STATUS="fail" + [[ "$MACOS_FRESH_STATUS" == "pass" ]] || die "macOS fresh baseline failed" +fi +if platform_enabled windows; then + wait_job "Windows fresh" "$windows_fresh_pid" "$RUN_DIR/windows-fresh.log" && WINDOWS_FRESH_STATUS="pass" || WINDOWS_FRESH_STATUS="fail" + [[ "$WINDOWS_FRESH_STATUS" == "pass" ]] || die "Windows fresh baseline failed" +fi +if platform_enabled linux; then + wait_job "Linux fresh" "$linux_fresh_pid" "$RUN_DIR/linux-fresh.log" && LINUX_FRESH_STATUS="pass" || LINUX_FRESH_STATUS="fail" + [[ "$LINUX_FRESH_STATUS" == "pass" ]] || die "Linux fresh baseline failed" +fi if [[ -z "$UPDATE_TARGET" || "$UPDATE_TARGET" == "local-main" ]]; then pack_main_tgz @@ -1591,48 +1648,64 @@ else [[ -n "$UPDATE_EXPECTED_NEEDLE" ]] || UPDATE_EXPECTED_NEEDLE="$UPDATE_TARGET_EFFECTIVE" fi fi -write_windows_update_script -start_server +if platform_enabled windows; then + write_windows_update_script +fi +if [[ -n "$MAIN_TGZ_PATH" ]] || platform_enabled windows; then + start_server +fi if [[ -n "$MAIN_TGZ_PATH" ]]; then UPDATE_TARGET_EFFECTIVE="http://$HOST_IP:$HOST_PORT/$(basename "$MAIN_TGZ_PATH")" fi -windows_update_script_url="http://$HOST_IP:$HOST_PORT/$(basename "$WINDOWS_UPDATE_SCRIPT_PATH")" +if platform_enabled windows; then + windows_update_script_url="http://$HOST_IP:$HOST_PORT/$(basename "$WINDOWS_UPDATE_SCRIPT_PATH")" +fi say "Run same-guest openclaw update to $UPDATE_TARGET_EFFECTIVE" -ensure_vm_running_for_update "$MACOS_VM" -ensure_vm_running_for_update "$WINDOWS_VM" -ensure_vm_running_for_update "$LINUX_VM" -run_macos_update "$UPDATE_TARGET_EFFECTIVE" "$UPDATE_EXPECTED_NEEDLE" >"$RUN_DIR/macos-update.log" 2>&1 & -macos_update_pid=$! -run_windows_update "$UPDATE_TARGET_EFFECTIVE" "$UPDATE_EXPECTED_NEEDLE" "$windows_update_script_url" >"$RUN_DIR/windows-update.log" 2>&1 & -windows_update_pid=$! -run_linux_update "$UPDATE_TARGET_EFFECTIVE" "$UPDATE_EXPECTED_NEEDLE" >"$RUN_DIR/linux-update.log" 2>&1 & -linux_update_pid=$! -macos_update_guard_pid="$(start_timeout_guard "macOS update" "$TIMEOUT_UPDATE_S" "$macos_update_pid" "$RUN_DIR/macos-update.log")" -windows_update_guard_pid="$(start_timeout_guard "Windows update" "$TIMEOUT_UPDATE_S" "$windows_update_pid" "$RUN_DIR/windows-update.log")" -linux_update_guard_pid="$(start_timeout_guard "Linux update" "$TIMEOUT_UPDATE_S" "$linux_update_pid" "$RUN_DIR/linux-update.log")" +update_monitor_args=() +if platform_enabled macos; then + ensure_vm_running_for_update "$MACOS_VM" + run_macos_update "$UPDATE_TARGET_EFFECTIVE" "$UPDATE_EXPECTED_NEEDLE" >"$RUN_DIR/macos-update.log" 2>&1 & + macos_update_pid=$! + macos_update_guard_pid="$(start_timeout_guard "macOS update" "$TIMEOUT_UPDATE_S" "$macos_update_pid" "$RUN_DIR/macos-update.log")" + update_monitor_args+=("macOS" "$macos_update_pid" "$RUN_DIR/macos-update.log") +fi +if platform_enabled windows; then + ensure_vm_running_for_update "$WINDOWS_VM" + run_windows_update "$UPDATE_TARGET_EFFECTIVE" "$UPDATE_EXPECTED_NEEDLE" "$windows_update_script_url" >"$RUN_DIR/windows-update.log" 2>&1 & + windows_update_pid=$! + windows_update_guard_pid="$(start_timeout_guard "Windows update" "$TIMEOUT_UPDATE_S" "$windows_update_pid" "$RUN_DIR/windows-update.log")" + update_monitor_args+=("Windows" "$windows_update_pid" "$RUN_DIR/windows-update.log") +fi +if platform_enabled linux; then + ensure_vm_running_for_update "$LINUX_VM" + run_linux_update "$UPDATE_TARGET_EFFECTIVE" "$UPDATE_EXPECTED_NEEDLE" >"$RUN_DIR/linux-update.log" 2>&1 & + linux_update_pid=$! + linux_update_guard_pid="$(start_timeout_guard "Linux update" "$TIMEOUT_UPDATE_S" "$linux_update_pid" "$RUN_DIR/linux-update.log")" + update_monitor_args+=("Linux" "$linux_update_pid" "$RUN_DIR/linux-update.log") +fi -monitor_jobs_progress "update" \ - "macOS" "$macos_update_pid" "$RUN_DIR/macos-update.log" \ - "Windows" "$windows_update_pid" "$RUN_DIR/windows-update.log" \ - "Linux" "$linux_update_pid" "$RUN_DIR/linux-update.log" +monitor_jobs_progress "update" "${update_monitor_args[@]}" -stop_timeout_guard "$macos_update_guard_pid" -stop_timeout_guard "$windows_update_guard_pid" -stop_timeout_guard "$linux_update_guard_pid" - -wait_job "macOS update" "$macos_update_pid" "$RUN_DIR/macos-update.log" && MACOS_UPDATE_STATUS="pass" || MACOS_UPDATE_STATUS="fail" -wait_job "Windows update" "$windows_update_pid" "$RUN_DIR/windows-update.log" && WINDOWS_UPDATE_STATUS="pass" || WINDOWS_UPDATE_STATUS="fail" -wait_job "Linux update" "$linux_update_pid" "$RUN_DIR/linux-update.log" && LINUX_UPDATE_STATUS="pass" || LINUX_UPDATE_STATUS="fail" - -[[ "$MACOS_UPDATE_STATUS" == "pass" ]] || die "macOS update failed" -[[ "$WINDOWS_UPDATE_STATUS" == "pass" ]] || die "Windows update failed" -[[ "$LINUX_UPDATE_STATUS" == "pass" ]] || die "Linux update failed" - -MACOS_UPDATE_VERSION="$(extract_last_version "$RUN_DIR/macos-update.log")" -WINDOWS_UPDATE_VERSION="$(extract_last_version "$RUN_DIR/windows-update.log")" -LINUX_UPDATE_VERSION="$(extract_last_version "$RUN_DIR/linux-update.log")" +if platform_enabled macos; then + stop_timeout_guard "$macos_update_guard_pid" + wait_job "macOS update" "$macos_update_pid" "$RUN_DIR/macos-update.log" && MACOS_UPDATE_STATUS="pass" || MACOS_UPDATE_STATUS="fail" + [[ "$MACOS_UPDATE_STATUS" == "pass" ]] || die "macOS update failed" + MACOS_UPDATE_VERSION="$(extract_last_version "$RUN_DIR/macos-update.log")" +fi +if platform_enabled windows; then + stop_timeout_guard "$windows_update_guard_pid" + wait_job "Windows update" "$windows_update_pid" "$RUN_DIR/windows-update.log" && WINDOWS_UPDATE_STATUS="pass" || WINDOWS_UPDATE_STATUS="fail" + [[ "$WINDOWS_UPDATE_STATUS" == "pass" ]] || die "Windows update failed" + WINDOWS_UPDATE_VERSION="$(extract_last_version "$RUN_DIR/windows-update.log")" +fi +if platform_enabled linux; then + stop_timeout_guard "$linux_update_guard_pid" + wait_job "Linux update" "$linux_update_pid" "$RUN_DIR/linux-update.log" && LINUX_UPDATE_STATUS="pass" || LINUX_UPDATE_STATUS="fail" + [[ "$LINUX_UPDATE_STATUS" == "pass" ]] || die "Linux update failed" + LINUX_UPDATE_VERSION="$(extract_last_version "$RUN_DIR/linux-update.log")" +fi SUMMARY_PACKAGE_SPEC="$PACKAGE_SPEC" \ SUMMARY_UPDATE_TARGET="$UPDATE_TARGET_EFFECTIVE" \