#!/bin/sh
# 
# **********
# test_J_pgbench
#
# 	This test script creates a standalone pgbench database 
#	as slony_test1 and then:
#
#	- initializes a primary node and starts the node daemon
#	- creates a set containing all 4 pgbench tables
#	- creates a second database as slony_test2
#	- adds database slony_test2 to the system
#	- starts the second replication daemon
#	- creates the pgbench tables (schema only)
#	- subscribes the replication set from the primary node
#	- creates a 3rd database node similar that replicates
#	  cascaded from the second node.
#	- waits until the pgbench is terminated and the user
#	  stopped all 3 replication engines.
#	- compares the 3 database.
# **********

TERMPROG=xterm
WHICHPROG=which

PATH=/usr/local/slony1/bin:$PATH
export PATH
TMPOUT=/tmp/output.$$
DB1=slony_test1
DB2=slony_test2
DB3=slony_test3
DEBUG_LEVEL=2

PGBENCH_SCALE=2
PGBENCH_CLIENTS=2
PGBENCH_TRANS=`expr 50000 / $PGBENCH_CLIENTS`

trap '
	echo ""
	echo "**** user abort"
	if [ ! -z $pgbench_pid ] ; then
		echo "**** killing pgbench"
		kill -15 $pgbench_pid
	fi
	if [ ! -z $slon1_pid ] ; then
		echo "**** killing node daemon 1"
		kill -15 $slon1_pid
	fi
	if [ ! -z $slon2_pid ] ; then
		echo "**** killing node daemon 2"
		kill -15 $slon2_pid
	fi
	if [ ! -z $slon3_pid ] ; then
		echo "**** killing node daemon 3"
		kill -15 $slon3_pid
	fi
	exit -1
' 2 15

######################################################################
# Preparations ... create a standalone pgbench database and
# have the "application" (pgbench) running.
######################################################################

#####
# Make sure the install is up to date
#####
WGM=`$WHICHPROG gmake | egrep '^/'`
if [ -z "$WGM" ] ; then
    MAKE=make
    CGNU=`make -v | grep GNU`
    if [ -z "$CGNU" ] ; then
	echo "GNU Make not found - please install GNU Make"
	exit 1
    fi
else
    MAKE=gmake
fi
echo -n "**** running 'make install' in src directory ... "
if ! ${MAKE} -C .. install >$TMPOUT 2>&1 ; then
    echo "failed"; cat $TMPOUT; rm $TMPOUT; exit -1
fi
echo "done"
rm $TMPOUT

#####
# Remove old databases, if they exist
#####
echo "**** remove old test databases"
dropdb $DB1 || echo "**** ignored"
sleep 1
dropdb $DB2 || echo "**** ignored"
sleep 1
dropdb $DB3 || echo "**** ignored"
sleep 1

#####
# Create the "Primary Node"
#####
echo "**** creating database for Node 1"

createdb $DB1 || exit -1
pgbench -i -s $PGBENCH_SCALE $DB1
pg_dump -s $DB1 >pgbench_schema.sql

#####
# Start pgbench in the background and give it rampup time
#####
pgbench -n -s $PGBENCH_SCALE -c $PGBENCH_CLIENTS -t $PGBENCH_TRANS $DB1 &
pgbench_pid=$!
echo "**** pgbench is running in background with pid $pgbench_pid"
echo -n "**** sleeping 10 seconds to give pgbench time for rampup ... "
sleep 10
echo "done"

echo ""
echo "**********************************************************************"
echo "**** $DB1 is now a standalone database with a running pgbench"
echo "**********************************************************************"
echo ""

######################################################################
# Setup DB1 as the primary cluster T1 node, start the node daemon,
# and create a replication set containing the pgbench tables.
######################################################################

echo "**** initializing $DB1 as Primary Node for Slony-I cluster T1"
slonik <<_EOF_
	cluster name = T1;
	node 1 admin conninfo = 'dbname=$DB1';
	node 2 admin conninfo = 'dbname=$DB1';
	node 3 admin conninfo = 'dbname=$DB1';
	init cluster (id = 1, comment = 'Node 1');
	echo 'Database $DB1 initialized as Node 1';
_EOF_
if [ $? -ne 0 ] ; then
	kill $pgbench_pid;
	exit -1
fi

echo "**** starting the Slony-I node daemon for $DB1"
$TERMPROG -title "Slon node 1" -e sh -c "slon -d$DEBUG_LEVEL T1 dbname=$DB1; echo -n 'Enter>'; read line" &
slon1_pid=$!
echo "slon[$slon1_pid] on dbname=$DB1"

