#!/bin/bash
set -e

# Build example
# ./configure --prefix=/tmp/pg --enable-debug --enable-cassert >/dev/null && make -j8 >/dev/null && make -j8 -C contrib >/dev/null && make install && make install -C contrib

# Choose server id
if [ -z $1 ]; then
  SID=01
else
  SID=$1
fi

# Set global variables
NUM_INSTALLCHECKS=200
NUM_ITERATIONS=50

PGPREFIX=/tmp/pg/
SRCCOPYDIR=/tmp/t/

PGDB=`pwd`/tmpdb
PGBIN=$PGPREFIX/bin
export PATH="$PGBIN:$PATH"
export LD_LIBRARY_PATH="$PGPREFIX/lib"

export PGHOST=127.0.0.1
export PGPORT=5432
export PGUSER=postgres
export PGDATABASE=test

# Stop previous instance in case it is left from a previous run
$PGBIN/pg_ctl -w -t 5 -D "$PGDB" stop || true

# And clear data and logs
rm -rf "$PGDB" server*.log rm -rf installcheck*.log || true

# Prepare installcheck directories
for c in `seq $NUM_INSTALLCHECKS`; do
  rm -rf $SRCCOPYDIR/ic$SID-$c || true
  mkdir $SRCCOPYDIR/ic$SID-$c/
  cp * $SRCCOPYDIR/ic$SID-$c/ >/dev/null 2>&1 || true
  echo "exit 0" > $SRCCOPYDIR/ic$SID-$c/config.status
  mkdir $SRCCOPYDIR/ic$SID-$c/src
  cp src/* $SRCCOPYDIR/ic$SID-$c/src/ >/dev/null 2>&1 || true
  cp -r src/test $SRCCOPYDIR/ic$SID-$c/src/
  sed -e 's/^all:/#all:/' -i $SRCCOPYDIR/ic$SID-$c/src/test/regress/GNUmakefile

  # Fixing tests

  cp3=`printf "%-3s" $c`
  c03=`printf "%03d" $c`
  sed -e "s/regression/regress$cp3/" -i $SRCCOPYDIR/ic$SID-$c/src/test/regress/expected/updatable_views.out 
  sed -e "s/regression/regress$cp3/" -i $SRCCOPYDIR/ic$SID-$c/src/test/regress/expected/sequence.out

  sed -e "s/ regression/ regress$c/" -i $SRCCOPYDIR/ic$SID-$c/src/test/regress/sql/publication.sql \
    $SRCCOPYDIR/ic$SID-$c/src/test/regress/expected/publication.out

  sed -e "s/ regression/ regress$c/" -i $SRCCOPYDIR/ic$SID-$c/src/test/regress/sql/dependency.sql \
    $SRCCOPYDIR/ic$SID-$c/src/test/regress/expected/dependency.out

  sed -e "s/SELECT obj_description(s.oid, 'pg_subscription') FROM pg_subscription s;/SELECT obj_description FROM (SELECT obj_description(s.oid, 'pg_subscription') FROM pg_subscription s) d WHERE obj_description IS NOT NULL LIMIT 1;/" -i \
    $SRCCOPYDIR/ic$SID-$c/src/test/regress/sql/subscription.sql \
    $SRCCOPYDIR/ic$SID-$c/src/test/regress/expected/subscription.out

  sed -e "s/SELECT pg_notification_queue_usage();/SELECT round(pg_notification_queue_usage() * 1000) \\/ 1000 AS pg_notification_queue_usage/" -i \
    $SRCCOPYDIR/ic$SID-$c/src/test/regress/sql/async.sql \
    $SRCCOPYDIR/ic$SID-$c/src/test/regress/expected/async.out

  # Disable test foreign_data as not fixable by a simple sed
  sed -e "s/foreign_data //" -i $SRCCOPYDIR/ic$SID-$c/src/test/regress/parallel_schedule
  sed -e "s/test: foreign_data\$//" -i $SRCCOPYDIR/ic$SID-$c/src/test/regress/serial_schedule

  # Disable test password as not fixable by a simple sed (md5 password contains the username (regress_passwd))
  sed -e "s/password //" -i $SRCCOPYDIR/ic$SID-$c/src/test/regress/parallel_schedule
  sed -e "s/test: password\$//" -i $SRCCOPYDIR/ic$SID-$c/src/test/regress/serial_schedule
 
  # Disable tests select_parallel and advisory_locks as unstable in parallel runs
  sed -e "s/select_parallel //" -i $SRCCOPYDIR/ic$SID-$c/src/test/regress/parallel_schedule
  sed -e "s/test: select_parallel\$//" -i $SRCCOPYDIR/ic$SID-$c/src/test/regress/serial_schedule
  sed -e "s/advisory_lock //" -i $SRCCOPYDIR/ic$SID-$c/src/test/regress/parallel_schedule
  sed -e "s/test: advisory_lock\$//" -i $SRCCOPYDIR/ic$SID-$c/src/test/regress/serial_schedule

  # Fix regress entities
  find  $SRCCOPYDIR/ic$SID-$c/src/test/ \( -name *.sql -o -name *.source -o -name *.out \) -exec sed -e \
"s/regress_\(tblspace\)/regr${c03}_\1/g; "\
"s/regress_\(vacuum\)/regr${c03}_\1/g; "\
"s/regress_\(other_partitioned_fk_owner\)/regr${c03}_\1/g; "\
"s/regress_\(testsub\)/regr${c03}_\1/g; "\
"s/regress_\(regrole_test\)/regr${c03}_\1/g; "\
"s/regression_\(atx_test_database\)/regress${c03}_\1/g; "\
"s/regress_\(constraint_comments\)/regr${c03}_\1/g; "\
"s/regress_\(no_child_access\)/regr${c03}_\1/g; "\
"s/regress_\(rol_lock1\)/regr${c03}_\1/g; "\
"s/regress_\(alice\|bob\|carol\|dave\)/regr${c03}_\1/g; "\
"s/regress_\([a-z_]*user[0-9]*\)/regr${c03}_\1/g; "\
"s/regress_\([a-z_]*role\)/regr${c03}_\1/g; "\
"s/regress_\([a-z_]*group\)/regr${c03}_\1/g; "\
"s/regress_\(test_[a-z0-9_]*\)/regr${c03}_\1/g; "\
"s/regress_\(priv_[a-z0-9]\+\)/regr${c03}_\1/g; "\
"s/regress_\(rls_[a-z0-9]\+\)/regr${c03}_\1/g; "\
"s/regress_\(passwd[a-z0-9_]*\)/regr${c03}_\1/g; " -i {} \;

done

# Prepare master node
$PGBIN/initdb -k -D "$PGDB" --username=postgres
echo "
shared_buffers = 1024MB
max_connections = 1000
max_locks_per_transaction = 500

log_min_messages = notice
log_min_error_statement = log

fsync = off
" >> "$PGDB/postgresql.auto.conf"

# Start server
$PGBIN/pg_ctl -w -t 15 -D "$PGDB" -l server$SID.log start

# Run `make installcheck` in a loop
result=0
time for i in `seq $NUM_ITERATIONS`; do
  echo "iteration $i: `date`"
  for c in `seq $NUM_INSTALLCHECKS`; do
    (cd $SRCCOPYDIR/ic$SID-$c; EXTRA_REGRESS_OPTS="--dbname=regress$c" time make installcheck NO_GENERATED_HEADERS=1) >> installcheck$SID-$c.log 2>&1 &
  done
  wait

  echo "installcheck finished: `date`"
  # There are still some unstable tests: stats, misc_sanity, create_index
  if grep 'test process exited with' installcheck*.log >fail.log || grep 'TODO: FAIL' installcheck*.log; then
     echo "installcheck FAILED"
     result=1
     break
  fi
  sleep 3
  coredumpctl && result=1
  [ $result -eq 0 ] || break
done

if [ $result -eq 0 ]; then
  # Stop server on success
  $PGBIN/pg_ctl -w -t 90 -D "$PGDB" stop
  echo "ok"
fi
exit $result
