#!/usr/bin/env bash

# Verifies that a PuppetDB jar will periodically check and shut down when it
# notices that the database is at an unrecognized schema/migration number
# This can happen anytime when there are multiple PuppetDB instances being used
# and one is upgraded before the other.
# The check happens in puppetlabs.puppetdb.cli.serverices/check-schema-version.

# You can specify PuppetDB jar location with env var PDB_JAR.
# PuppetDB configuration is sourced from PDBBOX sandbox or an ephemeral sandbox
# Flags --pgbin and --pgbin are necessary unless set with ext/bin/test-config

set -euo pipefail

usage() { echo 'Usage: [PDB_JAR=JAR] $(basename "$0") --pgbin PGBIN --pgport PGPORT'; }
misuse() { usage 1>&2; exit 2; }

argv=("$(cd "$(dirname "$0")" && pwd)/$(basename "$0")" "$@")
declare -A opt

# Validate arguments
while test $# -gt 0; do
    case "$1" in
        --pgbin|--pgport)
            test $# -gt 1 || misuse
            opt["${1:2}"]="$2"
            shift 2
            ;;
        *)
            misuse
    esac
done

# If pgbin directory is not provided with --pgbin, read ext/test-conf/pgbin
# If pgbin directory cannot be found, exit with error status
if test -z "${opt[pgbin]:-}"; then
    opt[pgbin]="$(ext/bin/test-config --get pgbin)"
    if test  -z "${opt[pgbin]:-}"; then
        echo 'Please specify --pgbin or set pgbin with ext/bin/test-config' 1>&2
        exit 2
    fi
fi

# If pgport number is not provided with --pgport, read ext/test-conf/pgport
# If pgport number cannot be found, exit with error status
if test -z "${opt[pgport]:-}"; then
    opt[pgport]="$(ext/bin/test-config --get pgport)"
     if test  -z "${opt[pgport]:-}"; then
        echo 'Please specify --pgport or set pgport with ext/bin/test-config' 1>&2
        exit 2
    fi
fi

set -x

# Create an ephemeral PuppetDB sandbox if one isn't set by PDBBOX
if test -z "${PDBBOX:-}"; then
    # No PDBBOX, set one up and run ourselves again
    tmpdir="$(mktemp -d "test-schema-mismatch-bails-XXXXXX")"
    tmpdir="$(cd "$tmpdir" && pwd)"
    trap "$(printf 'rm -rf %q' "$tmpdir")" EXIT
    # Don't exec (or we'll never run the trap)
    ext/bin/with-pdbbox --box "$tmpdir/box" \
                        --pgbin "${opt[pgbin]}" --pgport "${opt[pgport]}" \
                        -- "${argv[@]}"
    exit 0
fi

# Create temporary directory
tmpdir="$(mktemp -d "test-schema-mismatch-bails-XXXXXX")"
tmpdir="$(cd "$tmpdir" && pwd)"
trap "$(printf 'rm -rf %q' "$tmpdir")" EXIT

# Append low schema-check-interval value just after the [database] section header
# in PuppetDB config file to trigger a schema check quickly.

# MacOS sed appears to require the embedded newline
sed '/\[database\]/a\
  schema-check-interval = 500
' \
    "$PDBBOX/conf.d/pdb.ini" > "$tmpdir/pdb.ini"
mv "$tmpdir/pdb.ini" "$PDBBOX/conf.d/pdb.ini"

set -x
cat "$PDBBOX/conf.d/"*
set +x

# Use upgrade command to init pdb and apply all migrations
./pdb upgrade -c "$PDBBOX/conf.d"

# Start pdb in the background
touch "$tmpdir/pdb-out" "$tmpdir/pdb-err"
./pdb services -c "$PDBBOX/conf.d" 1>"$tmpdir/pdb-out" 2>"$tmpdir/pdb-err"  & pdb_pid=$!

# Allow time for pdb to start before changing migration level
while ! grep -F "PuppetDB finished starting" "$tmpdir/pdb-out" > /dev/null
do
    echo 'Waiting for pdb to start...'
    cat "$tmpdir/pdb-out" "$tmpdir/pdb-err"
    sleep 3
done

# Simulate a different pdb instance completing a new migration
psql -U puppetdb puppetdb -c 'INSERT INTO schema_migrations (version, time) VALUES (10000, now());'

# Wait for the background pdb to notice the migration change and exit
rc=0
wait $pdb_pid || rc=$?
test "$rc" -eq 77

cat "$tmpdir/pdb-out" "$tmpdir/pdb-err"
grep -F 'Please upgrade PuppetDB' "$tmpdir/pdb-err"
