diff options
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/unit/test_btrfs.bats | 35 | ||||
| -rw-r--r-- | tests/unit/test_build_aur.bats | 11 | ||||
| -rw-r--r-- | tests/unit/test_common.bats | 70 | ||||
| -rw-r--r-- | tests/unit/test_config.bats | 58 |
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" |
