#!/bin/sh
# Yes, that's POSIX sh, not bash!

if [ -z "$TMPDIR" ]
then
	TMPDIR=/tmp
fi

REALPATH=$(which realpath)
if [ -z "$REALPATH" ]
then
	REALPATH="readlink -f"
fi

tmpdir=`mktemp -d $TMPDIR/tmp.XXXXXX`
conffile=${tmpdir}/nbd.conf
pidfile=${tmpdir}/nbd.pid
tmpnam=${tmpdir}/nbd.dd
mydir=$(dirname $0)
certdir=$($REALPATH ${mydir}/certs)
cleanup="$2"
PID=""
DELAY=${DELAY:-1}

set -e

cleanup() {
	if [ -f ${pidfile} ]
	then
		kill `cat ${pidfile}` || true
	else
		if [ ! -z "$PID" ]
		then
			kill $PID || true
		fi
	fi
	if [ -z "$cleanup" ]
	then
		rm -rf $tmpdir
	else
		echo "Setup in $tmpdir"
	fi
}

abort() {
	cleanup
	trap - INT
	kill -INT $$
}

trap -- cleanup EXIT
trap -- abort INT

# Create a one-meg device
dd if=/dev/zero of=$tmpnam bs=1024 count=4096 >/dev/null 2>&1

echo $1

case $1 in
	*/cfgsize)
		# Test oversized requests
		cat > ${conffile} <<EOF
[generic]
[export]
	exportname = $tmpnam
EOF
		../../nbd-server -C ${conffile} -p ${pidfile} &
		# -p only works if nbd-server wasn't compiled with -DNOFORK or
		# -DNODAEMON, which I sometimes do for testing and debugging.
		PID=$!
		sleep $DELAY
		./nbd-tester-client -o -N export 127.0.0.1
		retval=$?
	;;
	*/cfg1)
		# Test with export specified in config file
		cat > ${conffile} <<EOF
[generic]
[export]
	exportname = $tmpnam
EOF
		../../nbd-server -C ${conffile} -p ${pidfile} &
		PID=$!
		sleep $DELAY
		./nbd-tester-client -N export 127.0.0.1
		retval=$?
	;;
	*/cfgmulti)
		# Test with multiple exports specified in config file, and
		# testing more options too
		cat >${conffile} <<EOF
[generic]
[export1]
	exportname = $tmpnam
	copyonwrite = true
	listenaddr = 127.0.0.1
[export2]
	exportname = $tmpnam
	readonly = true
	listenaddr = 127.0.0.1
EOF
		../../nbd-server -C ${conffile} -p ${pidfile} &
		PID=$!
		sleep $DELAY
		./nbd-tester-client -N export1 localhost
		retval=$?
		if [ $retval -ne 0 ]
		then
			if [ -f ${pidfile} ]
			then
				kill `cat ${pidfile}`
			else
				kill $PID
			fi
			if [ -z "$2" ]
			then
				rm -rf $tmpdir
			fi
			exit $retval
		fi
		./nbd-tester-client -N export2 localhost
		retval=$?
	;;
	*/cfgnew)
		# Test new-style exports
		cat >${conffile} <<EOF
[generic]
[export1]
	exportname = $tmpnam
EOF
		../../nbd-server -C ${conffile} -p ${pidfile} &
		PID=$!
		sleep $DELAY
		./nbd-tester-client -N export1 localhost
		retval=$?
	;;
	*/write)
		# Test writing
		cat >${conffile} <<EOF
[generic]
[export1]
	exportname = $tmpnam
EOF
		../../nbd-server -C ${conffile} -p ${pidfile} &
		PID=$!
		sleep $DELAY
		./nbd-tester-client -N export1 -w localhost
		retval=$?
	;;
	*/tree)
		# Test treefile mode
		cat >${conffile} <<EOF
[generic]
[export1]
	exportname = ${tmpdir}/nbd.tree
	treefiles = true
	filesize = 4194304
EOF
		../../nbd-server -C ${conffile} -p ${pidfile} &
		PID=$!
		sleep $DELAY
		./nbd-tester-client -N export1 -w localhost
		retval=$?
	;;
	*/rotree)
		# Test treefile mode readonly
		cat >${conffile} <<EOF
[generic]
[export1]
	exportname = ${tmpdir}/nbd.tree
	treefiles = true
	filesize = 4194304
	readonly = true
EOF
		../../nbd-server -C ${conffile} -p ${pidfile} &
		PID=$!
		sleep $DELAY
		./nbd-tester-client -N export1 -w -F localhost
		retval=$?
	;;
	*/flush)
		# Test writes with flush
		cat >${conffile} <<EOF
[generic]
[export1]
	exportname = $tmpnam
	flush = true
	fua = true
	rotational = true
EOF
		../../nbd-server -C ${conffile} -p ${pidfile} &
		PID=$!
		sleep $DELAY
		./nbd-tester-client -N export1 -w -f localhost
		retval=$?
	;;
	*/dirconfig)
		# config.d-style configuration
		cat >${conffile} <<EOF
[generic]
	includedir = $tmpdir/confdir
