install.test
#!/bin/bash
## Tests for `pave install` and `pave install-boot`.
##
## Boot triggers go into a fake root (PAVE_SYSROOT), and a fake `sudo` on PATH just runs its command,
## so the whole install flow runs as the current user.
## Installed triggers are then actually executed, to prove their quoting works;
## the goals dir has a space in its name to make that mean something.
# shellcheck source=tests/testlib.bash
source "${BASH_SOURCE[0]%/*}/testlib.bash"
mkdir -p "$scratch/fakebin"
printf '#!/bin/bash\n[ "$1" = -- ] && shift\nexec "$@"\n' >"$scratch/fakebin/sudo"
chmod +x "$scratch/fakebin/sudo"
export PATH="$scratch/fakebin:$PATH"
export PAVE_SYSROOT="$scratch/root"
G="$scratch/my goals"
M="$scratch/marks"
for phase in boot session login; do
goals "$G/$phase.bash" <<EOF
ensure_file "$M/$phase" 644 "\$PWD"
EOF
done
## fresh_root empties the fake root and run marks, then creates the given dirs and files in the root.
##
## - @param $1... paths under the root; ending in / makes a dir, otherwise an empty file.
fresh_root() {
rm -rf -- "$PAVE_SYSROOT" "$M"
local p
for p in "$@"; do
if [[ $p == */ ]]; then
mkdir -p -- "$PAVE_SYSROOT/$p"
else
mkdir -p -- "$PAVE_SYSROOT/${p%/*}"
: >"$PAVE_SYSROOT/$p"
fi
done
}
# ---- systemd, plus the user triggers; then idempotence and repointing ----
fresh_root run/systemd/system/
pv install "$G"
assert_eq "systemd: exit 0" 0 "$rc"
assert_has "systemd: kind reported" "pave: boot trigger kind: systemd"
unit="$PAVE_SYSROOT/etc/systemd/system/pave-boot.service"
assert "systemd: unit has the payload" grep -qxF "ExecStart=\"$PAVE\" run \"$G\" boot" "$unit"
assert_eq "systemd: unit enabled" ../pave-boot.service \
"$(readlink "$PAVE_SYSROOT/etc/systemd/system/multi-user.target.wants/pave-boot.service")"
assert_eq "install runs the boot phase" "$G" "$(<"$M/boot")"
desktop="$HOME/.config/autostart/pave-session.desktop"
assert "xdg-autostart: desktop entry has the payload" grep -qxF "Exec=\"$PAVE\" run \"$G\" session" "$desktop"
assert "profile: block added to ~/.profile" grep -qxF "\"$PAVE\" run \"$G\" login" "$HOME/.profile"
rm -rf -- "$M"
sh -c "$(sed -n 's/^ExecStart=//p' "$unit")" >/dev/null
assert_eq "systemd: ExecStart line runs the boot phase" "$G" "$(<"$M/boot")"
sh -c "$(sed -n 's/^Exec=//p' "$desktop")" >/dev/null
assert_eq "xdg-autostart: Exec line runs the session phase" "$G" "$(<"$M/session")"
sh -c ". \"\$HOME/.profile\"" >/dev/null
assert_eq "profile: sourcing it runs the login phase" "$G" "$(<"$M/login")"
pv install "$G"
assert_eq "reinstall: exit 0" 0 "$rc"
assert_count "reinstall: changes nothing" "pave: changed" 0
G2="$scratch/other-goals"
goals "$G2/boot.bash" <<<'true'
pv install "$G2"
assert "repoint: unit follows the new goals dir" grep -qxF "ExecStart=\"$PAVE\" run \"$G2\" boot" "$unit"
assert_eq "repoint: one profile block, updated" 1 "$(grep -c '>>> pave:trigger >>>' "$HOME/.profile")"
assert "repoint: profile block follows" grep -qxF "\"$PAVE\" run \"$G2\" login" "$HOME/.profile"
# ---- the login trigger goes where bash will read it ----
rm -f "$HOME/.profile"
: >"$HOME/.bash_profile"
pv install "$G"
assert "profile: ~/.bash_profile used when it exists" grep -qF 'pave:trigger' "$HOME/.bash_profile"
assert "profile: ~/.profile left alone then" test ! -e "$HOME/.profile"
# ---- the other boot kinds ----
fresh_root etc/local.d/
pv install "$G"
assert_has "openrc-local: kind reported" "pave: boot trigger kind: openrc-local"
start="$PAVE_SYSROOT/etc/local.d/pave.start"
assert_eq "openrc-local: executable" 755 "$(stat -c %a "$start")"
rm -rf -- "$M"
"$start" >/dev/null
assert_eq "openrc-local: script runs the boot phase" "$G" "$(<"$M/boot")"
fresh_root etc/rc.local etc/cron.d/
printf '#!/bin/sh -e\nexit 0\n' >"$PAVE_SYSROOT/etc/rc.local"
pv install "$G"
assert_has "rc-local: preferred over cron" "pave: boot trigger kind: rc-local"
assert_eq "rc-local: made executable" 755 "$(stat -c %a "$PAVE_SYSROOT/etc/rc.local")"
assert_eq "rc-local: block after the shebang, before exit" "#!/bin/sh -e" "$(head -n1 "$PAVE_SYSROOT/etc/rc.local")"
assert_eq "rc-local: exit stays last" "exit 0" "$(tail -n1 "$PAVE_SYSROOT/etc/rc.local")"
rm -rf -- "$M"
"$PAVE_SYSROOT/etc/rc.local" >/dev/null
assert_eq "rc-local: script runs the boot phase" "$G" "$(<"$M/boot")"
fresh_root etc/cron.d/
pv install "$G"
assert_has "cron-reboot: kind reported" "pave: boot trigger kind: cron-reboot"
assert "cron-reboot: entry has the payload" grep -qxF "@reboot root \"$PAVE\" run \"$G\" boot" "$PAVE_SYSROOT/etc/cron.d/pave"
# ---- refusals ----
fresh_root
pv install-boot "$G"
assert_eq "no boot hook: install-boot exit 10" 10 "$rc"
assert_has "no boot hook: explained" "found no boot hook pave knows"
pv install "$G"
assert_eq "no boot hook: install exit 12" 12 "$rc"
assert "no boot hook: user triggers still installed" test -f "$desktop"
fresh_root run/systemd/system/
mkdir -p "$scratch/bad\$dir"
pv install "$scratch/bad\$dir"
assert_eq "unsafe path: exit 9" 9 "$rc"
assert "unsafe path: nothing installed" test ! -e "$unit"
pv install "$scratch/no-such-goals"
assert_eq "missing goals dir: exit 5" 5 "$rc"
pv install
assert_eq "usage: exit 4" 4 "$rc"
verdict
tests/install.test · 5.1 KiB · 7240887182