]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
test: Initial systemd-sysext tests
authorKrzesimir Nowak <knowak@microsoft.com>
Thu, 15 Feb 2024 14:32:43 +0000 (15:32 +0100)
committerKrzesimir Nowak <knowak@microsoft.com>
Thu, 22 Feb 2024 18:06:22 +0000 (19:06 +0100)
The follow-up commit will refactor some code in systemd-sysext, so add some
tests to make sure that things didn't break. The tests will be later extended
with cases for new features added.

test/units/testsuite-50.sh

index e34cbd915bc2646f58a3356e67f1cb5320ee7f82..54a43338db6cc8055afb43b94da9dca2b6b43b58 100755 (executable)
@@ -8,10 +8,7 @@ set -o pipefail
 
 export SYSTEMD_LOG_LEVEL=debug
 
-# shellcheck disable=SC2317
-cleanup() {(
-    set +ex
-
+cleanup_image_dir() {
     if [ -z "${image_dir}" ]; then
         return
     fi
@@ -20,6 +17,39 @@ cleanup() {(
     umount "${image_dir}/app-nodistro"
     umount "${image_dir}/service-scoped-test"
     rm -rf "${image_dir}"
+}
+
+fake_roots_dir=/fake-roots
+
+cleanup_fake_rootfses() {
+    local tries=10 e
+    local -a lines fake_roots_mounts
+
+    while [[ ${tries} -gt 0 ]]; do
+        tries=$((tries - 1))
+        mapfile -t lines < <(mount | awk '{ print $3 }')
+        fake_roots_mounts=()
+        for e in "${lines[@]}"; do
+            if [[ ${e} = "${fake_roots_dir}"/* ]]; then
+                fake_roots_mounts+=( "${e}" )
+            fi
+        done
+        if [[ ${#fake_roots_mounts[@]} -eq 0 ]]; then
+            break
+        fi
+        for e in "${fake_roots_mounts[@]}"; do
+            umount "${e}"
+        done
+    done
+    rm -rf "${fake_roots_dir}"
+}
+
+# shellcheck disable=SC2317
+cleanup() {(
+    set +ex
+
+    cleanup_image_dir
+    cleanup_fake_rootfses
 )}
 
 udevadm control --log-level=debug
@@ -765,4 +795,248 @@ fi
 (! systemd-run -P -p RootImage="/this/should/definitely/not/exist.img" false)
 (! systemd-run -P -p ExtensionDirectories="/foo/bar /foo/baz" false)
 
+# general systemd-sysext tests
+
+shopt -s extglob
+
+die() {
+    echo "${*}"
+    exit 1
+}
+
+prep_root() {
+    local r=${1}; shift
+    local h=${1}; shift
+
+    mkdir -p "${r}${h}" "${r}/usr/lib" "${r}/var/lib/extensions"
+}
+
+gen_os_release() {
+    local r=${1}; shift
+
+    {
+        echo "ID=testtest"
+        echo "VERSION=1.2.3"
+    } >"${r}/usr/lib/os-release"
+}
+
+gen_test_ext_image() {
+    local r=${1}; shift
+    local h=${1}; shift
+
+    local n d f
+
+    n='test-extension'
+    d="${r}/var/lib/extensions/${n}"
+    f="${d}/usr/lib/extension-release.d/extension-release.${n}"
+    mkdir -p "$(dirname "${f}")"
+    echo "ID=_any" >"${f}"
+    mkdir -p "${d}/${h}"
+    touch "${d}${h}/preexisting-file-in-extension-image"
+}
+
+make_ro() {
+    local r=${1}; shift
+    local h=${1}; shift
+
+    mount -o bind "${r}${h}" "${r}${h}"
+    mount -o bind,remount,ro "${r}${h}"
+}
+
+prep_hierarchy() {
+    local r=${1}; shift
+    local h=${1}; shift
+
+    touch "${r}${h}/preexisting-file-in-hierarchy"
+}
+
+prep_ro_hierarchy() {
+    local r=${1}; shift
+    local h=${1}; shift
+
+    prep_hierarchy "${r}" "${h}"
+    make_ro "${r}" "${h}"
+}
+
+# extra args:
+# "e" for checking for the preexisting file in extension
+# "h" for checking for the preexisting file in hierarchy
+check_usual_suspects() {
+    local root=${1}; shift
+    local hierarchy=${1}; shift
+    local message=${1}; shift
+
+    local arg
+    # shellcheck disable=SC2034 # the variables below are used indirectly
+    local e='' h=''
+
+    for arg; do
+        case ${arg} in
+            e|h)
+                local -n v=${arg}
+                v=x
+                unset -n v
+                ;;
+            *)
+                die "invalid arg to ${0}: ${arg@Q}"
+                ;;
+        esac
+    done
+
+    # var name, file name
+    local pairs=(
+        e:preexisting-file-in-extension-image
+        h:preexisting-file-in-hierarchy
+    )
+    local pair name file desc full_path
+    for pair in "${pairs[@]}"; do
+        name=${pair%%:*}
+        file=${pair#*:}
+        desc=${file//-/ }
+        full_path="${root}${hierarchy}/${file}"
+        local -n v=${name}
+        if [[ -n ${v} ]]; then
+            test -f "${full_path}" || {
+                ls -la "$(dirname "${full_path}")"
+                die "${desc} is missing ${message}"
+            }
+        else
+            test ! -f "${full_path}" || {
+                ls -la "$(dirname "${full_path}")"
+                die "${desc} unexpectedly exists ${message}"
+            }
+        fi
+        unset -n v
+    done
+}
+
+check_usual_suspects_after_merge() {
+    local r=${1}; shift
+    local h=${1}; shift
+
+    check_usual_suspects "${r}" "${h}" "after merge" "${@}"
+}
+
+check_usual_suspects_after_unmerge() {
+    local r=${1}; shift
+    local h=${1}; shift
+
+    check_usual_suspects "${r}" "${h}" "after unmerge" "${@}"
+}
+
+
+
+#
+# simple case, read-only hierarchy
+#
+
+
+fake_root=${fake_roots_dir}/simple-read-only-with-read-only-hierarchy
+hierarchy=/usr
+
+prep_root "${fake_root}" "${hierarchy}"
+gen_os_release "${fake_root}"
+gen_test_ext_image "${fake_root}" "${hierarchy}"
+
+prep_ro_hierarchy "${fake_root}" "${hierarchy}"
+
+touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only"
+
+# run systemd-sysext
+SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" merge
+
+touch "${fake_root}${hierarchy}/should-still-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only"
+check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h
+
+SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge
+
+check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h
+
+touch "${fake_root}${hierarchy}/should-still-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only after unmerge"
+
+#
+# simple case, mutable hierarchy
+#
+
+
+fake_root=${fake_roots_dir}/simple-read-only-with-mutable-hierarchy
+hierarchy=/usr
+
+prep_root "${fake_root}" "${hierarchy}"
+gen_os_release "${fake_root}"
+gen_test_ext_image "${fake_root}" "${hierarchy}"
+
+prep_hierarchy "${fake_root}" "${hierarchy}"
+
+touch "${fake_root}${hierarchy}/should-succeed-on-mutable-fs" || die "${fake_root}${hierarchy} is not mutable"
+
+# run systemd-sysext
+SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" merge
+
+touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only"
+check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h
+
+SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge
+
+check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h
+
+touch "${fake_root}${hierarchy}/should-succeed-on-mutable-fs-again" || die "${fake_root}${hierarchy} is not mutable after unmerge"
+
+
+#
+# simple case, no hierarchy either
+#
+
+
+fake_root=${fake_roots_dir}/simple-read-only-with-missing-hierarchy
+hierarchy=/opt
+
+prep_root "${fake_root}" "${hierarchy}"
+rmdir "${fake_root}/${hierarchy}"
+gen_os_release "${fake_root}"
+gen_test_ext_image "${fake_root}" "${hierarchy}"
+
+# run systemd-sysext
+SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" merge
+
+touch "${fake_root}${hierarchy}/should-still-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only"
+check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e
+
+SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge
+
+check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}"
+
+
+#
+# simple case, an empty hierarchy
+#
+
+
+fake_root=${fake_roots_dir}/simple-read-only-with-empty-hierarchy
+hierarchy=/opt
+
+prep_root "${fake_root}" "${hierarchy}"
+gen_os_release "${fake_root}"
+gen_test_ext_image "${fake_root}" "${hierarchy}"
+
+make_ro "${fake_root}" "${hierarchy}"
+
+touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only"
+
+# run systemd-sysext
+SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" merge
+
+touch "${fake_root}${hierarchy}/should-still-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only"
+check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e
+
+SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge
+
+check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}"
+
+
+#
+# done
+#
+
+
 touch /testok