mirror of
https://github.com/jmcorgan/fips.git
synced 2026-07-30 19:46:15 +00:00
Every section of ping-test.sh is guarded by the profile name, so an unrecognised profile fell through all of them and the script exited 0 having run no assertion. A typo in the caller's argument produced a green run that tested nothing. Give it an else branch that names the valid profiles and exits 2. No existing leg changes behaviour: the hosted runner gates the ping step on matrix.type == 'static', which only static-mesh and static-chain carry, and ci-local passes only the two names in STATIC_SUITES. Worth noting while confirming that, though: ping-test.sh accepts a mesh-public profile that neither runner ever passes. Also record why the convergence waits are `|| true` — they are settling delays rather than assertions, and the directed-pair pings are what decides the run — and add admission-cap to the suite list in the ci-local header, which ran it without listing it.
180 lines
6.1 KiB
Bash
Executable File
180 lines
6.1 KiB
Bash
Executable File
#!/bin/bash
|
||
# End-to-end ping test between FIPS nodes via DNS resolution.
|
||
# Usage: ./ping-test.sh [mesh|chain]
|
||
#
|
||
# Requires containers to be running:
|
||
# docker compose --profile mesh up -d
|
||
# ./scripts/ping-test.sh mesh
|
||
set -e
|
||
|
||
# Exit entire script on Ctrl+C
|
||
trap 'echo ""; echo "Test interrupted"; exit 130' INT
|
||
|
||
PROFILE="${1:-mesh}"
|
||
COUNT=1
|
||
TIMEOUT=5
|
||
PASSED=0
|
||
FAILED=0
|
||
|
||
# Node identities (from generated env file)
|
||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
source "$SCRIPT_DIR/../../lib/wait-converge.sh"
|
||
ENV_FILE="$SCRIPT_DIR/../generated-configs${FIPS_CI_NAME_SUFFIX:-}/npubs.env"
|
||
if [ ! -f "$ENV_FILE" ]; then
|
||
echo "Error: $ENV_FILE not found. Run generate-configs.sh first." >&2
|
||
exit 1
|
||
fi
|
||
# shellcheck source=../generated-configs/npubs.env
|
||
source "$ENV_FILE"
|
||
|
||
NPUBS=("$NPUB_A" "$NPUB_B" "$NPUB_C" "$NPUB_D" "$NPUB_E")
|
||
LABELS=(A B C D E)
|
||
|
||
ping_test() {
|
||
local from="$1"
|
||
local to_npub="$2"
|
||
local label="$3"
|
||
|
||
echo -n " $label ... "
|
||
local output
|
||
if output=$(docker exec "fips-${from}${FIPS_CI_NAME_SUFFIX:-}" ping6 -c "$COUNT" -W "$TIMEOUT" "${to_npub}.fips" 2>&1); then
|
||
# Extract round-trip time from ping output
|
||
local rtt
|
||
rtt=$(echo "$output" | grep -oE 'time=[0-9.]+' | cut -d= -f2)
|
||
if [ -n "$rtt" ]; then
|
||
echo "OK (${rtt}ms)"
|
||
else
|
||
echo "OK"
|
||
fi
|
||
PASSED=$((PASSED + 1))
|
||
else
|
||
echo "FAIL"
|
||
FAILED=$((FAILED + 1))
|
||
fi
|
||
}
|
||
|
||
# Quietly ping all pairs to check FSP-level convergence.
|
||
ping_all_quiet() {
|
||
PASSED=0
|
||
FAILED=0
|
||
local n=${#LABELS[@]}
|
||
for ((i=0; i<n; i++)); do
|
||
for ((j=0; j<n; j++)); do
|
||
[ "$i" -eq "$j" ] && continue
|
||
if docker exec "fips-node-${LABELS[$i],,}${FIPS_CI_NAME_SUFFIX:-}" \
|
||
ping6 -c 1 -W 1 "${NPUBS[$j]}.fips" >/dev/null 2>&1; then
|
||
PASSED=$((PASSED + 1))
|
||
else
|
||
FAILED=$((FAILED + 1))
|
||
fi
|
||
done
|
||
done
|
||
}
|
||
|
||
echo "=== FIPS Ping Test ($PROFILE topology) ==="
|
||
echo ""
|
||
|
||
# Wait for nodes to converge — all nodes must reach expected peer counts.
|
||
#
|
||
# Every wait below is `|| true` on purpose, for the same reason the
|
||
# wait_until_connected call further down is: these are settling delays, not
|
||
# assertions. A node that has not reached its configured peer count by the
|
||
# deadline may still be reachable, and the directed-pair pings are what
|
||
# actually decide the run. Letting a wait fail the script here would turn a
|
||
# slow convergence into a failure the pings would have passed.
|
||
#
|
||
# The converse is what makes it safe: because these cannot fail, they also
|
||
# cannot pass, so nothing about the run's verdict rests on them.
|
||
echo "Waiting for mesh convergence..."
|
||
if [ "$PROFILE" = "chain" ]; then
|
||
# Chain: A-B-C-D-E, each interior node has 2 peers, endpoints have 1
|
||
wait_for_peers fips-node-a${FIPS_CI_NAME_SUFFIX:-} 1 20 || true
|
||
wait_for_peers fips-node-b${FIPS_CI_NAME_SUFFIX:-} 2 20 || true
|
||
wait_for_peers fips-node-c${FIPS_CI_NAME_SUFFIX:-} 2 20 || true
|
||
wait_for_peers fips-node-d${FIPS_CI_NAME_SUFFIX:-} 2 20 || true
|
||
wait_for_peers fips-node-e${FIPS_CI_NAME_SUFFIX:-} 1 20 || true
|
||
elif [ "$PROFILE" = "mesh" ] || [ "$PROFILE" = "mesh-public" ]; then
|
||
# Mesh: check all nodes reach their configured peer counts
|
||
wait_for_peers fips-node-a${FIPS_CI_NAME_SUFFIX:-} 2 20 || true
|
||
wait_for_peers fips-node-b${FIPS_CI_NAME_SUFFIX:-} 1 20 || true
|
||
wait_for_peers fips-node-c${FIPS_CI_NAME_SUFFIX:-} 3 20 || true
|
||
wait_for_peers fips-node-d${FIPS_CI_NAME_SUFFIX:-} 3 20 || true
|
||
wait_for_peers fips-node-e${FIPS_CI_NAME_SUFFIX:-} 3 20 || true
|
||
else
|
||
# An unrecognised profile used to fall straight through, and every
|
||
# section below is guarded by these same profile names, so the script
|
||
# ran no assertion at all and exited 0. A typo in the caller's profile
|
||
# argument produced a green run that tested nothing.
|
||
echo "ERROR: unknown profile '$PROFILE' (expected: chain, mesh, mesh-public)" >&2
|
||
exit 2
|
||
fi
|
||
# Wait for full pairwise connectivity, progress-aware: the actual pings
|
||
# are the convergence signal, the deadline extends while more pairs come
|
||
# up, and it only gives up if progress stalls — so it does not
|
||
# false-time-out under load while routing is still converging. The
|
||
# directed-pair ping assertions below remain the actual test.
|
||
wait_until_connected ping_all_quiet 45 15 || true
|
||
|
||
# Reset counters for the actual test
|
||
PASSED=0
|
||
FAILED=0
|
||
|
||
if [ "$PROFILE" = "mesh" ] || [ "$PROFILE" = "mesh-public" ]; then
|
||
# Sparse mesh topology: A-B, B-C, C-D, D-E, E-A, A-D
|
||
# Test all 20 directed pairs (5 nodes × 4 targets each)
|
||
echo ""
|
||
echo "From node-a:"
|
||
ping_test node-a "$NPUB_B" "A → B"
|
||
ping_test node-a "$NPUB_C" "A → C"
|
||
ping_test node-a "$NPUB_D" "A → D"
|
||
ping_test node-a "$NPUB_E" "A → E"
|
||
|
||
echo ""
|
||
echo "From node-b:"
|
||
ping_test node-b "$NPUB_A" "B → A"
|
||
ping_test node-b "$NPUB_C" "B → C"
|
||
ping_test node-b "$NPUB_D" "B → D"
|
||
ping_test node-b "$NPUB_E" "B → E"
|
||
|
||
echo ""
|
||
echo "From node-c:"
|
||
ping_test node-c "$NPUB_A" "C → A"
|
||
ping_test node-c "$NPUB_B" "C → B"
|
||
ping_test node-c "$NPUB_D" "C → D"
|
||
ping_test node-c "$NPUB_E" "C → E"
|
||
|
||
echo ""
|
||
echo "From node-d:"
|
||
ping_test node-d "$NPUB_A" "D → A"
|
||
ping_test node-d "$NPUB_B" "D → B"
|
||
ping_test node-d "$NPUB_C" "D → C"
|
||
ping_test node-d "$NPUB_E" "D → E"
|
||
|
||
echo ""
|
||
echo "From node-e:"
|
||
ping_test node-e "$NPUB_A" "E → A"
|
||
ping_test node-e "$NPUB_B" "E → B"
|
||
ping_test node-e "$NPUB_C" "E → C"
|
||
ping_test node-e "$NPUB_D" "E → D"
|
||
|
||
elif [ "$PROFILE" = "chain" ]; then
|
||
echo ""
|
||
echo "Adjacent peer tests:"
|
||
ping_test node-a "$NPUB_B" "A → B (1 hop)"
|
||
ping_test node-b "$NPUB_C" "B → C (1 hop)"
|
||
|
||
echo ""
|
||
echo "Multi-hop tests:"
|
||
ping_test node-a "$NPUB_C" "A → C (2 hops)"
|
||
ping_test node-a "$NPUB_D" "A → D (3 hops)"
|
||
ping_test node-a "$NPUB_E" "A → E (4 hops)"
|
||
|
||
echo ""
|
||
echo "Reverse multi-hop:"
|
||
ping_test node-e "$NPUB_A" "E → A (4 hops)"
|
||
fi
|
||
|
||
echo ""
|
||
echo "=== Results: $PASSED passed, $FAILED failed ==="
|
||
[ "$FAILED" -eq 0 ] && exit 0 || exit 1
|