Files
sower/install_e2e_test.sh
wweir 8e5fd3e805 test(install): cover install.sh end to end from make test
install.sh was only syntax-checked (sh -n), so the install and upgrade paths,
the config-preservation contract and the failure modes for a malformed release
tarball had no coverage. Add an offline, unprivileged E2E test that builds its
own tarballs and installs into a temp prefix with --service none: fresh
install, an in-place upgrade that keeps an operator-edited config, --with-server,
a dry run that creates nothing, three malformed tarballs that must fail closed,
and the CLI surface. Wire it into make test as test-install and syntax-check
the new script.
2026-10-10 14:57:10 +08:00

156 lines
5.7 KiB
Bash
Executable File

#!/bin/sh
# End-to-end test for install.sh.
#
# Everything runs offline against tarballs built here, with --service none into
# a throwaway prefix and config dir, so the test never needs root, never touches
# the system and never opens a network connection. It covers what `sh -n`
# cannot: the install and upgrade paths, the config-preservation contract, the
# dry-run contract, and the failure modes for a malformed release tarball.
set -eu
HERE=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
INSTALL="$HERE/install.sh"
WORK=$(mktemp -d)
trap 'rm -rf "$WORK"' EXIT INT TERM
fail() {
printf 'install_e2e_test: %s\n' "$*" >&2
exit 1
}
# stage_tarball <archive> <version> <member>...
# Builds a minimal release tarball. The binaries are shell stubs that echo
# their own name and version, so the test can tell a replaced binary from a
# stale one.
stage_tarball() {
archive=$1
version=$2
shift 2
stage="$WORK/stage-$version"
rm -rf "$stage"
mkdir -p "$stage"
for member in "$@"; do
case "$member" in
sower | sowerd)
printf '#!/bin/sh\necho "%s %s"\n' "$member" "$version" >"$stage/$member"
chmod 0755 "$stage/$member"
;;
sower.toml)
printf 'config %s\n' "$version" >"$stage/sower.toml"
;;
*)
printf '%s\n' "$member" >"$stage/$member"
;;
esac
done
tar -czf "$archive" -C "$stage" "$@"
rm -rf "$stage"
}
# run_install <archive> <prefix> <config-dir> [extra args...]
run_install() {
archive=$1
prefix=$2
config_dir=$3
shift 3
sh "$INSTALL" --tarball "$archive" --service none \
--prefix "$prefix" --config-dir "$config_dir" "$@"
}
# --- fresh install -----------------------------------------------------------
PREFIX="$WORK/prefix"
CONFDIR="$WORK/config"
stage_tarball "$WORK/release-v1.tar.gz" v1 sower sowerd sower.toml
if ! run_install "$WORK/release-v1.tar.gz" "$PREFIX" "$CONFDIR" >"$WORK/fresh.log" 2>&1; then
fail "fresh install failed:
$(cat "$WORK/fresh.log")"
fi
[ -x "$PREFIX/sower" ] || fail "sower was not installed as an executable"
[ "$("$PREFIX/sower")" = "sower v1" ] || fail "installed sower is not the tarball's binary"
[ -f "$CONFDIR/sower.toml" ] || fail "starter config was not written"
[ "$(cat "$CONFDIR/sower.toml")" = "config v1" ] || fail "starter config content mismatch"
config_mode=$(ls -l "$CONFDIR/sower.toml" | cut -c1-10)
[ "$config_mode" = "-rw-------" ] || fail "starter config mode is $config_mode, want -rw-------"
# --- upgrade in place --------------------------------------------------------
printf 'edited by the operator\n' >"$CONFDIR/sower.toml"
stage_tarball "$WORK/release-v2.tar.gz" v2 sower sowerd sower.toml
if ! run_install "$WORK/release-v2.tar.gz" "$PREFIX" "$CONFDIR" >"$WORK/upgrade.log" 2>&1; then
fail "upgrade failed:
$(cat "$WORK/upgrade.log")"
fi
[ "$("$PREFIX/sower")" = "sower v2" ] || fail "upgrade did not replace the binary"
[ "$(cat "$CONFDIR/sower.toml")" = "edited by the operator" ] ||
fail "upgrade overwrote the existing config"
grep -q 'keeping existing config' "$WORK/upgrade.log" || fail "upgrade did not report keeping the config"
# --- --with-server installs sowerd -------------------------------------------
if ! run_install "$WORK/release-v2.tar.gz" "$PREFIX" "$CONFDIR" --with-server >"$WORK/server.log" 2>&1; then
fail "--with-server install failed:
$(cat "$WORK/server.log")"
fi
[ -x "$PREFIX/sowerd" ] || fail "--with-server did not install sowerd"
# --- dry run must not touch the system --------------------------------------
DRY_PREFIX="$WORK/dry/prefix"
DRY_CONFDIR="$WORK/dry/config"
if ! run_install "$WORK/release-v1.tar.gz" "$DRY_PREFIX" "$DRY_CONFDIR" --dry-run >"$WORK/dry.log" 2>&1; then
fail "dry run failed:
$(cat "$WORK/dry.log")"
fi
[ ! -e "$DRY_PREFIX" ] || fail "dry run created the prefix directory"
[ ! -e "$DRY_CONFDIR" ] || fail "dry run created the config directory"
grep -q '^\[dry-run\]' "$WORK/dry.log" || fail "dry run printed no action preview"
# --- malformed tarballs ------------------------------------------------------
stage_tarball "$WORK/no-config.tar.gz" v1 sower sowerd
if run_install "$WORK/no-config.tar.gz" "$WORK/bad-a/prefix" "$WORK/bad-a/config" >"$WORK/no-config.log" 2>&1; then
fail "installer accepted a tarball without sower.toml"
fi
grep -q 'no sower.toml' "$WORK/no-config.log" ||
fail "unexpected failure for a tarball without sower.toml:
$(cat "$WORK/no-config.log")"
[ ! -e "$WORK/bad-a/config/sower.toml" ] || fail "half-written config left behind"
stage_tarball "$WORK/no-binary.tar.gz" v1 sower.toml
if run_install "$WORK/no-binary.tar.gz" "$WORK/bad-b/prefix" "$WORK/bad-b/config" >"$WORK/no-binary.log" 2>&1; then
fail "installer accepted a tarball without the sower binary"
fi
grep -q 'no sower binary' "$WORK/no-binary.log" ||
fail "unexpected failure for a tarball without the sower binary:
$(cat "$WORK/no-binary.log")"
[ ! -e "$WORK/bad-b/prefix/sower" ] || fail "installed a binary from a tarball without one"
stage_tarball "$WORK/no-server.tar.gz" v1 sower sower.toml
if run_install "$WORK/no-server.tar.gz" "$WORK/bad-c/prefix" "$WORK/bad-c/config" --with-server >"$WORK/no-server.log" 2>&1; then
fail "installer accepted --with-server from a tarball without sowerd"
fi
grep -q 'no sowerd binary' "$WORK/no-server.log" ||
fail "unexpected failure for a tarball without sowerd:
$(cat "$WORK/no-server.log")"
# --- CLI surface -------------------------------------------------------------
if ! sh "$INSTALL" --help >"$WORK/help.log" 2>&1; then
fail "--help exited non-zero"
fi
grep -q 'Install or upgrade the sower client' "$WORK/help.log" || fail "--help printed no usage"
if sh "$INSTALL" --not-a-flag >"$WORK/unknown.log" 2>&1; then
fail "installer accepted an unknown option"
fi
grep -q 'unknown option' "$WORK/unknown.log" || fail "unknown option reported nothing useful"
printf 'install_e2e_test: PASS\n'