aboutsummaryrefslogtreecommitdiff
path: root/tests/unit/test_test_install.bats
diff options
context:
space:
mode:
Diffstat (limited to 'tests/unit/test_test_install.bats')
-rw-r--r--tests/unit/test_test_install.bats152
1 files changed, 152 insertions, 0 deletions
diff --git a/tests/unit/test_test_install.bats b/tests/unit/test_test_install.bats
index bf43dd8..52ea037 100644
--- a/tests/unit/test_test_install.bats
+++ b/tests/unit/test_test_install.bats
@@ -318,6 +318,10 @@ error: failed to commit transaction (invalid or corrupted package (checksum))
@test "ssh_cmd picks up a caller-scoped INSTALLED_PASSWORD" {
# Proves local-instead-of-export still reaches ssh_cmd: bash's dynamic
# scoping exposes a caller's local to the functions it calls.
+ #
+ # timeout is stubbed as a pass-through because the real one is an external
+ # binary: it would exec the real sshpass and never see these stubs.
+ timeout() { shift; "$@"; }
sshpass() { echo "$2"; }
ssh() { :; }
caller_with_local() {
@@ -329,6 +333,7 @@ error: failed to commit transaction (invalid or corrupted package (checksum))
}
@test "a caller-scoped INSTALLED_PASSWORD does not leak past a failed return" {
+ timeout() { shift; "$@"; }
sshpass() { echo "$2"; }
ssh() { :; }
SSH_PASSWORD="live-iso-password"
@@ -350,3 +355,150 @@ error: failed to commit transaction (invalid or corrupted package (checksum))
grep -qE '^[[:space:]]*local INSTALLED_PASSWORD=' "$src"
! grep -qE '^[[:space:]]*export INSTALLED_PASSWORD' "$src"
}
+
+#############################
+# config_encrypt_flag
+#############################
+# Decides which passphrase-entry path a reboot needs. It's the one pure piece
+# of the boot-from-disk sequence, which is otherwise qemu orchestration, so it
+# carries the precedence rules the rest of that sequence depends on.
+
+mkcfg() {
+ local f
+ f=$(mktemp)
+ printf '%s\n' "$@" > "$f"
+ echo "$f"
+}
+
+@test "config_encrypt_flag reports luks for a LUKS config" {
+ local f; f=$(mkcfg 'LUKS_PASSPHRASE=secret' 'DISKS=/dev/vda')
+ [ "$(config_encrypt_flag "$f")" = "luks" ]
+ rm -f "$f"
+}
+
+@test "config_encrypt_flag reports zfs for a ZFS-passphrase config" {
+ local f; f=$(mkcfg 'ZFS_PASSPHRASE=secret' 'DISKS=/dev/vda')
+ [ "$(config_encrypt_flag "$f")" = "zfs" ]
+ rm -f "$f"
+}
+
+@test "config_encrypt_flag prefers luks when a config carries both" {
+ # Preserves the precedence the inline block had: LUKS is checked first,
+ # and a config with both is a misconfiguration rather than a real mode.
+ local f; f=$(mkcfg 'LUKS_PASSPHRASE=a' 'ZFS_PASSPHRASE=b')
+ [ "$(config_encrypt_flag "$f")" = "luks" ]
+ rm -f "$f"
+}
+
+@test "config_encrypt_flag reports nothing when NO_ENCRYPT overrides a passphrase" {
+ # The test configs set a passphrase *and* NO_ENCRYPT=yes; sending a
+ # passphrase to an unencrypted boot would type it at a login prompt.
+ #
+ # Asserted through `run` on purpose. A bare [ -z "$(...)" ] also passes
+ # when the function doesn't exist, so it can't fail for the reason the
+ # test exists — checking status too makes absence register as 127.
+ local f; f=$(mkcfg 'ZFS_PASSPHRASE=testpass' 'NO_ENCRYPT=yes')
+ run config_encrypt_flag "$f"
+ [ "$status" -eq 0 ]
+ [ -z "$output" ]
+ rm -f "$f"
+}
+
+@test "config_encrypt_flag reports nothing for an unencrypted config" {
+ local f; f=$(mkcfg 'DISKS=/dev/vda' 'HOSTNAME=x')
+ run config_encrypt_flag "$f"
+ [ "$status" -eq 0 ]
+ [ -z "$output" ]
+ rm -f "$f"
+}
+
+#############################
+# ssh_cmd timeout bound
+#############################
+# ConnectTimeout bounds the connection, not execution. On 2026-08-03 a remote
+# `zfs destroy` blocked behind an uninterruptible txg_quiesce with the
+# connection healthy, and the suite sat dead for 40 minutes. A wedged guest
+# should cost one scenario, not the run.
+
+@test "ssh_cmd bounds the remote command with the default timeout" {
+ timeout() { echo "bound=$1"; }
+ run ssh_cmd true
+ [[ "$output" == "bound=$SSH_CMD_TIMEOUT" ]]
+}
+
+@test "ssh_cmd honors a per-call timeout override" {
+ # run_install's installer call legitimately runs for many minutes and
+ # raises this; every other call keeps the short default.
+ timeout() { echo "bound=$1"; }
+ 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"* ]]
+}