travis: run tests from inside VM + support test execution outside of Travis CI
[grml-debootstrap.git] / travis / execute.sh
index 52e3d26..77016ea 100755 (executable)
 #!/bin/bash
 
 set -eu -o pipefail
+set -x
+
+if [ -z "${TRAVIS:-}" ] ; then
+  echo "Running outside of Travis."
+
+  if [ "$#" -ne 1 ] ; then
+    echo "Usage: $(basename "$0") ./grml-debootstrap*.deb" >&2
+    exit 1
+  else
+    GRML_DEBOOTSTRAP_DEB="$1"
+    if [ "$(dirname "$(realpath "$GRML_DEBOOTSTRAP_DEB")")" != "$(pwd)" ] ; then
+      echo "Error: the grml-debootstrap*.deb needs to be inside $(pwd) to be shared with docker container." >&2
+      exit 1
+    fi
+  fi
+fi
 
 RELEASE="${RELEASE:-stretch}"
 export RELEASE
 
+TARGET="${TARGET:-qemu.img}"
+
+bailout() {
+  if [ -n "${QEMU_PID:-}" ] ; then
+    # shellcheck disable=SC2009
+    ps --pid="${QEMU_PID}" -o pid= | grep -q '.' && kill "${QEMU_PID:-}"
+  fi
+
+  if [ -f "${TARGET:-}" ] ; then
+    sudo kpartx -dv "$(realpath "${TARGET}")"
+  fi
+
+  if [ -n "${LOOP_DISK:-}" ] ; then
+    if sudo dmsetup ls | grep -q "${LOOP_DISK}"; then
+      sudo kpartx -d "/dev/${LOOP_DISK}"
+    fi
+  fi
+
+  local loopmount
+  loopmount="$(sudo losetup -a | grep "$(realpath "${TARGET}")" | cut -f1 -d: || true)"
+
+  if [ -n "${loopmount:-}" ] ; then
+    sudo losetup -d "${loopmount}"
+  fi
+
+  [ -n "${1:-}" ] && EXIT_CODE="$1" || EXIT_CODE=1
+  exit "$EXIT_CODE"
+}
+trap bailout 1 2 3 6 14 15
+
 # run shellcheck tests
 docker run koalaman/shellcheck:stable --version
-docker run -v "$(pwd)":/code koalaman/shellcheck:stable -e SC2181 /code/chroot-script /code/grml-debootstrap
+docker run --rm -v "$(pwd)":/code koalaman/shellcheck:stable -e SC2181 /code/chroot-script /code/grml-debootstrap
 
 # build Debian package
-wget -O- https://travis.debian.net/script.sh | sh -
-
-if ! [ "${TRAVIS_DEBIAN_DISTRIBUTION:-}" = "unstable" ] ; then
-  echo "TRAVIS_DEBIAN_DISTRIBUTION is $TRAVIS_DEBIAN_DISTRIBUTION and not unstable, skipping VM build tests."
-  exit 0
+if [ -z "${TRAVIS:-}" ] ; then
+  echo "Not running under Travis, installing local grml-debootstrap package ${GRML_DEBOOTSTRAP_DEB}."
+else
+  if ! [ "${TRAVIS_DEBIAN_DISTRIBUTION:-}" = "unstable" ] ; then
+    echo "TRAVIS_DEBIAN_DISTRIBUTION is $TRAVIS_DEBIAN_DISTRIBUTION and not unstable, skipping VM build tests."
+    exit 0
+  fi
+  wget -O- https://travis.debian.net/script.sh | sh -
+  # copy only the binary from the TRAVIS_DEBIAN_INCREMENT_VERSION_NUMBER=true build
+  cp ../grml-debootstrap_*travis*deb .
 fi
 
-# copy only the binary from the TRAVIS_DEBIAN_INCREMENT_VERSION_NUMBER=true build
-cp ../grml-debootstrap_*travis*deb .
-
 # we need to run in privileged mode to be able to use loop devices
 docker run --privileged -v "$(pwd)":/code --rm -i -t debian:stretch /code/travis/build-vm.sh
 
 [ -x ./goss ] || curl -fsSL https://goss.rocks/install | GOSS_DST="$(pwd)" sh
 
