diff --git a/build-aux/smoketest.sh b/build-aux/smoketest.sh new file mode 100755 index 00000000..e58aad87 --- /dev/null +++ b/build-aux/smoketest.sh @@ -0,0 +1,217 @@ +#!/bin/sh +# Copyright (c) 2022 Jonas 'Sortie' Termansen. +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +# +# smoketest.sh +# Test an .iso release boots and passes rudimentary tests. + +set -e + +unset display +display="-display none" +unset enable_kvm +unset host +unset hostname +hostname=smoketest +unset iso +unset port +unset qemu +unset vm_root + +dashdash= +previous_option= +for argument do + if [ -n "$previous_option" ]; then + eval $previous_option=\$argument + previous_option= + continue + fi + + case $argument in + *=?*) parameter=$(expr "X$argument" : '[^=]*=\(.*\)' || true) ;; + *=) parameter= ;; + *) parameter=yes ;; + esac + + case $dashdash$argument in + --) dashdash=yes ;; + --display=*) display=$parameter ;; + --display) previous_option=display ;; + --enable-kvm) enable_kvm=-enable-kvm ;; + --host=*) host=$parameter ;; + --host) previous_option=host ;; + --hostname=*) hostname=$parameter ;; + --hostname) previous_option=hostname ;; + --iso=*) iso=$parameter ;; + --iso) previous_option=iso ;; + --port=*) port=$parameter ;; + --port) previous_option=port ;; + --qemu=*) qemu=$parameter ;; + --qemu) previous_option=qemu ;; + --vm-root=*) vm_root=$parameter ;; + --vm-root) previous_option=vm_root ;; + -*) echo "$0: unrecognized option $argument" >&2 + exit 1 ;; + *) + echo "$0: unexpected extra operand $argument" >&2 + exit 1 + ;; + esac +done + +if [ -n "$previous_option" ]; then + echo "$0: option '$argument' requires an argument" >&2 + exit 1 +fi + +if [ -z "$host" ]; then + echo "$0: error: No --host was specified" >&2 + exit 1 +fi + +if [ -z "$iso" ]; then + echo "$0: error: No --iso was specified" >&2 + exit 1 +fi +iso=$(realpath -- "$iso") + +if [ -z "$port" ]; then + echo "$0: error: No --port was specified" >&2 + exit 1 +fi + +if [ -z "$qemu" ]; then + case "$host" in + i[3456]86-*) qemu=qemu-system-i386;; + x86_64-*) qemu=qemu-system-x86_64;; + *) echo "$0: error: Unable to detect qemu program for: $HOST" >&2 + exit 1 + esac +fi + +set -x + +unset tmpdir +# Reclaim a persistent VM directory (if any) and kill any leaked processes. +if [ -n "$vm_root" ]; then + unset tmpdir + export TMPDIR="$vm_root/$hostname" + mkdir -p -- "$TMPDIR" + if [ -e "$TMPDIR/pid" ]; then + kill -KILL "$(cat "$TMPDIR/pid")" || true + fi + rm -rf -- "$TMPDIR"/* +# Otherwise use a temporary directory that will be deleted upon completion. +else + export TMPDIR=$(mktemp -d -t "$hostname.vm.XXXXXXXXX") + tmpdir="$TMPDIR" +fi + +# On exit, power off the virtual machine and clean up the working directory. +unset vmpid +cleanup_tmpdir() { + if [ -n "$vmpid" ]; then + kill -KILL $vmpid || true + fi + rm -f "$TMPDIR/pid" + if [ -n "$tmpdir" ]; then + rm -rf -- "$tmpdir" + elif [ -n "$TMPDIR" ]; then + rm -rf -- "$TMPDIR"/* + fi +} +trap cleanup_tmpdir EXIT HUP INT QUIT +cd "$TMPDIR" + +# Configure the ssh authentication and enabling sshd. +ssh-keygen -f id_rsa -N '' +rm -rf liveconfig bootconfig +tix-iso-liveconfig \ + --hostname="$hostname" \ + --root-ssh-authorized-keys=id_rsa.pub \ + --sshd-keygen \ + --sshd-key-known-hosts-file=sortix.iso.known_hosts \ + --sshd-key-known-hosts-hosts='localhost 127.0.0.1' \ + liveconfig +mkdir -p liveconfig/etc liveconfig/etc/init +cat > liveconfig/etc/init/local << EOF +require sshd optional +EOF +tix-iso-bootconfig \ + --random-seed \ + --timeout=0 \ + --disable-gui \ + --liveconfig=liveconfig \ + bootconfig +mkdir -p bootconfig/boot/grub +cat >> bootconfig/boot/grub/hooks.cfg << EOF +select_ports_set_no +port_binutils=true +port_dash=true +port_gcc=true +port_grep=true +port_make=true +port_sed=true +port_ssh=true +EOF +tix-iso-add "$iso" bootconfig -o sortix.iso + +# Spawn the virtual machine in the background. +$qemu \ + $enable_kvm \ + -name "$hostname" \ + -nodefaults \ + $display \ + -m 256 \ + -vga std \ + -boot d \ + -cdrom sortix.iso \ + -device e1000,netdev=net0 \ + -netdev user,id=net0,hostfwd=tcp:127.0.0.1:$port-:22 & +vmpid=$! +echo $vmpid > pid + +# Wait for the virtual machine to boot to sshd. +do_ssh() { + ssh \ + -i id_rsa \ + -oUserKnownHostsFile=sortix.iso.known_hosts \ + -oConnectionAttempts=30 \ + -p $port \ + root@localhost \ + "$@" +} +retries=30 +while true; do + if ! do_ssh 'uname -a'; then + if [ $retries = 1 ]; then + exit 1 + fi + sleep 1 + if ! kill -WINCH "$vmpid"; then + unset vmpid + rm -f "$TMPDIR/pid" + exit 1 + fi + retries=$(expr $retries - 1) + continue + fi + break +done + +# Test for smoke. +do_ssh 'regress' +do_ssh 'cd /src/editor && make' +do_ssh '! grep -Ei "failed|exited unsuccessfully" /var/log/init.log' +do_ssh 'memstat -a && df -h'