#! /bin/sh
# $OpenLDAP$
## This work is part of OpenLDAP Software <http://www.openldap.org/>.
##
## Copyright 1998-2018 The OpenLDAP Foundation.
## All rights reserved.
##
## Redistribution and use in source and binary forms, with or without
## modification, are permitted only as authorized by the OpenLDAP
## Public License.
##
## A copy of this license is available in the file LICENSE in the
## top-level directory of the distribution or, alternatively, at
## <http://www.OpenLDAP.org/license.html>.

echo "running defines.sh"
. $SRCDIR/scripts/defines.sh

if test $SYNCPROV = syncprovno; then
	echo "Syncrepl provider overlay not available, test skipped"
	exit 0
fi
if test $ACCESSLOG = accesslogno; then
	echo "Accesslog overlay not available, test skipped"
	exit 0
fi
if test $BACKEND = ldif ; then
	echo "$BACKEND backend unsuitable, test skipped"
	exit 0
fi

dtest=`date +%N|sed s/...$//`

if test $dtest = N; then
	echo "nanosecond date values not supported, test skipped"
	exit 0
fi

echo "This test tracks a case where slapd deadlocks during a significant write load"
echo "See http://www.openldap.org/its/index.cgi/?findid=8752 for more information."

MMR=4
XDIR=$TESTDIR/srv

mkdir -p $TESTDIR

ITS=8752
ITSDIR=$DATADIR/regressions/its$ITS

n=1
while [ $n -le $MMR ]; do
	DBDIR=${XDIR}$n/db
	mkdir -p ${XDIR}$n $DBDIR.1 $DBDIR.2
	n=`expr $n + 1`
done

KILLPIDS=

echo "Starting slapd on TCP/IP port $PORT1..."
. $CONFFILTER $BACKEND $MONITORDB < $ITSDIR/slapd.conf > $CONF1
$SLAPD -f $CONF1 -h $URI1 -d $LVL $TIMING > $LOG1 2>&1 &
PID=$!
if test $WAIT != 0 ; then
	echo PID $PID
	read foo
fi
KILLPIDS="$PID"

sleep 1

echo "Using ldapsearch to check that slapd is running..."
for i in 0 1 2 3 4 5; do
	$LDAPSEARCH -s base -b "$MONITOR" -h $LOCALHOST -p $PORT1 \
		'objectclass=*' > /dev/null 2>&1
	RC=$?
	if test $RC = 0 ; then
		break
	fi
	echo "Waiting 5 seconds for slapd to start..."
	sleep 5
done

if test $RC != 0 ; then
	echo "ldapsearch failed ($RC)!"
	test $KILLSERVERS != no && kill -HUP $KILLPIDS
	exit $RC
fi

echo "Populating database on first provider..."
$LDAPADD -D $MANAGERDN -H $URI1 -w $PASSWD << EOMODS >> $TESTOUT 2>&1
dn: $BASEDN
objectClass: organization
objectClass: dcObject
o: Example, Inc.
dc: example

dn: ou=People,$BASEDN
objectClass: organizationalUnit
ou: People

dn: ou=Groups,$BASEDN
objectClass: organizationalUnit
ou: Groups

dn: cn=Roger Rabbit,ou=People,$BASEDN
objectClass: inetOrgPerson
cn: Roger Rabbit
sn: Rabbit

dn: cn=Baby Herman,ou=People,$BASEDN
objectClass: inetOrgPerson
cn: Baby Herman
sn: Herman

dn: cn=Jessica_Rabbit,ou=People,$BASEDN
objectClass: inetOrgPerson
cn: Jessica_Rabbit
sn: Rabbit

dn: cn=Bugs_Bunny,ou=People,$BASEDN
objectClass: inetOrgPerson
cn: Bugs_Bunny
sn: Bunny

dn: cn=Daffy_Duck,ou=People,$BASEDN
objectClass: inetOrgPerson
cn: Daffy_Duck
sn: Duck

dn: cn=Elmer_Fudd,ou=People,$BASEDN
objectClass: inetOrgPerson
cn: Elmer_Fudd
sn: Fudd

dn: cn=Cartoonia,ou=Groups,$BASEDN
objectClass: groupOfNames
cn: Cartoonia
member: cn=Roger Rabbit,ou=People,$BASEDN
member: cn=Baby Herman,ou=People,$BASEDN
EOMODS

RC=$?

if test $RC != 0 ; then
	echo "ldapadd failed ($RC)!"
	test $KILLSERVERS != no && kill -HUP $KILLPIDS
	exit $RC
