mirror of
https://github.com/cozystack/cozystack.git
synced 2026-10-27 15:17:13 +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>
221 lines
7.7 KiB
Bash
221 lines
7.7 KiB
Bash
#!/usr/bin/env bats
|
|
# Unit coverage for the single post-install HelmRelease readiness gate.
|
|
|
|
load test_helper
|
|
|
|
helmrelease_snapshot() {
|
|
count="$1"
|
|
not_ready="${2:-0}"
|
|
stalled="${3:-0}"
|
|
stale="${4:-0}"
|
|
jq -nc --argjson count "$count" --argjson notReady "$not_ready" --argjson stalled "$stalled" --argjson stale "$stale" '
|
|
{items: [range(1; $count + 1) as $i |
|
|
{metadata: {namespace: "ns", name: ("hr-" + ($i | tostring)), generation: 2},
|
|
status: {observedGeneration: (if $i == $stale then 1 else 2 end), conditions:
|
|
([{type: "Ready", status: (if $i == $notReady then "False" else "True" end), reason: "Progressing", message: "working"}]
|
|
+ (if $i == $stalled then [{type: "Stalled", status: "True", message: "terminal failure"}] else [] end))}}
|
|
]}
|
|
'
|
|
}
|
|
|
|
@test "stale Ready stays closed until the current generation is observed" {
|
|
. hack/e2e-wait-helmreleases.sh
|
|
clock=$(mktemp)
|
|
printf '0\n' > "$clock"
|
|
date() { sed -n '1p' "$clock"; }
|
|
sleep() {
|
|
now=$(sed -n '1p' "$clock")
|
|
printf '%s\n' "$(( now + $1 ))" > "$clock"
|
|
}
|
|
kubectl() {
|
|
now=$(sed -n '1p' "$clock")
|
|
if [ "$now" -lt 4 ]; then
|
|
helmrelease_snapshot 11 0 0 3
|
|
else
|
|
helmrelease_snapshot 11
|
|
fi
|
|
}
|
|
|
|
cozy_wait_all_helmreleases_ready 30 11 4 2 >/dev/null
|
|
[ "$(sed -n '1p' "$clock")" -ge 8 ] || {
|
|
echo "the gate accepted Ready=True from an unobserved generation" >&2
|
|
exit 1
|
|
}
|
|
}
|
|
|
|
@test "a late HelmRelease resets stability and is included before success" {
|
|
. hack/e2e-wait-helmreleases.sh
|
|
clock=$(mktemp)
|
|
calls=$(mktemp)
|
|
printf '0\n' > "$clock"
|
|
date() { sed -n '1p' "$clock"; }
|
|
sleep() {
|
|
now=$(sed -n '1p' "$clock")
|
|
printf '%s\n' "$(( now + $1 ))" > "$clock"
|
|
}
|
|
kubectl() {
|
|
printf '%s\n' "$*" >> "$calls"
|
|
now=$(sed -n '1p' "$clock")
|
|
if [ "$now" -lt 2 ]; then
|
|
helmrelease_snapshot 11
|
|
elif [ "$now" -lt 4 ]; then
|
|
helmrelease_snapshot 12 12
|
|
else
|
|
helmrelease_snapshot 12
|
|
fi
|
|
}
|
|
|
|
cozy_wait_all_helmreleases_ready 30 11 5 2 >/dev/null
|
|
[ "$(sed -n '1p' "$clock")" -ge 10 ] || {
|
|
echo "the gate returned before the late release became Ready and stabilized" >&2
|
|
exit 1
|
|
}
|
|
[ "$(grep -c -- '-o json' "$calls")" -ge 6 ]
|
|
}
|
|
|
|
@test "Stalled HelmRelease fails immediately without sleeping to timeout" {
|
|
. hack/e2e-wait-helmreleases.sh
|
|
calls=$(mktemp)
|
|
date() { printf '100\n'; }
|
|
sleep() { echo "sleep must not run after Stalled=True" >&2; return 1; }
|
|
kubectl() {
|
|
printf '%s\n' "$*" >> "$calls"
|
|
helmrelease_snapshot 11 3 3
|
|
}
|
|
|
|
if cozy_wait_all_helmreleases_ready 900 11 5 2 >/dev/null 2>&1; then
|
|
echo "a terminal Stalled HelmRelease passed readiness" >&2
|
|
exit 1
|
|
fi
|
|
[ "$(wc -l < "$calls")" -eq 1 ] || {
|
|
echo "the Stalled path kept polling instead of failing immediately" >&2
|
|
exit 1
|
|
}
|
|
}
|
|
|
|
@test "a transient list error keeps the gate closed" {
|
|
. hack/e2e-wait-helmreleases.sh
|
|
clock=$(mktemp)
|
|
calls=$(mktemp)
|
|
printf '0\n' > "$clock"
|
|
date() { sed -n '1p' "$clock"; }
|
|
sleep() {
|
|
now=$(sed -n '1p' "$clock")
|
|
printf '%s\n' "$(( now + $1 ))" > "$clock"
|
|
}
|
|
kubectl() {
|
|
count=$(wc -l < "$calls")
|
|
printf '%s\n' "$*" >> "$calls"
|
|
if [ "$count" -eq 0 ]; then
|
|
echo 'temporary apiserver error' >&2
|
|
return 1
|
|
fi
|
|
helmrelease_snapshot 11
|
|
}
|
|
|
|
cozy_wait_all_helmreleases_ready 30 11 4 2 >/dev/null 2>&1
|
|
[ "$(sed -n '1p' "$clock")" -ge 6 ] || {
|
|
echo "the list error was mistaken for an all-Ready snapshot" >&2
|
|
exit 1
|
|
}
|
|
}
|
|
|
|
@test "a Ready but short release set keeps the gate closed" {
|
|
# The minimum-count half of the gate is what replaced the `wc -l` existence
|
|
# backstop removed from hack/e2e-install-cozystack.bats, and it is the only
|
|
# thing separating "everything is Ready" from "almost nothing got created":
|
|
# an install that produced three HelmReleases and stopped has every one of
|
|
# them Ready. Every other case here passes 11 or 12 items against a minimum
|
|
# of 11, so without this one the condition can be deleted outright and the
|
|
# suite stays green.
|
|
. hack/e2e-wait-helmreleases.sh
|
|
clock=$(mktemp)
|
|
printf '0\n' > "$clock"
|
|
date() { sed -n '1p' "$clock"; }
|
|
sleep() {
|
|
now=$(sed -n '1p' "$clock")
|
|
printf '%s\n' "$(( now + $1 ))" > "$clock"
|
|
}
|
|
kubectl() { helmrelease_snapshot 3; }
|
|
|
|
if cozy_wait_all_helmreleases_ready 30 11 4 2 >/dev/null 2>&1; then
|
|
echo "the gate opened on 3 Ready HelmReleases against a minimum of 11" >&2
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
@test "a failed read invalidates a stability window already in progress" {
|
|
# The list-error branch resets stable_fingerprint and stable_since, and the
|
|
# "transient list error" case above does not pin that: its read fails on the
|
|
# first call, when there is no window to invalidate. Reverting the reset left
|
|
# the suite green. Here the failure lands mid-window, so a gate that kept
|
|
# counting through it returns at the original start plus quiet_seconds
|
|
# instead of restarting the clock -- which would accept a set that was never
|
|
# observed stable across the gap.
|
|
. hack/e2e-wait-helmreleases.sh
|
|
clock=$(mktemp)
|
|
calls=$(mktemp)
|
|
printf '0\n' > "$clock"
|
|
date() { sed -n '1p' "$clock"; }
|
|
sleep() {
|
|
now=$(sed -n '1p' "$clock")
|
|
printf '%s\n' "$(( now + $1 ))" > "$clock"
|
|
}
|
|
kubectl() {
|
|
count=$(wc -l < "$calls")
|
|
printf 'call\n' >> "$calls"
|
|
# Ready on the first read, unreadable on the second, Ready again after:
|
|
# the window opens at t=0, is broken at t=2, and may only complete a
|
|
# full quiet period measured from the read that reopened it.
|
|
if [ "$count" -eq 1 ]; then
|
|
echo 'temporary apiserver error' >&2
|
|
return 1
|
|
fi
|
|
helmrelease_snapshot 11
|
|
}
|
|
|
|
cozy_wait_all_helmreleases_ready 60 11 6 2 >/dev/null 2>&1
|
|
if [ "$(sed -n '1p' "$clock")" -lt 10 ]; then
|
|
echo "the gate counted the broken read as part of the stability window" >&2
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
@test "a read slower than the poll interval is charged against the deadline" {
|
|
# `now` is sampled after the list read, not before it. Sampled before, a read
|
|
# that costs more than the poll interval is priced at zero and the loop buys
|
|
# another full iteration past the deadline -- so the ceiling the caller asked
|
|
# for is not one. Counted in kubectl calls: one snapshot plus the final
|
|
# diagnostic read is the whole run; a third call means a second poll happened
|
|
# after the deadline had already passed.
|
|
. hack/e2e-wait-helmreleases.sh
|
|
clock=$(mktemp)
|
|
calls=$(mktemp)
|
|
printf '0\n' > "$clock"
|
|
date() { sed -n '1p' "$clock"; }
|
|
sleep() {
|
|
now=$(sed -n '1p' "$clock")
|
|
printf '%s\n' "$(( now + $1 ))" > "$clock"
|
|
}
|
|
kubectl() {
|
|
printf 'call\n' >> "$calls"
|
|
now=$(sed -n '1p' "$clock")
|
|
printf '%s\n' "$(( now + 40 ))" > "$clock"
|
|
helmrelease_snapshot 11 1
|
|
}
|
|
|
|
cozy_wait_all_helmreleases_ready 30 11 4 2 >/dev/null 2>&1 || true
|
|
if [ "$(wc -l < "$calls")" -ne 2 ]; then
|
|
echo "expected one snapshot read and one diagnostic read, got $(wc -l < "$calls")" >&2
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
@test "install suite has one unmasked HelmRelease gate" {
|
|
[ "$(grep -c 'cozy_wait_all_helmreleases_ready 900 11 5 2' hack/e2e-install-cozystack.bats)" -eq 1 ]
|
|
if grep -q 'kubectl wait hr --all -A.*|| true' hack/e2e-install-cozystack.bats; then
|
|
echo "the old masked HelmRelease wait survived" >&2
|
|
exit 1
|
|
fi
|
|
}
|