Files
ServerKit/scripts/test/vm-install.sh
T
Juan DenisandClaude Opus 4.7 099c61d859 Make E2E test harness actually run end-to-end on Windows
Fixes a cascade of PowerShell + Multipass quirks found during the first
real run:

- Rewrote orchestrator sequentially. Start-Job's separate runspace was
  hiding the real errors below behind opaque "method on null" failures.
- Removed `function Mp` helper. PowerShell ships a built-in alias `mp`
  for Move-ItemProperty that silently shadows same-named functions and
  turned multipass calls into Move-ItemProperty calls. Inline `& $MpExe`
  everywhere instead.
- Lowered ErrorActionPreference from Stop to Continue. Multipass writes
  harmless "cannot set permissions" warnings to stderr when transferring
  to NTFS; Stop turned those into fatal aborts.
- Stopped piping `multipass exec` stdout through Tee-Object. The pipe
  could stay open indefinitely after the remote command exited, hanging
  the orchestrator for 45+ min on a finished install. Now redirects to a
  file on the VM and only checks the exit code.
- Tightened tar excludes. Tarball dropped from 305 MB to 20 MB.
- Added `npm ci` in vm-install.sh after the local-code overlay. The
  original installer ran `npm ci` from origin/main, then the overlay
  dropped in a dev package.json that needed different deps, causing a
  spurious frontend build failure.
- Added -ReuseVm flag for re-running just the harness against an
  already-installed VM (skips the 20-min launch cost).

First successful end-to-end run on Ubuntu 24.04: 10/10 tests passed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 00:14:59 -04:00

87 lines
3.2 KiB
Bash

#!/bin/bash
# Runs inside the test VM.
# Strategy:
# 1. Run install.sh from the uploaded local source (so it bootstraps deps).
# 2. After install, replace /opt/serverkit with the uploaded local working
# tree (overlay), rebuild frontend, reinstall Python deps, restart.
# 3. Probe health endpoint and exit non-zero if anything failed.
#
# This way we test the EXACT local code, including uncommitted changes,
# instead of whatever is on origin/main.
set -u # NB: not -e — we want to capture failures and still emit a report
SRC=/opt/serverkit-src
INSTALL_DIR=/opt/serverkit
LOG=/var/log/serverkit-test-install.log
log() { echo "[vm-install] $*" | tee -a "$LOG"; }
fail() { echo "[vm-install] FAIL: $*" | tee -a "$LOG"; exit 1; }
mkdir -p "$(dirname "$LOG")"
: > "$LOG"
[ -d "$SRC" ] || fail "source dir $SRC missing — multipass transfer broken"
[ -f "$SRC/install.sh" ] || fail "install.sh not found in source"
log "Step 1/4: running install.sh (this clones origin/main, installs deps)"
# install.sh clones from GitHub — we let it, then overlay our local code.
bash "$SRC/install.sh" >> "$LOG" 2>&1
INSTALL_RC=$?
log "install.sh exit=$INSTALL_RC"
if [ ! -d "$INSTALL_DIR" ]; then
fail "install.sh did not create $INSTALL_DIR (rc=$INSTALL_RC)"
fi
log "Step 2/4: overlaying local working tree onto $INSTALL_DIR"
# Preserve .env / instance / nginx ssl from the install
rsync -a \
--exclude='.env' \
--exclude='backend/instance/' \
--exclude='nginx/ssl/' \
--exclude='backend/venv/' \
--exclude='backend/.venv/' \
--exclude='backend/.venv-wsl/' \
--exclude='frontend/node_modules/' \
--exclude='frontend/dist/' \
--exclude='.git/' \
"$SRC/" "$INSTALL_DIR/" >> "$LOG" 2>&1 || fail "rsync overlay failed"
log "Step 3/4: rebuild + restart with local code"
cd "$INSTALL_DIR" || fail "cd $INSTALL_DIR"
# Reinstall Python deps in case requirements.txt changed
if [ -d "$INSTALL_DIR/venv" ]; then
"$INSTALL_DIR/venv/bin/pip" install -r "$INSTALL_DIR/backend/requirements.txt" >> "$LOG" 2>&1 \
|| log "WARN: pip install had non-zero exit"
fi
# Reinstall + rebuild frontend (package.json may have changed in the overlay)
cd "$INSTALL_DIR/frontend" || fail "cd frontend"
npm ci --prefer-offline >> "$LOG" 2>&1 || fail "npm ci failed"
NODE_OPTIONS="--max-old-space-size=1024" npm run build >> "$LOG" 2>&1 \
|| fail "frontend build failed"
cd "$INSTALL_DIR" || true
docker compose build >> "$LOG" 2>&1 || log "WARN: docker compose build had non-zero exit"
docker compose up -d >> "$LOG" 2>&1 || log "WARN: docker compose up had non-zero exit"
systemctl restart serverkit >> "$LOG" 2>&1 || fail "systemctl restart serverkit failed"
systemctl restart nginx >> "$LOG" 2>&1 || log "WARN: nginx restart had non-zero exit"
log "Step 4/4: waiting for health endpoint"
for i in $(seq 1 30); do
if curl -fsS http://127.0.0.1:5000/api/v1/system/health > /dev/null 2>&1; then
log "Backend healthy after ${i}s"
echo "OK" > /tmp/serverkit-install-status
exit 0
fi
sleep 1
done
log "Backend never became healthy"
systemctl status serverkit --no-pager >> "$LOG" 2>&1 || true
journalctl -u serverkit --no-pager -n 100 >> "$LOG" 2>&1 || true
echo "FAIL" > /tmp/serverkit-install-status
exit 1