blob: eb1d3bafcff2ae580a9fac7178b888e1082d9a04 [file] [log] [blame]
#!/usr/bin/env bash
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
set -euo pipefail
# -----------------------------
# Config (overridable via args)
# -----------------------------
MASTER_REF="${MASTER_REF:-master}" # branch or commit for "baseline"
PR_REF="${PR_REF:-HEAD}" # commit to test (assumes current checkout)
HOST="${HOST:-127.0.0.1}"
PORT="${PORT:-8090}"
WAIT_SECS="${WAIT_SECS:-60}"
BATCHES="${BATCHES:-50}"
MSGS_PER_BATCH="${MSGS_PER_BATCH:-100}"
KEEP_TMP="${KEEP_TMP:-false}"
# -----------------------------
# Helpers
# -----------------------------
info(){ printf "\n\033[1;36m➤ %s\033[0m\n" "$*"; }
ok(){ printf "\033[0;32m✓ %s\033[0m\n" "$*"; }
err(){ printf "\033[0;31m✗ %s\033[0m\n" "$*" >&2; }
die(){ err "$*"; exit 1; }
need() {
command -v "$1" >/dev/null 2>&1 || die "missing dependency: $1"
}
wait_for_port() {
local host="$1" port="$2" deadline=$((SECONDS + WAIT_SECS))
while (( SECONDS < deadline )); do
if command -v nc >/dev/null 2>&1; then
if nc -z "$host" "$port" 2>/dev/null; then return 0; fi
else
if (echo >"/dev/tcp/$host/$port") >/dev/null 2>&1; then return 0; fi
fi
sleep 1
done
return 1
}
stop_pid() {
local pid="$1" name="${2:-process}"
if kill -0 "$pid" 2>/dev/null; then
kill -TERM "$pid" || true
for _ in $(seq 1 15); do
kill -0 "$pid" 2>/dev/null || { ok "stopped $name (pid $pid)"; return 0; }
sleep 1
done
err "$name (pid $pid) still running; sending SIGKILL"
kill -KILL "$pid" || true
fi
}
print_logs_if_any() {
local dir="$1"
if compgen -G "$dir/local_data/logs/iggy*" > /dev/null; then
echo "---- $dir/local_data/logs ----"
cat "$dir"/local_data/logs/iggy* || true
echo "------------------------------"
else
echo "(no iggy logs found in $dir/local_data/logs)"
fi
}
# -----------------------------
# Args
# -----------------------------
usage() {
cat <<EOF
Usage: $0 [--master-ref REF] [--pr-ref REF] [--host 127.0.0.1] [--port 8090]
[--wait-secs 60] [--batches 50] [--msgs-per-batch 100] [--keep-tmp]
Runs a backwards-compatibility check:
1) Build and run master (or REF), write data via benches
2) Stop server, capture local_data/
3) Build PR (or REF), restore local_data/
4) Run consumer bench; fail if anything breaks
Env overrides supported: MASTER_REF, PR_REF, HOST, PORT, WAIT_SECS, BATCHES, MSGS_PER_BATCH, KEEP_TMP
EOF
}
while [[ $# -gt 0 ]]; do
case "$1" in
--master-ref) MASTER_REF="$2"; shift 2;;
--pr-ref) PR_REF="$2"; shift 2;;
--host) HOST="$2"; shift 2;;
--port) PORT="$2"; shift 2;;
--wait-secs) WAIT_SECS="$2"; shift 2;;
--batches) BATCHES="$2"; shift 2;;
--msgs-per-batch) MSGS_PER_BATCH="$2"; shift 2;;
--keep-tmp) KEEP_TMP=true; shift;;
-h|--help) usage; exit 0;;
*) die "unknown arg: $1";;
esac
done
# -----------------------------
# Pre-flight
# -----------------------------
need git
need cargo
need pkill
need pgrep
need awk
need sed
command -v timeout >/dev/null 2>&1 || true # optional, we'll use it if present
REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
cd "$REPO_ROOT"
# Free the port proactively (best-effort)
pkill -f iggy-server >/dev/null 2>&1 || true
TMP_ROOT="$(mktemp -d -t iggy-backcompat-XXXXXX)"
MASTER_DIR="$TMP_ROOT/master"
PR_DIR="$REPO_ROOT" # assume script is run from PR checkout
MASTER_LOG="$TMP_ROOT/server-master.stdout.log"
PR_LOG="$TMP_ROOT/server-pr.stdout.log"
cleanup() {
# Stop any leftover iggy-server
pkill -f iggy-server >/dev/null 2>&1 || true
git worktree remove --force "$MASTER_DIR" >/dev/null 2>&1 || true
if [[ "$KEEP_TMP" != "true" ]]; then
rm -rf "$TMP_ROOT" || true
else
info "keeping temp dir: $TMP_ROOT"
fi
}
trap cleanup EXIT
# -----------------------------
# 1) Prepare master worktree
# -----------------------------
info "Preparing baseline worktree at '$MASTER_REF'"
git fetch --all --tags --prune >/dev/null 2>&1 || true
git worktree add --force "$MASTER_DIR" "$MASTER_REF"
ok "worktree at $MASTER_DIR"
# -----------------------------
# 2) Build & run master server
# -----------------------------
pushd "$MASTER_DIR" >/dev/null
info "Building iggy-server & benches (baseline: $MASTER_REF)"
IGGY_CI_BUILD=true cargo build --bins
ok "built baseline"
info "Starting iggy-server (baseline)"
set +e
( IGGY_ROOT_USERNAME=iggy IGGY_ROOT_PASSWORD=iggy nohup target/debug/iggy-server >"$MASTER_LOG" 2>&1 & echo $! > "$TMP_ROOT/master.pid" )
set -e
MASTER_PID="$(cat "$TMP_ROOT/master.pid")"
ok "iggy-server started (pid $MASTER_PID), logs: $MASTER_LOG"
info "Waiting for $HOST:$PORT to be ready (up to ${WAIT_SECS}s)"
if ! wait_for_port "$HOST" "$PORT"; then
err "server did not become ready in ${WAIT_SECS}s"
print_logs_if_any "$MASTER_DIR"
[[ -f "$MASTER_LOG" ]] && { tail -n 200 "$MASTER_LOG" || true; }
exit 1
fi
ok "server is ready"
# Producer bench (baseline)
info "Running producer bench on baseline"
BENCH_CMD=( target/debug/iggy-bench --verbose --message-batches "$BATCHES" --messages-per-batch "$MSGS_PER_BATCH" pinned-producer tcp )
if command -v timeout >/dev/null 2>&1; then timeout 60s "${BENCH_CMD[@]}"; else "${BENCH_CMD[@]}"; fi
ok "producer bench done"
# Consumer bench (baseline)
info "Running consumer bench on baseline"
BENCH_CMD=( target/debug/iggy-bench --verbose --message-batches "$BATCHES" --messages-per-batch "$MSGS_PER_BATCH" pinned-consumer tcp )
if command -v timeout >/dev/null 2>&1; then timeout 60s "${BENCH_CMD[@]}"; else "${BENCH_CMD[@]}"; fi
ok "consumer bench done (baseline)"
# Stop baseline server
info "Stopping baseline server"
stop_pid "$MASTER_PID" "iggy-server(baseline)"
print_logs_if_any "$MASTER_DIR"
# Clean baseline logs (like CI step)
if compgen -G "local_data/logs/iggy*" > /dev/null; then
rm -f local_data/logs/iggy* || true
fi
# Snapshot local_data/
info "Snapshotting baseline local_data/"
cp -a local_data "$TMP_ROOT/local_data"
ok "snapshot stored at $TMP_ROOT/local_data"
popd >/dev/null
# -----------------------------
# 3) Build PR & restore data
# -----------------------------
pushd "$PR_DIR" >/dev/null
info "Ensuring PR ref is present: $PR_REF"
git rev-parse --verify "$PR_REF^{commit}" >/dev/null 2>&1 || die "PR_REF '$PR_REF' not found"
git checkout -q "$PR_REF"
info "Building iggy-server & benches (PR: $PR_REF)"
IGGY_CI_BUILD=true cargo build --bins
ok "built PR"
info "Restoring baseline local_data/ into PR workspace"
rm -rf local_data
cp -a "$TMP_ROOT/local_data" ./local_data
ok "restored local_data/"
# -----------------------------
# 4) Run PR server & consumer bench
# -----------------------------
info "Starting iggy-server (PR)"
set +e
( IGGY_ROOT_USERNAME=iggy IGGY_ROOT_PASSWORD=iggy nohup target/debug/iggy-server >"$PR_LOG" 2>&1 & echo $! > "$TMP_ROOT/pr.pid" )
set -e
PR_PID="$(cat "$TMP_ROOT/pr.pid")"
ok "iggy-server (PR) started (pid $PR_PID), logs: $PR_LOG"
info "Waiting for $HOST:$PORT to be ready (up to ${WAIT_SECS}s)"
if ! wait_for_port "$HOST" "$PORT"; then
err "PR server did not become ready in ${WAIT_SECS}s"
print_logs_if_any "$PR_DIR"
[[ -f "$PR_LOG" ]] && { tail -n 200 "$PR_LOG" || true; }
exit 1
fi
ok "PR server is ready"
# Only consumer bench against PR
info "Running consumer bench on PR (compat check)"
BENCH_CMD=( target/debug/iggy-bench --verbose --message-batches "$BATCHES" --messages-per-batch "$MSGS_PER_BATCH" pinned-consumer tcp )
if command -v timeout >/dev/null 2>&1; then timeout 60s "${BENCH_CMD[@]}"; else "${BENCH_CMD[@]}"; fi
ok "consumer bench done (PR)"
# Stop PR server
info "Stopping PR server"
stop_pid "$PR_PID" "iggy-server(PR)"
print_logs_if_any "$PR_DIR"
ok "backwards-compatibility check PASSED"
popd >/dev/null