mirror of
https://github.com/cozystack/cozystack.git
synced 2026-11-04 11:07:03 +09:00
The shell translator rewrites test bodies and loses Bats reporting. The unit lane needs complete TAP results and JUnit reports without changing how live-cluster suites run. Sourced production helpers still need a dash pass, and unit test bodies need nounset without exporting shell options into subprocesses. Assisted-by: LLM Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
165 lines
4.9 KiB
Bash
165 lines
4.9 KiB
Bash
#!/usr/bin/env bats
|
|
# -----------------------------------------------------------------------------
|
|
# Unit tests for packages/core/platform/images/migrations/run-migrations.sh.
|
|
#
|
|
# The migration hook Job retries a failed pod with the environment rendered for
|
|
# the first one, so CURRENT_VERSION is what the cluster was on before any
|
|
# migration of this upgrade ran. Every migration that finished has stamped the
|
|
# cozystack-version ConfigMap since, and a retried pod must start from that
|
|
# stamp, or it runs finished migrations a second time.
|
|
#
|
|
# The runner executes in the migrations image's alpine base (busybox ash, the
|
|
# interpreter it ships with) against stand-in migrations and a fake kubectl
|
|
# that keeps the stamped version in a file, so one pod's stamps are what the
|
|
# next pod reads. The harness shape is hack/migration-58-http-cache-freeze.bats's.
|
|
#
|
|
# Run with: bats hack/run-migrations.bats from the repo root.
|
|
# -----------------------------------------------------------------------------
|
|
|
|
load test_helper
|
|
|
|
FAKEBIN="$PWD/hack/testdata/run-migrations"
|
|
RUNNER="$PWD/packages/core/platform/images/migrations/run-migrations.sh"
|
|
LIB="$PWD/packages/core/platform/images/migrations/migrations/lib"
|
|
ALPINE=$(sed -n 's/^FROM \(alpine:[^ ]*\).*$/\1/p' \
|
|
"$PWD/packages/core/platform/images/migrations/Dockerfile" | head -1)
|
|
WORKROOT="${TMPDIR:-/tmp}/cozy-run-migrations-$$"
|
|
|
|
cozy_cleanup() {
|
|
rm -rf "$WORKROOT"
|
|
return 0
|
|
}
|
|
|
|
# prep <stamped version, or "none" for no ConfigMap>
|
|
prep() {
|
|
docker info >/dev/null 2>&1 || {
|
|
echo "docker is required: these tests run run-migrations.sh inside $ALPINE," >&2
|
|
echo "the migrations image's base." >&2
|
|
return 1
|
|
}
|
|
mkdir -p "$WORKROOT"
|
|
WORK=$(mktemp -d "$WORKROOT/XXXXXX")
|
|
mkdir -p "$WORK/migrations"
|
|
cp -R "$LIB" "$WORK/migrations/lib"
|
|
for n in 57 58 59; do
|
|
cp "$FAKEBIN/migration" "$WORK/migrations/$n"
|
|
done
|
|
: > "$WORK/ran"
|
|
[ "$1" = none ] || printf '%s' "$1" > "$WORK/state"
|
|
chmod +x "$FAKEBIN/kubectl"
|
|
unset FAKE_FAIL_AT FAKE_READ_FAIL || true
|
|
return 0
|
|
}
|
|
|
|
# run_pod <CURRENT_VERSION> <TARGET_VERSION> -- one pod of the hook Job.
|
|
run_pod() {
|
|
_run_pod_rc=0
|
|
docker run --rm --network none \
|
|
--user "$(id -u):$(id -g)" \
|
|
-v "$RUNNER:/usr/bin/run-migrations.sh:ro" \
|
|
-v "$WORK/migrations:/migrations" \
|
|
-v "$FAKEBIN:/fakebin:ro" \
|
|
-v "$WORK:/work" \
|
|
-e PATH=/fakebin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin \
|
|
-e FAKE_STATE=/work/state \
|
|
-e FAKE_FAIL_AT="${FAKE_FAIL_AT-}" \
|
|
-e FAKE_READ_FAIL="${FAKE_READ_FAIL-}" \
|
|
-e NAMESPACE=cozy-system \
|
|
-e CURRENT_VERSION="$1" \
|
|
-e TARGET_VERSION="$2" \
|
|
"$ALPINE" /bin/sh /usr/bin/run-migrations.sh || _run_pod_rc=$?
|
|
return "$_run_pod_rc"
|
|
}
|
|
|
|
ran() {
|
|
tr '\n' ' ' < "$WORK/ran" | sed 's/ $//'
|
|
return 0
|
|
}
|
|
|
|
@test "a retried pod starts from the version the failed pod stamped" {
|
|
prep 57
|
|
export FAKE_FAIL_AT=59
|
|
rc=0
|
|
run_pod 57 60 || rc=$?
|
|
[ "$rc" -ne 0 ]
|
|
[ "$(cat "$WORK/state")" = 59 ]
|
|
|
|
unset FAKE_FAIL_AT
|
|
rc=0
|
|
run_pod 57 60 || rc=$?
|
|
echo "ran: $(ran)"
|
|
[ "$rc" -eq 0 ]
|
|
[ "$(ran)" = "57 58 59 59" ]
|
|
[ "$(cat "$WORK/state")" = 60 ]
|
|
rm -rf "$WORK"
|
|
}
|
|
|
|
@test "a pod that finds the target already stamped runs nothing" {
|
|
prep 60
|
|
rc=0
|
|
run_pod 57 60 || rc=$?
|
|
echo "ran: $(ran)"
|
|
[ "$rc" -eq 0 ]
|
|
[ -z "$(ran)" ]
|
|
rm -rf "$WORK"
|
|
}
|
|
|
|
@test "a ConfigMap with no version falls back to the rendered one" {
|
|
prep ""
|
|
rc=0
|
|
run_pod 58 60 || rc=$?
|
|
echo "ran: $(ran)"
|
|
[ "$rc" -eq 0 ]
|
|
[ "$(ran)" = "58 59" ]
|
|
rm -rf "$WORK"
|
|
}
|
|
|
|
# A non-integer start fails the -ge test inside an if and makes seq fail
|
|
# inside the for list, and neither trips set -e: without the fallback such a
|
|
# stamp gives a green Job that ran nothing and moved no stamp.
|
|
@test "a ConfigMap with a non-integer version falls back to the rendered one" {
|
|
prep v58
|
|
rc=0
|
|
run_pod 58 60 || rc=$?
|
|
echo "ran: $(ran)"
|
|
[ "$rc" -eq 0 ]
|
|
[ "$(ran)" = "58 59" ]
|
|
rm -rf "$WORK"
|
|
}
|
|
|
|
# The same unguarded -ge and empty seq turn an all-digit stamp past the shell's
|
|
# integer range into a green Job that ran nothing. Falling back is no answer:
|
|
# the chart's int renders such a stamp as 0, which would replay every migration.
|
|
@test "a stamped version outside the shell's integer range stops before any migration" {
|
|
prep 999999999999999999999999999999
|
|
rc=0
|
|
run_pod 0 60 || rc=$?
|
|
echo "ran: $(ran)"
|
|
[ "$rc" -ne 0 ]
|
|
[ -z "$(ran)" ]
|
|
rm -rf "$WORK"
|
|
}
|
|
|
|
@test "a failed read of the stamped version stops before any migration" {
|
|
prep 58
|
|
export FAKE_READ_FAIL="Error from server (Timeout): the server was unable to return a response in the time allotted"
|
|
rc=0
|
|
run_pod 57 60 || rc=$?
|
|
echo "ran: $(ran)"
|
|
[ "$rc" -ne 0 ]
|
|
[ -z "$(ran)" ]
|
|
[ "$(cat "$WORK/state")" = 58 ]
|
|
rm -rf "$WORK"
|
|
}
|
|
|
|
@test "with no ConfigMap it stamps the target and runs nothing" {
|
|
prep none
|
|
rc=0
|
|
run_pod 57 60 || rc=$?
|
|
echo "ran: $(ran)"
|
|
[ "$rc" -eq 0 ]
|
|
[ -z "$(ran)" ]
|
|
[ "$(cat "$WORK/state")" = 60 ]
|
|
rm -rf "$WORK"
|
|
}
|