#!/bin/bash # A VERSION NUMBER IS PUSHED ONCE — the test for build.sh's registry check (v0.316.0). # # WHY IT EXISTS: 0.315.0 was built and pushed three times from three different commits. A box that # pulled between the first and the last runs different code under the same number and will never # fetch the fix, because to the box that number is already current. The check in build.sh is the # mechanism; this is the test that it convicts. # # HOW IT TESTS WITHOUT A REGISTRY: a fake `docker` is put first on PATH. Every case drives the REAL # build.sh, so the test cannot pass while the check has been deleted — which is the red-proof. # Nothing is ever pushed: the fake refuses `build` and `push` loudly, so a build that got past the # check would fail the test rather than reach the network. # # Run from controller/: bash scripts/test_build_push_once.sh set -u HERE="$(cd "$(dirname "$0")" && pwd)" BUILD_SH="$(dirname "$HERE")/build.sh" fails=0; ran=0 [[ -f "$BUILD_SH" ]] || { echo "FAIL: build.sh not found at $BUILD_SH"; exit 1; } # A fake `docker` whose answer to `manifest inspect` is set by FAKE_MODE. make_fake_docker() { local dir="$1" mkdir -p "$dir" cat > "$dir/docker" <<'FAKE' #!/bin/bash case "$1 $2" in "manifest inspect") case "${FAKE_MODE}" in present) echo '{"schemaVersion":2}'; exit 0 ;; absent) echo "manifest unknown: manifest unknown" >&2; exit 1 ;; down) echo "Get \"https://gitea.dooplex.hu/v2/\": dial tcp: connection refused" >&2; exit 1 ;; denied) echo "unauthorized: authentication required" >&2; exit 1 ;; esac ;; "build "*|"buildx "*|"push "*) echo "FAKE-DOCKER-REACHED: $*" ; exit 0 ;; esac # anything else (version checks etc.) succeeds quietly exit 0 FAKE chmod +x "$dir/docker" } # Run build.sh with the fake docker, from a throwaway cwd, and capture everything. run_build() { local mode="$1"; shift local tmp; tmp="$(mktemp -d)" make_fake_docker "$tmp/bin" FAKE_MODE="$mode" PATH="$tmp/bin:$PATH" bash "$BUILD_SH" "$@" >"$tmp/out" 2>&1 rc=$? out="$(cat "$tmp/out")" rm -rf "$tmp" return $rc } check() { local name="$1" want_rc="$2" want_text="$3" forbid_text="${4:-}" ran=$((ran+1)) if [[ "$rc" != "$want_rc" ]]; then fails=$((fails+1)); echo " FAIL $name: exit $rc, want $want_rc" echo "$out" | tail -6 | sed 's/^/ /'; return fi if [[ -n "$want_text" ]] && ! grep -qi -- "$want_text" <<<"$out"; then fails=$((fails+1)); echo " FAIL $name: output does not contain '$want_text'" echo "$out" | tail -6 | sed 's/^/ /'; return fi if [[ -n "$forbid_text" ]] && grep -qi -- "$forbid_text" <<<"$out"; then fails=$((fails+1)); echo " FAIL $name: output contains '$forbid_text', which must not happen" echo "$out" | tail -6 | sed 's/^/ /'; return fi echo " ok $name" } echo "build.sh — a version number is pushed once" # 1. The tag is already in the registry -> refuse, before building, and push nothing. run_build present 0.999.0 --push check "--push, tag present -> refuses" 1 "already exists in the registry" "FAKE-DOCKER-REACHED" # 2. The tag is new -> say so and carry on INTO the build. # The exit code is deliberately not asserted: past the check, build.sh runs the real build steps, # which cannot complete in a test sandbox. What matters is that the check let it through, so the # assertion is its verdict line plus the ABSENCE of a refusal. run_build absent 0.999.0 --push check "--push, tag absent -> proceeds" "$rc" "is not present in the registry" "already exists in the registry" # 3. --multiarch gets the same refusal (the task's edge case). run_build present 0.999.0 --multiarch check "--multiarch, tag present -> refuses" 1 "already exists in the registry" "FAKE-DOCKER-REACHED" # 4. The registry cannot be asked -> refuse. "I could not ask" is not proof the tag is new. run_build down 0.999.0 --push check "--push, registry unreachable -> refuses" 1 "Could not establish whether" "FAKE-DOCKER-REACHED" # 5. An auth failure is just as unanswered as a network failure. run_build denied 0.999.0 --push check "--push, auth failure -> refuses" 1 "Could not establish whether" "FAKE-DOCKER-REACHED" # 6. A LOCAL build is untouched — reusing a version while iterating is the normal case, and the # check must not even run (no registry question is asked, so `present` must not refuse). run_build present 0.999.0 check "local build, tag present -> not refused" 0 "" "already exists in the registry" echo if [[ $fails -eq 0 ]]; then echo "all $ran cases behaved — a pushed version cannot be overwritten" exit 0 fi echo "$fails of $ran cases FAILED" exit 1