diff --git a/docker/verify-pending-updates.sh b/docker/verify-pending-updates.sh index 95472e2e..45b84eb1 100755 --- a/docker/verify-pending-updates.sh +++ b/docker/verify-pending-updates.sh @@ -1,5 +1,5 @@ #!/bin/bash -set -uo pipefail +set -euo pipefail # Live gate for the PER-SITE ARTIFACT REVISION that backs the pending-updates indicator # (design docs/plans/2026-09-14-pending-updates-design.md, plan task 10). Drives the real @@ -17,11 +17,15 @@ set -uo pipefail # E Central UI /admin/sites answers 200 and serves the Artifacts badge markup (soft) # # NOTE on step E: the Sites page badge and the rail-footer indicator are Blazor Server -# interactive content — the badge text only lands after the circuit's post-render -# LoadUpdatesAsync, which curl never sees. E is therefore a reachability + static-markup -# smoke only; the real browser coverage is +# interactive content — with login ENABLED the badge text only lands after the circuit's +# post-render LoadUpdatesAsync, which curl never sees. E is therefore a reachability + +# static-markup smoke only; the real browser coverage is # tests/ZB.MOM.WW.ScadaBridge.CentralUI.PlaywrightTests/PendingUpdatesTests.cs. # +# EVERY read of the site list is checked for both a failed CLI call and a short row count +# (read_rows below). Without that an empty list would pass the whole gate vacuously: "no +# rows" means no malformed hash to report and no difference between two row sets. +# # Usage: bash docker/verify-pending-updates.sh # SCADABRIDGE_URL=http://localhost:9000 bash docker/verify-pending-updates.sh @@ -36,6 +40,10 @@ PASS=0; FAIL=0 pass() { PASS=$((PASS+1)); echo " PASS $*"; } fail() { FAIL=$((FAIL+1)); echo " FAIL $*"; } +# Bail out mid-run without losing the tally. Used for the failures that make every later +# assertion meaningless (no sites, an unreachable management API, a short row read). +abort() { echo ""; echo "PASS $PASS / FAIL $FAIL"; exit 1; } + [ -x "$CLI" ] || { echo "CLI not found at $CLI — build it: dotnet build src/ZB.MOM.WW.ScadaBridge.CLI"; exit 1; } # The CLI's JSON envelope varies by command (bare array vs {"data": [...]}); normalise once. @@ -46,24 +54,85 @@ if isinstance(d, dict): d = d.get("data", d) ' -# Prints one "\t\t\t" line per site, id-sorted. +# Prints one "\t\t\t" line per site, id-sorted +# NUMERICALLY. Exits non-zero if the CLI call fails (pipefail) or the list is empty. site_rows() { - "$CLI" site list "${A[@]}" 2>/dev/null | python3 -c "$UNWRAP"' -for s in sorted(d, key=lambda x: x["id"]): + "$CLI" site list "${A[@]}" | python3 -c "$UNWRAP"' +import sys +if not d: + sys.exit(2) +for s in sorted(d, key=lambda x: int(x["id"])): print("%s\t%s\t%s\t%s" % (s["id"], s.get("siteIdentifier"), s.get("artifactRevisionHash") or "-", s.get("artifactsDeployedAt") or "-")) ' } -deploy_all() { - "$CLI" site deploy-artifacts "${A[@]}" > /tmp/pu-deploy.$$ 2>&1 - local rc=$? - if [ $rc -ne 0 ]; then - echo " deploy-artifacts exited $rc:"; sed 's/^/ /' /tmp/pu-deploy.$$ +# read_rows