20260713_2 落地升级环境变量优先级契约(#114 主工作树收口)
This commit is contained in:
206
deploy/docker-installer/tests/upgrade_env_contract_test.sh
Normal file
206
deploy/docker-installer/tests/upgrade_env_contract_test.sh
Normal file
@@ -0,0 +1,206 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
INSTALLER_SOURCE="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
TEST_ROOT="$(mktemp -d "${TMPDIR:-/tmp}/ours-rp-installer-env-contract.XXXXXX")"
|
||||
|
||||
cleanup() {
|
||||
rm -rf "$TEST_ROOT"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
fail() {
|
||||
printf 'FAIL: %s\n' "$*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
assert_equals() {
|
||||
local expected="$1"
|
||||
local actual="$2"
|
||||
local message="$3"
|
||||
[[ "$actual" == "$expected" ]] || fail "$message (expected=$expected actual=$actual)"
|
||||
}
|
||||
|
||||
assert_not_contains() {
|
||||
local needle="$1"
|
||||
local path="$2"
|
||||
! grep -Fq "$needle" "$path" || fail "unexpected value in $path: $needle"
|
||||
}
|
||||
|
||||
expect_exit() {
|
||||
local expected_status="$1"
|
||||
local output_path="$2"
|
||||
shift 2
|
||||
local actual_status
|
||||
|
||||
set +e
|
||||
"$@" >"$output_path" 2>&1
|
||||
actual_status=$?
|
||||
set -e
|
||||
[[ "$actual_status" == "$expected_status" ]] || {
|
||||
cat "$output_path" >&2 || true
|
||||
fail "unexpected exit status (expected=$expected_status actual=$actual_status)"
|
||||
}
|
||||
}
|
||||
|
||||
host_arch() {
|
||||
case "$(uname -m)" in
|
||||
x86_64) printf 'amd64\n' ;;
|
||||
aarch64) printf 'arm64\n' ;;
|
||||
*) fail "unsupported test host architecture: $(uname -m)" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
env_value() {
|
||||
local env_path="$1"
|
||||
local key="$2"
|
||||
(
|
||||
# shellcheck disable=SC1090
|
||||
source "$INSTALLER_SOURCE/scripts/common.sh"
|
||||
env_file_value "$env_path" "$key"
|
||||
)
|
||||
}
|
||||
|
||||
create_fixture() {
|
||||
local name="$1"
|
||||
local fixture="$TEST_ROOT/$name"
|
||||
local arch
|
||||
arch="$(host_arch)"
|
||||
|
||||
mkdir -p "$fixture"
|
||||
cp -a "$INSTALLER_SOURCE"/. "$fixture"/
|
||||
rm -rf "$fixture/tests"
|
||||
mkdir -p "$fixture/images" "$fixture/fake-bin"
|
||||
sed -i \
|
||||
-e "s|__PACKAGE_ARCH__|$arch|g" \
|
||||
-e "s|__PACKAGE_PLATFORM__|linux/$arch|g" \
|
||||
-e "s|__RUNTIME_IMAGE__|ours-rp-runtime-$arch:new|g" \
|
||||
-e "s|__METRICS_IMAGE__|ours-rp-metrics-$arch:new|g" \
|
||||
-e "s|__HOST_DATA_DIR__|$fixture/data|g" \
|
||||
"$fixture/.env.example"
|
||||
cat > "$fixture/PACKAGE-MANIFEST.env" <<EOF
|
||||
PACKAGE_ARCH=$arch
|
||||
PACKAGE_PLATFORM=linux/$arch
|
||||
EOF
|
||||
cat > "$fixture/fake-bin/docker" <<'EOF'
|
||||
#!/usr/bin/env bash
|
||||
printf '%s\n' "$*" >> "$FAKE_DOCKER_LOG"
|
||||
if [[ "${1:-}" == "compose" && "${2:-}" == "version" ]]; then
|
||||
exit 0
|
||||
fi
|
||||
exit 99
|
||||
EOF
|
||||
chmod +x "$fixture/fake-bin/docker"
|
||||
for command in jq rsync curl gzip tar; do
|
||||
cat > "$fixture/fake-bin/$command" <<'EOF'
|
||||
#!/usr/bin/env bash
|
||||
exit 0
|
||||
EOF
|
||||
chmod +x "$fixture/fake-bin/$command"
|
||||
done
|
||||
printf '%s\n' "$fixture"
|
||||
}
|
||||
|
||||
run_upgrade() {
|
||||
local fixture="$1"
|
||||
local old_env="$2"
|
||||
shift 2
|
||||
(
|
||||
cd "$fixture"
|
||||
export PATH="$fixture/fake-bin:$PATH"
|
||||
export FAKE_DOCKER_LOG="$fixture/fake-docker.log"
|
||||
"$@" ./scripts/upgrade.sh --reuse-env-from "$old_env"
|
||||
)
|
||||
}
|
||||
|
||||
run_upgrade_without_reuse() {
|
||||
local fixture="$1"
|
||||
(
|
||||
cd "$fixture"
|
||||
export PATH="$fixture/fake-bin:$PATH"
|
||||
export FAKE_DOCKER_LOG="$fixture/fake-docker.log"
|
||||
./scripts/upgrade.sh
|
||||
)
|
||||
}
|
||||
|
||||
new_fixture_with_old_env() {
|
||||
local name="$1"
|
||||
local fixture
|
||||
fixture="$(create_fixture "$name")"
|
||||
cat > "$fixture/old.env" <<'EOF'
|
||||
INTERVAL_SECS=120
|
||||
RPKI_IMAGE=ours-rp-runtime-old:old
|
||||
REMOVED_LEGACY_KEY=legacy-value
|
||||
EOF
|
||||
printf '%s\n' "$fixture"
|
||||
}
|
||||
|
||||
fixture="$(create_fixture template-defaults)"
|
||||
expect_exit 99 "$fixture/template.log" run_upgrade_without_reuse "$fixture"
|
||||
assert_equals "600" "$(env_value "$fixture/.env" INTERVAL_SECS)" "template default must be retained without reuse"
|
||||
|
||||
fixture="$(new_fixture_with_old_env default-old)"
|
||||
expect_exit 99 "$fixture/default.log" run_upgrade "$fixture" "$fixture/old.env"
|
||||
assert_equals "120" "$(env_value "$fixture/.env" INTERVAL_SECS)" "old value must override template default"
|
||||
assert_equals "ours-rp-runtime-$(host_arch):new" "$(env_value "$fixture/.env" RPKI_IMAGE)" "standard upgrade must retain package image"
|
||||
assert_equals "10" "$(env_value "$fixture/.env" METRICS_POLL_SECS)" "template default must fill a key absent from old environment"
|
||||
! grep -q '^REMOVED_LEGACY_KEY=' "$fixture/.env" || fail "removed old key was copied into target environment"
|
||||
grep -q 'reused_keys=INTERVAL_SECS' "$fixture/default.log" || fail "reused key summary missing"
|
||||
grep -q 'ignored_removed_old_keys=REMOVED_LEGACY_KEY' "$fixture/default.log" || fail "removed key summary missing"
|
||||
grep -q 'template_only_keys=' "$fixture/default.log" || fail "template key summary missing"
|
||||
|
||||
fixture="$(new_fixture_with_old_env invocation-overrides)"
|
||||
expect_exit 99 "$fixture/override.log" run_upgrade "$fixture" "$fixture/old.env" env INTERVAL_SECS=300 GRAFANA_ADMIN_PASSWORD='secret with space'
|
||||
assert_equals "300" "$(env_value "$fixture/.env" INTERVAL_SECS)" "invocation value must override old value"
|
||||
assert_equals "secret with space" "$(env_value "$fixture/.env" GRAFANA_ADMIN_PASSWORD)" "invocation value must preserve shell-sensitive content"
|
||||
grep -q 'command_override_keys=INTERVAL_SECS,GRAFANA_ADMIN_PASSWORD' "$fixture/override.log" || fail "override key summary missing"
|
||||
assert_not_contains 'secret with space' "$fixture/override.log"
|
||||
|
||||
fixture="$(new_fixture_with_old_env invocation-special-characters)"
|
||||
special_password="O'Reilly"
|
||||
special_password+=' $literal `tick` slash\'
|
||||
expect_exit 99 "$fixture/special.log" run_upgrade "$fixture" "$fixture/old.env" env GRAFANA_ADMIN_PASSWORD="$special_password"
|
||||
assert_equals "$special_password" "$(env_value "$fixture/.env" GRAFANA_ADMIN_PASSWORD)" "invocation value with dotenv-sensitive characters must round-trip"
|
||||
assert_not_contains "$special_password" "$fixture/special.log"
|
||||
|
||||
fixture="$(create_fixture existing-target-env)"
|
||||
cp "$fixture/.env.example" "$fixture/.env"
|
||||
sed -i 's/^INTERVAL_SECS=.*/INTERVAL_SECS=180/' "$fixture/.env"
|
||||
cat > "$fixture/old.env" <<'EOF'
|
||||
INTERVAL_SECS=120
|
||||
EOF
|
||||
expect_exit 99 "$fixture/existing.log" run_upgrade "$fixture" "$fixture/old.env" env INTERVAL_SECS=300
|
||||
assert_equals "300" "$(env_value "$fixture/.env" INTERVAL_SECS)" "invocation value must override an existing target environment"
|
||||
|
||||
fixture="$(new_fixture_with_old_env explicit-empty)"
|
||||
expect_exit 1 "$fixture/empty.log" run_upgrade "$fixture" "$fixture/old.env" env INTERVAL_SECS=
|
||||
[[ ! -s "$fixture/fake-docker.log" ]] || fail "explicit empty value reached Docker"
|
||||
grep -q 'INTERVAL_SECS' "$fixture/empty.log" || fail "empty-value error did not identify key"
|
||||
|
||||
fixture="$(create_fixture empty-old-value)"
|
||||
cat > "$fixture/old.env" <<'EOF'
|
||||
INTERVAL_SECS=
|
||||
EOF
|
||||
expect_exit 1 "$fixture/old-empty.log" run_upgrade "$fixture" "$fixture/old.env"
|
||||
[[ ! -s "$fixture/fake-docker.log" ]] || fail "empty reused value reached Docker"
|
||||
grep -q 'INTERVAL_SECS' "$fixture/old-empty.log" || fail "empty reused value error did not identify key"
|
||||
|
||||
fixture="$(create_fixture empty-template)"
|
||||
sed -i 's/^INTERVAL_SECS=.*/INTERVAL_SECS=/' "$fixture/.env.example"
|
||||
cat > "$fixture/old.env" <<'EOF'
|
||||
INTERVAL_SECS=120
|
||||
EOF
|
||||
expect_exit 1 "$fixture/template-empty.log" run_upgrade "$fixture" "$fixture/old.env"
|
||||
[[ ! -s "$fixture/fake-docker.log" ]] || fail "empty template default reached Docker"
|
||||
grep -q 'INTERVAL_SECS' "$fixture/template-empty.log" || fail "empty template error did not identify key"
|
||||
|
||||
fixture="$(new_fixture_with_old_env package-guard)"
|
||||
arch="$(host_arch)"
|
||||
other_arch="amd64"
|
||||
[[ "$arch" == "amd64" ]] && other_arch="arm64"
|
||||
expect_exit 1 "$fixture/arch.log" run_upgrade "$fixture" "$fixture/old.env" env PACKAGE_ARCH="$other_arch"
|
||||
[[ ! -s "$fixture/fake-docker.log" ]] || fail "package architecture mismatch reached Docker"
|
||||
grep -q 'mismatches manifest PACKAGE_ARCH' "$fixture/arch.log" || fail "package architecture guard did not reject override"
|
||||
|
||||
printf 'PASS: Docker installer upgrade environment contract\n'
|
||||
Reference in New Issue
Block a user