140 lines
5.3 KiB
Bash
Executable File
140 lines
5.3 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
SERVICE_URL="${RENDEZVOUS_SMOKE_HTTP_URL:-http://127.0.0.1:8080/}"
|
|
MEDIATOR="${RENDEZVOUS_SMOKE_UDP_ENDPOINT:-127.0.0.1:9050}"
|
|
TIMEOUT_SECONDS="${RENDEZVOUS_SMOKE_TIMEOUT_SECONDS:-30}"
|
|
LOCAL_KEY="${RENDEZVOUS_SMOKE_LOCAL_KEY:-$ROOT/deploy/compose/secrets/signing-key}"
|
|
PROJECT="$ROOT/src/FinalFactory.Rendezvous.TestClient/FinalFactory.Rendezvous.TestClient.csproj"
|
|
BUILD_CONFIGURATION="${RENDEZVOUS_SMOKE_CONFIGURATION:-Release}"
|
|
GAME_ID="${RENDEZVOUS_SMOKE_GAME_ID:-space-game}"
|
|
ENVIRONMENT_ID="${RENDEZVOUS_SMOKE_ENVIRONMENT_ID:-smoke}"
|
|
REGION="${RENDEZVOUS_SMOKE_REGION:-local}"
|
|
PROTOCOL_VERSION="${RENDEZVOUS_SMOKE_PROTOCOL_VERSION:-1}"
|
|
|
|
for command in curl dotnet jq mktemp tail; do
|
|
command -v "$command" >/dev/null || {
|
|
printf 'Missing required command: %s\n' "$command" >&2
|
|
exit 2
|
|
}
|
|
done
|
|
|
|
if [[ ! "$TIMEOUT_SECONDS" =~ ^[0-9]+$ ]] || (( TIMEOUT_SECONDS < 1 || TIMEOUT_SECONDS > 300 )); then
|
|
printf 'RENDEZVOUS_SMOKE_TIMEOUT_SECONDS must be an integer from 1 through 300.\n' >&2
|
|
exit 2
|
|
fi
|
|
if [[ ! "$PROTOCOL_VERSION" =~ ^[0-9]+$ ]] || (( PROTOCOL_VERSION < 1 )); then
|
|
printf 'RENDEZVOUS_SMOKE_PROTOCOL_VERSION must be a positive integer.\n' >&2
|
|
exit 2
|
|
fi
|
|
for scoped_value in "$GAME_ID" "$ENVIRONMENT_ID" "$REGION"; do
|
|
if [[ -z "$scoped_value" ]]; then
|
|
printf 'Smoke game, environment, and region values must not be empty.\n' >&2
|
|
exit 2
|
|
fi
|
|
done
|
|
|
|
local_credential() {
|
|
if [[ "$GAME_ID" != space-game || "$ENVIRONMENT_ID" != smoke \
|
|
|| "$REGION" != local || "$PROTOCOL_VERSION" != 1 ]]; then
|
|
printf 'The local credential helper supports only space-game/smoke/local protocol 1. Supply RENDEZVOUS_PUBLISHER_CREDENTIAL for any other scope.\n' >&2
|
|
exit 2
|
|
fi
|
|
RENDEZVOUS_SMOKE_LOCAL_KEY="$LOCAL_KEY" \
|
|
"$ROOT/scripts/mint-local-publisher-credential.sh"
|
|
}
|
|
|
|
credential="${RENDEZVOUS_PUBLISHER_CREDENTIAL:-}"
|
|
if [[ -z "$credential" ]]; then
|
|
credential="$(local_credential)"
|
|
fi
|
|
export RENDEZVOUS_PUBLISHER_CREDENTIAL="$credential"
|
|
|
|
curl --fail --silent --show-error --max-time 5 "${SERVICE_URL%/}/health/live" >/dev/null
|
|
curl --fail --silent --show-error --max-time 5 "${SERVICE_URL%/}/health/ready" >/dev/null
|
|
|
|
temp_dir="$(mktemp -d)"
|
|
host_log="$temp_dir/host.jsonl"
|
|
join_log="$temp_dir/join.jsonl"
|
|
host_pid=''
|
|
sanitize_log() {
|
|
jq -Rrc 'fromjson? | {
|
|
event: (.event // "unknown"),
|
|
status: (.status // "unknown"),
|
|
phase: (.phase // "unknown"),
|
|
hasListingId: (((.listingId // "") | length) > 0)
|
|
}' "$1"
|
|
}
|
|
cleanup() {
|
|
local status="$?"
|
|
if [[ -n "$host_pid" ]] && kill -0 "$host_pid" 2>/dev/null; then
|
|
kill -TERM "$host_pid" 2>/dev/null || true
|
|
wait "$host_pid" 2>/dev/null || true
|
|
fi
|
|
if [[ "$status" -ne 0 ]]; then
|
|
printf 'Deployment smoke failed; sanitized diagnostic events follow.\n' >&2
|
|
[[ -f "$host_log" ]] && sanitize_log "$host_log" >&2 || true
|
|
[[ -f "$join_log" ]] && sanitize_log "$join_log" >&2 || true
|
|
fi
|
|
rm -rf "$temp_dir"
|
|
return "$status"
|
|
}
|
|
trap cleanup EXIT
|
|
trap 'exit 130' INT
|
|
trap 'exit 143' TERM
|
|
|
|
dotnet run --project "$PROJECT" --configuration "$BUILD_CONFIGURATION" --no-build -- \
|
|
host --service "$SERVICE_URL" --mediator "$MEDIATOR" \
|
|
--game "$GAME_ID" --environment "$ENVIRONMENT_ID" --region "$REGION" --protocol "$PROTOCOL_VERSION" \
|
|
--script --json --exit-after-echo --timeout-seconds "$TIMEOUT_SECONDS" \
|
|
>"$host_log" 2>&1 &
|
|
host_pid="$!"
|
|
|
|
ready=false
|
|
listing_id=''
|
|
for ((iteration = 0; iteration < TIMEOUT_SECONDS * 4; iteration++)); do
|
|
if listing_id="$(jq -er '
|
|
select(.event == "host.ready" and .status == "ready")
|
|
| .listingId // empty
|
|
' "$host_log" 2>/dev/null | tail -n 1)" && [[ -n "$listing_id" ]]; then
|
|
ready=true
|
|
break
|
|
fi
|
|
if ! kill -0 "$host_pid" 2>/dev/null; then
|
|
printf 'Host diagnostic stopped before it became ready.\n' >&2
|
|
sanitize_log "$host_log" >&2 || true
|
|
exit 1
|
|
fi
|
|
sleep 0.25
|
|
done
|
|
if [[ "$ready" != true ]]; then
|
|
printf 'Host diagnostic did not report a ready listing within %s seconds.\n' "$TIMEOUT_SECONDS" >&2
|
|
exit 1
|
|
fi
|
|
|
|
dotnet run --project "$PROJECT" --configuration "$BUILD_CONFIGURATION" --no-build -- \
|
|
join --service "$SERVICE_URL" --mediator "$MEDIATOR" \
|
|
--game "$GAME_ID" --environment "$ENVIRONMENT_ID" --region "$REGION" --protocol "$PROTOCOL_VERSION" \
|
|
--listing "$listing_id" --script --json --timeout-seconds "$TIMEOUT_SECONDS" \
|
|
>"$join_log" 2>&1
|
|
wait "$host_pid"
|
|
host_pid=''
|
|
|
|
if ! jq -s -e '
|
|
any(.[]; .event == "host.direct-traffic" and .status == "verified")
|
|
and any(.[]; .event == "host.deregistered" and .status == "complete")
|
|
' "$host_log" >/dev/null; then
|
|
printf 'Host diagnostic did not complete authenticated traffic and deregistration.\n' >&2
|
|
exit 1
|
|
fi
|
|
if ! jq -s -e '
|
|
any(.[]; .event == "join.direct-traffic" and .status == "verified")
|
|
and any(.[]; .event == "join.outcome-report" and .status == "accepted")
|
|
' "$join_log" >/dev/null; then
|
|
printf 'Join diagnostic did not complete authenticated traffic and outcome reporting.\n' >&2
|
|
exit 1
|
|
fi
|
|
|
|
printf 'Rendezvous deployment smoke passed: HTTP live/ready and authenticated UDP mediation/direct traffic.\n'
|