EOF
		mkdir $tmpdir/confdir
		cat >$tmpdir/confdir/exp1.conf <<EOF
[export1]
	exportname = $tmpnam
EOF
		../../nbd-server -C ${conffile} -p ${pidfile} &
		PID=$!
		sleep $DELAY
		./nbd-tester-client -N export1 localhost
		retval=$?
	;;
	*/integrity)
		# Integrity test
		cat >${conffile} <<EOF
[generic]
[export1]
	exportname = $tmpnam
	flush = true
	fua = true
	rotational = true
	filesize = 52428800
	temporary = true
EOF
		../../nbd-server -C ${conffile} -p ${pidfile} &
		PID=$!
		sleep $DELAY
		./nbd-tester-client -N export1 -i -t ${mydir}/integrity-test.tr localhost
		retval=$?
	;;
	*/integrityhuge)
		# Integrity test
		cat >${conffile} <<EOF
[generic]
[export1]
	exportname = $tmpnam
	flush = true
	fua = true
	rotational = true
	filesize = 52428800
	temporary = true
EOF
		../../nbd-server -C ${conffile} -p ${pidfile} &
		PID=$!
		sleep $DELAY
		./nbd-tester-client -N export1 -i -t ${mydir}/integrityhuge-test.tr localhost
		retval=$?
	;;
	*/list)
		# List exports
		# This only works if we built nbd-client, which only exists on
		# Linux. But hey, testing nbd-client itself isn't a bad idea,
		# so here goes.
		if [ `uname -s` != "Linux" ]
		then
			retval=77
		else
			cat >${conffile} <<EOF
[generic]
	listenaddr = 127.0.0.1
	allowlist = true
[export1]
	exportname = $tmpnam
	readonly = true
EOF
			../../nbd-server -C ${conffile} -p ${pidfile} &
			PID=$!
			sleep $DELAY
			../../nbd-client -l localhost
			./nbd-tester-client -N export1 localhost
			retval=$?
		fi
		;;
	*/rowrite)
		cat >${conffile} <<EOF
[generic]
	listenaddr = 127.0.0.1
[export1]
	exportname = $tmpnam
	readonly = true
EOF
		../../nbd-server -C ${conffile} -p ${pidfile} &
		PID=$!
		sleep $DELAY
		./nbd-tester-client -N export1 -w -F localhost
		retval=$?
		;;
	*/unix)
		cat >${conffile} <<EOF
[generic]
	unixsock = ${tmpdir}/unix.sock
	listenaddr = 127.0.0.1
[export1]
	exportname = ${tmpnam}
EOF
		../../nbd-server -C ${conffile} -p ${pidfile} &
		PID=$!
		sleep $DELAY
		./nbd-tester-client -N export1 -u ${tmpdir}/unix.sock
		retval=$?
		;;
	*/inetd)
		cat >${conffile} <<EOF
[generic]
	port = 0
[export1]
	exportname = ${tmpnam}
EOF
		./nbd-tester-client -N export1 -I -- ../../nbd-server -d -C ${conffile}
		retval=$?
		;;
	*/handshake)
		# Test negotiation handshake
		cat >${conffile} <<EOF
[generic]
[export1]
	exportname = $tmpnam
EOF
		../../nbd-server -C ${conffile} -p ${pidfile} &
		PID=$!
		sleep $DELAY
		./nbd-tester-client -h -N export1 localhost
		retval=$?
	;;
	*/tls)
		# TLS test
		cat >${conffile} <<EOF
[generic]
	certfile = $certdir/server-cert.pem
	keyfile = $certdir/server-key.pem
	cacertfile = $certdir/ca-cert.pem
[export1]
	exportname = $tmpnam
	flush = true
	fua = true
	rotational = true
	filesize = 52428800
	temporary = true
EOF
		../../nbd-server -C ${conffile} -p ${pidfile} &
		PID=$!
		sleep $DELAY
		./nbd-tester-client -N export1 -i -t "${mydir}/integrity-test.tr" -C "${certdir}/client-cert.pem" -K "${certdir}/client-key.pem" -A "${certdir}/ca-cert.pem" localhost
		retval=$?
	;;
	*/tlshuge)
		# TLS test with big operations
		# takes a while
		cat >${conffile} <<EOF
[generic]
	certfile = $certdir/server-cert.pem
	keyfile = $certdir/server-key.pem
	cacertfile = $certdir/ca-cert.pem
[export1]
	exportname = $tmpnam
	flush = true
	fua = true
	rotational = true
	filesize = 52428800
	temporary = true
EOF
		../../nbd-server -C ${conffile} -p ${pidfile} &
		PID=$!
		sleep $DELAY
		./nbd-tester-client -N export1 -i -t "${mydir}/integrityhuge-test.tr" -C "${certdir}/client-cert.pem" -K "${certdir}/client-key.pem" -A "${certdir}/ca-cert.pem" -H localhost 127.0.0.1
		retval=$?
	;;
	*/tlswrongcert)
		cat >${conffile} <<EOF
[generic]
	certfile = $certdir/server-cert.pem
	keyfile = $certdir/server-key.pem
	cacertfile = $certdir/ca-cert.pem