echo "**** creating a replication set containing the 4 pgbench tables ... "
slonik <<_EOF_
	cluster name = T1;
	node 1 admin conninfo = 'dbname=$DB1';
	node 2 admin conninfo = 'dbname=$DB2';
	node 3 admin conninfo = 'dbname=$DB3';

	try {
		table add key (node id = 1, fully qualified name = 'public.history');
	}
	on error {
		exit -1;
	}

	try {
		create set (id = 100, origin = 1, comment = 'Set 100 - accounts');
		create set (id = 200, origin = 1, comment = 'Set 200 - branches');
		create set (id = 300, origin = 1, comment = 'Set 300 - tellers');
		create set (id = 400, origin = 1, comment = 'Set 400 - history');
		set add table (set id = 100, origin = 1,
			id = 1, fully qualified name = 'public.accounts',
			comment = 'Table accounts');
		set add table (set id = 200, origin = 1,
			id = 2, fully qualified name = 'public.branches',
			comment = 'Table branches');
		set add table (set id = 300, origin = 1,
			id = 3, fully qualified name = 'public.tellers',
			comment = 'Table tellers');
		set add table (set id = 400, origin = 1,
			id = 4, fully qualified name = 'public.history',
			key = serial, comment = 'Table accounts');
	}
	on error {
		exit -1;
	}
_EOF_
if [ $? -ne 0 ] ; then
	echo "failed"
	kill $pgbench_pid 2>/dev/null
	kill $slon1_pid 2>/dev/null
	cat $TMPOUT
	rm $TMPOUT
	exit -1
fi
echo "**** set created"

#####
# Check that pgbench is still running
#####
if ! kill -0 $pgbench_pid 2>/dev/null ; then
	echo "**** pgbench terminated ???"
	kill $slon1_pid 2>/dev/null
	exit -1
fi

echo ""
echo "**********************************************************************"
echo "**** $DB1 is now the Slony-I origin for sets 100..400"
echo "**********************************************************************"
echo ""

######################################################################
# Setup DB2 as a subscriber node and let it subscribe the replication
# set of the running pgbench
######################################################################
echo "**** creating database for Node 2"
if ! createdb $DB2 ; then
	kill $pgbench_pid 2>/dev/null
	kill $slon1_pid 2>/dev/null
	exit -1
fi

echo "**** initializing $DB2 as Node 2 of Slony-I cluster T1"
slonik <<_EOF_
	cluster name = T1;
	node 1 admin conninfo = 'dbname=$DB1';
	node 2 admin conninfo = 'dbname=$DB2';
	node 3 admin conninfo = 'dbname=$DB3';

	try {
		store node (id = 2, comment = 'Node 2', event node=1);
		store path (server = 1, client = 2, conninfo = 'dbname=$DB1');
		store path (server = 2, client = 1, conninfo = 'dbname=$DB2');
	}
	on error { exit -1; }
	echo 'Database $DB2 added as Node 2';
_EOF_

if [ $? -ne 0 ] ; then
	kill $pgbench_pid 2>/dev/null
	kill $slon1_pid 2>/dev/null
	exit -1
fi

echo "**** starting the Slony-I node daemon for $DB2"
$TERMPROG -title "Slon node 2" -e sh -c "slon -d$DEBUG_LEVEL T1 dbname=$DB2; echo -n 'Enter>'; read line" &
slon2_pid=$!
echo "slon[$slon2_pid] on dbname=$DB2"

#####
# Check that pgbench is still running
#####
if ! kill -0 $pgbench_pid 2>/dev/null ; then
	echo "**** pgbench terminated ???"
	kill $slon1_pid 2>/dev/null
	exit -1
fi

######################################################################
# And now comes the moment where the big elephant starts to pee
# and the attendants in the first row climb on their chairs ...
######################################################################
echo "**** creating pgbench tables and subscribing Node 2 to set 1"
(
	cat pgbench_schema.sql
) | psql -q $DB2
slonik <<_EOF_
	cluster name = T1;
	node 1 admin conninfo = 'dbname=$DB1';
	node 2 admin conninfo = 'dbname=$DB2';
	node 3 admin conninfo = 'dbname=$DB3';

	subscribe set ( id = 100, provider = 1, receiver = 2, forward = yes );
	subscribe set ( id = 200, provider = 1, receiver = 2, forward = yes );
	subscribe set ( id = 300, provider = 1, receiver = 2, forward = yes );
	subscribe set ( id = 400, provider = 1, receiver = 2, forward = yes );

	echo '**** Waiting for node 2 to finish subscription of set 400';
	wait for event (origin = 2, confirmed = 1, wait on = 2);
	sync (id = 1);
	wait for event (origin = 1, confirmed = 2, wait on = 1);
_EOF_

echo ""
echo "**********************************************************************"
echo "**** $DB2 should now be attempting to catch up."
echo "**********************************************************************"
echo ""

######################################################################
# Setup DB2 as a subscriber node and let it subscribe the replication
# set of the running pgbench
######################################################################
echo "**** creating database for Node 3"
if ! createdb $DB3 ; then
	kill $pgbench_pid 2>/dev/null
	kill $slon1_pid 2>/dev/null
	kill $slon2_pid 2>/dev/null
	exit -1
fi

