- CU-07-01: install.sh gains --yes/--no-auto-launch flags; on first install with a TTY, auto-launches mosaic wizard then mosaic gateway install before the summary. Non-interactive / --no-auto-launch falls back to guidance text. - CU-07-02: wizard writes transient session state to $XDG_RUNTIME_DIR/ mosaic-install-state.json on completion; gateway install reads it on startup, announces the resume, and applies mosaicHome for custom-home installs. State is cleared on successful gateway install. - CU-07-03: new packages/mosaic/src/commands/gateway/verify.ts exports runPostInstallVerification() (3 checks: gateway /health, admin token on file, /api/bootstrap/status). Called at end of runInstall. Registered as mosaic gateway verify subcommand. fetchWithRetry retries non-OK responses to handle startup races. - CU-07-04: tools/e2e-install-test.sh — Docker-based e2e harness that runs the full install.sh -> wizard -> gateway install -> verify flow in a clean node:22-alpine container. Skips gracefully if Docker is unavailable. Gateway verify step skips with explanation when the published CLI pre-dates the new command (expected until next release). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
185 lines
7.3 KiB
Bash
Executable File
185 lines
7.3 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# ─── Mosaic Stack — End-to-End Install Test ────────────────────────────────────
|
|
#
|
|
# Runs a clean-container install test to verify the full first-run flow:
|
|
# tools/install.sh -> mosaic wizard (non-interactive)
|
|
# -> mosaic gateway install
|
|
# -> mosaic gateway verify
|
|
#
|
|
# Usage:
|
|
# bash tools/e2e-install-test.sh
|
|
#
|
|
# Requirements:
|
|
# - Docker (skips gracefully if not available)
|
|
# - Run from the repository root
|
|
#
|
|
# How it works:
|
|
# 1. Mounts the repository into a node:22-alpine container.
|
|
# 2. Installs prerequisites (bash, curl, jq, git) inside the container.
|
|
# 3. Runs `bash tools/install.sh --yes --no-auto-launch` to install the
|
|
# framework and CLI from the Gitea registry.
|
|
# 4. Runs `mosaic wizard --non-interactive` to set up SOUL/USER.
|
|
# 5. Runs `mosaic gateway install` with piped defaults (non-interactive).
|
|
# 6. Runs `mosaic gateway verify` and checks its exit code.
|
|
# NOTE: `mosaic gateway verify` is a new command added in the
|
|
# feat/mosaic-first-run-ux branch. If the installed CLI version
|
|
# pre-dates this branch (does not have `gateway verify`), the test
|
|
# marks this step as EXPECTED-SKIP and reports the installed version.
|
|
# 7. Reports PASS or FAIL with a summary.
|
|
#
|
|
# To run manually:
|
|
# cd /path/to/mosaic-stack
|
|
# bash tools/e2e-install-test.sh
|
|
#
|
|
# ──────────────────────────────────────────────────────────────────────────────
|
|
|
|
set -euo pipefail
|
|
|
|
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
IMAGE="node:22-alpine"
|
|
CONTAINER_NAME="mosaic-e2e-install-$$"
|
|
|
|
# ─── Colour helpers ───────────────────────────────────────────────────────────
|
|
if [[ -t 1 ]]; then
|
|
R=$'\033[0;31m' G=$'\033[0;32m' Y=$'\033[0;33m' BOLD=$'\033[1m' RESET=$'\033[0m'
|
|
else
|
|
R="" G="" Y="" BOLD="" RESET=""
|
|
fi
|
|
|
|
info() { echo "${BOLD}[e2e]${RESET} $*"; }
|
|
ok() { echo "${G}[PASS]${RESET} $*"; }
|
|
fail() { echo "${R}[FAIL]${RESET} $*" >&2; }
|
|
warn() { echo "${Y}[WARN]${RESET} $*"; }
|
|
|
|
# ─── Docker availability check ────────────────────────────────────────────────
|
|
if ! command -v docker &>/dev/null; then
|
|
warn "Docker not found — skipping e2e install test."
|
|
warn "Install Docker and re-run this script to exercise the full install flow."
|
|
exit 0
|
|
fi
|
|
|
|
if ! docker info &>/dev/null 2>&1; then
|
|
warn "Docker daemon is not running or not accessible — skipping e2e install test."
|
|
exit 0
|
|
fi
|
|
|
|
info "Docker available — proceeding with e2e install test."
|
|
info "Repo root: ${REPO_ROOT}"
|
|
info "Container image: ${IMAGE}"
|
|
|
|
# ─── Inline script that runs INSIDE the container ────────────────────────────
|
|
INNER_SCRIPT="$(mktemp /tmp/mosaic-e2e-inner-XXXXXX.sh)"
|
|
trap 'rm -f "$INNER_SCRIPT"' EXIT
|
|
|
|
cat > "$INNER_SCRIPT" <<'INNER_SCRIPT_EOF'
|
|
#!/bin/sh
|
|
# Bootstrap: /bin/sh until bash is installed, then re-exec.
|
|
set -e
|
|
|
|
echo "=== [inner] Installing system prerequisites ==="
|
|
apk add --no-cache bash curl jq git 2>/dev/null || \
|
|
apt-get install -y -q bash curl jq git 2>/dev/null || true
|
|
|
|
# Re-exec under bash.
|
|
if [ -z "${BASH_VERSION:-}" ] && command -v bash >/dev/null 2>&1; then
|
|
exec bash "$0" "$@"
|
|
fi
|
|
|
|
# ── bash from here ────────────────────────────────────────────────────────────
|
|
set -euo pipefail
|
|
|
|
echo "=== [inner] Node.js / npm versions ==="
|
|
node --version
|
|
npm --version
|
|
|
|
echo "=== [inner] Setting up npm global prefix ==="
|
|
export NPM_PREFIX="/root/.npm-global"
|
|
mkdir -p "$NPM_PREFIX/bin"
|
|
npm config set prefix "$NPM_PREFIX" 2>/dev/null || true
|
|
export PATH="$NPM_PREFIX/bin:$PATH"
|
|
|
|
echo "=== [inner] Running install.sh --yes --no-auto-launch ==="
|
|
# Install both framework and CLI from the Gitea registry.
|
|
MOSAIC_SKIP_SKILLS_SYNC=1 \
|
|
MOSAIC_ASSUME_YES=1 \
|
|
bash /repo/tools/install.sh --yes --no-auto-launch
|
|
|
|
INSTALLED_VERSION="$(mosaic --version 2>/dev/null || echo 'unknown')"
|
|
echo "[inner] mosaic CLI installed: ${INSTALLED_VERSION}"
|
|
|
|
echo "=== [inner] Running mosaic wizard (non-interactive) ==="
|
|
mosaic wizard \
|
|
--non-interactive \
|
|
--name "test-agent" \
|
|
--user-name "tester" \
|
|
--pronouns "they/them" \
|
|
--timezone "UTC" || {
|
|
echo "[WARN] mosaic wizard exited non-zero — continuing"
|
|
}
|
|
|
|
echo "=== [inner] Running mosaic gateway install ==="
|
|
# Feed non-interactive answers:
|
|
# "1" → storage tier: local
|
|
# "" → port: accept default (14242)
|
|
# "" → ANTHROPIC_API_KEY: skip
|
|
# "" → CORS origin: accept default
|
|
# Then admin bootstrap: name, email, password
|
|
printf '1\n\n\n\nTest Admin\ntest@example.com\ntestpassword123\n' \
|
|
| mosaic gateway install
|
|
INSTALL_EXIT="$?"
|
|
if [ "${INSTALL_EXIT}" -ne 0 ]; then
|
|
echo "[ERR] mosaic gateway install exited ${INSTALL_EXIT}"
|
|
mosaic gateway status 2>/dev/null || true
|
|
exit "${INSTALL_EXIT}"
|
|
fi
|
|
|
|
echo "=== [inner] Running mosaic gateway verify ==="
|
|
# `gateway verify` was added in feat/mosaic-first-run-ux.
|
|
# If the installed version pre-dates this, skip gracefully.
|
|
if ! mosaic gateway --help 2>&1 | grep -q 'verify'; then
|
|
echo "[SKIP] 'mosaic gateway verify' not available in installed version ${INSTALLED_VERSION}."
|
|
echo "[SKIP] This command was added in the feat/mosaic-first-run-ux release."
|
|
echo "[SKIP] Re-run after the new version is published to validate this step."
|
|
# Treat as pass — the install flow itself worked.
|
|
exit 0
|
|
fi
|
|
|
|
mosaic gateway verify
|
|
VERIFY_EXIT="$?"
|
|
echo "=== [inner] verify exit code: ${VERIFY_EXIT} ==="
|
|
exit "${VERIFY_EXIT}"
|
|
INNER_SCRIPT_EOF
|
|
|
|
chmod +x "$INNER_SCRIPT"
|
|
|
|
# ─── Pull image ───────────────────────────────────────────────────────────────
|
|
info "Pulling ${IMAGE}…"
|
|
docker pull "${IMAGE}" --quiet
|
|
|
|
# ─── Run container ────────────────────────────────────────────────────────────
|
|
info "Starting container ${CONTAINER_NAME}…"
|
|
|
|
EXIT_CODE=0
|
|
docker run --rm \
|
|
--name "${CONTAINER_NAME}" \
|
|
--volume "${REPO_ROOT}:/repo:ro" \
|
|
--volume "${INNER_SCRIPT}:/e2e-inner.sh:ro" \
|
|
--network host \
|
|
"${IMAGE}" \
|
|
/bin/sh /e2e-inner.sh \
|
|
|| EXIT_CODE=$?
|
|
|
|
# ─── Report ───────────────────────────────────────────────────────────────────
|
|
echo ""
|
|
if [[ "$EXIT_CODE" -eq 0 ]]; then
|
|
ok "End-to-end install test PASSED (exit ${EXIT_CODE})"
|
|
else
|
|
fail "End-to-end install test FAILED (exit ${EXIT_CODE})"
|
|
echo ""
|
|
echo " Troubleshooting:"
|
|
echo " - Review the output above for the failing step."
|
|
echo " - Re-run with bash -x tools/e2e-install-test.sh for verbose trace."
|
|
echo " - Run mosaic gateway logs inside a manual container for daemon output."
|
|
exit 1
|
|
fi
|