Files
2026-07-13 12:32:25 +08:00

307 lines
9.3 KiB
Bash
Executable File

#!/bin/bash
# Doltgresql compatibility test runner.
#
# Downloads specified doltgresql release binaries, creates test repositories
# using them, and runs BATS test suites to verify backward, forward, and
# bidirectional compatibility.
#
# Usage: ./runner.sh
# Run from the integration-tests/compatibility directory.
#
# Environment variables (optional):
# DOLTGRES_SKIP_BACKWARD — skip backward-compatibility tests if set
# DOLTGRES_SKIP_FORWARD — skip forward-compatibility tests if set
# DOLTGRES_SKIP_BIDIR — skip bidirectional-compatibility tests if set
set -eo pipefail
PLATFORM_TUPLE=""
# ---------------------------------------------------------------------------
# Platform detection
# ---------------------------------------------------------------------------
get_platform_tuple() {
local OS ARCH
OS=$(uname)
ARCH=$(uname -m)
if [ "$OS" != Linux ] && [ "$OS" != Darwin ]; then
echo "tests only support linux or macOS." >&2
exit 1
fi
if [ "$OS" = Linux ]; then
PLATFORM_TUPLE=linux
else
PLATFORM_TUPLE=darwin
fi
if [ "$ARCH" = x86_64 ]; then
PLATFORM_TUPLE="${PLATFORM_TUPLE}-amd64"
elif [ "$ARCH" = arm64 ] || [ "$ARCH" = aarch64 ]; then
PLATFORM_TUPLE="${PLATFORM_TUPLE}-arm64"
else
echo "unsupported architecture: $ARCH" >&2
exit 1
fi
echo "$PLATFORM_TUPLE"
}
# ---------------------------------------------------------------------------
# Release download
# ---------------------------------------------------------------------------
# download_release <version>
# Downloads doltgresql-<platform>.tar.gz for the given version tag, extracts it
# into binaries/<version>/, and prints the path to the bin directory.
download_release() {
local ver="$1"
local dirname="binaries/$ver"
mkdir -p "$dirname"
local basename="doltgresql-${PLATFORM_TUPLE}"
local filename="${basename}.tar.gz"
local filepath="${dirname}/${filename}"
local url="https://github.com/dolthub/doltgresql/releases/download/${ver}/${filename}"
echo "Downloading doltgresql ${ver} for ${PLATFORM_TUPLE} ..." >&2
curl -L -o "$filepath" "$url"
tar -zxf "$filepath" -C "$dirname"
# Binary lives at doltgresql-<os>-<arch>/bin/doltgres
echo "${dirname}/${basename}/bin"
}
# ---------------------------------------------------------------------------
# Server management helpers used by the runner (not BATS)
# ---------------------------------------------------------------------------
_pick_port() {
for i in {0..99}; do
local port=$((RANDOM % 4096 + 2048))
if ! nc -z localhost "$port" 2>/dev/null; then
echo "$port"
return 0
fi
done
echo "ERROR: could not find a free port" >&2
return 1
}
_write_config() {
local dir="$1" port="$2"
cat > "$dir/runner-config.yaml" <<EOF
log_level: warning
behavior:
read_only: false
disable_client_multi_statements: false
listener:
host: localhost
port: $port
EOF
}
# start_server <binary> <datadir> <logfile> → sets RUNNER_SERVER_PID and RUNNER_SERVER_PORT
start_server() {
local binary="$1" datadir="$2" logfile="$3"
RUNNER_SERVER_PORT=$(_pick_port)
_write_config "$datadir" "$RUNNER_SERVER_PORT"
PGPASSWORD=password "$binary" -data-dir="$datadir" \
--config="$datadir/runner-config.yaml" > "$logfile" 2>&1 &
RUNNER_SERVER_PID=$!
local end=$((SECONDS + 20))
while [ $SECONDS -lt $end ]; do
if PGPASSWORD=password psql -U postgres -h localhost -p "$RUNNER_SERVER_PORT" \
-c "SELECT 1;" postgres >/dev/null 2>&1; then
return 0
fi
sleep 0.5
done
echo "ERROR: server failed to start on port $RUNNER_SERVER_PORT" >&2
cat "$logfile" >&2
kill "$RUNNER_SERVER_PID" 2>/dev/null
return 1
}
stop_server() {
if [ -n "$RUNNER_SERVER_PID" ]; then
kill "$RUNNER_SERVER_PID" 2>/dev/null || true
wait "$RUNNER_SERVER_PID" 2>/dev/null || true
RUNNER_SERVER_PID=""
RUNNER_SERVER_PORT=""
fi
}
RUNNER_SERVER_PID=""
RUNNER_SERVER_PORT=""
# ---------------------------------------------------------------------------
# Repository setup
# ---------------------------------------------------------------------------
# setup_repo <label> [<binary>]
# Creates a test repository under repos/<label>/ using the given binary
# (defaults to doltgres from PATH). Sets REPO_DIR to the resulting directory.
setup_repo() {
local label="$1"
local binary="${2:-doltgres}"
REPO_DIR="$(pwd)/repos/${label}"
mkdir -p "$REPO_DIR"
./test_files/setup_repo.sh "$REPO_DIR" "$binary"
}
# ---------------------------------------------------------------------------
# Version list helpers
# ---------------------------------------------------------------------------
list_backward_compatible_versions() {
grep -v '^ *#' < test_files/backward_compatible_versions.txt
}
list_forward_compatible_versions() {
grep -v '^ *#' < test_files/forward_compatible_versions.txt
}
# ---------------------------------------------------------------------------
# Test runners
# ---------------------------------------------------------------------------
test_backward_compatibility() {
local ver="$1"
local bin
bin=$(download_release "$ver")
echo "=== Backward compat: creating repo with doltgresql ${ver} ==="
setup_repo "$ver" "${bin}/doltgres"
echo "=== Backward compat: testing HEAD doltgresql against repo from ${ver} ==="
DOLTGRES_TEST_BIN="$(which doltgres)" \
REPO_DIR="$(pwd)/repos/${ver}" \
bats --print-output-on-failure ./test_files/bats/
# Backward-only workflows (test_files/bats/backwards/): tests that only make
# sense with the old binary writing first and HEAD continuing. Each test
# manages its own server lifecycle and needs both binaries.
if [ -d ./test_files/bats/backwards ]; then
local scratch="$(pwd)/repos/${ver}-backward-workflow"
mkdir -p "$scratch"
echo "=== Backward workflow: old=${ver}, new=HEAD ==="
DOLTGRES_LEGACY_BIN="${bin}/doltgres" \
DOLTGRES_NEW_BIN="$(which doltgres)" \
REPO_DIR="$scratch" \
bats --print-output-on-failure ./test_files/bats/backwards/
fi
}
test_forward_compatibility() {
if [ -z $1 ]; then
return
fi
local ver="$1"
local bin
bin=$(download_release "$ver")
echo "=== Forward compat: testing doltgresql ${ver} against repo from HEAD ==="
# repos/HEAD was already created by the main flow (see _main).
DOLTGRES_TEST_BIN="${bin}/doltgres" \
REPO_DIR="$(pwd)/repos/HEAD" \
bats --print-output-on-failure ./test_files/bats/
}
test_bidirectional_compatibility() {
if [ -z $1 ]; then
return
fi
local ver="$1"
local bin
bin=$(download_release "$ver")
local head_bin
head_bin="$(which doltgres)"
# Forward direction: old = released version, new = HEAD
local scratch_fwd="$(pwd)/repos/${ver}-bidir-forward"
mkdir -p "$scratch_fwd"
echo "=== Bidirectional (forward): old=${ver}, new=HEAD ==="
DOLTGRES_LEGACY_BIN="${bin}/doltgres" \
DOLTGRES_NEW_BIN="$head_bin" \
REPO_DIR="$scratch_fwd" \
bats --print-output-on-failure ./test_files/bats/bidirectional/bidirectional_compat.bats
# Reverse direction: old = HEAD, new = released version
local scratch_rev="$(pwd)/repos/${ver}-bidir-reverse"
mkdir -p "$scratch_rev"
echo "=== Bidirectional (reverse): old=HEAD, new=${ver} ==="
DOLTGRES_LEGACY_BIN="$head_bin" \
DOLTGRES_NEW_BIN="${bin}/doltgres" \
REPO_DIR="$scratch_rev" \
bats --print-output-on-failure ./test_files/bats/bidirectional/bidirectional_compat.bats
}
# ---------------------------------------------------------------------------
# Cleanup
# ---------------------------------------------------------------------------
cleanup() {
stop_server
rm -rf repos binaries
}
# ---------------------------------------------------------------------------
# Main
# ---------------------------------------------------------------------------
_main() {
PLATFORM_TUPLE=$(get_platform_tuple)
mkdir -p repos binaries
trap cleanup EXIT
# --- Backward compatibility ---
if [ -z "$DOLTGRES_SKIP_BACKWARD" ] && [ -s "test_files/backward_compatible_versions.txt" ]; then
echo "=== Running backward compatibility tests ==="
while IFS= read -r ver; do
test_backward_compatibility "$ver"
done < <(list_backward_compatible_versions)
fi
# --- Create HEAD repo (used for forward compat and the sanity check) ---
echo "=== Creating HEAD repo ==="
setup_repo HEAD
# --- Forward compatibility ---
if [ -z "$DOLTGRES_SKIP_FORWARD" ] && [ -s "test_files/forward_compatible_versions.txt" ]; then
echo "=== Running forward compatibility tests ==="
while IFS= read -r ver; do
test_forward_compatibility "$ver"
done < <(list_forward_compatible_versions)
fi
# --- Bidirectional compatibility (uses forward_compatible_versions list) ---
if [ -z "$DOLTGRES_SKIP_BIDIR" ] && [ -s "test_files/forward_compatible_versions.txt" ]; then
echo "=== Running bidirectional compatibility tests ==="
while IFS= read -r ver; do
test_bidirectional_compatibility "$ver"
done < <(list_forward_compatible_versions)
fi
# --- Sanity check: HEAD against HEAD ---
echo "=== Sanity check: HEAD doltgresql against HEAD repo ==="
DOLTGRES_TEST_BIN="$(which doltgres)" \
REPO_DIR="$(pwd)/repos/HEAD" \
bats --print-output-on-failure ./test_files/bats/compatibility.bats
DOLTGRES_TEST_BIN="$(which doltgres)" \
REPO_DIR="$(pwd)/repos/HEAD" \
bats --print-output-on-failure ./test_files/bats/types_compatibility.bats
}
_main