#!/usr/bin/env bash # # The MongoDB Stable release gate (design §30, plan Task 50). # # Runs every lane that produces one of the Stable evidence categories: # # mapping, transaction, migration, change-stream, security, # failover, performance, compatibility # # The gate exists because "the test suite is green" and "every category has evidence" are different # statements. A suite passes happily with a whole lane skipped -- no Docker, a disabled tag, a # renamed task -- and a release built on that suite has no failover or compatibility evidence at # all, silently. Each lane below is therefore run by name, and a skipped lane is reported as skipped # rather than counted as passed. # # Advanced capabilities are NOT promoted or transitively included here. See # scripts/verify-mongodb-advanced.sh. # # Usage: # bash scripts/verify-mongodb-platform.sh # hermetic lanes only # MONGODB_DOCKER=1 bash scripts/verify-mongodb-platform.sh # + container lanes # set -euo pipefail REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" GRADLE_DIR="${REPO_ROOT}/src" MODULE=':adapter:outbound:persistence-mongo' GRADLE=(./gradlew --console=plain) RESULTS_DIR="${GRADLE_DIR}/adapter/outbound/persistence-mongo/build/test-results" RAN=() SKIPPED=() FAILED=() # Counts the tests a lane actually executed, from its JUnit XML. # # A lane whose filter matches nothing passes: Gradle runs the task, discovers no tests, and reports # success. That is the failure mode this whole gate exists to prevent -- an empty lane is not # evidence, it is the absence of evidence wearing a green tick. Any lane that reports zero executed # tests is treated as a failure. executed_tests() { local task="$1" local dir="${RESULTS_DIR}/${task}" [[ -d "${dir}" ]] || { echo 0; return; } local total=0 shopt -s nullglob for xml in "${dir}"/*.xml; do local count count=$(sed -n 's/.*]* tests="\([0-9]*\)".*/\1/p' "${xml}" | head -1) total=$(( total + ${count:-0} )) done shopt -u nullglob echo "${total}" } run_lane() { local category="$1" local task="$2" shift 2 echo "" echo "=== [${category}] ${task}" if ! (cd "${GRADLE_DIR}" && "${GRADLE[@]}" "${MODULE}:${task}" "$@"); then FAILED+=("${category}:${task}") return fi # `check` aggregates several tasks and has no results directory of its own. if [[ "${task}" == "check" ]]; then RAN+=("${category}:${task}") return fi local executed executed=$(executed_tests "${task}") if (( executed == 0 )); then echo "!!! ${task} passed without executing a single test — the lane's filter matches nothing," echo "!!! so the '${category}' evidence category is empty." FAILED+=("${category}:${task} (0 tests executed)") else RAN+=("${category}:${task} (${executed} tests)") fi } skip_lane() { local category="$1" local task="$2" local reason="$3" echo "" echo "=== [${category}] ${task} -- SKIPPED (${reason})" SKIPPED+=("${category}:${task} (${reason})") } docker_available() { [[ "${MONGODB_DOCKER:-0}" == "1" ]] && command -v docker >/dev/null 2>&1 && docker info >/dev/null 2>&1 } echo "MongoDB Stable release gate" echo "repository: ${REPO_ROOT}" # --- Always-on lanes ------------------------------------------------------------------------- # Static analysis, architecture boundaries, unit and hermetic contract tests. These produce the # mapping, transaction, migration, change-stream and security evidence that does not need a server. run_lane "static-analysis" "check" -x "mongoStableContractTest" run_lane "mapping+transaction+migration+change-stream+security" "mongoStableContractTest" # --- Container lanes ------------------------------------------------------------------------- # A lane that needs Docker inside `check` teaches people to skip `check`, so these are opt-in -- # but opting out is recorded, not silent. if docker_available; then run_lane "compatibility" "mongoCompatibilityTest" run_lane "migration" "mongoMigrationTest" run_lane "security" "mongoSecurityIntegrationTest" run_lane "failover" "mongoReplicaSetTest" run_lane "failover" "mongoFailoverTest" run_lane "performance" "mongoPerformanceTest" else reason="MONGODB_DOCKER!=1 or Docker unavailable" skip_lane "compatibility" "mongoCompatibilityTest" "${reason}" skip_lane "migration" "mongoMigrationTest" "${reason}" skip_lane "security" "mongoSecurityIntegrationTest" "${reason}" skip_lane "failover" "mongoReplicaSetTest" "${reason}" skip_lane "failover" "mongoFailoverTest" "${reason}" skip_lane "performance" "mongoPerformanceTest" "${reason}" fi # --- Architecture-wide gates ----------------------------------------------------------------- echo "" echo "=== [architecture] repository-wide verification" if (cd "${GRADLE_DIR}" \ && "${GRADLE[@]}" verifyCleanArchitectureDependencies \ && "${GRADLE[@]}" :app-bootstrap:test --tests '*CleanArchitectureTest'); then RAN+=("architecture:repository-wide") else FAILED+=("architecture:repository-wide") fi # --- Report ------------------------------------------------------------------------------------ echo "" echo "---------------------------------------------------------------" echo "ran: ${#RAN[@]}" for entry in "${RAN[@]:-}"; do [[ -n "${entry}" ]] && echo " + ${entry}"; done echo "skipped: ${#SKIPPED[@]}" for entry in "${SKIPPED[@]:-}"; do [[ -n "${entry}" ]] && echo " ~ ${entry}"; done echo "failed: ${#FAILED[@]}" for entry in "${FAILED[@]:-}"; do [[ -n "${entry}" ]] && echo " - ${entry}"; done # --- promotion manifest ------------------------------------------------------------------------- # What was actually certified, tied to what produced it. A gate output that says "PASSED" and # nothing else cannot be checked later against the artefact it supposedly certified: the commit, the # server image and the driver version are exactly what somebody reads during an incident. MANIFEST_DIR="${REPO_ROOT}/src/adapter/outbound/persistence-mongo/build/reports/mongo-release" mkdir -p "${MANIFEST_DIR}" { echo "{" echo " \"commit\": \"$(git -C "${REPO_ROOT}" rev-parse HEAD)\"," echo " \"commitDirty\": $( [[ -n "$(git -C "${REPO_ROOT}" status --porcelain)" ]] && echo true || echo false )," echo " \"serverImage\": \"${MONGODB_IMAGE:-mongo:8.0.16}\"," echo " \"generatedAt\": \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"," echo " \"contractManifest\": \"src/config/mongodb/release-contracts.json\"," echo " \"contractManifestSha256\": \"$(sha256sum "${REPO_ROOT}/src/config/mongodb/release-contracts.json" | cut -d' ' -f1)\"" echo "}" } > "${MANIFEST_DIR}/promotion.json" echo "promotion manifest: ${MANIFEST_DIR}/promotion.json" echo "---------------------------------------------------------------" if (( ${#FAILED[@]} > 0 )); then echo "STABLE GATE: FAILED" exit 1 fi if (( ${#SKIPPED[@]} > 0 )); then echo "STABLE GATE: INCOMPLETE -- lanes above were not run, so their evidence categories are absent." echo "A release requires every category. Re-run with MONGODB_DOCKER=1 on a host with Docker." exit 2 fi echo "STABLE GATE: PASSED -- every evidence category produced."