From 1e35f2b50043a442da0917237371091ef4b745d8 Mon Sep 17 00:00:00 2001 From: "sec-check[bot]" Date: Thu, 17 Sep 2026 17:13:54 -0400 Subject: [PATCH] test(dynamic-wallpaper): BATS coverage for the 20-dynamic-wallpaper.sh user-setup hook system_files/bluefin/usr/share/ublue-os/user-setup.hooks.d/20-dynamic-wallpaper.sh was the only file under */*.hooks.d/ without a test suite. Add tests/test_dynamic_wallpaper_hook.bats, following the tests/test_theming_hook.bats pattern, covering the once-only version-script gate, the --user scope and exact unit name of the timer enable, the deliberately tolerated helper failure, and the set -e abort when systemctl fails. The last case is a characterization test: version-script stamps the version before the hook body runs, so a run that dies at systemctl enable burns version 1 and never retries. Asserted as-is so the behaviour is visible. Register the suite in the Justfile test recipe. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: sec-check[bot] --- Justfile | 1 + tests/test_dynamic_wallpaper_hook.bats | 119 +++++++++++++++++++++++++ 2 files changed, 120 insertions(+) create mode 100644 tests/test_dynamic_wallpaper_hook.bats diff --git a/Justfile b/Justfile index f5fcdb4d..8dfff0c9 100644 --- a/Justfile +++ b/Justfile @@ -31,6 +31,7 @@ test: bats tests/test_bonedigger_report.bats bats tests/test_hardware_hooks.bats bats tests/test_theming_hook.bats + bats tests/test_dynamic_wallpaper_hook.bats bats tests/test_nvidia_flatpak_sync.bats bats tests/test_system_just.bats bats tests/test_brew_tap_trust.bats diff --git a/tests/test_dynamic_wallpaper_hook.bats b/tests/test_dynamic_wallpaper_hook.bats new file mode 100644 index 00000000..5f2aff4a --- /dev/null +++ b/tests/test_dynamic_wallpaper_hook.bats @@ -0,0 +1,119 @@ +#!/usr/bin/env bats +# Tests for system_files/bluefin/usr/share/ublue-os/user-setup.hooks.d/20-dynamic-wallpaper.sh +# +# Run: bats tests/test_dynamic_wallpaper_hook.bats + +REPO_ROOT="$BATS_TEST_DIRNAME/.." +WALLPAPER_HOOK="${REPO_ROOT}/system_files/bluefin/usr/share/ublue-os/user-setup.hooks.d/20-dynamic-wallpaper.sh" +LIBSETUP_REAL="${REPO_ROOT}/system_files/shared/usr/lib/ublue/setup-services/libsetup.sh" +TIMER_UNIT="${REPO_ROOT}/system_files/bluefin/usr/lib/systemd/user/bluefin-dynamic-wallpaper.timer" + +WORKDIR="" +PATCHED_HOOK="" + +setup() { + WORKDIR="$(mktemp -d)" + mkdir -p "${WORKDIR}/bin" + + # Exit codes the mocks below read, so a test can make either dependency fail. + echo 0 > "${WORKDIR}/systemctl.rc" + echo 0 > "${WORKDIR}/wallpaper.rc" + + cat > "${WORKDIR}/bin/systemctl" << MOCK +#!/bin/bash +echo "\$*" >> "${WORKDIR}/systemctl.log" +exit "\$(cat "${WORKDIR}/systemctl.rc")" +MOCK + chmod +x "${WORKDIR}/bin/systemctl" + + cat > "${WORKDIR}/bin/bluefin-dynamic-wallpaper" << MOCK +#!/bin/bash +echo "invoked" >> "${WORKDIR}/wallpaper.log" +exit "\$(cat "${WORKDIR}/wallpaper.rc")" +MOCK + chmod +x "${WORKDIR}/bin/bluefin-dynamic-wallpaper" + + # Patch the absolute paths the hook uses so it runs against the real + # libsetup.sh and the mock helper instead of an installed image. + PATCHED_HOOK="${WORKDIR}/20-dynamic-wallpaper.sh" + sed \ + -e "s|source /usr/lib/ublue/setup-services/libsetup.sh|source ${LIBSETUP_REAL}|g" \ + -e "s|/usr/libexec/bluefin-dynamic-wallpaper|${WORKDIR}/bin/bluefin-dynamic-wallpaper|g" \ + "${WALLPAPER_HOOK}" > "${PATCHED_HOOK}" + chmod +x "${PATCHED_HOOK}" + + export PATH="${WORKDIR}/bin:${PATH}" + export SETUP_CHECKER_FILE="${WORKDIR}/setup_versioning.json" +} + +teardown() { + rm -rf "${WORKDIR}" +} + +@test "20-dynamic-wallpaper: first run enables the timer and sets the initial wallpaper" { + run bash "${PATCHED_HOOK}" + [ "${status}" -eq 0 ] + grep -qx -- "--user enable --now bluefin-dynamic-wallpaper.timer" "${WORKDIR}/systemctl.log" + [ "$(wc -l < "${WORKDIR}/wallpaper.log")" -eq 1 ] +} + +@test "20-dynamic-wallpaper: the timer it enables is the unit shipped by this repo" { + [ -f "${TIMER_UNIT}" ] +} + +@test "20-dynamic-wallpaper: enabling the timer is a --user (not system) operation" { + run bash "${PATCHED_HOOK}" + [ "${status}" -eq 0 ] + ! grep -q -- "--system" "${WORKDIR}/systemctl.log" +} + +@test "20-dynamic-wallpaper: records version 1 under the user service namespace" { + run bash "${PATCHED_HOOK}" + [ "${status}" -eq 0 ] + [ "$(jq -r '.version.user."dynamic-wallpaper"' "${SETUP_CHECKER_FILE}")" = "1" ] +} + +@test "20-dynamic-wallpaper: version-script gate makes a second run a no-op" { + run bash "${PATCHED_HOOK}" + [ "${status}" -eq 0 ] + + run bash "${PATCHED_HOOK}" + [ "${status}" -eq 0 ] + + [ "$(wc -l < "${WORKDIR}/systemctl.log")" -eq 1 ] + [ "$(wc -l < "${WORKDIR}/wallpaper.log")" -eq 1 ] +} + +@test "20-dynamic-wallpaper: a failing wallpaper helper does not fail the hook" { + echo 1 > "${WORKDIR}/wallpaper.rc" + + run bash "${PATCHED_HOOK}" + [ "${status}" -eq 0 ] + grep -qx -- "--user enable --now bluefin-dynamic-wallpaper.timer" "${WORKDIR}/systemctl.log" + [ "$(wc -l < "${WORKDIR}/wallpaper.log")" -eq 1 ] +} + +@test "20-dynamic-wallpaper: a failing systemctl aborts before the wallpaper is set" { + echo 1 > "${WORKDIR}/systemctl.rc" + + run bash "${PATCHED_HOOK}" + [ "${status}" -ne 0 ] + [ ! -e "${WORKDIR}/wallpaper.log" ] +} + +# Characterization test, not an endorsement: version-script stamps the version +# before the hook body runs, so a run that dies at `systemctl enable` still +# burns version 1 and no later run ever retries. Asserted here so the current +# behaviour is visible and a fix has to update this test deliberately. +@test "20-dynamic-wallpaper: a failed run still burns the version and never retries" { + echo 1 > "${WORKDIR}/systemctl.rc" + run bash "${PATCHED_HOOK}" + [ "${status}" -ne 0 ] + [ "$(jq -r '.version.user."dynamic-wallpaper"' "${SETUP_CHECKER_FILE}")" = "1" ] + + echo 0 > "${WORKDIR}/systemctl.rc" + run bash "${PATCHED_HOOK}" + [ "${status}" -eq 0 ] + [ ! -e "${WORKDIR}/wallpaper.log" ] + [ "$(wc -l < "${WORKDIR}/systemctl.log")" -eq 1 ] +}