#!/usr/bin/env bash # Sandboxed selftests for the release layer. # # Fast cases (version validation) need no Docker. State-machine cases # (status/activate/refusal) run against a sandboxed config and therefore # require the Docker daemon; they are skipped when it is unavailable. set -uo pipefail cd "$(dirname "$0")/.." SANDBOX="$(mktemp -d)" RELEASE_BACKUP="$(mktemp)" cp RELEASE "$RELEASE_BACKUP" # One exit trap: the repo RELEASE is ALWAYS restored from the backup, # regardless of how the test run ends. # Compose names the project after the checkout directory unless told otherwise, # and `compose run --rm` leaves the project's _default network behind. # Every run gets its own project, and the exit trap removes that one network # (row 305). It never runs `compose down` and never touches another network. COMPOSE_ID="$(basename "$SANDBOX")" COMPOSE_ID="$(printf '%s' "${COMPOSE_ID##*.}" | tr -cd '[:alnum:]' | tr '[:upper:]' '[:lower:]')" export COMPOSE_PROJECT_NAME="mosaic-test-release-$COMPOSE_ID" remove_compose_network() { # absent is fine; any other failure is one stderr line, never a status command -v docker >/dev/null 2>&1 || return 0 local net="${COMPOSE_PROJECT_NAME}_default" err err="$(docker network rm "$net" 2>&1 >/dev/null)" && return 0 case "$err" in *"not found"*|*"No such network"*) return 0 ;; esac echo "test-release: could not remove network $net: ${err%%$'\n'*}" >&2 return 0 } trap 'cp "$RELEASE_BACKUP" RELEASE 2>/dev/null; rm -rf "$SANDBOX" "$RELEASE_BACKUP"; remove_compose_network' EXIT # Compose mounts PI_AUTH_FILE. Point it at a fixture so no activation reaches # the host's pi credential (row 244). chmod after the write: umask-proof (row 243). { mkdir -p "$SANDBOX/pi" && printf '{}' > "$SANDBOX/pi/auth.json" && chmod 600 "$SANDBOX/pi/auth.json"; } \ || { echo "cannot write the pi auth fixture" >&2; exit 1; } export PI_AUTH_FILE="$SANDBOX/pi/auth.json" PASS=0 # Status colors: terminal-only, NO_COLOR-respecting; plain when piped. if [ -t 1 ] && [ -z "${NO_COLOR:-}" ]; then C_OK=$'\033[0;32m'; C_FAIL=$'\033[0;31m'; C_RESET=$'\033[0m' else C_OK=""; C_FAIL=""; C_RESET="" fi FAIL=0 expect_exit() { local name="$1" expected="$2" shift 3 local rc "$@" >/dev/null 2>&1 rc=$? if [ "$rc" -eq "$expected" ]; then PASS=$((PASS+1)); echo "${C_OK}OK${C_RESET} $name (exit $rc)" else FAIL=$((FAIL+1)); echo "${C_FAIL}FAIL${C_RESET} $name (exit $rc, expected $expected)" fi } check() { if [ "$2" = "0" ]; then PASS=$((PASS+1)); echo "${C_OK}OK${C_RESET} $1"; else FAIL=$((FAIL+1)); echo "${C_FAIL}FAIL${C_RESET} $1"; fi } # ---------- fast: release identity ---------- expect_exit "valid RELEASE resolves" 0 -- bash -c 'source scripts/common.sh && load_release' printf 'garbage\n' > RELEASE expect_exit "invalid RELEASE exits 1" 1 -- bash -c 'source scripts/common.sh && load_release' mv RELEASE "$SANDBOX/RELEASE.hidden" expect_exit "missing RELEASE exits 1" 1 -- bash -c 'source scripts/common.sh && load_release' cp "$RELEASE_BACKUP" RELEASE bash -c 'source scripts/common.sh && load_release' >/dev/null 2>&1 bash -c 'source scripts/common.sh && load_release && case "$MOSAIC_IMAGE_TAG" in mosaic-poc-agent:*-r'"$(cat RELEASE)"') exit 0;; *) exit 1;; esac' >/dev/null 2>&1 check "valid RELEASE leaves image tag consistent with version" $? # ---------- sandboxed state machine (Docker required) ---------- if docker info >/dev/null 2>&1; then mkdir -p "$SANDBOX/data" # The mock adapter: no credential and no provider call in the gate (row 244, # ruling A, sage-1914). This suite proves the release state machine, image and # Compose path, not that the pi image reaches the provider. cat > "$SANDBOX/config.json" </dev/null 2>&1; then NET="${COMPOSE_PROJECT_NAME}_default" BEFORE="$(docker network ls -q --filter "name=^${NET}\$")" && [ -n "$BEFORE" ] \ && remove_compose_network \ && AFTER="$(docker network ls -q --filter "name=^${NET}\$")" && [ -z "$AFTER" ] \ && check "compose network made under the run's project and removed after the run" 0 \ || check "compose network made under the run's project and removed after the run" 1 else echo "skip compose network check (docker daemon unavailable)" fi echo echo "selftest: $PASS passed, $FAIL failed" [ "$FAIL" -eq 0 ]