summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/fixtures/bazzite-44/usr/bin/bazzite-steam10
-rw-r--r--tests/fixtures/bazzite-44/usr/libexec/bazzite-hardware-setup10
-rw-r--r--tests/fixtures/bazzite-44/usr/libexec/bazzite-user-setup16
-rwxr-xr-xtests/test-aerocore-anaconda-profile.sh16
-rw-r--r--tests/test-build-channel-metadata.sh20
-rwxr-xr-xtests/test-configure-target-gpt-root.sh51
-rwxr-xr-xtests/test-decky-mirror-ujust.sh51
-rwxr-xr-xtests/test-desktop-branding-migration.sh59
-rwxr-xr-xtests/test-dotenv-precedence.sh28
-rwxr-xr-xtests/test-patch-bazzite-deck-identity.sh58
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"