diff --git a/.ci/lib/testlib.sh b/.ci/lib/testlib.sh index 83e873fb4..a9c0bcf0f 100755 --- a/.ci/lib/testlib.sh +++ b/.ci/lib/testlib.sh @@ -1,5 +1,5 @@ #!/bin/sh -# Unit tests for the postmarketOS initramfs +# Unit testing framework for shell scripts # Invoke with the path to a tests/ subdir of a package and the # package name as arguments. Or source it with the following # variables set: @@ -27,15 +27,19 @@ _test_statefile="$(mktemp)" results_dir="${results_dir:-}" test_log() { - printf "%s\n" "$*" >&2 + # ash supports echo -e + # shellcheck disable=SC3037 + echo -e "$*" >&2 } test_info() { - printf "${BLUE}%s${RESET}\n" "$*" >&2 + # shellcheck disable=SC3037 + echo -e "${BLUE}$*${RESET}" >&2 } test_debug() { - printf "${YELLOW}%s${RESET}\n" "$*" >&2 + # shellcheck disable=SC3037 + echo -e "${YELLOW}$*${RESET}" >&2 } assert_strequal() { @@ -189,6 +193,7 @@ run_tests() { if [ -n "$failed" ]; then exit 1; else exit 0; fi } +# FIXME: probably not the best way to determine if this was sourced if [ $# -gt 0 ]; then run_tests "$1" "$2" fi diff --git a/main/postmarketos-initramfs/tests/.gitlab-ci.yml b/main/postmarketos-initramfs/tests/.gitlab-ci.yml new file mode 100644 index 000000000..966f95adb --- /dev/null +++ b/main/postmarketos-initramfs/tests/.gitlab-ci.yml @@ -0,0 +1,9 @@ + +initramfs-unit-tests: + extends: .package-test + script: + - .ci/lib/testlib.sh main/postmarketos-initramfs/tests + rules: + - if: $CI_PIPELINE_SOURCE == "merge_request_event" || $CI_COMMIT_REF_PROTECTED == "false" + changes: + - main/postmarketos-initramfs/*.sh diff --git a/main/postmarketos-initramfs/tests/01-parse-cmdline.sh b/main/postmarketos-initramfs/tests/01-parse-cmdline.sh new file mode 100755 index 000000000..4176007b6 --- /dev/null +++ b/main/postmarketos-initramfs/tests/01-parse-cmdline.sh @@ -0,0 +1,73 @@ +#!/bin/sh + +srcdir="$(dirname "$(realpath $0)")/.." +testlib_path="$1" +shift +# Used by testlib.sh +# shellcheck disable=SC2034 +results_dir="$1" +shift + +# All arguments have to be consumed before sourcing testlib! +# shellcheck disable=SC1090 +. "$testlib_path" + +### Test 1 ### + +start_test "Ensure all boolean variables can be set" +. "$srcdir/init_functions.sh" + +# busybox ash supports process substitution +# shellcheck disable=SC3001 +parse_cmdline < <(echo \ +pmos.bootchart2 pmos.debug-shell pmos.force-partition-resize \ +pmos.nosplash pmos.stowaway rd.info \ +) + +assert_equal "bootchart2" "y" +assert_equal "debug_shell" "y" +assert_equal "force_partition_resize" "y" +assert_equal "nosplash" "y" +assert_equal "log_info" "y" +end_test + +### Test 2 ### + +start_test "Ensure non-boolean variables can be set" +. $srcdir/init_functions.sh + +# busybox ash supports process substitution +# shellcheck disable=SC3001 +parse_cmdline < <(echo \ +pmos.boot_uuid=xyz-789 pmos.root_uuid=abc-123 \ +pmos.usb-storage=/dev/sdc \ +pmos.boot=/dev/mapper/userdata1 \ +pmos.root=/dev/disk/by-partlabel/userdata \ +pmos.rootfsopts=default +) + +assert_equal "boot_uuid" "xyz-789" +assert_equal "root_uuid" "abc-123" +assert_equal "usb_storage" "/dev/sdc" +assert_equal "boot_path" "/dev/mapper/userdata1" +assert_equal "root_path" "/dev/disk/by-partlabel/userdata" +assert_equal "rootfsopts" ",default" + +test_info "Checking other variables are unset" +assert_unset debug_shell +assert_unset nosplash +assert_unset bootchart2 +end_test + +### Test 3 ### + +start_test "Test info loglevel" +. $srcdir/init_functions.sh + +assert_unset log_info +assert_unset "(info hello world)" +logeval parse_cmdline_item "rd.info" +assert_equal "(info hello world)" "hello world" +end_test + +end_testsuite diff --git a/main/postmarketos-initramfs/tests/02-find-partition.sh b/main/postmarketos-initramfs/tests/02-find-partition.sh new file mode 100755 index 000000000..3549e2f78 --- /dev/null +++ b/main/postmarketos-initramfs/tests/02-find-partition.sh @@ -0,0 +1,196 @@ +#!/bin/sh + +srcdir="$(dirname "$(realpath "$0")")/.." +testlib_path="$1" +shift +# Used by testlib.sh +# shellcheck disable=SC2034 +results_dir="$1" +shift + +# All arguments have to be consumed before sourcing testlib! +# shellcheck disable=SC1090 +. "$testlib_path" + +# Mock blkid that produces a path for all expected arguments +# except for --label if the label isn't "pmOS_valid" +blkid_mock_find_all() { + local fail + test_debug "+ blkid $*" + case "$1" in + --uuid) + case "$2" in + "abcd-1234") + echo "/dev/sda2" + ;; + "deaf-5678") + echo "/dev/sda1" + ;; + *) + fail="Unexpected arguments to blkid: $*" + assert_unset fail + ;; + esac + ;; + --label) + if [ "$2" = "pmOS_valid" ]; then + echo "/dev/disk/by-label/pmOS_root" + fi + return + ;; + --match-token) + assert_strequal "$2" "TYPE=crypto_LUKS" + echo "/dev/sda17" + ;; + *) + fail="Unexpected arguments to blkid: $*" + assert_unset fail + ;; + esac +} + +### Test 1 ### + +start_test "Test find_partition happy paths" +. "$srcdir/init_functions.sh" + +# For this we need to mock a few things +pretty_dm_path() { + echo "$1" +} + +blkid() { + # Splitting is intentional + # shellcheck disable=SC2068 + blkid_mock_find_all $@ +} + +# Test all the happy paths, for all of these we assume that blkid would succeed +test_info "A) Valid UUID (ideal case)" +logeval 'found="$(find_partition abcd-1234 /dev/null pmOS_root "TYPE=crypto_LUKS")"' +assert_equal found /dev/sda2 + +test_info +test_info "B) No UUID but valid path from pmos.root=" +logeval 'found="$(find_partition "" /dev/null pmOS_root "TYPE=crypto_LUKS")"' +assert_equal found /dev/null + +test_info +test_info "C) No UUID or path, rely on the label" +logeval 'found="$(find_partition "" "" pmOS_valid "TYPE=crypto_LUKS")"' +assert_equal found /dev/disk/by-label/pmOS_root + +test_info +test_info "D) No UUID, path, and missing label (FDE case)" +logeval 'found="$(find_partition "" "" pmOS_invalid "TYPE=crypto_LUKS")"' +assert_equal found /dev/sda17 + +end_test + +### Test 2 ### + +start_test "Test find_partition sad paths" +. $srcdir/init_functions.sh + + +# For this we need to mock a few things +pretty_dm_path() { + echo "$1" +} + +test_info "A) Partition with given UUID doesn't exist, no other lookup is done" +# Returns nothing when called with --uuid, fails for any other +# arguments. This simulates a partition with the given UUID +# not existing AND that we never call with blkid to look up +# by label or match token. +blkid() { + test_debug "blkid $*" + case "$1" in + --uuid) + assert_strequal "$2" "abcd-1234" + return + ;; + *) + fail="Unexpected arguments to blkid: $*" + assert_unset fail + ;; + esac +} + +logeval 'found="$(find_partition abcd-1234 /dev/null pmOS_root "TYPE=crypto_LUKS")"' +assert_unset found + +test_info "B) No UUID, partition with given path doesn't exist, no other lookup is done" +logeval 'found="$(find_partition "" /dev/notablockdev pmOS_root "TYPE=crypto_LUKS")"' +assert_unset found + +test_info "C) No UUID, no path, label and match token not found" +# Returns nothing, errors if not called with --uuid, +# --label, or --match-token +blkid() { + test_debug "blkid $*" + case "$1" in + --uuid) + assert_strequal "$2" "abcd-1234" + return + ;; + --label) + assert_strequal "$2" "pmOS_root" + return + ;; + --match-token) + assert_strequal "$2" "TYPE=crypto_LUKS" + return + ;; + *) + fail="Unexpected arguments to blkid: $*" + assert_unset fail + ;; + esac +} +logeval 'found="$(find_partition "" "" pmOS_root "TYPE=crypto_LUKS")"' +assert_unset found + +end_test + +### Test 3 ### + +start_test "Test find_root_partition and find_boot_partition" +. $srcdir/init_functions.sh + +# Mocks +pretty_dm_path() { + echo "$1" +} + +blkid() { + # Splitting is intentional + # shellcheck disable=SC2068 + blkid_mock_find_all $@ +} + +test_info "A) Valid UUID, result is cached" +logeval 'root_uuid=abcd-1234' +logeval 'boot_uuid=deaf-5678' + +logeval 'find_root_partition found' +assert_equal found /dev/sda2 +logeval 'find_boot_partition found' +assert_equal found /dev/sda1 + +blkid() { + local fail + # fail is used indirectly + # shellcheck disable=SC2034 + fail="blkid called when expecting cached result" + assert_unset fail +} + +logeval 'find_root_partition found' +assert_equal found /dev/sda2 +logeval 'find_boot_partition found' +assert_equal found /dev/sda1 + +end_test + +end_testsuite