fi

echo "Stopping slapd and reworking configuration for MMR..."

test $KILLSERVERS != no && kill -HUP $KILLPIDS
wait $KILLPIDS

KILLPIDS=
n=1
while [ $n -le $MMR ]; do
	MYURI=`eval echo '$URI'$n`
	MYLOG=`eval echo '$LOG'$n`
	MYCONF=`eval echo '$CONF'$n`
	echo "Starting provider slapd on TCP/IP URI $MYURI"
	. $CONFFILTER $BACKEND $MONITORDB < $ITSDIR/slapd.conf.mmr > $TESTDIR/slapd.conf
	sed -e "s/MMR/$n/g" $TESTDIR/slapd.conf > $MYCONF
	j=1
	while [ $j -le $MMR ]; do
		MMCURI=`eval echo '$URI'$j`
		sed -e "s|MMC${j}|${MMCURI}|" $MYCONF > $TESTDIR/slapd.conf
		mv $TESTDIR/slapd.conf $MYCONF
		j=`expr $j + 1`
	done
	if [ -f $TESTDIR/slapd.conf ]; then
		rm -f $TESTDIR/slapd.conf
	fi
	$SLAPD -f $MYCONF -h $MYURI  -d $LVL $TIMING >> $MYLOG 2>&1 &
	PID=$!
	if test $WAIT != 0 ; then
		echo PID $PID
		read foo
	fi
	KILLPIDS="$PID $KILLPIDS"
	sleep 1

	echo "Using ldapsearch to check that provider slapd is running..."
	for i in 0 1 2 3 4 5; do
		$LDAPSEARCH -s base -b "" -H $MYURI \
			'objectclass=*' > /dev/null 2>&1
		RC=$?
		if test $RC = 0 ; then
			break
		fi
		echo "Waiting 5 seconds for slapd to start..."
		sleep 5
	done
	
	if test $RC != 0 ; then
		echo "ldapsearch failed ($RC)!"
		test $KILLSERVERS != no && kill -HUP $KILLPIDS
		exit $RC
	fi
	n=`expr $n + 1`
done

echo "Setting up accesslog on each master..."
n=1
while [ $n -le $MMR ]; do
	echo "Modifying dn: cn=Elmer_Fudd,ou=People,dc=example,dc=com on master $n"
	MYURI=`eval echo '$URI'$n`
	$LDAPMODIFY -v -D "$MANAGERDN" -H $MYURI -w $PASSWD > \
		$TESTOUT 2>&1 << EOMODS

dn: cn=Elmer_Fudd,ou=People,$BASEDN
changetype: modify
replace: sn
sn: Fudd
EOMODS
	sleep 5
	n=`expr $n + 1`
done

echo "Sleeping 30 seconds to ensure replication is reconciled between all nodes"
echo "The next step of the test will perform 20000 random write operations and may take some time."
echo "As this test is for a deadlock, it will take manual intervention to exit the test if one occurs."
sleep 30

echo "Starting random master/entry modifications..."
DN1="cn=Elmer_Fudd,ou=People,$BASEDN"
VAL1="Fudd"

DN2="cn=Jessica_Rabbit,ou=People,$BASEDN"
VAL2="Rabbit"

DN3="cn=Bugs_Bunny,ou=People,$BASEDN"
VAL3="Bunny"

DN4="cn=Daffy_Duck,ou=People,$BASEDN"
VAL4="Duck"

n=1
while [ $n -le 20000 ]; do
	seed=`date +%N|sed s/...$//`
	rvalue=`echo|awk "BEGIN {srand($seed)
{print int(1+rand()*4)}}"`
	MYURI=`eval echo '$URI'$rvalue`
	seed=`date +%N|sed s/...$//`
	rvalue=`echo|awk "BEGIN {srand($seed)
{print int(1+rand()*4)}}"`
	MYDN=`eval echo '$DN'$rvalue`
	MYVAL=`eval echo '$VAL'$rvalue`
	echo "Modifying $MYURI entry $MYDN with value $MYVAL iteration $n of 20000"
	$LDAPMODIFY -v -D "$MANAGERDN" -H $MYURI -w $PASSWD > \
		$TESTOUT 2>&1 << EOMODS

dn: $MYDN
changetype: modify
replace: sn
sn: $MYVAL
EOMODS
	n=`expr $n + 1`
done

test $KILLSERVERS != no && kill -HUP $KILLPIDS

echo ">>>>> Test succeeded"

test $KILLSERVERS != no && wait

exit 0
