aboutsummaryrefslogtreecommitdiff
path: root/tests/unit
diff options
context:
space:
mode:
Diffstat (limited to 'tests/unit')
-rw-r--r--tests/unit/test_btrfs.bats35
-rw-r--r--tests/unit/test_build_aur.bats11
-rw-r--r--tests/unit/test_common.bats70
-rw-r--r--tests/unit/test_config.bats58
4 files changed, 170 insertions, 4 deletions
diff --git a/tests/unit/test_btrfs.bats b/tests/unit/test_btrfs.bats
index 890bba2..15bf141 100644
--- a/tests/unit/test_btrfs.bats
+++ b/tests/unit/test_btrfs.bats
@@ -54,3 +54,38 @@ setup() {
[ "$status" -eq 0 ]
[ -z "$output" ]
}
+
+#############################
+# parse_btrfs_subvol_opts
+#############################
+# Composes the mount-option string for one subvolume from the shared
+# BTRFS_OPTS plus the per-subvol extra flags. Pure string transform,
+# shared by mount_btrfs_subvolumes and generate_btrfs_fstab. BTRFS_OPTS
+# is set at the top of btrfs.sh (sourced in setup), so these pin behavior
+# against the real default option string.
+
+@test "parse_btrfs_subvol_opts: no extra flags keeps the default opts" {
+ run parse_btrfs_subvol_opts "@home" ""
+ [ "$status" -eq 0 ]
+ [ "$output" = "subvol=@home,noatime,compress=zstd,space_cache=v2,discard=async" ]
+}
+
+@test "parse_btrfs_subvol_opts: compress=no drops compress=zstd" {
+ run parse_btrfs_subvol_opts "@media" "compress=no"
+ [ "$output" = "subvol=@media,noatime,space_cache=v2,discard=async" ]
+}
+
+@test "parse_btrfs_subvol_opts: nodatacow adds nodatacow and drops compress=zstd" {
+ run parse_btrfs_subvol_opts "@vms" "nodatacow"
+ [ "$output" = "subvol=@vms,noatime,space_cache=v2,discard=async,nodatacow" ]
+}
+
+@test "parse_btrfs_subvol_opts: nosuid adds nosuid,nodev and keeps compression" {
+ run parse_btrfs_subvol_opts "@tmp" "nosuid"
+ [ "$output" = "subvol=@tmp,noatime,compress=zstd,space_cache=v2,discard=async,nosuid,nodev" ]
+}
+
+@test "parse_btrfs_subvol_opts: nodatacow and nosuid combine" {
+ run parse_btrfs_subvol_opts "@x" "nodatacow,nosuid"
+ [ "$output" = "subvol=@x,noatime,space_cache=v2,discard=async,nodatacow,nosuid,nodev" ]
+}
diff --git a/tests/unit/test_build_aur.bats b/tests/unit/test_build_aur.bats
index 4da66fe..360f2b7 100644
--- a/tests/unit/test_build_aur.bats
+++ b/tests/unit/test_build_aur.bats
@@ -15,12 +15,12 @@ setup() {
# aur_v1_packages — single source of truth for the v1 build set
#############################
-@test "aur_v1_packages lists the nine audited v1 packages" {
+@test "aur_v1_packages lists the eight audited v1 packages" {
run aur_v1_packages
[ "$status" -eq 0 ]
- [ "$(echo "$output" | wc -l)" -eq 9 ]
+ [ "$(echo "$output" | wc -l)" -eq 8 ]
for pkg in downgrade yay informant zrepl pacman-cleanup-hook \
- sanoid zfs-auto-snapshot topgrade ventoy-bin; do
+ zfs-auto-snapshot topgrade ventoy-bin; do
[[ "$output" == *"$pkg"* ]]
done
}
@@ -28,9 +28,12 @@ setup() {
@test "aur_v1_packages excludes the vNext-deferred packages" {
run aur_v1_packages
[ "$status" -eq 0 ]
- # paru (second helper) and mkinitcpio-firmware (AUR-of-AUR deps) are vNext
+ # paru (second helper), mkinitcpio-firmware, and sanoid all pull AUR-of-AUR
+ # deps (sanoid needs perl-config-inifiles, AUR-only) — deferred to the
+ # vNext helper-driven dependency-resolution work.
[[ "$output" != *"paru"* ]]
[[ "$output" != *"mkinitcpio-firmware"* ]]
+ [[ "$output" != *"sanoid"* ]]
}
@test "aur_v1_packages emits one package per line" {
diff --git a/tests/unit/test_common.bats b/tests/unit/test_common.bats
index 6f9d1b1..c76b6a4 100644
--- a/tests/unit/test_common.bats
+++ b/tests/unit/test_common.bats
@@ -666,6 +666,26 @@ Boot0001* ZFSBootMenu"
rm -f "$f"
}
+@test "strip_repo_stanza preserves the target file mode (no 0600 clobber)" {
+ local f
+ f=$(mktemp)
+ printf '%s\n' '[core]' '[aur]' 'Server = file:///usr/share/aur-packages' '[extra]' > "$f"
+ chmod 644 "$f"
+ strip_repo_stanza aur "$f"
+ [ "$(stat -c %a "$f")" = "644" ]
+ rm -f "$f"
+}
+
+@test "strip_repo_stanza preserves a non-default file mode" {
+ local f
+ f=$(mktemp)
+ printf '%s\n' '[core]' '[aur]' 'Server = x' '[extra]' > "$f"
+ chmod 640 "$f"
+ strip_repo_stanza aur "$f"
+ [ "$(stat -c %a "$f")" = "640" ]
+ rm -f "$f"
+}
+
#############################
# aur_repo_available
#############################
@@ -720,3 +740,53 @@ Boot0001* ZFSBootMenu"
[ "$status" -eq 0 ]
[ -z "$output" ]
}
+
+#############################
+# aur_zfs_only_packages / filter_aur_for_fs
+#############################
+
+@test "aur_zfs_only_packages lists zfs-auto-snapshot and zrepl" {
+ run aur_zfs_only_packages
+ [ "$status" -eq 0 ]
+ [[ "$output" == *"zfs-auto-snapshot"* ]]
+ [[ "$output" == *"zrepl"* ]]
+}
+
+@test "filter_aur_for_fs zfs keeps every package including zfs-only tooling" {
+ run filter_aur_for_fs zfs downgrade yay zrepl zfs-auto-snapshot topgrade
+ [ "$status" -eq 0 ]
+ [ "${#lines[@]}" -eq 5 ]
+ [[ "$output" == *"zfs-auto-snapshot"* ]]
+ [[ "$output" == *"zrepl"* ]]
+ [[ "$output" == *"yay"* ]]
+}
+
+@test "filter_aur_for_fs btrfs drops zfs-only tooling, keeps the rest" {
+ run filter_aur_for_fs btrfs downgrade yay zrepl zfs-auto-snapshot topgrade
+ [ "$status" -eq 0 ]
+ [ "${#lines[@]}" -eq 3 ]
+ [[ "$output" != *"zfs-auto-snapshot"* ]]
+ [[ "$output" != *"zrepl"* ]]
+ [[ "$output" == *"downgrade"* ]]
+ [[ "$output" == *"yay"* ]]
+ [[ "$output" == *"topgrade"* ]]
+}
+
+@test "filter_aur_for_fs btrfs with only zfs-only tooling prints nothing" {
+ run filter_aur_for_fs btrfs zfs-auto-snapshot zrepl
+ [ "$status" -eq 0 ]
+ [ -z "$output" ]
+}
+
+@test "filter_aur_for_fs with no package arguments prints nothing" {
+ run filter_aur_for_fs btrfs
+ [ "$status" -eq 0 ]
+ [ -z "$output" ]
+}
+
+@test "filter_aur_for_fs preserves input order" {
+ run filter_aur_for_fs zfs yay downgrade topgrade
+ [ "$status" -eq 0 ]
+ [ "${lines[0]}" = "yay" ]
+ [ "${lines[2]}" = "topgrade" ]
+}
diff --git a/tests/unit/test_config.bats b/tests/unit/test_config.bats
index af23e4a..4169c5e 100644
--- a/tests/unit/test_config.bats
+++ b/tests/unit/test_config.bats
@@ -5,6 +5,8 @@ setup() {
# shellcheck disable=SC1091
source "${BATS_TEST_DIRNAME}/../../installer/lib/common.sh"
# shellcheck disable=SC1091
+ source "${BATS_TEST_DIRNAME}/../../installer/lib/raid.sh"
+ # shellcheck disable=SC1091
source "${BATS_TEST_DIRNAME}/../../installer/lib/config.sh"
}
@@ -93,6 +95,62 @@ EOF
[[ "$output" == *"4 error"* ]]
}
+@test "validate_config under set -e reports every error, not just the first" {
+ # Reproduces the monolith's call structure: `set -e` is active and
+ # validate_config is invoked as the final command of an && list. A
+ # post-increment that returns the pre-increment value (0 on the first
+ # error) trips set -e and aborts the function after one warning. This
+ # test runs outside bats' `run` shield (which sets +e) so the real
+ # accumulate-and-report behavior is exercised.
+ run bash -c '
+ set -e
+ source "'"${BATS_TEST_DIRNAME}"'/../../installer/lib/common.sh"
+ source "'"${BATS_TEST_DIRNAME}"'/../../installer/lib/raid.sh"
+ source "'"${BATS_TEST_DIRNAME}"'/../../installer/lib/config.sh"
+ HOSTNAME=""; TIMEZONE=""; SELECTED_DISKS=(); ROOT_PASSWORD=""
+ UNATTENDED=true
+ [[ "$UNATTENDED" == true ]] && validate_config
+ '
+ [ "$status" -eq 1 ]
+ [[ "$output" == *"HOSTNAME not set"* ]]
+ [[ "$output" == *"TIMEZONE not set"* ]]
+ [[ "$output" == *"No disks selected"* ]]
+ [[ "$output" == *"ROOT_PASSWORD not set"* ]]
+ [[ "$output" == *"4 error"* ]]
+}
+
+@test "validate_config rejects a RAID_LEVEL invalid for the disk count" {
+ HOSTNAME=h
+ TIMEZONE=UTC
+ ROOT_PASSWORD=x
+ SELECTED_DISKS=(/dev/sda /dev/sdb)
+ RAID_LEVEL=raidz1
+ run validate_config
+ [ "$status" -eq 1 ]
+ [[ "$output" == *"Invalid RAID_LEVEL"* ]]
+ [[ "$output" == *"raidz1"* ]]
+}
+
+@test "validate_config accepts a RAID_LEVEL valid for the disk count" {
+ HOSTNAME=h
+ TIMEZONE=UTC
+ ROOT_PASSWORD=x
+ SELECTED_DISKS=(/dev/sda /dev/sdb /dev/sdc)
+ RAID_LEVEL=raidz1
+ run validate_config
+ [[ "$output" != *"Invalid RAID_LEVEL"* ]]
+}
+
+@test "validate_config accepts an empty RAID_LEVEL for a single disk" {
+ HOSTNAME=h
+ TIMEZONE=UTC
+ ROOT_PASSWORD=x
+ SELECTED_DISKS=(/dev/sda)
+ RAID_LEVEL=""
+ run validate_config
+ [[ "$output" != *"Invalid RAID_LEVEL"* ]]
+}
+
@test "validate_config rejects an invalid timezone" {
HOSTNAME="h"
TIMEZONE="Not/A_Real_Zone_xyz"