aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xscripts/test-install.sh47
-rw-r--r--tests/unit/test_test_install.bats69
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"* ]]
+}