#!/usr/bin/env bash set -euo pipefail ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" TMP="$(mktemp -d "${TMPDIR:-/tmp}/mosaic-next-install-test-XXXXXX")" trap 'rm -rf "$TMP"' EXIT FAKE_BIN="$TMP/bin" HOME_DIR="$TMP/home" PREFIX="$TMP/prefix" MOSAIC_HOME="$TMP/mosaic" STATE="$TMP/state" LOG="$TMP/npm.log" mkdir -p "$FAKE_BIN" "$HOME_DIR" "$STATE" cat > "$FAKE_BIN/npm" <<'FAKE_NPM' #!/usr/bin/env bash set -euo pipefail LOG="${MOSAIC_TEST_NPM_LOG:?}" STATE="${MOSAIC_TEST_STATE:?}" echo "$*" >> "$LOG" if [[ "$1" == "view" ]]; then case "$2 $3" in "@mosaicstack/mosaic@next version") echo "0.0.49-next.999" ;; "@mosaicstack/gateway@next version") echo "${MOSAIC_TEST_GATEWAY_NEXT_VERSION:-0.0.7-next.999}" ;; "@mosaicstack/mosaic version") echo "0.0.48" ;; *) echo "unexpected npm view: $*" >&2; exit 1 ;; esac exit 0 fi if [[ "$1" == "install" ]]; then case "$*" in *"@mosaicstack/mosaic@0.0.49-next.999"*) echo "0.0.49-next.999" > "$STATE/mosaic" ;; *"@mosaicstack/gateway@0.0.7-next.999"*) if [[ "${MOSAIC_TEST_FAIL_NEXT_GATEWAY_INSTALL:-0}" == "1" ]]; then echo "forced gateway install failure" >&2 exit 1 fi echo "0.0.7-next.999" > "$STATE/gateway" ;; *"mosaicstack-mosaic-0.0.0-source.tgz"*) echo "0.0.0-source" > "$STATE/mosaic" ;; *"mosaicstack-gateway-0.0.0-source.tgz"*) echo "0.0.0-source" > "$STATE/gateway" ;; *) echo "unexpected npm install: $*" >&2; exit 1 ;; esac exit 0 fi if [[ "$1" == "ls" ]]; then cli="$(cat "$STATE/mosaic" 2>/dev/null || true)" gateway="$(cat "$STATE/gateway" 2>/dev/null || true)" node -e ' const cli = process.argv[1]; const gateway = process.argv[2]; const dependencies = {}; if (cli) dependencies["@mosaicstack/mosaic"] = { version: cli }; if (gateway) dependencies["@mosaicstack/gateway"] = { version: gateway }; process.stdout.write(JSON.stringify({ dependencies })); ' "$cli" "$gateway" exit 0 fi echo "unexpected npm command: $*" >&2 exit 1 FAKE_NPM chmod +x "$FAKE_BIN/npm" cat > "$FAKE_BIN/curl" <<'FAKE_CURL' #!/usr/bin/env bash set -euo pipefail # The fake tar creates the source tree; curl only needs to keep the pipe alive. exit 0 FAKE_CURL chmod +x "$FAKE_BIN/curl" cat > "$FAKE_BIN/tar" <<'FAKE_TAR' #!/usr/bin/env bash set -euo pipefail dest="" while [[ $# -gt 0 ]]; do case "$1" in -C) dest="$2"; shift 2 ;; *) shift ;; esac done if [[ -z "$dest" ]]; then echo "fake tar missing -C destination" >&2 exit 1 fi mkdir -p "$dest/stack/packages/mosaic" "$dest/stack/apps/gateway" FAKE_TAR chmod +x "$FAKE_BIN/tar" cat > "$FAKE_BIN/pnpm" <<'FAKE_PNPM' #!/usr/bin/env bash set -euo pipefail LOG="${MOSAIC_TEST_NPM_LOG:?}" echo "pnpm $*" >> "$LOG" if [[ "$1" == "pack" ]]; then out="" while [[ $# -gt 0 ]]; do case "$1" in --pack-destination) out="$2"; shift 2 ;; *) shift ;; esac done if [[ -z "$out" ]]; then echo "fake pnpm pack missing destination" >&2 exit 1 fi mkdir -p "$out" case "$PWD" in */apps/gateway) touch "$out/mosaicstack-gateway-0.0.0-source.tgz" ;; */packages/mosaic) touch "$out/mosaicstack-mosaic-0.0.0-source.tgz" ;; *) echo "unexpected pnpm pack cwd: $PWD" >&2; exit 1 ;; esac exit 0 fi # install/build commands are no-ops in this harness. exit 0 FAKE_PNPM chmod +x "$FAKE_BIN/pnpm" reset_state() { : > "$LOG" rm -f "$STATE"/* } reset_state echo "[test] --next fast path pins resolved package versions" OUTPUT="$( HOME="$HOME_DIR" \ MOSAIC_HOME="$MOSAIC_HOME" \ MOSAIC_PREFIX="$PREFIX" \ MOSAIC_NO_COLOR=1 \ MOSAIC_TEST_NPM_LOG="$LOG" \ MOSAIC_TEST_STATE="$STATE" \ PATH="$FAKE_BIN:$PATH" \ bash "$ROOT/tools/install.sh" --cli --next --yes --no-auto-launch )" grep -qF 'Installed @next packages: CLI 0.0.49-next.999, gateway 0.0.7-next.999' <<<"$OUTPUT" grep -qF 'install -g @mosaicstack/gateway@0.0.7-next.999' "$LOG" grep -qF 'install -g @mosaicstack/mosaic@0.0.49-next.999' "$LOG" if grep -qE '^install -g .+@next( |$)' "$LOG"; then echo "expected exact-version installs, found mutable @next install" >&2 exit 1 fi if grep -qF 'Downloading source from next' <<<"$OUTPUT"; then echo "fast path unexpectedly fell back to source" >&2 exit 1 fi reset_state echo "[test] fast path failure falls back to source build" OUTPUT="$( HOME="$HOME_DIR" \ MOSAIC_HOME="$MOSAIC_HOME" \ MOSAIC_PREFIX="$PREFIX" \ MOSAIC_NO_COLOR=1 \ MOSAIC_TEST_NPM_LOG="$LOG" \ MOSAIC_TEST_STATE="$STATE" \ MOSAIC_TEST_FAIL_NEXT_GATEWAY_INSTALL=1 \ PATH="$FAKE_BIN:$PATH" \ bash "$ROOT/tools/install.sh" --cli --next --yes --no-auto-launch )" grep -qF 'Fast gateway @next install failed.' <<<"$OUTPUT" grep -qF 'Falling back to source build at ref next; --next will not hard-fail on registry issues.' <<<"$OUTPUT" grep -qF 'Downloading source from next' <<<"$OUTPUT" grep -qF 'Installed from source: CLI 0.0.0-source' <<<"$OUTPUT" grep -qF 'install -g @mosaicstack/mosaic@0.0.49-next.999' "$LOG" grep -qE 'install -g .*/mosaicstack-gateway-0\.0\.0-source\.tgz' "$LOG" grep -qE 'install -g .*/mosaicstack-mosaic-0\.0\.0-source\.tgz' "$LOG" [[ "$(cat "$STATE/mosaic")" == "0.0.0-source" ]] [[ "$(cat "$STATE/gateway")" == "0.0.0-source" ]] reset_state echo "[test] explicit --ref keeps source lane and avoids @next lookup" OUTPUT="$( HOME="$HOME_DIR" \ MOSAIC_HOME="$MOSAIC_HOME" \ MOSAIC_PREFIX="$PREFIX" \ MOSAIC_NO_COLOR=1 \ MOSAIC_TEST_NPM_LOG="$LOG" \ MOSAIC_TEST_STATE="$STATE" \ PATH="$FAKE_BIN:$PATH" \ bash "$ROOT/tools/install.sh" --check --cli --next --ref feature-x )" grep -qF 'explicit ref wins, build-from-source' <<<"$OUTPUT" if grep -qF '@next version' "$LOG"; then echo "explicit ref should not query @next dist-tags" >&2 exit 1 fi reset_state echo "[test] --check --next warns on mismatched prerelease pipeline suffixes" OUTPUT="$( HOME="$HOME_DIR" \ MOSAIC_HOME="$MOSAIC_HOME" \ MOSAIC_PREFIX="$PREFIX" \ MOSAIC_NO_COLOR=1 \ MOSAIC_TEST_NPM_LOG="$LOG" \ MOSAIC_TEST_STATE="$STATE" \ MOSAIC_TEST_GATEWAY_NEXT_VERSION="0.0.7-next.1000" \ PATH="$FAKE_BIN:$PATH" \ bash "$ROOT/tools/install.sh" --check --cli --next )" grep -qF '@next registry lane incomplete, mismatched, or unreachable; --next would fall back to source.' <<<"$OUTPUT" echo "[test] installer next lane tests passed"