#!/bin/sh # Tests for nox-mesh-host-rollback. # # It runs on a machine where the host will not start, which is the one moment nobody can afford it to # be wrong — and the one moment it is hardest to debug. So it is tested here, against a real # filesystem holding real delivered versions. # # **These used to stub a package manager.** The script reinstalled the known-good version with # `pacman -U` out of the package cache, which no machine in this mesh used and which two of the three # operating systems the host is built for do not have (novox/hq ADR 0141). Going back is now choosing # a directory, so there is nothing to stub: the thing under test is the filesystem, and a fake would # only assert that the fake behaves as expected (novox/hq ADR 0017). set -eu cd "$(dirname "$0")" SCRIPT="$PWD/nox-mesh-host-rollback" PASS=0; FAIL=0 setup() { WORK="$(mktemp -d)" export MESH_HOST_STATE_DIR="$WORK/state" export MESH_HOST_LIBEXEC="$WORK/libexec" mkdir -p "$MESH_HOST_STATE_DIR" "$MESH_HOST_LIBEXEC/versions" } # deliver a version the way the mesh would: a directory named for it, with the binary inside. deliver() { mkdir -p "$MESH_HOST_LIBEXEC/versions/$1" printf '#!/bin/sh\nexit 0\n' > "$MESH_HOST_LIBEXEC/versions/$1/nox-mesh-host" chmod +x "$MESH_HOST_LIBEXEC/versions/$1/nox-mesh-host" } check() { # name, condition-description, actual, expected if [ "$3" = "$4" ]; then PASS=$((PASS+1)); printf ' ok %s\n' "$1" else FAIL=$((FAIL+1)); printf ' FAIL %s\n %s\n got: %s\n expected: %s\n' "$1" "$2" "$3" "$4"; fi } # --- a normal rollback --------------------------------------------------------------------- setup deliver 1.4.2 deliver 1.5.0 echo 1.4.2 > "$MESH_HOST_STATE_DIR/known-good" RC=0; "$SCRIPT" >/dev/null 2>&1 || RC=$? check "pins the known-good version" "the launcher reads the pin and runs that version instead of the newest" \ "$(cat "$MESH_HOST_STATE_DIR/rollback-pinned" 2>/dev/null || echo MISSING)" "1.4.2" check "records that it rolled back" "the attempted marker holds the version" \ "$(cat "$MESH_HOST_STATE_DIR/rollback-attempted" 2>/dev/null || echo MISSING)" "1.4.2" check "succeeds" "a rollback that found its version is not a failure" "$RC" "0" # It chooses and stops. The launcher runs the host next, and starting it here would run two # (novox/hq ADR 0005). check "does not start anything itself" "the launcher owns starting" \ "$(ls "$MESH_HOST_STATE_DIR" | grep -c started || true)" "0" # The version it rolled back FROM is left alone: it is the newest, and retiring it is the running # host's job after a reconcile it completes, never a recovery's. check "leaves the failing version on disk" "a recovery deletes nothing" \ "$([ -x "$MESH_HOST_LIBEXEC/versions/1.5.0/nox-mesh-host" ] && echo present || echo gone)" "present" # --- it rolls back only once --------------------------------------------------------------- setup deliver 1.4.2 echo 1.4.2 > "$MESH_HOST_STATE_DIR/known-good" echo 1.4.2 > "$MESH_HOST_STATE_DIR/rollback-attempted" "$SCRIPT" >/dev/null 2>&1 || true check "does not roll back twice" "a second failure is the machine, not the binary" \ "$([ -e "$MESH_HOST_STATE_DIR/rollback-pinned" ] && echo pinned || echo untouched)" "untouched" # --- nothing to roll back to --------------------------------------------------------------- setup RC=0; "$SCRIPT" >/dev/null 2>&1 || RC=$? check "no known-good: does nothing" "a host that never reconciled has no version to return to" \ "$([ -e "$MESH_HOST_STATE_DIR/rollback-attempted" ] && echo attempted || echo untouched)" "untouched" # The exit code is asserted from a real run, not from a literal. An earlier version of this # compared "0" to "0" and could not fail — which hid an injected fault that made the script die # here instead of returning cleanly. check "no known-good: exits zero" "an installation failure is not a rollback failure" "$RC" "0" setup printf ' \n' > "$MESH_HOST_STATE_DIR/known-good" "$SCRIPT" >/dev/null 2>&1 || true check "blank known-good: refuses to guess" "pinning nothing and reporting success is the fault this prevents" \ "$([ -e "$MESH_HOST_STATE_DIR/rollback-pinned" ] && echo pinned || echo untouched)" "untouched" # --- the known-good version is not delivered ------------------------------------------------- # It was retired, or that host was placed on the machine by hand and never delivered — which is how # every first host arrives. Pinning it anyway would have the launcher ignore the pin and start the # newest again, which is the binary that is failing. setup deliver 1.5.0 echo 1.4.2 > "$MESH_HOST_STATE_DIR/known-good" RC=0; "$SCRIPT" >/dev/null 2>&1 || RC=$? check "version not delivered: fails loudly" "cannot roll back, and says so rather than reporting success" "$RC" "1" check "version not delivered: pins nothing" "a pin the launcher would ignore is worse than none" \ "$([ -e "$MESH_HOST_STATE_DIR/rollback-pinned" ] && echo pinned || echo untouched)" "untouched" # --- a version directory with no binary in it ------------------------------------------------ # An interrupted delivery leaves one. Pinning it would start nothing. setup mkdir -p "$MESH_HOST_LIBEXEC/versions/1.4.2" echo 1.4.2 > "$MESH_HOST_STATE_DIR/known-good" RC=0; "$SCRIPT" >/dev/null 2>&1 || RC=$? check "half-delivered version: fails loudly" "a directory is not a version; the binary is" "$RC" "1" printf '\nrollback: %d passed, %d failed\n' "$PASS" "$FAIL" [ "$FAIL" -eq 0 ]