diff options
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/fixtures/bazzite-44/usr/bin/bazzite-steam | 10 | ||||
| -rw-r--r-- | tests/fixtures/bazzite-44/usr/libexec/bazzite-hardware-setup | 10 | ||||
| -rw-r--r-- | tests/fixtures/bazzite-44/usr/libexec/bazzite-user-setup | 16 | ||||
| -rwxr-xr-x | tests/test-aerocore-anaconda-profile.sh | 16 | ||||
| -rw-r--r-- | tests/test-build-channel-metadata.sh | 20 | ||||
| -rwxr-xr-x | tests/test-configure-target-gpt-root.sh | 51 | ||||
| -rwxr-xr-x | tests/test-decky-mirror-ujust.sh | 51 | ||||
| -rwxr-xr-x | tests/test-desktop-branding-migration.sh | 59 | ||||
| -rwxr-xr-x | tests/test-dotenv-precedence.sh | 28 | ||||
| -rwxr-xr-x | tests/test-patch-bazzite-deck-identity.sh | 58 |
10 files changed, 319 insertions, 0 deletions
diff --git a/tests/fixtures/bazzite-44/usr/bin/bazzite-steam b/tests/fixtures/bazzite-44/usr/bin/bazzite-steam new file mode 100644 index 0000000..9249ce1 --- /dev/null +++ b/tests/fixtures/bazzite-44/usr/bin/bazzite-steam @@ -0,0 +1,10 @@ +#!/usr/bin/bash + +# Minimal structural fixture from Bazzite 44.20260820. +if [[ $IMAGE_NAME =~ "deck" ]]; then + if [[ ! -d $HOME/.local/share/Steam ]]; then + mkdir -p "$HOME/.local/share" + fi + + DECK_OPTION="-steamdeck" +fi diff --git a/tests/fixtures/bazzite-44/usr/libexec/bazzite-hardware-setup b/tests/fixtures/bazzite-44/usr/libexec/bazzite-hardware-setup new file mode 100644 index 0000000..54aa246 --- /dev/null +++ b/tests/fixtures/bazzite-44/usr/libexec/bazzite-hardware-setup @@ -0,0 +1,10 @@ +#!/usr/bin/bash + +# Minimal structural fixture from Bazzite 44.20260820. +if [[ "$IMAGE_NAME" != *deck* && "$IMAGE_NAME" != *dx* ]]; then + rm -f /etc/sddm.conf.d/steamos.conf +fi + +if [[ $IMAGE_NAME =~ "deck" ]]; then + systemctl mask tuned.service +fi diff --git a/tests/fixtures/bazzite-44/usr/libexec/bazzite-user-setup b/tests/fixtures/bazzite-44/usr/libexec/bazzite-user-setup new file mode 100644 index 0000000..9466a0b --- /dev/null +++ b/tests/fixtures/bazzite-44/usr/libexec/bazzite-user-setup @@ -0,0 +1,16 @@ +#!/usr/bin/bash + +pkexec /usr/libexec/bazzite-privileged-user-setup "$USER" + +# Minimal structural fixture from Bazzite 44.20260820. +if [[ $IMAGE_NAME =~ "deck" ]]; then + touch "$HOME/Desktop/Return.desktop" +fi + +if [[ $IMAGE_NAME =~ "deck" ]]; then + touch "$HOME/.config/bazzite/desktop-configured" +fi + +if [[ $IMAGE_NAME =~ "deck" ]]; then + systemctl --user enable --now sdgyrodsu.service +fi diff --git a/tests/test-aerocore-anaconda-profile.sh b/tests/test-aerocore-anaconda-profile.sh new file mode 100755 index 0000000..3b3bb61 --- /dev/null +++ b/tests/test-aerocore-anaconda-profile.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +set -euo pipefail + +project_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +profile="${project_root}/installer/system_files/overrides/etc/anaconda/profile.d/aerocore.conf" +build_script="${project_root}/installer/build.sh" + +grep -qx 'profile_id = aerocore' "${profile}" +grep -qx 'os_id = aerocore' "${profile}" +grep -Fqx "sed -i 's/^ID=.*/ID=aerocore/' /usr/lib/os-release" "${build_script}" + +if grep -Eq '^[[:space:]]*(UserSpoke|anaconda-screen-accounts)[[:space:]]*$' "${profile}"; then + echo "AeroCore's Anaconda profile must leave account creation visible" >&2 + exit 1 +fi diff --git a/tests/test-build-channel-metadata.sh b/tests/test-build-channel-metadata.sh new file mode 100644 index 0000000..75a2827 --- /dev/null +++ b/tests/test-build-channel-metadata.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +set -euo pipefail + +repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" + +# The build recipe's positional tag must be authoritative for channel +# metadata. This protects `just build ... testing` from stale dotenv values. +grep -Fqx ' "--build-arg" "IMAGE_BRANCH={{ tag }}"' "${repo_root}/Justfile" +grep -Fqx ' "--build-arg" "VERSION_TAG={{ tag }}"' "${repo_root}/Justfile" +grep -Fqx ' "--build-arg" "VERSION_PRETTY={{ tag }}"' "${repo_root}/Justfile" +grep -Fqx ' LABELS+=("--label" "org.opencontainers.image.version={{ tag }}-${GIT_SHA}")' "${repo_root}/Justfile" +grep -Fqx ' "image-tag": "$IMAGE_BRANCH_NORMALIZED",' "${repo_root}/build_files/image-info" + +if grep -Fq ' "image-tag": "stable",' "${repo_root}/build_files/image-info"; then + echo 'image-info must not hard-code stable as the image tag' >&2 + exit 1 +fi + +echo 'Build channel metadata checks passed' diff --git a/tests/test-configure-target-gpt-root.sh b/tests/test-configure-target-gpt-root.sh new file mode 100755 index 0000000..ed5e33e --- /dev/null +++ b/tests/test-configure-target-gpt-root.sh @@ -0,0 +1,51 @@ +#!/usr/bin/env bash + +set -euo pipefail + +project_root="$(git rev-parse --show-toplevel)" +tmp_dir="$(mktemp -d)" +trap 'rm -rf "${tmp_dir}"' EXIT +mkdir -p "${tmp_dir}/bin" + +# shellcheck disable=SC2016 # The generated fixture expands this in its own process. +printf '%s\n' \ + '#!/usr/bin/env bash' \ + 'if [[ " $* " == *" -no SOURCE "* ]]; then' \ + ' [[ " $* " == *" --nofsroot "* ]] || exit 97' \ + ' printf "%s\\n" "${TEST_FINDMNT_SOURCE:?}"' \ + 'else' \ + " printf '252:3\\n'" \ + 'fi' > "${tmp_dir}/bin/findmnt" + +printf '%s\n' \ + '#!/usr/bin/env bash' \ + 'case " $* " in' \ + " *\" PKNAME \"*) printf 'vda\\n' ;;" \ + " *\" PARTN \"*) printf '3\\n' ;;" \ + " *\" PARTNUM \"*) exit 98 ;;" \ + " *) printf '/dev/vda3 252:3\\n' ;;" \ + 'esac' > "${tmp_dir}/bin/lsblk" + +# shellcheck disable=SC2016 # The generated fixture expands TEST_OUTPUT itself. +printf '%s\n' \ + '#!/usr/bin/env bash' \ + 'printf "%s\\n" "$*" > "${TEST_OUTPUT:?}"' > "${tmp_dir}/bin/sgdisk" + +printf '%s\n' '#!/usr/bin/env bash' 'exit 0' > "${tmp_dir}/bin/partprobe" + +chmod +x "${tmp_dir}/bin/"* + +run_fixture() { + local findmnt_source=$1 + + TEST_FINDMNT_SOURCE="${findmnt_source}" TEST_OUTPUT="${tmp_dir}/sgdisk.args" \ + PATH="${tmp_dir}/bin:${PATH}" \ + bash "${project_root}/installer/configure-target-gpt-root.sh" /mnt/sysroot + + grep -qx -- '--typecode=3:4f68bce3-e8cd-4db1-96e7-fbcaf984b709 /dev/vda' \ + "${tmp_dir}/sgdisk.args" +} + +run_fixture root +run_fixture '/dev/vda3[/root]' +printf 'GPT root bind-mount and Btrfs subvolume fixtures passed\n' diff --git a/tests/test-decky-mirror-ujust.sh b/tests/test-decky-mirror-ujust.sh new file mode 100755 index 0000000..6950c31 --- /dev/null +++ b/tests/test-decky-mirror-ujust.sh @@ -0,0 +1,51 @@ +#!/usr/bin/env bash +set -euo pipefail + +project_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +recipe="${project_root}/system_files/usr/share/ublue-os/just/92-aerocore-decky-mirror.just" + +if [[ ! -f "${recipe}" ]]; then + echo "Missing Decky mirror ujust recipe: ${recipe}" >&2 + exit 1 +fi + +if ! rg -q '^setup-decky-mirror ACTION=""' "${recipe}"; then + echo "Decky mirror recipe must expose ujust setup-decky-mirror" >&2 + exit 1 +fi + +if ! rg -q 'decky\.mirror\.aerocore\.com\.cn' "${recipe}"; then + echo "Decky mirror recipe must default to the AeroCore Decky mirror host" >&2 + exit 1 +fi + +if rg -q 'https://github\.com/SteamDeckHomebrew/decky-installer' "${recipe}"; then + echo "Decky mirror recipe must not install from GitHub" >&2 + exit 1 +fi + +if ! rg -q 'configure_plugin_store\(\)' "${recipe}" || \ + ! rg -q 'plugins\.decky\.mirror\.aerocore\.com\.cn' "${recipe}" || \ + ! rg -q 'DECKY_PLUGIN_STORE_URL=.*\/plugins' "${recipe}"; then + echo "Decky mirror recipe must configure the AeroCore plugin store URL" >&2 + exit 1 +fi + +if ! rg -q 'loader\.json' "${recipe}" || ! rg -q '\.store = 2' "${recipe}" || ! rg -q 'store-url' "${recipe}"; then + echo "Decky mirror recipe must persist the custom plugin store in loader.json" >&2 + exit 1 +fi + +if ! rg -q 'rm -rf.*HOMEBREW_FOLDER.*/services/PluginLoader' "${recipe}" || + ! rg -q 'rm -f.*USER_DIR.*/\.steam/steam/\.cef-enable-remote-debugging' "${recipe}" || + ! rg -q 'rm -f.*USER_DIR.*/\.var/app/com\.valvesoftware\.Steam/data/Steam/\.cef-enable-remote-debugging' "${recipe}"; then + echo "Decky mirror recipe must make uninstall safe for missing paths" >&2 + exit 1 +fi + +for script_name in install_release.sh install_prerelease.sh uninstall.sh; do + if ! rg -q "\\$\\{DECKY_INSTALLER_BASE\\}/${script_name}" "${recipe}"; then + echo "Decky mirror recipe does not route ${script_name} through the mirror base" >&2 + exit 1 + fi +done diff --git a/tests/test-desktop-branding-migration.sh b/tests/test-desktop-branding-migration.sh new file mode 100755 index 0000000..4715010 --- /dev/null +++ b/tests/test-desktop-branding-migration.sh @@ -0,0 +1,59 @@ +#!/usr/bin/env bash + +set -euo pipefail + +repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +test_root="$(mktemp -d -t aerocore-desktop-branding.XXXXXXXXXX)" +trap 'rm -rf "${test_root}"' EXIT + +mkdir -p \ + "${test_root}/var/home/stock/.config" \ + "${test_root}/var/home/custom/.config" + +printf '%s\n' 'icon=distributor-logo-steamdeck' \ + > "${test_root}/var/home/stock/.config/plasma-org.kde.plasma.desktop-appletsrc" +printf '%s\n' 'icon=user-selected-logo' \ + > "${test_root}/var/home/custom/.config/plasma-org.kde.plasma.desktop-appletsrc" + +HOME="${test_root}/var/home/stock" \ + bash "${repo_root}/system_files/usr/libexec/aerocore-desktop-branding" + +grep -Fxq 'icon=aerocore-logo' \ + "${test_root}/var/home/stock/.config/plasma-org.kde.plasma.desktop-appletsrc" +grep -Fxq 'icon=user-selected-logo' \ + "${test_root}/var/home/custom/.config/plasma-org.kde.plasma.desktop-appletsrc" + +# The migration must also be idempotent. +first_digest="$(sha256sum \ + "${test_root}/var/home/stock/.config/plasma-org.kde.plasma.desktop-appletsrc")" +HOME="${test_root}/var/home/stock" \ + bash "${repo_root}/system_files/usr/libexec/aerocore-desktop-branding" +second_digest="$(sha256sum \ + "${test_root}/var/home/stock/.config/plasma-org.kde.plasma.desktop-appletsrc")" +test "${first_digest}" = "${second_digest}" + +for path in \ + bazzite.webm \ + bazzite-oled.webm \ + bazzite-suspend.webm \ + bazzite-suspend-oled.webm; do + grep -Fq "${path}" "${repo_root}/build_files/build.sh" +done + +# The About System logo may be a symlink in the Bazzite base image. Both image +# build paths must explicitly replace that directory entry with AeroCore's PNG. +grep -Fq '"/usr/share/pixmaps/system-logo-white.png"' \ + "${repo_root}/build_files/build.sh" +grep -Fq 'rm -f /usr/share/pixmaps/system-logo-white.png' \ + "${repo_root}/installer/build.sh" + +# Branding migration is user setup, not a system boot service. +if rg -n 'aerocore-desktop-branding\.service|systemctl enable aerocore-desktop-branding' \ + "${repo_root}/build_files" "${repo_root}/system_files"; then + echo "Desktop branding must not be enabled as a system service" >&2 + exit 1 +fi +test ! -e "${repo_root}/system_files/usr/lib/systemd/system/aerocore-desktop-branding.service" +test -x "${repo_root}/system_files/usr/libexec/aerocore-desktop-branding-privileged" + +echo "Desktop branding migration fixture passed" diff --git a/tests/test-dotenv-precedence.sh b/tests/test-dotenv-precedence.sh new file mode 100755 index 0000000..f2cc760 --- /dev/null +++ b/tests/test-dotenv-precedence.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash + +set -euo pipefail + +project_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +tmp_dir="$(mktemp -d)" +trap 'rm -rf "${tmp_dir}"' EXIT + +grep -Fqx 'set dotenv-filename := ".env"' "${project_root}/Justfile" +grep -Fqx '.env' "${project_root}/.gitignore" +if rg -F -- '--dotenv-path image-template.env' "${project_root}/.github/workflows"; then + echo 'CI must not load image-template.env as a dotenv file' >&2 + exit 1 +fi + +printf '%s\n' \ + 'set dotenv-load' \ + 'value := env_var("VALUE")' \ + 'show:' \ + ' @echo "{{value}}"' > "${tmp_dir}/justfile" +printf '%s\n' 'VALUE=from-dotenv' > "${tmp_dir}/.env" + +[[ "$(cd "${tmp_dir}" && just show)" == 'from-dotenv' ]] +[[ "$(cd "${tmp_dir}" && VALUE=from-runtime just show)" == 'from-runtime' ]] + +mkdir "${tmp_dir}/without-dotenv" +cp "${tmp_dir}/justfile" "${tmp_dir}/without-dotenv/justfile" +[[ "$(cd "${tmp_dir}/without-dotenv" && VALUE=from-runtime just show)" == 'from-runtime' ]] diff --git a/tests/test-patch-bazzite-deck-identity.sh b/tests/test-patch-bazzite-deck-identity.sh new file mode 100755 index 0000000..fa420ce --- /dev/null +++ b/tests/test-patch-bazzite-deck-identity.sh @@ -0,0 +1,58 @@ +#!/usr/bin/env bash + +set -euo pipefail + +repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +fixture_root="${repo_root}/tests/fixtures/bazzite-44" +test_root="$(mktemp -d -t aerocore-deck-identity.XXXXXXXXXX)" +trap 'rm -rf "${test_root}"' EXIT + +cp -a "${fixture_root}/." "${test_root}/" + +run_patch() { + AEROCORE_DECK_COMPAT_ROOT="${test_root}" \ + bash "${repo_root}/build_files/patch-bazzite-deck-identity.sh" +} + +assert_count() { + local expected="$1" + local pattern="$2" + local file="$3" + local actual + + actual="$(grep -Foc "${pattern}" "${file}" || true)" + if [[ "${actual}" != "${expected}" ]]; then + echo "Expected ${expected} occurrence(s) of '${pattern}' in ${file}, found ${actual}" >&2 + exit 1 + fi +} + +hardware_setup="${test_root}/usr/libexec/bazzite-hardware-setup" +steam="${test_root}/usr/bin/bazzite-steam" +user_setup="${test_root}/usr/libexec/bazzite-user-setup" +# shellcheck disable=SC2016 +deck_condition='if [[ $IMAGE_NAME =~ "deck" || $IMAGE_NAME == aerocore-os ]]; then' +# shellcheck disable=SC2016 +non_deck_condition='if [[ "$IMAGE_NAME" != aerocore-os && "$IMAGE_NAME" != *deck* && "$IMAGE_NAME" != *dx* ]]; then' + +run_patch + +assert_count 1 "${non_deck_condition}" "${hardware_setup}" +assert_count 1 "${deck_condition}" "${hardware_setup}" +assert_count 1 "${deck_condition}" "${steam}" +assert_count 3 "${deck_condition}" "${user_setup}" +assert_count 1 'AeroCore Steam state migration' "${steam}" + +# A second run must recognize the patched fixture and make no further changes. +first_digest="$(sha256sum "${hardware_setup}" "${steam}" "${user_setup}")" +run_patch +second_digest="$(sha256sum "${hardware_setup}" "${steam}" "${user_setup}")" + +if [[ "${first_digest}" != "${second_digest}" ]]; then + echo "Deck identity patch is not idempotent" >&2 + exit 1 +fi + +assert_count 1 'AeroCore Steam state migration' "${steam}" + +echo "Bazzite 44 Deck identity fixture passed" |
