feat: initial commit — void-installer multi-profile (stable-cinnamon + mainline-niri)
This commit is contained in:
242
tests/run-qemu-test.sh
Executable file
242
tests/run-qemu-test.sh
Executable file
@@ -0,0 +1,242 @@
|
||||
#!/bin/bash
|
||||
# Automated headless QEMU smoke test for the Void installer.
|
||||
#
|
||||
# Workflow:
|
||||
# 1. Build (or reuse) a TEST variant of the ISO with UNATTENDED=1 +
|
||||
# TEST_MODE=1 and our test pubkey baked in for moze@.
|
||||
# 2. Build a fresh test disk image mimicking the XPS 17 layout.
|
||||
# 3. Boot the ISO under QEMU/OVMF; installer runs unattended; VM powers off.
|
||||
# 4. Boot the installed disk; ssh in as moze; run smoke checks.
|
||||
|
||||
set -Eeuo pipefail
|
||||
|
||||
PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
OUT_DIR="$PROJECT_DIR/out"
|
||||
LOG_DIR="$OUT_DIR/qemu-logs"
|
||||
mkdir -p "$OUT_DIR" "$LOG_DIR"
|
||||
|
||||
QEMU="${QEMU:-qemu-system-x86_64}"
|
||||
OVMF_CODE="${OVMF_CODE:-}"
|
||||
OVMF_VARS_TPL="${OVMF_VARS_TPL:-}"
|
||||
RAM_MB="${RAM_MB:-4096}"
|
||||
SMP="${SMP:-4}"
|
||||
SSH_PORT="${SSH_PORT:-2222}"
|
||||
TIMEOUT_INSTALL="${TIMEOUT_INSTALL:-3600}"
|
||||
TIMEOUT_BOOT="${TIMEOUT_BOOT:-300}"
|
||||
ACCEL="${ACCEL:-kvm:tcg}"
|
||||
|
||||
# Auto-detect OVMF paths.
|
||||
for c in /usr/share/OVMF/OVMF_CODE.fd /usr/share/edk2-ovmf/x64/OVMF_CODE.fd \
|
||||
/usr/share/edk2/x64/OVMF_CODE.fd /usr/share/qemu/OVMF_CODE.fd; do
|
||||
[[ -z "$OVMF_CODE" && -r "$c" ]] && OVMF_CODE="$c"
|
||||
done
|
||||
for v in /usr/share/OVMF/OVMF_VARS.fd /usr/share/edk2-ovmf/x64/OVMF_VARS.fd \
|
||||
/usr/share/edk2/x64/OVMF_VARS.fd /usr/share/qemu/OVMF_VARS.fd; do
|
||||
[[ -z "$OVMF_VARS_TPL" && -r "$v" ]] && OVMF_VARS_TPL="$v"
|
||||
done
|
||||
[[ -r "$OVMF_CODE" ]] || { echo "OVMF_CODE not found"; exit 1; }
|
||||
[[ -r "$OVMF_VARS_TPL" ]] || { echo "OVMF_VARS not found"; exit 1; }
|
||||
|
||||
red() { printf '\033[31m%s\033[0m\n' "$*" >&2; }
|
||||
green() { printf '\033[32m%s\033[0m\n' "$*"; }
|
||||
blue() { printf '\033[34m==> %s\033[0m\n' "$*"; }
|
||||
|
||||
# ---------- 0) start xbps caching proxy ----------
|
||||
blue "starting XBPS caching proxy"
|
||||
"$PROJECT_DIR/tools/start-xbps-proxy.sh"
|
||||
PIDFILE="$OUT_DIR/qemu.pid"
|
||||
cleanup_all() {
|
||||
# Kill any QEMU started by this run (pidfile + name fallback).
|
||||
[[ -f "$PIDFILE" ]] && kill "$(cat "$PIDFILE")" 2>/dev/null || true
|
||||
rm -f "$PIDFILE"
|
||||
# Defensive: kill any lingering qemu by our unique -name tags.
|
||||
pkill -f 'qemu-system.*void-install(er-test|ed-test)' 2>/dev/null || true
|
||||
"$PROJECT_DIR/tools/stop-xbps-proxy.sh" 2>/dev/null || true
|
||||
}
|
||||
trap cleanup_all EXIT INT TERM
|
||||
|
||||
# ---------- 1) test ssh keypair ----------
|
||||
TEST_KEY="$OUT_DIR/id_test"
|
||||
if [[ ! -f "$TEST_KEY" ]]; then
|
||||
blue "generating test ssh keypair"
|
||||
ssh-keygen -t ed25519 -N '' -C 'qemu-test' -f "$TEST_KEY" >/dev/null
|
||||
fi
|
||||
TEST_PUBKEY=$(cat "${TEST_KEY}.pub")
|
||||
export TEST_PUBKEY
|
||||
|
||||
# ---------- 2) build TEST ISO ----------
|
||||
TEST_ISO="$OUT_DIR/void-install-TEST.iso"
|
||||
TEST_OVERLAY_DIR="$OUT_DIR/test-overlay"
|
||||
"$PROJECT_DIR/tests/lib/make-test-overlay.sh" "$TEST_OVERLAY_DIR"
|
||||
|
||||
if [[ ! -f "$TEST_ISO" || -n "${REBUILD_ISO:-}" ]]; then
|
||||
blue "building test ISO -> $TEST_ISO"
|
||||
EXTRA_INCLUDE_DIR="$TEST_OVERLAY_DIR" \
|
||||
OUTPUT_ISO="$TEST_ISO" \
|
||||
INSTALL_REPO_URL="http://10.0.2.2:3142/current" \
|
||||
BOOT_CMDLINE="console=tty0 console=ttyS0,115200" \
|
||||
"$PROJECT_DIR/iso/build-iso.sh"
|
||||
else
|
||||
blue "reusing cached test ISO $TEST_ISO (set REBUILD_ISO=1 to rebuild)"
|
||||
fi
|
||||
|
||||
# ---------- 3) test disk ----------
|
||||
DISK="$OUT_DIR/test-disk.img"
|
||||
blue "creating fresh test disk -> $DISK"
|
||||
"$PROJECT_DIR/tests/make-test-disk.sh" "$DISK"
|
||||
|
||||
# ---------- 4) OVMF VARS copy ----------
|
||||
VARS="$OUT_DIR/OVMF_VARS.fd"
|
||||
cp "$OVMF_VARS_TPL" "$VARS"
|
||||
|
||||
# ---------- 5) install phase ----------
|
||||
blue "boot ISO + run installer (timeout ${TIMEOUT_INSTALL}s)"
|
||||
SERIAL_LOG="$LOG_DIR/install.serial.log"
|
||||
: > "$SERIAL_LOG"
|
||||
|
||||
set +e
|
||||
timeout "$TIMEOUT_INSTALL" "$QEMU" \
|
||||
-name void-installer-test \
|
||||
-machine q35,accel="$ACCEL" \
|
||||
-cpu max \
|
||||
-m "$RAM_MB" \
|
||||
-smp "$SMP" \
|
||||
-display none \
|
||||
-monitor none \
|
||||
-serial "file:$SERIAL_LOG" \
|
||||
-drive "if=pflash,format=raw,readonly=on,file=$OVMF_CODE" \
|
||||
-drive "if=pflash,format=raw,file=$VARS" \
|
||||
-drive "if=virtio,file=$DISK,format=raw,cache=none" \
|
||||
-cdrom "$TEST_ISO" \
|
||||
-boot order=d,menu=off \
|
||||
-netdev user,id=n0 -device virtio-net-pci,netdev=n0 \
|
||||
-no-reboot
|
||||
RC=$?
|
||||
set -e
|
||||
blue "install QEMU exited rc=$RC"
|
||||
|
||||
if ! grep -q 'Installation complete' "$SERIAL_LOG"; then
|
||||
echo "------ tail of $SERIAL_LOG ------" >&2
|
||||
tail -200 "$SERIAL_LOG" >&2 || true
|
||||
red "installer did not report 'Installation complete'"; exit 1
|
||||
fi
|
||||
green "installer reported success"
|
||||
|
||||
# ---------- 6) boot installed system ----------
|
||||
blue "boot installed system, ssh on 127.0.0.1:$SSH_PORT"
|
||||
BOOT_LOG="$LOG_DIR/boot.serial.log"
|
||||
: > "$BOOT_LOG"
|
||||
|
||||
"$QEMU" \
|
||||
-name void-installed-test \
|
||||
-machine q35,accel="$ACCEL" \
|
||||
-cpu max \
|
||||
-m "$RAM_MB" \
|
||||
-smp "$SMP" \
|
||||
-display none \
|
||||
-serial "file:$BOOT_LOG" \
|
||||
-drive "if=pflash,format=raw,readonly=on,file=$OVMF_CODE" \
|
||||
-drive "if=pflash,format=raw,file=$VARS" \
|
||||
-drive "if=virtio,file=$DISK,format=raw,cache=none" \
|
||||
-netdev "user,id=n0,hostfwd=tcp:127.0.0.1:$SSH_PORT-:22" \
|
||||
-device virtio-net-pci,netdev=n0 \
|
||||
-daemonize \
|
||||
-pidfile "$PIDFILE"
|
||||
|
||||
blue "waiting for sshd"
|
||||
SSH_READY=0
|
||||
for i in $(seq 1 "$TIMEOUT_BOOT"); do
|
||||
if ssh -i "$TEST_KEY" -o StrictHostKeyChecking=no \
|
||||
-o UserKnownHostsFile=/dev/null \
|
||||
-o ConnectTimeout=2 -o BatchMode=yes \
|
||||
-p "$SSH_PORT" moze@127.0.0.1 true 2>/dev/null; then
|
||||
SSH_READY=1
|
||||
green "ssh reachable after ${i}s"
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
if [[ $SSH_READY -ne 1 ]]; then
|
||||
tail -200 "$BOOT_LOG" >&2 || true
|
||||
red "sshd never came up"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ---------- 7) smoke checks ----------
|
||||
blue "running smoke tests"
|
||||
SSHCMD=(ssh -i "$TEST_KEY" -o StrictHostKeyChecking=no
|
||||
-o UserKnownHostsFile=/dev/null -p "$SSH_PORT" moze@127.0.0.1)
|
||||
|
||||
FAILED=0
|
||||
assert() {
|
||||
local desc="$1"; shift
|
||||
if "${SSHCMD[@]}" "$@" >/dev/null 2>&1; then
|
||||
green " ok $desc"
|
||||
else
|
||||
red " FAIL $desc"
|
||||
FAILED=$((FAILED+1))
|
||||
fi
|
||||
}
|
||||
|
||||
assert "/ on btrfs subvol=@" "findmnt -no FSTYPE,OPTIONS / | grep -q 'subvol=/@'"
|
||||
assert "user moze in wheel" "id -nG moze | tr ' ' '\\n' | grep -qx wheel"
|
||||
assert "user moze in docker" "id -nG moze | tr ' ' '\\n' | grep -qx docker"
|
||||
assert "sudo via wheel" "sudo -n -l | grep -q 'ALL'"
|
||||
assert "cinnamon-session present" "command -v cinnamon-session"
|
||||
assert "lightdm enabled" "test -L /var/service/lightdm"
|
||||
assert "docker enabled" "test -L /var/service/docker"
|
||||
assert "vscode (code) installed" "command -v code"
|
||||
assert "nvidia kmod metadata" "modinfo nvidia"
|
||||
assert ".ssh dir mode 700" "test \$(stat -c '%a' /home/moze/.ssh) = 700"
|
||||
assert "id_github private key" "test -f /home/moze/.ssh/id_github"
|
||||
assert "ssh config copied" "test -f /home/moze/.ssh/config"
|
||||
assert "EFI vfat mounted" "findmnt -no FSTYPE /boot/efi | grep -q vfat"
|
||||
assert "EFI/Microsoft preserved" "test -f /boot/efi/EFI/Microsoft/Boot/bootmgfw.efi"
|
||||
assert "GRUB has Void entry" "sudo -n grep -q -i 'Void' /boot/grub/grub.cfg"
|
||||
assert "nix-daemon running" "pgrep -x nix-daemon"
|
||||
assert "zram swap active" "swapon --show=NAME --noheadings | grep -q '^/dev/zram'"
|
||||
assert "hostname is xps9700" "test \$(hostname) = xps9700"
|
||||
assert "timezone is Europe/Zurich" "readlink /etc/localtime | grep -q 'Europe/Zurich'"
|
||||
assert "keymap ch-fr_nodeadkeys" "grep -q 'ch-fr_nodeadkeys' /etc/rc.conf"
|
||||
assert "alacritty installed" "command -v alacritty"
|
||||
assert "no firefox installed" "! command -v firefox"
|
||||
assert "gruvbox theme present" "ls -d /usr/share/themes/Gruvbox* >/dev/null 2>&1"
|
||||
assert "gruvbox-dark exact" "test -d /usr/share/themes/Gruvbox-Dark"
|
||||
assert "gruvbox icons present" "ls -d /usr/share/icons/Gruvbox-Plus-Dark >/dev/null 2>&1"
|
||||
assert "bibata cursor present" "test -d /usr/share/icons/Bibata-Modern-Ice"
|
||||
assert "dconf cursor=bibata" "grep -q \"cursor-theme='Bibata-Modern-Ice'\" /etc/dconf/db/local.d/00-cinnamon"
|
||||
assert "dconf gtk=Gruvbox-Dark" "grep -q \"gtk-theme='Gruvbox-Dark'\" /etc/dconf/db/local.d/00-cinnamon"
|
||||
assert "wallpapers deployed" "test -f /usr/share/backgrounds/void-installer/pxfuel.jpg"
|
||||
assert "user .bashrc deployed" "grep -q 'NVM_DIR' /home/moze/.bashrc"
|
||||
assert "vscode settings deployed" "test -f /home/moze/.config/Code/User/settings.json"
|
||||
assert "X11 keymap pinned ch(fr)" "grep -q 'XkbLayout.*ch' /etc/X11/xorg.conf.d/00-keyboard.conf"
|
||||
assert "dconf cinnamon defaults" "test -f /etc/dconf/db/local.d/00-cinnamon"
|
||||
assert "first-login script staged" "test -x /usr/local/libexec/first-login.sh"
|
||||
assert "first-login autostart" "test -f /etc/xdg/autostart/void-installer-first-login.desktop"
|
||||
assert "local-bin profile.d" "test -f /etc/profile.d/local-bin.sh"
|
||||
assert "claude installer used" "grep -q 'claude.ai/install.sh' /usr/local/libexec/first-login.sh"
|
||||
assert "nix unfree allowed" "grep -q 'NIXPKGS_ALLOW_UNFREE' /usr/local/libexec/first-boot-nix.sh"
|
||||
assert "vscode-extensions list" "test -f /etc/installer-vscode-extensions.txt"
|
||||
assert "cups installed" "command -v cupsd"
|
||||
assert "cups service enabled" "test -L /etc/runit/runsvdir/default/cupsd"
|
||||
assert "timeshift installed" "command -v timeshift"
|
||||
assert "flameshot installed" "command -v flameshot"
|
||||
assert "libinput-gestures present" "command -v libinput-gestures"
|
||||
assert "gestures default config" "test -f /etc/skel/.config/libinput-gestures.conf"
|
||||
assert "btrfs snapshot hook" "test -x /usr/local/sbin/xbps-pre-upgrade-snapshot.sh"
|
||||
assert "xbps-install wrapper" "test -x /usr/local/bin/xbps-install"
|
||||
assert "void-upgrade GUI" "test -x /usr/local/bin/void-upgrade-gui"
|
||||
assert "void-upgrade .desktop" "test -f /usr/share/applications/void-upgrade.desktop"
|
||||
assert "Print Screen -> flameshot" "grep -q 'Print' /etc/dconf/db/local.d/00-cinnamon"
|
||||
assert "tray applets configured" "grep -q 'systray@cinnamon.org' /etc/dconf/db/local.d/00-cinnamon"
|
||||
assert "Nemo VS Code action" "test -f /usr/share/nemo/actions/open-vscode.nemo_action"
|
||||
|
||||
cleanup_all
|
||||
echo
|
||||
if [[ $FAILED -eq 0 ]]; then
|
||||
green "ALL SMOKE TESTS PASSED"
|
||||
exit 0
|
||||
else
|
||||
red "$FAILED smoke test(s) failed"
|
||||
exit 1
|
||||
fi
|
||||
Reference in New Issue
Block a user