Files
ProxMenux/tests/lxc_updates/test_apply_updates.sh

165 lines
6.5 KiB
Bash

#!/bin/bash
set -euo pipefail
REPO_ROOT=$(cd "$(dirname "$0")/../.." && pwd)
RUNNER="$REPO_ROOT/scripts/lxc/apply_updates.sh"
TEST_ROOT=$(mktemp -d "${TMPDIR:-/tmp}/proxmenux-update-test.XXXXXX")
trap 'rm -rf "$TEST_ROOT"' EXIT
MOCK_BIN="$TEST_ROOT/bin"
mkdir -p "$MOCK_BIN" "$TEST_ROOT/locks"
cat >"$MOCK_BIN/pct" <<'EOF'
#!/bin/bash
echo "pct $*" >>"$MOCK_LOG"
case "$1" in
list)
printf 'VMID Status Name\n101 %s test\n' "${MOCK_INITIAL_STATE:-running}"
;;
status)
printf 'status: %s\n' "${MOCK_INITIAL_STATE:-running}"
;;
start|shutdown|reboot)
;;
exec)
shift 3
joined="$*"
case "$joined" in
*'grep -E "^ID="'*) echo 'ID=debian' ;;
'test -f /usr/bin/update') [[ "${MOCK_HAS_WRAPPER:-1}" == "1" ]] ;;
'cat /usr/bin/update')
case "${MOCK_WRAPPER_FORMAT:-legacy}" in
modern)
printf '%s\n' \
'#!/usr/bin/env bash' \
'# Regenerated on install and on every successful update.' \
"export SCRIPT_SLUG=\"${MOCK_HELPER_SLUG:-jellyfin}\"" \
"export UPDATE_SCRIPT_NAME=\"${MOCK_HELPER_SLUG:-jellyfin}\"" \
'bash -c "$(curl -fsSL "${COMMUNITY_SCRIPTS_URL}/ct/${UPDATE_SCRIPT_NAME}.sh")"'
;;
update-name)
printf "export UPDATE_SCRIPT_NAME='%s'\n" "${MOCK_HELPER_SLUG:-jellyfin}"
;;
unsafe)
printf '%s\n' 'export SCRIPT_SLUG="$(touch /tmp/proxmenux-unsafe)"'
;;
*)
echo "bash -c \"\$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/${MOCK_HELPER_SLUG:-jellyfin}.sh)\""
;;
esac
;;
*'command -v wget'*) ;;
bash\ -c*) echo HELPER_EXEC >>"$MOCK_LOG" ;;
sh\ -c*)
echo CUSTOM_EXEC >>"$MOCK_LOG"
[[ "${MOCK_CUSTOM_FAIL:-0}" != "1" ]]
;;
env\ DEBIAN_FRONTEND=noninteractive*) echo OS_EXEC >>"$MOCK_LOG" ;;
esac
;;
esac
EOF
cat >"$MOCK_BIN/flock" <<'EOF'
#!/bin/bash
[[ "${MOCK_FLOCK_FAIL:-0}" != "1" ]]
EOF
cat >"$MOCK_BIN/python3" <<'EOF'
#!/bin/bash
cat >/dev/null
if [[ "${2:-}" == 'protect-update-command' ]]; then
printf '%s' "$UPDATE_COMMAND"
exit 0
fi
[[ "${MOCK_HELPER_SELECTED:-1}" == "1" ]]
EOF
cat >"$MOCK_BIN/sleep" <<'EOF'
#!/bin/bash
exit 0
EOF
cat >"$MOCK_BIN/vzdump" <<'EOF'
#!/bin/bash
echo "vzdump $*" >>"$MOCK_LOG"
EOF
chmod +x "$MOCK_BIN"/*
fail() { echo "FAIL: $*" >&2; exit 1; }
count() { grep -c "$1" "$MOCK_LOG" 2>/dev/null || true; }
run_case() {
local name=$1
shift
export MOCK_LOG="$TEST_ROOT/$name.log"
: >"$MOCK_LOG"
set +e
env PATH="$MOCK_BIN:$PATH" PROXMENUX_LOCK_DIR="$TEST_ROOT/locks" \
VMID=101 TARGET=app BACKUP=0 RESTART=0 "$@" bash "$RUNNER" \
>"$TEST_ROOT/$name.out" 2>&1
CASE_RC=$?
set -e
}
run_case helper_only RUN_HELPER=1 UPDATE_COMMAND=
[[ $CASE_RC -eq 0 ]] || fail "helper_only returned $CASE_RC"
[[ $(count HELPER_EXEC) -eq 1 ]] || fail "helper_only did not run helper exactly once"
[[ $(count CUSTOM_EXEC) -eq 0 ]] || fail "helper_only unexpectedly ran custom"
run_case helper_not_selected RUN_HELPER=1 UPDATE_COMMAND= MOCK_HELPER_SELECTED=0
[[ $CASE_RC -eq 5 ]] || fail "helper_not_selected expected 5, got $CASE_RC"
[[ $(count HELPER_EXEC) -eq 0 ]] || fail "unselected helper was executed"
run_case modern_helper RUN_HELPER=1 UPDATE_COMMAND= MOCK_WRAPPER_FORMAT=modern MOCK_HELPER_SLUG=nginxproxymanager
[[ $CASE_RC -eq 0 ]] || fail "modern_helper returned $CASE_RC"
[[ $(count HELPER_EXEC) -eq 1 ]] || fail "modern_helper did not run helper exactly once"
grep -qF 'slug: nginxproxymanager' "$TEST_ROOT/modern_helper.out" \
|| fail "modern_helper did not resolve SCRIPT_SLUG"
run_case update_name_helper RUN_HELPER=1 UPDATE_COMMAND= MOCK_WRAPPER_FORMAT=update-name MOCK_HELPER_SLUG=qbittorrent
[[ $CASE_RC -eq 0 ]] || fail "update_name_helper returned $CASE_RC"
[[ $(count HELPER_EXEC) -eq 1 ]] || fail "update_name_helper did not run helper exactly once"
grep -qF 'slug: qbittorrent' "$TEST_ROOT/update_name_helper.out" \
|| fail "update_name_helper did not resolve UPDATE_SCRIPT_NAME"
run_case unsafe_wrapper RUN_HELPER=1 UPDATE_COMMAND= MOCK_WRAPPER_FORMAT=unsafe
[[ $CASE_RC -eq 5 ]] || fail "unsafe_wrapper expected 5, got $CASE_RC"
[[ $(count HELPER_EXEC) -eq 0 ]] || fail "unsafe_wrapper ran helper"
[[ ! -e /tmp/proxmenux-unsafe ]] || fail "unsafe_wrapper evaluated CT content"
run_case custom_override RUN_HELPER=0 UPDATE_COMMAND='update-custom'
[[ $CASE_RC -eq 0 ]] || fail "custom_override returned $CASE_RC"
[[ $(count HELPER_EXEC) -eq 0 ]] || fail "custom_override unexpectedly ran helper"
[[ $(count CUSTOM_EXEC) -eq 1 ]] || fail "custom_override did not run custom exactly once"
run_case custom_replaces_helper RUN_HELPER=1 UPDATE_COMMAND='replace-helper'
[[ $CASE_RC -eq 0 ]] || fail "custom_replaces_helper returned $CASE_RC"
[[ $(count HELPER_EXEC) -eq 0 ]] || fail "custom_replaces_helper unexpectedly ran helper"
[[ $(count CUSTOM_EXEC) -eq 1 ]] || fail "custom_replaces_helper did not run custom exactly once"
grep -qF 'skipping Proxmox VE Helper-Scripts updater' "$TEST_ROOT/custom_replaces_helper.out" \
|| fail "custom_replaces_helper did not report the replacement rule"
run_case explicit_multi_app RUN_HELPER=1 ALLOW_HELPER_WITH_CUSTOM=1 UPDATE_COMMAND='update-another-app'
[[ $CASE_RC -eq 0 ]] || fail "explicit_multi_app returned $CASE_RC"
[[ $(count HELPER_EXEC) -eq 1 ]] || fail "explicit_multi_app did not run helper exactly once"
[[ $(count CUSTOM_EXEC) -eq 1 ]] || fail "explicit_multi_app did not run custom exactly once"
run_case missing_wrapper RUN_HELPER=1 UPDATE_COMMAND= MOCK_HAS_WRAPPER=0
[[ $CASE_RC -eq 5 ]] || fail "missing_wrapper expected 5, got $CASE_RC"
[[ $(count HELPER_EXEC) -eq 0 ]] || fail "missing_wrapper ran helper"
run_case base_os_wrapper RUN_HELPER=1 UPDATE_COMMAND= MOCK_HELPER_SLUG=debian
[[ $CASE_RC -eq 5 ]] || fail "base_os_wrapper expected 5, got $CASE_RC"
[[ $(count HELPER_EXEC) -eq 0 ]] || fail "base_os_wrapper ran helper"
run_case stopped_restore RUN_HELPER=0 UPDATE_COMMAND='update-custom' MOCK_INITIAL_STATE=stopped
[[ $CASE_RC -eq 0 ]] || fail "stopped_restore returned $CASE_RC"
[[ $(count 'pct start 101') -eq 1 ]] || fail "stopped CT was not started exactly once"
[[ $(count 'pct shutdown 101 --timeout 60') -eq 1 ]] || fail "stopped CT state was not restored"
run_case locked RUN_HELPER=0 UPDATE_COMMAND='update-custom' MOCK_FLOCK_FAIL=1
[[ $CASE_RC -eq 7 ]] || fail "locked expected 7, got $CASE_RC"
[[ $(count CUSTOM_EXEC) -eq 0 ]] || fail "locked run executed an updater"
echo "apply_updates.sh: all deterministic tests passed"