echo "**** initializing $DB3 as Node 3 of Slony-I cluster T1"
slonik <<_EOF_
	cluster name = T1;
	node 1 admin conninfo = 'dbname=$DB1';
	node 2 admin conninfo = 'dbname=$DB2';
	node 3 admin conninfo = 'dbname=$DB3';

	store node (id = 3, comment = 'Node 3', event node=1);

	store path (server = 1, client = 3, conninfo = 'dbname=$DB1');
	store path (server = 2, client = 3, conninfo = 'dbname=$DB2');
	store path (server = 3, client = 1, conninfo = 'dbname=$DB3');
	store path (server = 3, client = 2, conninfo = 'dbname=$DB3');

	echo 'Database $DB2 added as Node 2';
_EOF_

if [ $? -ne 0 ] ; then
	kill $pgbench_pid 2>/dev/null
	kill $slon1_pid 2>/dev/null
	kill $slon2_pid 2>/dev/null
	exit -1
fi

echo "**** starting the Slony-I node daemon for $DB3"
$TERMPROG -title "Slon node 3" -e sh -c "slon -d$DEBUG_LEVEL T1 dbname=$DB3; echo -n 'Enter>'; read line" &
slon3_pid=$!
echo "slon[$slon3_pid] on dbname=$DB3"

#####
# Check that pgbench is still running
#####
if ! kill -0 $pgbench_pid 2>/dev/null ; then
	echo "**** pgbench terminated ???"
	kill $slon1_pid 2>/dev/null
	exit -1
fi

######################################################################
# Create the pgbench tables and subscribe to set 1
######################################################################
echo "**** creating pgbench tables and subscribing Node 2 to set 1"
(
	cat pgbench_schema.sql
) | psql -q $DB3
slonik <<_EOF_
	cluster name = T1;
	node 1 admin conninfo = 'dbname=$DB1';
	node 2 admin conninfo = 'dbname=$DB2';
	node 3 admin conninfo = 'dbname=$DB3';

	subscribe set ( id = 100, provider = 2, receiver = 3, forward = no );
	subscribe set ( id = 200, provider = 2, receiver = 3, forward = no );
	subscribe set ( id = 300, provider = 2, receiver = 3, forward = no );
	subscribe set ( id = 400, provider = 2, receiver = 3, forward = no );

	echo '**** Waiting for node 3 to finish subscription of set 400';
	wait for event (origin = 3, confirmed = 1, wait on = 3);
	sync (id = 1);
	wait for event (origin = 1, confirmed = 3, wait on = 1);
_EOF_

echo ""
echo "**********************************************************************"
echo "**** $DB3 should now be attempting to catch up."
echo "**********************************************************************"
echo ""



echo -n "**** waiting for pgbench to finish "
while kill -0 $pgbench_pid 2>/dev/null ; do
	echo -n "."
	sleep 10
done
echo "**** pgbench finished"
echo "**** please terminate the replication engines when caught up."
wait $slon1_pid
wait $slon2_pid
wait $slon3_pid

kill $pgbench_pid 2>/dev/null
kill $slon1_pid 2>/dev/null
kill $slon2_pid 2>/dev/null
kill $slon3_pid 2>/dev/null

echo -n "**** comparing databases ... "
psql $DB1 -o dump.tmp.1.$$ <<_EOF_
	select 'accounts:'::text, aid, bid, abalance, filler
			from accounts order by aid;
	select 'branches:'::text, bid, bbalance, filler
			from branches order by bid;
	select 'tellers:'::text, tid, bid, tbalance, filler
			from tellers order by tid;
	select 'history:'::text, tid, bid, aid, delta, mtime, filler,
			"_Slony-I_T1_rowID" from history order by "_Slony-I_T1_rowID";
_EOF_
psql $DB2 -o dump.tmp.2.$$ <<_EOF_
	select 'accounts:'::text, aid, bid, abalance, filler
			from accounts order by aid;
	select 'branches:'::text, bid, bbalance, filler
			from branches order by bid;
	select 'tellers:'::text, tid, bid, tbalance, filler
			from tellers order by tid;
	select 'history:'::text, tid, bid, aid, delta, mtime, filler,
			"_Slony-I_T1_rowID" from history order by "_Slony-I_T1_rowID";
_EOF_
psql $DB3 -o dump.tmp.3.$$ <<_EOF_
	select 'accounts:'::text, aid, bid, abalance, filler
			from accounts order by aid;
	select 'branches:'::text, bid, bbalance, filler
			from branches order by bid;
	select 'tellers:'::text, tid, bid, tbalance, filler
			from tellers order by tid;
	select 'history:'::text, tid, bid, aid, delta, mtime, filler,
			"_Slony-I_T1_rowID" from history order by "_Slony-I_T1_rowID";
_EOF_

if diff dump.tmp.1.$$ dump.tmp.2.$$ >test_J.1-2.diff ; then
	echo "success - databases 1 and 2 are equal."
	rm dump.tmp.2.$$
	rm test_J.1-2.diff
else
	echo "FAILED - see test_J.1-2.diff for database differences"
fi
echo -n "**** comparing databases ... "
if diff dump.tmp.1.$$ dump.tmp.3.$$ >test_J.1-3.diff ; then
	echo "success - databases 1 and 3 are equal."
	rm dump.tmp.3.$$
	rm dump.tmp.1.$$
	rm test_J.1-3.diff
else
	echo "FAILED - see test_J.1-3.diff for database differences"
fi