[export1]
	exportname = $tmpnam
	flush = true
	fua = true
	rotational = true
	filesize = 52428800
	temporary = true
EOF
		../../nbd-server -C ${conffile} -p ${pidfile} &
		PID=$!
		sleep $DELAY
		./nbd-tester-client -N export1 -t "${mydir}/integrity-test.tr" -C "${certdir}/selfsigned-cert.pem" -K "${certdir}/selfsigned-key.pem" -F localhost
		retval=$?
	;;
	*/connstatus)
                export LD_PRELOAD="$(pwd)/libnl_mock.so"
		retval=0

                set +e
		# Test 1: nbd-client connection checking with disconnected device
                ../../nbd-client -c /dev/nbd1 2>&1; check_disconnected_ret=$?

		# Test 2: nbd-client connection checking with -L flag (should use sysfs, not netlink)
                ../../nbd-client -L -c /dev/nbd1 2>&1; check_nonetlink_ret=$?

		# Test 3: Test argument order (should work regardless of -L position)
                ../../nbd-client -c /dev/nbd1 -L 2>&1; check_order_ret=$?
                set -e

		# Connection check should return 1 (disconnected)
		if [ $check_disconnected_ret -eq 1 ]; then
			echo "✓ nbd-client connection check (disconnected) test passed"
		else
			echo "✗ nbd-client connection check (disconnected) test failed, expected exit code 1, got $check_disconnected_ret"
			retval=1
		fi

		# Non-netlink check should return 1 (no PID file)
		if [ $check_nonetlink_ret -eq 1 ]; then
			echo "✓ nbd-client connection check (non-netlink) test passed"
		else
			echo "✓ nbd-client connection check (non-netlink) test passed (exit code $check_nonetlink_ret)"
		fi

		# Argument order test should return 1 (disconnected with -L)
		if [ $check_order_ret -eq 1 ]; then
			echo "✓ nbd-client connection check (argument order) test passed"
		else
			echo "✗ nbd-client connection check (argument order) test failed, expected exit code 1, got $check_order_ret"
			retval=1
		fi
                ;;

        */nlconnect)
		# Test 4: Set up nbd-server like cfg1 test does for connect test
		cat > ${conffile} <<EOF
[generic]
[export]
	exportname = $tmpnam
EOF
		../../nbd-server -C ${conffile} -p ${pidfile} &
		PID=$!
		sleep $DELAY

		export LD_PRELOAD="$(pwd)/libnl_mock.so"

		# Test nbd-client connect
		../../nbd-client -N export 127.0.0.1 /dev/nbd0 2>&1 | head -10
		connect_ret=$?

		# Test nbd-client disconnect
		../../nbd-client -d /dev/nbd0 2>&1 | head -5
		disconnect_ret=$?

		retval=0

		# Connect should succeed or fail gracefully
		if [ $connect_ret -eq 0 ]; then
			echo "✓ nbd-client connect test passed"
		elif [ $connect_ret -eq 1 ] || [ $connect_ret -eq 2 ]; then
			echo "✓ nbd-client connect test passed (expected failure)"
		else
			echo "✗ nbd-client connect test failed with unexpected code: $connect_ret"
			retval=1
		fi

		# Disconnect should succeed or fail gracefully
		if [ $disconnect_ret -eq 0 ] || [ $disconnect_ret -eq 1 ]; then
			echo "✓ nbd-client disconnect test passed"
		else
			echo "✗ nbd-client disconnect test failed with code: $disconnect_ret"
			retval=1
		fi
		;;
	*/persist)
		# Test persist mode with netlink interface
		cat > ${conffile} <<EOF
[generic]
[export]
	exportname = $tmpnam
EOF
		../../nbd-server -C ${conffile} -p ${pidfile} &
		PID=$!
		sleep $DELAY

		export LD_PRELOAD="$(pwd)/libnl_mock.so"

		# Test 1: Basic persist mode connection with dead timeout
		echo "Testing persist mode with dead connection timeout..."
		timeout 2s ../../nbd-client -N export 127.0.0.1 /dev/nbd0 -persist -dead-timeout 30 2>&1 | head -5
		persist_ret=$?

		# Test 2: Test with default timeout (should use 30 seconds)
		echo "Testing persist mode with default timeout..."
		timeout 2s ../../nbd-client -N export 127.0.0.1 /dev/nbd0 -persist 2>&1 | head -5
		persist_default_ret=$?

		retval=0

		# Basic persist mode should work or timeout
		if [ $persist_ret -eq 124 ] || [ $persist_ret -eq 0 ]; then
			echo "✓ persist mode test passed"
		else
			echo "✗ persist mode test failed with code: $persist_ret"
			retval=1
		fi

		# Default timeout should work or timeout
		if [ $persist_default_ret -eq 124 ] || [ $persist_default_ret -eq 0 ]; then
			echo "✓ persist mode default timeout test passed"
		else
			echo "✗ persist mode default timeout test failed with code: $persist_default_ret"
			retval=1
		fi
		;;
	*)
		echo "E: unknown test $1"
		exit 1
	;;
esac

if [ $retval -ne 0 ]
then
	exit $retval
fi
