Files
cozystack/hack/backup-examples-shared-helpers.bats
T
Myasnikov Daniil cc942fed68 test(tests): run unit suites with Bats and retain POSIX coverage
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>
2026-10-07 11:04:00 +03:00

96 lines
3.4 KiB
Bash

#!/usr/bin/env bats
# Contract for the wait helpers the backup walkthroughs share: each is defined
# once, in examples/backups/_lib/wait-helpers.sh, so a fix made there reaches
# every walkthrough; each walkthrough's 00-helpers.sh provides them; and
# wait_for_field reports why kubectl could not read a field while staying quiet
# about a resource that does not exist yet.
load test_helper
SHARED=examples/backups/_lib/wait-helpers.sh
SHARED_HELPERS="wait_for_field wait_hr_ready wait_deleted"
@test "each shared wait helper is defined once, in the shared file" {
fail=
for fn in $SHARED_HELPERS; do
definers=$(grep -rlE --include='*.sh' "^[[:space:]]*(function[[:space:]]+)?${fn}[[:space:]]*\(\)" examples packages | sort)
if [ "$definers" != "$SHARED" ]; then
fail="$fail
${fn} is defined in:
${definers:- (nowhere)}"
fi
done
[ -z "$fail" ] || {
echo "a walkthrough carries its own copy of a shared helper; use the one in $SHARED:$fail" >&2
exit 1
}
}
@test "every walkthrough's helpers provide the shared wait helpers" {
# Some helpers read the cluster while being sourced (kafka resolves its
# image from the operator); a stub keeps this test off any real cluster.
stub=$(mktemp -d)
printf '#!/bin/sh\nexit 1\n' > "$stub/kubectl"
chmod +x "$stub/kubectl"
for helpers in examples/backups/*/00-helpers.sh; do
PATH="$stub:$PATH" bash -c '
set -euo pipefail
. "$1"
for fn in $2; do
declare -F "$fn" >/dev/null || { echo "$1 does not provide $fn" >&2; exit 1; }
done
' _ "$helpers" "$SHARED_HELPERS"
done
}
@test "wait_for_field shows why kubectl could not read the field" {
# A Forbidden read has to reach the caller; swallowed, it looks like a
# field that is still empty.
stub=$(mktemp -d)
printf '#!/bin/sh\necho "Error from server (Forbidden): backupjobs is forbidden" >&2\nexit 1\n' > "$stub/kubectl"
chmod +x "$stub/kubectl"
err=$(mktemp)
if PATH="$stub:$PATH" bash -c '
set -euo pipefail
. examples/backups/postgres/00-helpers.sh
wait_for_field backupjob demo "{.status.phase}" Succeeded tenant-test 0
' 2>"$err"; then
echo "wait_for_field succeeded against a kubectl that cannot read" >&2
exit 1
fi
grep -q 'backupjobs is forbidden' "$err" || {
echo "wait_for_field dropped kubectl's reason:" >&2
cat "$err" >&2
exit 1
}
}
@test "wait_for_field stays quiet while the resource does not exist yet" {
# The stub answers like kubectl: NotFound on stderr and exit 1, unless the
# read asks for --ignore-not-found, which makes an absent resource empty.
stub=$(mktemp -d)
cat > "$stub/kubectl" <<'EOF'
#!/bin/sh
case " $* " in
*" --ignore-not-found "*) exit 0 ;;
esac
echo 'Error from server (NotFound): backupjobs.backups.cozystack.io "demo" not found' >&2
exit 1
EOF
chmod +x "$stub/kubectl"
err=$(mktemp)
if PATH="$stub:$PATH" bash -c '
set -euo pipefail
. examples/backups/postgres/00-helpers.sh
wait_for_field backupjob demo "{.status.phase}" Succeeded tenant-test 0
' 2>"$err"; then
echo "wait_for_field succeeded against a resource that does not exist" >&2
exit 1
fi
if grep -q 'NotFound' "$err"; then
echo "wait_for_field printed kubectl's NotFound for a resource it is waiting on:" >&2
cat "$err" >&2
exit 1
fi
}