diff options
| -rwxr-xr-x | scripts/test-install.sh | 47 | ||||
| -rw-r--r-- | tests/unit/test_test_install.bats | 69 |
2 files changed, 116 insertions, 0 deletions
diff --git a/scripts/test-install.sh b/scripts/test-install.sh index d61f95d..cbca9b3 100755 --- a/scripts/test-install.sh +++ b/scripts/test-install.sh @@ -100,6 +100,49 @@ list_configs() { done } +# Drop the cached archzfs repo before the first scenario. +# +# archzfs re-uploads its GitHub Releases assets under the same filenames, so +# pacoloco ends up holding package bodies that no longer match what its +# archzfs.db advertises. Every ZFS scenario then dies at pacstrap with +# "invalid or corrupted package" or "Maximum file size exceeded", which reads +# exactly like an installer regression and isn't one. It went stale twice on +# 2026-08-06, the second time *during* a run: fresh at scenario one, rotten by +# scenario six, and the whole ZFS half was lost. +# +# Clear the directory, not the zfs-dkms/zfs-utils globs build.sh uses. Removing +# the bodies while leaving a stale db just trades a checksum error for a size +# error, which is how the second failure disguised itself as a new bug. +# +# Best-effort by design. The cache is pacoloco-owned so removal needs root, and +# a run without root is still worth having — it just carries the risk this +# exists to remove, so say so rather than failing silently. +# +# The path is injectable so tests can exercise this against a temp directory. +# Without that it hardcoded a system path, and merely sourcing the file and +# calling the function ran `sudo rm -rf` on the real cache — which is what +# happened the first time this was written. +clear_archzfs_cache() { + local dir="${ARCHZFS_CACHE_DIR:-/var/cache/pacoloco/pkgs/archzfs}" + [[ -d "$dir" ]] || return 0 + + # This is `rm -rf` under sudo on an overridable path, so validate the shape + # before running it. A mistyped override should cost a warning, not the + # machine. + if [[ "$(basename "$dir")" != archzfs || "$(dirname "$dir")" == / ]]; then + warn "Refusing to clear implausible archzfs cache path: $dir" + return 0 + fi + + if sudo -n rm -rf "$dir" 2>/dev/null; then + info "Cleared cached archzfs repo (pacoloco refetches on first use)" + else + warn "Could not clear $dir — needs root." + warn "A stale archzfs cache fails every ZFS scenario at pacstrap; clear it by hand if that happens." + fi + return 0 +} + find_iso() { ISO_FILE=$(ls -t "$PROJECT_DIR/out/"*.iso 2>/dev/null | head -1) if [[ -z "$ISO_FILE" ]]; then @@ -1308,6 +1351,10 @@ main() { # Find ISO find_iso + # Before the first scenario, so a stale upstream re-upload can't fail every + # ZFS install with an error that looks like a regression. + clear_archzfs_cache + # Determine which configs to run if [[ ${#configs[@]} -eq 0 ]]; then # Run all configs diff --git a/tests/unit/test_test_install.bats b/tests/unit/test_test_install.bats index 34da2b0..52ea037 100644 --- a/tests/unit/test_test_install.bats +++ b/tests/unit/test_test_install.bats @@ -433,3 +433,72 @@ mkcfg() { SSH_CMD_TIMEOUT=1800 run ssh_cmd true [[ "$output" == "bound=1800" ]] } + +############################# +# clear_archzfs_cache +############################# +# Exercised against an injected directory, never the real one. An earlier +# version of this block hardcoded the system path, so running the unit suite +# invoked `sudo rm -rf /var/cache/pacoloco/pkgs/archzfs` on the live machine. +# A unit test must not reach outside its sandbox. + +@test "clear_archzfs_cache is a no-op when the cache directory is absent" { + ARCHZFS_CACHE_DIR="$BATS_TEST_TMPDIR/absent" run clear_archzfs_cache + [ "$status" -eq 0 ] + [ -z "$output" ] +} + +@test "clear_archzfs_cache removes an existing cache directory" { + local dir="$BATS_TEST_TMPDIR/archzfs" + mkdir -p "$dir" + touch "$dir/archzfs.db" "$dir/zfs-dkms-1-1-x86_64.pkg.tar.zst" + # Stub sudo so the test needs no privilege and stays in its sandbox. + sudo() { shift; "$@"; } + ARCHZFS_CACHE_DIR="$dir" run clear_archzfs_cache + [ "$status" -eq 0 ] + [ ! -d "$dir" ] +} + +@test "clear_archzfs_cache clears the db too, not just the package bodies" { + # Removing bodies while leaving a stale archzfs.db trades a checksum error + # for "Maximum file size exceeded" — same cause, new message. + local dir="$BATS_TEST_TMPDIR/db/archzfs" + mkdir -p "$dir" + touch "$dir/archzfs.db" + sudo() { shift; "$@"; } + ARCHZFS_CACHE_DIR="$dir" run clear_archzfs_cache + [ ! -e "$dir/archzfs.db" ] +} + +@test "clear_archzfs_cache warns and succeeds when removal is denied" { + local dir="$BATS_TEST_TMPDIR/denied/archzfs" + mkdir -p "$dir" + sudo() { return 1; } + ARCHZFS_CACHE_DIR="$dir" run clear_archzfs_cache + # Non-fatal: a run without root is still worth having, but must say so. + [ "$status" -eq 0 ] + [[ "$output" == *"needs root"* ]] + [ -d "$dir" ] +} + +@test "clear_archzfs_cache refuses a path that isn't shaped like the cache" { + # The removal runs `rm -rf` under sudo, so a mistyped override must cost a + # warning rather than the machine. + local dir="$BATS_TEST_TMPDIR/not-the-cache" + mkdir -p "$dir" + sudo() { echo "SUDO RAN"; } + ARCHZFS_CACHE_DIR="$dir" run clear_archzfs_cache + [ "$status" -eq 0 ] + [[ "$output" == *"Refusing"* ]] + [[ "$output" != *"SUDO RAN"* ]] + [ -d "$dir" ] +} + +@test "clear_archzfs_cache refuses a top-level directory" { + sudo() { echo "SUDO RAN"; } + ARCHZFS_CACHE_DIR="/archzfs" run clear_archzfs_cache + # /archzfs won't exist, so this exits on the -d guard; the point is that + # neither guard lets a root-level path reach the removal. + [ "$status" -eq 0 ] + [[ "$output" != *"SUDO RAN"* ]] +} |