+# Ubuntu trusty (14.04LTS) doesn't have realpath in coreutils yet
+if ! command -v realpath &>/dev/null ; then
+  REALPATH_PACKAGE=realpath
+fi
+
 sudo apt-get update
-sudo apt-get -y install qemu-system-x86
+sudo apt-get -y install qemu-system-x86 kpartx python-pexpect python-serial ${REALPATH_PACKAGE:-}
 
-# sudo timeout --preserve-status --foreground 120 qemu-system-x86_64 -hda qemu.img -serial stdio -display none | tee -a qemu.log
-sudo qemu-system-x86_64 -hda qemu.img -serial stdio -display none | tee -a qemu.log &
+# run tests from inside Debian system
+DEVINFO=$(sudo kpartx -asv "${TARGET}")
+LOOP_PART="${DEVINFO##add map }"
+LOOP_PART="${LOOP_PART// */}"
+LOOP_DISK="${LOOP_PART%p*}"
+IMG_FILE="/dev/mapper/$LOOP_PART"
 
-timeout=120
+MNTPOINT="$(mktemp -d)"
+sudo mount "$IMG_FILE" "${MNTPOINT}"
+
+sudo cp ./goss "${MNTPOINT}"/usr/local/bin/goss
+sudo cp ./travis/goss.yaml "${MNTPOINT}"/root/goss.yaml
+
+sudo umount "${MNTPOINT}"
+sudo kpartx -dv "$(realpath "${TARGET}")"
+if sudo dmsetup ls | grep -q "${LOOP_DISK}"; then
+  sudo kpartx -d "/dev/${LOOP_DISK}"
+fi
+
+rmdir "$MNTPOINT"
+
+sudo chown "$(id -un)" qemu.img
+rm -f ./serial0
+mkfifo ./serial0
+qemu-system-x86_64 -hda qemu.img -display none -vnc :0 \
+                   -device virtio-serial-pci \
+                   -chardev pipe,id=ch0,path=./serial0 \
+                   -device virtserialport,chardev=ch0,name=serial0 \
+                   -serial pty &>qemu.log &
+QEMU_PID="$!"
+
+timeout=30
 success=0
-while [ "$timeout" -gt 0 ]; do
+while [ "$timeout" -gt 0 ] ; do
   ((timeout--))
-  if ./goss --gossfile ./travis/goss.yaml validate --format nagios ; then
+  if grep -q 'char device redirected to ' qemu.log ; then
     success=1
     sleep 1
     break
   else
-    echo "Tests didn't pass YET, will retry again [$timeout retries left]"
+    echo "No serial console from Qemu found yet [$timeout retries left]"
     sleep 1
   fi
 done
 
 if [ "$success" = "1" ] ; then
-  echo "All tests passed! (◕‿◕)"
+  serial_port=$(awk '/char device redirected/ {print $5}' qemu.log)
 else
-  echo "Reached timeout after $timeout seconds with failing tests. ¯\(º o)/¯ ☂" >&2
-  echo "Latest test run results:"
-  ./goss --gossfile ./travis/goss.yaml validate
+  echo "Error: Failed to identify serial console port." >&2
+  exit 1
+fi
+
+timeout=30
+success=0
+while [ "$timeout" -gt 0 ] ; do
+  ((timeout--))
+  if [ -c "$serial_port" ] ; then
+    success=1
+    sleep 1
+    break
+  else
+    echo "No block device for serial console found yet [$timeout retries left]"
+    sleep 1
+  fi
+done
+
+if [ "$success" = "0" ] ; then
+  echo "Error: can't access serial console block device." >&2
   exit 1
 fi
+
+sudo chown "$(id -un)" "$serial_port"
+./travis/serial-console-connection --port "$serial_port" --hostname "$RELEASE" --pipefile "serial0" --vmoutput "vm-output.txt"
+
+cat vm-output.txt
+
+RC=0
+if grep -q '^failure_exit' vm-output.txt ; then
+  echo "We noticed failing tests."
+  RC=1
+else
+  echo "All tests passed."
+fi
+
+echo "Finished serial console connection [timeout=${timeout}]."
+
+bailout $RC
+
+# EOF