233 lines
8.9 KiB
Bash
233 lines
8.9 KiB
Bash
#!/usr/bin/env bash
|
|
# Exit-asserting RM-03 regression harness for ci-queue-wait.sh.
|
|
# Every case is a process-level assertion: a classifier-only green cannot satisfy it.
|
|
|
|
set -u
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
WORK_DIR="${MOSAIC_TEST_WORK_DIR:-$PWD/.mosaic-test-work/ci-queue-wait-tristate}"
|
|
REPO_DIR="$WORK_DIR/repo"
|
|
STUB_DIR="$WORK_DIR/stubs"
|
|
AUDIT_LOG="$WORK_DIR/audit/ci-queue-wait.jsonl"
|
|
FEATURE_BRANCH="fix/rm-03-fixture"
|
|
|
|
rm -rf "$WORK_DIR"
|
|
mkdir -p "$REPO_DIR" "$STUB_DIR"
|
|
git -C "$REPO_DIR" init -q
|
|
git -C "$REPO_DIR" checkout -q -b "$FEATURE_BRANCH"
|
|
git -C "$REPO_DIR" remote add origin https://git.example.test/acme/widgets.git
|
|
|
|
cat > "$STUB_DIR/curl" <<'SH'
|
|
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
url=""
|
|
has_write_out=0
|
|
for arg in "$@"; do
|
|
case "$arg" in
|
|
-w) has_write_out=1 ;;
|
|
http://*|https://*) url="$arg" ;;
|
|
esac
|
|
done
|
|
printf '%s\n' "$url" >> "${MOSAIC_STUB_URL_LOG:?}"
|
|
|
|
case "$url" in
|
|
*/branches/*)
|
|
if [[ "${MOSAIC_STUB_BRANCH_MODE:-ok}" == "unreachable" ]]; then
|
|
exit 7
|
|
fi
|
|
body='{"commit":{"id":"deadbeefcafef00d0123456789abcdef01234567"}}'
|
|
if [[ "$has_write_out" -eq 1 ]]; then
|
|
printf '%s\n200' "$body"
|
|
else
|
|
printf '%s' "$body"
|
|
fi
|
|
;;
|
|
*/status)
|
|
case "${MOSAIC_STUB_STATUS_MODE:?}" in
|
|
success) printf '%s' '{"state":"success","statuses":[{"status":"success"}]}' ;;
|
|
pending) printf '%s' '{"state":"pending","statuses":[{"status":"pending","context":"ci/test"}]}' ;;
|
|
failure) printf '%s' '{"state":"failure","statuses":[{"status":"failure"}]}' ;;
|
|
no-status) printf '%s' '{"state":"","statuses":[]}' ;;
|
|
aggregate-success-no-status) printf '%s' '{"state":"success","statuses":[]}' ;;
|
|
malformed) printf '%s' 'not-json' ;;
|
|
malformed-statuses-type) printf '%s' '{"state":"success","statuses":"corrupt"}' ;;
|
|
malformed-status-entry) printf '%s' '{"state":"success","statuses":[null]}' ;;
|
|
large-success)
|
|
python3 -c 'import json; print(json.dumps({"state":"success", "statuses":[{"status":"success"}], "padding":"x" * (160 * 1024)}), end="")'
|
|
;;
|
|
unreachable) exit 7 ;;
|
|
*) echo "unknown status mode" >&2; exit 2 ;;
|
|
esac
|
|
;;
|
|
*) echo "unexpected curl URL: $url" >&2; exit 2 ;;
|
|
esac
|
|
SH
|
|
chmod +x "$STUB_DIR/curl"
|
|
|
|
run_guard() {
|
|
local status_mode="$1"
|
|
local audit_log="${2:-$AUDIT_LOG}"
|
|
shift 2 || true
|
|
(
|
|
cd "$REPO_DIR" || exit
|
|
export PATH="$STUB_DIR:$PATH"
|
|
export MOSAIC_CREDENTIALS_FILE="$WORK_DIR/no-credentials.json"
|
|
if [[ "$status_mode" == "credential-unresolvable" ]]; then
|
|
export HOME="$WORK_DIR/empty-home"
|
|
mkdir -p "$HOME"
|
|
unset GITEA_TOKEN GITEA_URL MOSAIC_GIT_IDENTITY
|
|
export MOSAIC_STUB_STATUS_MODE=success
|
|
else
|
|
export GITEA_TOKEN=stub-token
|
|
export GITEA_URL=https://git.example.test
|
|
export MOSAIC_STUB_STATUS_MODE="$status_mode"
|
|
fi
|
|
export MOSAIC_STUB_URL_LOG="$WORK_DIR/urls.log"
|
|
export MOSAIC_CI_QUEUE_AUDIT_LOG="$audit_log"
|
|
"$SCRIPT_DIR/ci-queue-wait.sh" --purpose "${MOSAIC_TEST_PURPOSE:-push}" -t 0 -i 0 "$@"
|
|
)
|
|
}
|
|
|
|
failures=0
|
|
run_assertion() {
|
|
local name="$1" expected_rc="$2" status_mode="$3" required_text="$4"
|
|
local output rc
|
|
shift 4
|
|
set +e
|
|
output=$(run_guard "$status_mode" "$AUDIT_LOG" "$@" 2>&1)
|
|
rc=$?
|
|
set -e
|
|
|
|
case "$expected_rc" in
|
|
zero)
|
|
if [[ "$rc" -ne 0 ]]; then
|
|
echo "FAIL $name: expected rc=0, got rc=$rc" >&2
|
|
failures=$((failures + 1))
|
|
fi
|
|
;;
|
|
nonzero)
|
|
if [[ "$rc" -eq 0 ]]; then
|
|
echo "FAIL $name: expected rc!=0, got rc=0" >&2
|
|
failures=$((failures + 1))
|
|
fi
|
|
;;
|
|
not126)
|
|
if [[ "$rc" -eq 126 ]]; then
|
|
echo "FAIL $name: payload transport hit ARG_MAX (rc=126)" >&2
|
|
failures=$((failures + 1))
|
|
fi
|
|
;;
|
|
esac
|
|
if [[ "$output" != *"$required_text"* ]]; then
|
|
echo "FAIL $name: output missing '$required_text' (rc=$rc)" >&2
|
|
printf '%s\n' "$output" >&2
|
|
failures=$((failures + 1))
|
|
fi
|
|
}
|
|
|
|
set -e
|
|
: > "$WORK_DIR/urls.log"
|
|
run_assertion success zero success 'state=terminal-success'
|
|
run_assertion pending nonzero pending 'ASSERTED_NOT_READY'
|
|
run_assertion failure nonzero failure 'ASSERTED_NOT_READY'
|
|
run_assertion no-status nonzero no-status 'ASSERTED_NOT_READY'
|
|
run_assertion aggregate-success-no-status nonzero aggregate-success-no-status 'ASSERTED_NOT_READY'
|
|
run_assertion malformed nonzero malformed 'ASSERTED_NOT_READY'
|
|
run_assertion malformed-statuses-type nonzero malformed-statuses-type 'ASSERTED_NOT_READY'
|
|
run_assertion malformed-status-entry nonzero malformed-status-entry 'ASSERTED_NOT_READY'
|
|
run_assertion large-payload not126 large-success 'state=terminal-success'
|
|
run_assertion credential-unresolvable zero credential-unresolvable 'CANNOT_ASSERT'
|
|
run_assertion provider-unreachable zero unreachable 'CANNOT_ASSERT'
|
|
|
|
if [[ ! -s "$AUDIT_LOG" ]] || ! grep -q '"outcome":"CANNOT_ASSERT"' "$AUDIT_LOG"; then
|
|
echo "FAIL provider-unreachable-audit: expected durable CANNOT_ASSERT JSONL record" >&2
|
|
failures=$((failures + 1))
|
|
fi
|
|
|
|
# Merge cannot proceed without exact-head evidence. CANNOT_ASSERT is retryable exit 75,
|
|
# distinct from ASSERTED_NOT_READY (3/124), and still writes its audit record.
|
|
merge_audit_lines_before=$(wc -l < "$AUDIT_LOG")
|
|
set +e
|
|
merge_unreachable_output=$(MOSAIC_TEST_PURPOSE=merge run_guard unreachable "$AUDIT_LOG" 2>&1)
|
|
merge_unreachable_rc=$?
|
|
set -e
|
|
if [[ "$merge_unreachable_rc" -ne 75 ]]; then
|
|
echo "FAIL merge-provider-unreachable: expected rc=75, got rc=$merge_unreachable_rc" >&2
|
|
failures=$((failures + 1))
|
|
fi
|
|
if [[ "$merge_unreachable_output" != *"CANNOT_ASSERT"* ]]; then
|
|
echo "FAIL merge-provider-unreachable: expected loud CANNOT_ASSERT diagnostic" >&2
|
|
failures=$((failures + 1))
|
|
fi
|
|
merge_audit_lines_after=$(wc -l < "$AUDIT_LOG")
|
|
if [[ "$merge_audit_lines_after" -le "$merge_audit_lines_before" ]]; then
|
|
echo "FAIL merge-provider-unreachable: expected an additional audit record" >&2
|
|
failures=$((failures + 1))
|
|
fi
|
|
|
|
# A feature-branch push with no -B must inspect the checked-out feature branch.
|
|
if ! grep -q "/branches/$FEATURE_BRANCH" "$WORK_DIR/urls.log"; then
|
|
echo "FAIL implicit-branch: provider was not queried for $FEATURE_BRANCH" >&2
|
|
failures=$((failures + 1))
|
|
fi
|
|
|
|
# Merge callers can pin both a fork repository and the exact reviewed head SHA.
|
|
exact_sha=0123456789abcdef0123456789abcdef01234567
|
|
: > "$WORK_DIR/urls.log"
|
|
run_assertion exact-fork-head zero success 'state=terminal-success' \
|
|
-B fix/rm-03-fixture -R contributor/widgets-fork --sha "$exact_sha"
|
|
if ! grep -q "/repos/contributor/widgets-fork/commits/$exact_sha/status" "$WORK_DIR/urls.log"; then
|
|
echo "FAIL exact-fork-head: status URL did not bind fork repository and exact SHA" >&2
|
|
failures=$((failures + 1))
|
|
fi
|
|
if grep -q '/branches/' "$WORK_DIR/urls.log"; then
|
|
echo "FAIL exact-fork-head: explicit SHA must not be re-resolved through a branch" >&2
|
|
failures=$((failures + 1))
|
|
fi
|
|
|
|
# Platform/repository discovery failures use the same audited CANNOT_ASSERT path.
|
|
audit_lines_before=$(wc -l < "$AUDIT_LOG")
|
|
git -C "$REPO_DIR" remote set-url origin https://gitlab.com/acme/widgets.git
|
|
set +e
|
|
unsupported_output=$(run_guard success "$AUDIT_LOG" 2>&1)
|
|
unsupported_rc=$?
|
|
set -e
|
|
git -C "$REPO_DIR" remote set-url origin https://git.example.test/acme/widgets.git
|
|
if [[ "$unsupported_rc" -ne 0 ]]; then
|
|
echo "FAIL unsupported-platform: expected degraded rc=0, got rc=$unsupported_rc" >&2
|
|
failures=$((failures + 1))
|
|
fi
|
|
if [[ "$unsupported_output" != *"CANNOT_ASSERT"* ]]; then
|
|
echo "FAIL unsupported-platform: expected loud CANNOT_ASSERT diagnostic" >&2
|
|
failures=$((failures + 1))
|
|
fi
|
|
audit_lines_after=$(wc -l < "$AUDIT_LOG")
|
|
if [[ "$audit_lines_after" -le "$audit_lines_before" ]]; then
|
|
echo "FAIL unsupported-platform: expected an additional audit record" >&2
|
|
failures=$((failures + 1))
|
|
fi
|
|
|
|
# A degraded pass is forbidden if the audit receipt cannot be written.
|
|
mkdir -p "$WORK_DIR/not-a-directory"
|
|
printf 'file' > "$WORK_DIR/not-a-directory/parent"
|
|
set +e
|
|
audit_failure_output=$(run_guard unreachable "$WORK_DIR/not-a-directory/parent/audit.jsonl" 2>&1)
|
|
audit_failure_rc=$?
|
|
set -e
|
|
if [[ "$audit_failure_rc" -eq 0 ]]; then
|
|
echo "FAIL audit-unavailable: expected rc!=0, got rc=0" >&2
|
|
failures=$((failures + 1))
|
|
fi
|
|
if [[ "$audit_failure_output" != *"audit"* ]]; then
|
|
echo "FAIL audit-unavailable: expected loud audit failure diagnostic" >&2
|
|
failures=$((failures + 1))
|
|
fi
|
|
|
|
if [[ "$failures" -ne 0 ]]; then
|
|
echo "ci-queue-wait tri-state regression failed ($failures assertions)" >&2
|
|
exit 1
|
|
fi
|
|
|
|
echo "ci-queue-wait tri-state regression passed (all outcome classes)"
|