Files
relspecgo/tests/dbtest/dbtest.sh
T

131 lines
3.6 KiB
Bash
Executable File

#!/usr/bin/env bash
# Reusable podman/docker test database tool for postgres, mssql and mysql.
# Usage: dbtest.sh <command> <db> [args]
set -euo pipefail
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT="$(cd "$HERE/../.." && pwd)"
TIMEOUT="${DBTEST_TIMEOUT:-120}"
ALL_DBS=(postgres mssql mysql)
usage() {
cat <<USAGE
dbtest.sh <command> <db|all> [args]
commands:
up <db> start container, wait until ready, run init
down <db> stop and remove container
restart <db> down + up
status <db> running state and connection string
env <db> print 'export VAR=conn' (use: eval "\$(dbtest.sh env postgres)")
logs <db> container logs
shell <db> interactive client
exec <db> <file> run a SQL file against the database
test <db> [pkgs] up, run go tests with conn env set, down (keep with DBTEST_KEEP=1)
list supported databases
dbs: ${ALL_DBS[*]}
env: DBTEST_RUNTIME=podman|docker DBTEST_TIMEOUT=secs DBTEST_KEEP=1 DBTEST_GOFLAGS=...
USAGE
}
die() { echo "error: $*" >&2; exit 1; }
log() { echo "[dbtest] $*" >&2; }
detect_runtime() {
if [ -n "${DBTEST_RUNTIME:-}" ]; then echo "$DBTEST_RUNTIME"; return; fi
if command -v podman >/dev/null 2>&1; then echo podman
elif command -v docker >/dev/null 2>&1; then echo docker
else die "neither podman nor docker is installed"; fi
}
RUNTIME="$(detect_runtime)"
rt() { "$RUNTIME" "$@"; }
load_db() {
local f="$HERE/dbs/${1:-}.sh"
[ -f "$f" ] || die "unknown db '${1:-}' (supported: ${ALL_DBS[*]})"
# shellcheck disable=SC1090
source "$f"
}
is_running() { [ "$(rt inspect -f '{{.State.Running}}' "$DB_CONTAINER" 2>/dev/null || true)" = "true" ]; }
cmd_up() {
if is_running; then
log "$DB_NAME already running"
else
rt rm -f "$DB_CONTAINER" >/dev/null 2>&1 || true
log "starting $DB_NAME ($DB_IMAGE) on port $DB_PORT using $RUNTIME"
rt run -d --name "$DB_CONTAINER" "${DB_ENV[@]}" \
-p "$DB_PORT:$DB_INTERNAL_PORT" \
-v "$DB_INIT_MOUNT:ro,Z" "$DB_IMAGE" >/dev/null
fi
log "waiting for $DB_NAME (max ${TIMEOUT}s)"
local i=0
until db_ready; do
i=$((i + 1))
if [ "$i" -ge "$TIMEOUT" ]; then
rt logs --tail 50 "$DB_CONTAINER" >&2 || true
die "$DB_NAME did not become ready"
fi
sleep 1
done
db_post_init
log "$DB_NAME ready: $DB_CONN_VAR=$DB_CONN"
}
cmd_down() {
rt rm -f "$DB_CONTAINER" >/dev/null 2>&1 || true
log "$DB_NAME removed"
}
cmd_status() {
if is_running; then echo "$DB_NAME: running ($DB_CONTAINER, port $DB_PORT)"; else echo "$DB_NAME: stopped"; fi
echo "$DB_CONN_VAR=$DB_CONN"
}
cmd_test() {
local pkgs="${*:-$DB_DEFAULT_PKGS}"
[ -n "$pkgs" ] || die "no test packages for $DB_NAME; pass packages as arguments"
cmd_up
[ -n "${DBTEST_KEEP:-}" ] || trap cmd_down EXIT
export "$DB_CONN_VAR=$DB_CONN"
cd "$ROOT"
# shellcheck disable=SC2086
go test -count=1 ${DBTEST_GOFLAGS:-} $pkgs
}
cmd="${1:-}"
case "$cmd" in
""|-h|--help|help) usage; exit 0 ;;
list) printf '%s\n' "${ALL_DBS[@]}"; exit 0 ;;
esac
shift
target="${1:-}"
[ -n "$target" ] || die "missing <db>"
shift || true
run_one() {
load_db "$1"
shift
case "$cmd" in
up) cmd_up ;;
down) cmd_down ;;
restart) cmd_down; cmd_up ;;
status) cmd_status ;;
env) echo "export $DB_CONN_VAR='$DB_CONN'" ;;
logs) rt logs "$DB_CONTAINER" ;;
shell) db_shell "$@" ;;
exec) [ -f "${1:-}" ] || die "usage: exec <db> <file>"; db_exec_file "$1" ;;
test) cmd_test "$@" ;;
*) usage; die "unknown command '$cmd'" ;;
esac
}
if [ "$target" = "all" ]; then
case "$cmd" in up|down|restart|status|env) ;; *) die "'all' is only valid for up/down/restart/status/env" ;; esac
for d in "${ALL_DBS[@]}"; do (run_one "$d"); done
else
run_one "$target" "$@"
fi