make lint runs shellcheck on every tracked bash script, make test runs the bats suite in tests/, and make check runs both. The tests cover the update orchestrator (hook isolation, failure reporting, pull and free-space handling) and utils.sh (migrations, package install and removal, services, initramfs build check), using stub commands so they never touch the real system. Fixes from the first lint run: 20-aur.sh stops if a cd fails rather than building or deleting in the wrong directory, and 80-gnome-extensions.sh refuses to rm -rf with an empty path. The rest are false positives, silenced in .shellcheckrc or per line. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
144 lines
3.7 KiB
Bash
144 lines
3.7 KiB
Bash
#!/usr/bin/env bats
|
|
|
|
load test_helper
|
|
|
|
# Each test runs the real update script from a fake CoreDesktop checkout in the
|
|
# test's HOME, with fake hooks in updates.d/ that log to $RAN when they run.
|
|
|
|
setup() {
|
|
# A checkout with nothing but the update script and the files it installs
|
|
common_setup
|
|
CD="$HOME/.local/share/coredesktop"
|
|
mkdir -p "$CD/updates.d" "$HOME/.local/bin"
|
|
cp "$REPO/update" "$CD/update"
|
|
for script in refresh sibling version configure audit; do
|
|
echo '#!/bin/bash' > "$CD/$script"
|
|
done
|
|
|
|
export RAN="$BATS_TEST_TMPDIR/ran"
|
|
unset UPDATE_REEXECED UPDATE_PULL_FAILED UPDATE_FORCE
|
|
|
|
stub clear
|
|
stub git 'exit "${GIT_STATUS:-0}"'
|
|
stub sudo 'exit "${SUDO_STATUS:-0}"'
|
|
stub df 'printf "Avail\n%s\n" "${DF_AVAIL:-104857600}"'
|
|
# Let go of bats' output pipes so the sudo keepalive's leftover sleep
|
|
# doesn't keep the test waiting
|
|
stub sleep 'exec > /dev/null 2>&1 3>&-; exec /usr/bin/sleep "$@"'
|
|
}
|
|
|
|
# hook NAME BODY: add updates.d/NAME.sh with BODY as its run_update
|
|
hook() {
|
|
printf '#!/bin/bash\nrun_update() {\n%s\n}\n' "$2" > "$CD/updates.d/$1.sh"
|
|
}
|
|
|
|
ran() {
|
|
[ "$(cat "$RAN" 2> /dev/null)" = "$(printf '%s\n' "$@")" ]
|
|
}
|
|
|
|
@test "update pulls, installs its scripts, and runs every hook in order" {
|
|
hook 20-b 'echo b >> "$RAN"'
|
|
hook 10-a 'echo a >> "$RAN"'
|
|
|
|
run "$CD/update"
|
|
[ "$status" -eq 0 ]
|
|
[[ "$output" == *"Done."* ]]
|
|
called git -C "$CD" pull
|
|
ran a b
|
|
for script in update refresh sibling version configure audit; do
|
|
[ -x "$HOME/.local/bin/$script" ]
|
|
done
|
|
}
|
|
|
|
@test "update pulls only once, before re-running its new copy" {
|
|
hook 10-a 'echo a >> "$RAN"'
|
|
|
|
run "$CD/update"
|
|
[ "$status" -eq 0 ]
|
|
[ "$(grep -c '^git ' "$STUB_LOG")" -eq 1 ]
|
|
ran a
|
|
}
|
|
|
|
@test "a failing hook doesn't stop the hooks after it" {
|
|
hook 10-a 'echo a >> "$RAN"'
|
|
hook 20-b 'echo b >> "$RAN"; return 1'
|
|
hook 30-c 'echo c >> "$RAN"'
|
|
|
|
run "$CD/update"
|
|
[ "$status" -eq 1 ]
|
|
[[ "$output" == *"Done, with errors in: 20-b.sh"* ]]
|
|
ran a b c
|
|
}
|
|
|
|
@test "a hook that exits doesn't end the update" {
|
|
hook 10-a 'echo a >> "$RAN"; exit 0'
|
|
hook 20-b 'echo b >> "$RAN"'
|
|
|
|
run "$CD/update"
|
|
[ "$status" -eq 0 ]
|
|
ran a b
|
|
}
|
|
|
|
@test "a hook using set -e fails at its first failing command" {
|
|
hook 10-a 'set -e; echo a >> "$RAN"; false; echo after >> "$RAN"'
|
|
hook 20-b 'echo b >> "$RAN"'
|
|
|
|
run "$CD/update"
|
|
[ "$status" -eq 1 ]
|
|
[[ "$output" == *"errors in: 10-a.sh"* ]]
|
|
ran a b
|
|
}
|
|
|
|
@test "a hook's is_installed and functions don't leak into the next hook" {
|
|
printf '%s\n' '#!/bin/bash' 'is_installed() { false; }' \
|
|
'run_update() { echo a >> "$RAN"; }' > "$CD/updates.d/10-a.sh"
|
|
# 10-a's is_installed must not stop 20-b, and its run_update must not run
|
|
# again for 30-c, which has none
|
|
printf '%s\n' '#!/bin/bash' 'run_update() { echo b >> "$RAN"; }' \
|
|
> "$CD/updates.d/20-b.sh"
|
|
printf '%s\n' '#!/bin/bash' 'true' > "$CD/updates.d/30-c.sh"
|
|
|
|
run "$CD/update"
|
|
[ "$status" -eq 0 ]
|
|
ran b
|
|
}
|
|
|
|
@test "update runs the hooks on disk when git pull fails, and reports it" {
|
|
export GIT_STATUS=1
|
|
hook 10-a 'echo a >> "$RAN"'
|
|
|
|
run "$CD/update"
|
|
[ "$status" -eq 1 ]
|
|
[[ "$output" == *"could not pull"* ]]
|
|
[[ "$output" == *"errors in: git pull"* ]]
|
|
ran a
|
|
}
|
|
|
|
@test "update stops before any hook when / is low on space" {
|
|
export DF_AVAIL=1048576
|
|
hook 10-a 'echo a >> "$RAN"'
|
|
|
|
run "$CD/update"
|
|
[ "$status" -eq 1 ]
|
|
[[ "$output" == *"needs at least 10 GiB"* ]]
|
|
[ ! -e "$RAN" ]
|
|
}
|
|
|
|
@test "UPDATE_FORCE skips the free space check" {
|
|
export DF_AVAIL=1048576 UPDATE_FORCE=1
|
|
hook 10-a 'echo a >> "$RAN"'
|
|
|
|
run "$CD/update"
|
|
[ "$status" -eq 0 ]
|
|
ran a
|
|
}
|
|
|
|
@test "update stops when sudo fails" {
|
|
export SUDO_STATUS=1
|
|
hook 10-a 'echo a >> "$RAN"'
|
|
|
|
run "$CD/update"
|
|
[ "$status" -eq 1 ]
|
|
[ ! -e "$RAN" ]
|
|
}
|