nut/tests/NIT/nit.sh
2022-06-29 12:37:36 +02:00

853 lines
26 KiB
Bash
Executable file

#!/bin/sh
# NUT Integration Testing suite, assumes the codebase was built and
# arranges running of the binaries to test driver-client-server
# ability to start and their interactions.
#
# Note: currently it is a PoC-quality mess that gets the job done
# but could be refactored for better maintainability and generic
# approach. Part of the goal was to let this script set up the
# sandbox to run tests which could be defined in other files.
#
# WARNING: Current working directory when starting the script should be
# the location where it may create temporary data (e.g. the BUILDDIR).
# Caller can export envvars to impact the script behavior, e.g.:
# DEBUG=true to print debug messages, running processes, etc.
# DEBUG_SLEEP=60 to sleep after tests, with driver+server running
# NUT_DEBUG_MIN=3 to set (minimum) debug level for drivers, upsd...
# NUT_PORT=12345 custom port for upsd to listen and clients to query
#
# Design note: written with dumbed-down POSIX shell syntax, to
# properly work in whatever different OSes have (bash, dash,
# ksh, busybox sh...)
#
# Copyright
# 2022 Jim Klimov <jimklimov+nut@gmail.com>
#
# License: GPLv2+
TZ=UTC
LANG=C
LC_ALL=C
export TZ LANG LC_ALL
log_separator() {
echo "" >&2
echo "================================" >&2
}
shouldDebug() {
[ -n "$DEBUG" ] || [ -n "$DEBUG_SLEEP" ]
}
log_debug() {
if shouldDebug ; then
echo "[DEBUG] $@" >&2
fi
}
log_info() {
echo "[INFO] $@" >&2
}
log_error() {
echo "[ERROR] $@" >&2
}
die() {
echo "[FATAL] $@" >&2
exit 1
}
# Note: current directory is assumed to be writeable for temporary
# data, e.g. the $(builddir) from the Makefile. Static resources
# from the source codebase are where the script resides, e.g.
# the $(srcdir) from the Makefile. If we are not in the source
# tree, tests would use binaries in PATH (e.g. packaged install).
BUILDDIR="`pwd`"
TOP_BUILDDIR=""
case "${BUILDDIR}" in
*/tests/NIT)
TOP_BUILDDIR="`cd "${BUILDDIR}"/../.. && pwd`" ;;
*) log_info "Current directory '${BUILDDIR}' is not a .../tests/NIT" ;;
esac
if ! test -w "${BUILDDIR}" ; then
log_error "BUILDDIR='${BUILDDIR}' is not writeable, tests may fail below"
fi
SRCDIR="`dirname "$0"`"
SRCDIR="`cd "$SRCDIR" && pwd`"
TOP_SRCDIR=""
case "${SRCDIR}" in
*/tests/NIT)
TOP_SRCDIR="`cd "${SRCDIR}"/../.. && pwd`" ;;
*) log_info "Script source directory '${SRCDIR}' is not a .../tests/NIT" ;;
esac
# No fuss about LD_LIBRARY_PATH: for binaries that need it,
# PATH entries below would contain libtool wrapper scripts;
# for other builds we use system default or caller's env.
PATH_ADD="${BUILDDIR}"
if [ x"${SRCDIR}" != x"${BUILDDIR}" ]; then
PATH_ADD="${PATH_ADD}:${SRCDIR}"
fi
if [ x"${TOP_BUILDDIR}" != x ]; then
PATH_ADD="${PATH_ADD}:${TOP_BUILDDIR}/clients:${TOP_BUILDDIR}/drivers:${TOP_BUILDDIR}/server:${TOP_BUILDDIR}/tools:${TOP_BUILDDIR}/tools/nut-scanner"
fi
if [ x"${TOP_SRCDIR}" != x ]; then
PATH_ADD="${PATH_ADD}:${TOP_SRCDIR}/clients:${TOP_SRCDIR}/drivers:${TOP_SRCDIR}/server:${TOP_SRCDIR}/tools:${TOP_SRCDIR}/tools/nut-scanner"
fi
PATH="${PATH_ADD}:${PATH}"
export PATH
unset PATH_ADD
log_debug "Using PATH='$PATH'"
for PROG in upsd upsc dummy-ups upsmon ; do
(command -v ${PROG}) || die "Useless setup: ${PROG} not found in PATH: ${PATH}"
done
PID_UPSD=""
PID_DUMMYUPS=""
PID_DUMMYUPS1=""
PID_DUMMYUPS2=""
TESTDIR="$BUILDDIR/tmp"
# Technically the limit is sizeof(sockaddr.sun_path) for complete socket
# pathname, which varies 104-108 chars max on systems seen in CI farm;
# we reserve 17 chars for "/dummy-ups-dummy" longest filename.
if [ `echo "$TESTDIR" | wc -c` -gt 80 ]; then
log_info "'$TESTDIR' is too long to store AF_UNIX socket files, will mktemp"
if ! ( [ -n "${TMPDIR-}" ] && [ -d "${TMPDIR-}" ] && [ -w "${TMPDIR-}" ] ) ; then
if [ -d /dev/shm ] && [ -w /dev/shm ]; then TMPDIR=/dev/shm ; else TMPDIR=/tmp ; fi
fi
TESTDIR="`mktemp -d "${TMPDIR}/nit-tmp.$$.XXXXXX"`" || die "Failed to mktemp"
else
rm -rf "${TESTDIR}" || true
fi
log_info "Using '$TESTDIR' for generated configs and state files"
mkdir -p "${TESTDIR}/etc" "${TESTDIR}/run" && chmod 750 "${TESTDIR}/run" \
|| die "Failed to create temporary FS structure for the NIT"
stop_daemons() {
if [ -n "$PID_UPSD$PID_DUMMYUPS$PID_DUMMYUPS1$PID_DUMMYUPS2" ] ; then
log_info "Stopping test daemons"
kill -15 $PID_UPSD $PID_DUMMYUPS $PID_DUMMYUPS1 $PID_DUMMYUPS2 2>/dev/null
fi
}
trap 'RES=$?; stop_daemons; if [ "${TESTDIR}" != "${BUILDDIR}/tmp" ] ; then rm -rf "${TESTDIR}" ; fi; exit $RES;' 0 1 2 3 15
NUT_STATEPATH="${TESTDIR}/run"
NUT_ALTPIDPATH="${TESTDIR}/run"
NUT_CONFPATH="${TESTDIR}/etc"
export NUT_STATEPATH NUT_ALTPIDPATH NUT_CONFPATH
# TODO: Find a portable way to (check and) grab a random unprivileged port?
[ -n "${NUT_PORT-}" ] && [ "$NUT_PORT" -gt 0 ] && [ "$NUT_PORT" -lt 65536 ] \
|| {
DELTA1="`date +%S`" || DELTA1=0
DELTA2="`expr $$ % 99`" || DELTA2=0
NUT_PORT="`expr 34931 + $DELTA1 + $DELTA2`" \
&& [ "$NUT_PORT" -gt 0 ] && [ "$NUT_PORT" -lt 65536 ] \
|| NUT_PORT=34931
}
export NUT_PORT
### upsd.conf: ##################################################
generatecfg_upsd_trivial() {
# Populate the configs for the run
cat > "$NUT_CONFPATH/upsd.conf" << EOF
STATEPATH "$NUT_STATEPATH"
LISTEN localhost $NUT_PORT
EOF
[ $? = 0 ] || die "Failed to populate temporary FS structure for the NIT: upsd.conf"
chmod 640 "$NUT_CONFPATH/upsd.conf"
# Some systems listining on symbolic "localhost" actually
# only bind to IPv6, and Python telnetlib resolves IPv4
# and fails its connection tests. Others fare well with
# both addresses in one command.
for LH in 127.0.0.1 '::1' ; do
if (
( cat /etc/hosts || getent hosts ) | grep "$LH" \
|| ping -c 1 "$LH"
) 2>/dev/null >/dev/null ; then
echo "LISTEN $LH $NUT_PORT" >> "$NUT_CONFPATH/upsd.conf"
fi
done
if [ -n "${NUT_DEBUG_MIN-}" ] ; then
echo "DEBUG_MIN ${NUT_DEBUG_MIN}" >> "$NUT_CONFPATH/upsd.conf" || exit
fi
}
generatecfg_upsd_nodev() {
generatecfg_upsd_trivial
echo "ALLOW_NO_DEVICE true" >> "$NUT_CONFPATH/upsd.conf" \
|| die "Failed to populate temporary FS structure for the NIT: upsd.conf"
}
### upsd.users: ##################################################
TESTPASS_ADMIN='mypass'
TESTPASS_TESTER='pass words'
TESTPASS_UPSMON_PRIMARY='P@ssW0rdAdm'
TESTPASS_UPSMON_SECONDARY='P@ssW0rd'
generatecfg_upsdusers_trivial() {
cat > "$NUT_CONFPATH/upsd.users" << EOF
[admin]
password = $TESTPASS_ADMIN
actions = SET
instcmds = ALL
[tester]
password = "${TESTPASS_TESTER}"
instcmds = test.battery.start
instcmds = test.battery.stop
[dummy-admin-m]
password = "${TESTPASS_UPSMON_PRIMARY}"
upsmon master
[dummy-admin]
password = "${TESTPASS_UPSMON_PRIMARY}"
upsmon primary
[dummy-user-s]
password = "${TESTPASS_UPSMON_SECONDARY}"
upsmon slave
[dummy-user]
password = "${TESTPASS_UPSMON_SECONDARY}"
upsmon secondary
EOF
[ $? = 0 ] || die "Failed to populate temporary FS structure for the NIT: upsd.users"
chmod 640 "$NUT_CONFPATH/upsd.users"
}
### upsmon.conf: ##################################################
generatecfg_upsmon_trivial() {
# Populate the configs for the run
( echo 'MINSUPPLIES 0' > "$NUT_CONFPATH/upsmon.conf" || exit
echo 'SHUTDOWNCMD "echo TESTING_DUMMY_SHUTDOWN_NOW"' >> "$NUT_CONFPATH/upsmon.conf" || exit
if [ -n "${NUT_DEBUG_MIN-}" ] ; then
echo "DEBUG_MIN ${NUT_DEBUG_MIN}" >> "$NUT_CONFPATH/upsmon.conf" || exit
fi
) || die "Failed to populate temporary FS structure for the NIT: upsmon.conf"
chmod 640 "$NUT_CONFPATH/upsmon.conf"
}
generatecfg_upsmon_master() {
generatecfg_upsmon_trivial
echo "MONITOR 'dummy@localhost:$NUT_PORT' 0 'dummy-admin-m' '${TESTPASS_UPSMON_PRIMARY}' master" >> "$NUT_CONFPATH/upsmon.conf" \
|| die "Failed to populate temporary FS structure for the NIT: upsmon.conf"
}
generatecfg_upsmon_primary() {
generatecfg_upsmon_trivial
echo "MONITOR 'dummy@localhost:$NUT_PORT' 0 'dummy-admin' '${TESTPASS_UPSMON_PRIMARY}' primary" >> "$NUT_CONFPATH/upsmon.conf" \
|| die "Failed to populate temporary FS structure for the NIT: upsmon.conf"
}
generatecfg_upsmon_slave() {
generatecfg_upsmon_trivial
echo "MONITOR 'dummy@localhost:$NUT_PORT' 0 'dummy-user-s' '${TESTPASS_UPSMON_SECONDARY}' slave" >> "$NUT_CONFPATH/upsmon.conf" \
|| die "Failed to populate temporary FS structure for the NIT: upsmon.conf"
}
generatecfg_upsmon_secondary() {
generatecfg_upsmon_trivial
echo "MONITOR 'dummy@localhost:$NUT_PORT' 0 'dummy-user' '${TESTPASS_UPSMON_SECONDARY}' secondary" >> "$NUT_CONFPATH/upsmon.conf" \
|| die "Failed to populate temporary FS structure for the NIT: upsmon.conf"
}
### ups.conf: ##################################################
generatecfg_ups_trivial() {
# Populate the configs for the run
( echo 'maxretry = 3' > "$NUT_CONFPATH/ups.conf" || exit
if [ x"${TOP_BUILDDIR}" != x ]; then
echo "driverpath = '${TOP_BUILDDIR}/drivers'" >> "$NUT_CONFPATH/ups.conf" || exit
fi
if [ -n "${NUT_DEBUG_MIN-}" ] ; then
echo "debug_min = ${NUT_DEBUG_MIN}" >> "$NUT_CONFPATH/ups.conf" || exit
fi
) || die "Failed to populate temporary FS structure for the NIT: ups.conf"
chmod 640 "$NUT_CONFPATH/ups.conf"
}
generatecfg_ups_dummy() {
generatecfg_ups_trivial
cat > "$NUT_CONFPATH/dummy.seq" << EOF
ups.status: OB
TIMER 5
ups.status: OL
TIMER 5
EOF
[ $? = 0 ] || die "Failed to populate temporary FS structure for the NIT: dummy.seq"
cat >> "$NUT_CONFPATH/ups.conf" << EOF
[dummy]
driver = dummy-ups
desc = "Crash Dummy"
port = dummy.seq
#mode = dummy-loop
EOF
[ $? = 0 ] || die "Failed to populate temporary FS structure for the NIT: ups.conf"
if [ x"${TOP_SRCDIR}" != x ]; then
cp "${TOP_SRCDIR}/data/evolution500.seq" "${TOP_SRCDIR}/data/epdu-managed.dev" "$NUT_CONFPATH/"
cat >> "$NUT_CONFPATH/ups.conf" << EOF
[UPS1]
driver = dummy-ups
desc = "Example event sequence"
port = evolution500.seq
[UPS2]
driver = dummy-ups
desc = "Example ePDU data dump"
port = epdu-managed.dev
mode = dummy-once
EOF
[ $? = 0 ] || die "Failed to populate temporary FS structure for the NIT: ups.conf"
# HACK: Avoid empty ups.status that may be present in example docs
# FIXME: Might we actually want that value (un-)set for tests?..
# TODO: Check if the problem was with dummy-ups looping? [#1385]
for F in "$NUT_CONFPATH/"*.dev "$NUT_CONFPATH/"*.seq ; do
sed -e 's,^ups.status: *$,ups.status: OL BOOST,' -i'.bak' "$F"
grep -E '^ups.status:' "$F" >/dev/null || { echo "ups.status: OL BOOST" >> "$F"; }
done
fi
}
#####################################################
isPidAlive() {
[ -n "$1" ] && [ "$1" -gt 0 ] || return
[ -d "/proc/$1" ] || kill -0 "$1" 2>/dev/null
}
FAILED=0
PASSED=0
testcase_upsd_no_configs_at_all() {
log_separator
log_info "Test UPSD without configs at all"
upsd -F
if [ "$?" = 0 ]; then
log_error "upsd should fail without configs"
FAILED="`expr $FAILED + 1`"
else
log_info "OK, upsd failed to start in wrong conditions"
PASSED="`expr $PASSED + 1`"
fi
}
testcase_upsd_no_configs_driver_file() {
log_separator
log_info "Test UPSD without driver config file"
generatecfg_upsd_trivial
upsd -F
if [ "$?" = 0 ]; then
log_error "upsd should fail without driver config file"
FAILED="`expr $FAILED + 1`"
else
log_info "OK, upsd failed to start in wrong conditions"
PASSED="`expr $PASSED + 1`"
fi
}
testcase_upsd_no_configs_in_driver_file() {
log_separator
log_info "Test UPSD without drivers defined in config file"
generatecfg_upsd_trivial
generatecfg_ups_trivial
upsd -F
if [ "$?" = 0 ]; then
log_error "upsd should fail without drivers defined in config file"
FAILED="`expr $FAILED + 1`"
else
log_info "OK, upsd failed to start in wrong conditions"
PASSED="`expr $PASSED + 1`"
fi
}
testcase_upsd_allow_no_device() {
log_separator
log_info "Test UPSD allowed to run without driver configs"
generatecfg_upsd_nodev
generatecfg_upsdusers_trivial
generatecfg_ups_trivial
upsd -F &
PID_UPSD="$!"
sleep 2
if isPidAlive "$PID_UPSD"; then
log_info "OK, upsd is running"
PASSED="`expr $PASSED + 1`"
log_separator
log_info "Test that UPSD responds to UPSC"
OUT="`upsc -l localhost:$NUT_PORT`" || die "upsd does not respond: $OUT"
if [ -n "$OUT" ] ; then
log_error "got reply for upsc listing when none was expected: $OUT"
FAILED="`expr $FAILED + 1`"
else
log_info "OK, empty response as expected"
PASSED="`expr $PASSED + 1`"
fi
else
log_error "upsd was expected to be running although no devices are defined"
FAILED="`expr $FAILED + 1`"
fi
kill -15 $PID_UPSD
wait $PID_UPSD
}
testgroup_upsd_invalid_configs() {
testcase_upsd_no_configs_at_all
testcase_upsd_no_configs_driver_file
testcase_upsd_no_configs_in_driver_file
}
testgroup_upsd_questionable_configs() {
testcase_upsd_allow_no_device
}
#########################################################
### Tests in a common sandbox with driver(s) + server ###
#########################################################
SANDBOX_CONFIG_GENERATED=false
sandbox_generate_configs() {
if $SANDBOX_CONFIG_GENERATED ; then return ; fi
log_info "Generating configs for sandbox"
generatecfg_upsd_nodev
generatecfg_upsdusers_trivial
generatecfg_ups_dummy
SANDBOX_CONFIG_GENERATED=true
}
sandbox_forget_configs() {
SANDBOX_CONFIG_GENERATED=false
if [ -z "${DEBUG_SLEEP-}" ] ; then
stop_daemons
fi
}
sandbox_start_upsd() {
if isPidAlive "$PID_UPSD" ; then
return 0
fi
sandbox_generate_configs
log_info "Starting UPSD for sandbox"
upsd -F &
PID_UPSD="$!"
sleep 5
}
sandbox_start_drivers() {
if isPidAlive "$PID_DUMMYUPS" \
&& { [ x"${TOP_SRCDIR}" != x ] && isPidAlive "$PID_DUMMYUPS1" && isPidAlive "$PID_DUMMYUPS2" \
|| [ x"${TOP_SRCDIR}" = x ] ; } \
; then
# All drivers expected for this environment are already running
return 0
fi
sandbox_generate_configs
log_info "Starting dummy-ups driver(s) for sandbox"
#upsdrvctl -F start dummy &
dummy-ups -a dummy -F &
PID_DUMMYUPS="$!"
if [ x"${TOP_SRCDIR}" != x ]; then
dummy-ups -a UPS1 -F &
PID_DUMMYUPS1="$!"
dummy-ups -a UPS2 -F &
PID_DUMMYUPS2="$!"
fi
sleep 5
if shouldDebug ; then
(ps -ef || ps -xawwu) 2>/dev/null | grep -E '(ups|nut|dummy)' || true
fi
}
testcase_sandbox_start_upsd_alone() {
log_separator
log_info "Test starting UPSD but not a driver before it"
sandbox_start_upsd
EXPECTED_UPSLIST='dummy'
if [ x"${TOP_SRCDIR}" != x ]; then
EXPECTED_UPSLIST="$EXPECTED_UPSLIST
UPS1
UPS2"
fi
log_info "Query listing from UPSD by UPSC (driver not running yet)"
OUT="`upsc -l localhost:$NUT_PORT`" || die "upsd does not respond: $OUT"
if [ x"$OUT" != x"$EXPECTED_UPSLIST" ] ; then
log_error "got this reply for upsc listing when '$EXPECTED_UPSLIST' was expected: $OUT"
FAILED="`expr $FAILED + 1`"
else
PASSED="`expr $PASSED + 1`"
fi
log_info "Query driver state from UPSD by UPSC (driver not running yet)"
OUT="`upsc dummy@localhost:$NUT_PORT 2>&1`" && {
log_error "upsc was supposed to answer with error exit code: $OUT"
FAILED="`expr $FAILED + 1`"
}
if ! echo "$OUT" | grep 'Error: Driver not connected' ; then
log_error "got reply for upsc query when 'Error: Driver not connected' was expected: '$OUT'"
FAILED="`expr $FAILED + 1`"
else
PASSED="`expr $PASSED + 1`"
fi
}
testcase_sandbox_start_upsd_after_drivers() {
# Historically this is a fallback from testcase_sandbox_start_drivers_after_upsd
kill -15 $PID_UPSD 2>/dev/null
wait $PID_UPSD
upsd -F &
PID_UPSD="$!"
sandbox_start_drivers
sandbox_start_upsd
sleep 5
upsc dummy@localhost:$NUT_PORT || die "upsd does not respond"
}
testcase_sandbox_start_drivers_after_upsd() {
#sandbox_start_upsd
testcase_sandbox_start_upsd_alone
sandbox_start_drivers
log_info "Query driver state from UPSD by UPSC after driver startup"
upsc dummy@localhost:$NUT_PORT || {
# Should not get to this, except on very laggy systems maybe
log_error "Query failed, retrying with UPSD started after drivers"
testcase_sandbox_start_upsd_after_drivers
}
if [ x"${TOP_SRCDIR}" != x ]; then
log_info "Wait for dummy UPSes with larger data sets to initialize"
for U in UPS1 UPS2 ; do
COUNTDOWN=60
while ! upsc $U@localhost:$NUT_PORT ups.status ; do
sleep 1
COUNTDOWN="`expr $COUNTDOWN - 1`"
# Systemic error, e.g. could not create socket file?
[ "$COUNTDOWN" -lt 1 ] && die "Dummy driver did not start or respond in time"
done
done
fi
log_info "Expected drivers are now responding via UPSD"
}
testcase_sandbox_upsc_query_model() {
OUT="`upsc dummy@localhost:$NUT_PORT device.model`" || die "upsd does not respond: $OUT"
if [ x"$OUT" != x"Dummy UPS" ] ; then
log_error "got this reply for upsc query when 'Dummy UPS' was expected: $OUT"
FAILED="`expr $FAILED + 1`"
else
PASSED="`expr $PASSED + 1`"
fi
}
testcase_sandbox_upsc_query_bogus() {
log_info "Query driver state from UPSD by UPSC for bogus info"
OUT="`upsc dummy@localhost:$NUT_PORT ups.bogus.value 2>&1`" && {
log_error "upsc was supposed to answer with error exit code: $OUT"
FAILED="`expr $FAILED + 1`"
}
if ! echo "$OUT" | grep 'Error: Variable not supported by UPS' ; then
log_error "got reply for upsc query when 'Error: Variable not supported by UPS' was expected: $OUT"
FAILED="`expr $FAILED + 1`"
else
PASSED="`expr $PASSED + 1`"
fi
}
testcase_sandbox_upsc_query_timer() {
log_separator
log_info "Test that dummy-ups TIMER action changes the reported state"
# Driver is set up to flip ups.status every 5 sec, so check every 3
OUT1="`upsc dummy@localhost:$NUT_PORT ups.status`" || die "upsd does not respond: $OUT1" ; sleep 3
OUT2="`upsc dummy@localhost:$NUT_PORT ups.status`" || die "upsd does not respond: $OUT2"
OUT3=""
OUT4=""
if [ x"$OUT1" = x"$OUT2" ]; then
sleep 3
OUT3="`upsc dummy@localhost:$NUT_PORT ups.status`" || die "upsd does not respond: $OUT3"
if [ x"$OUT2" = x"$OUT3" ]; then
sleep 3
OUT4="`upsc dummy@localhost:$NUT_PORT ups.status`" || die "upsd does not respond: $OUT4"
fi
fi
if echo "$OUT1$OUT2$OUT3$OUT4" | grep "OB" && echo "$OUT1$OUT2$OUT3$OUT4" | grep "OL" ; then
log_info "OK, ups.status flips over time"
PASSED="`expr $PASSED + 1`"
else
log_error "ups.status did not flip over time"
FAILED="`expr $FAILED + 1`"
fi
}
isTestablePython() {
# We optionally make python module (if interpreter is found):
if [ x"${TOP_BUILDDIR}" = x ] \
|| [ ! -x "${TOP_BUILDDIR}/scripts/python/module/test_nutclient.py" ] \
; then
return 1
fi
return 0
}
testcase_sandbox_python_without_credentials() {
isTestablePython || return 0
log_separator
log_info "Call Python module test suite: PyNUT (NUT Python bindings) without login credentials"
if ( unset NUT_USER || true
unset NUT_PASS || true
"${TOP_BUILDDIR}/scripts/python/module/test_nutclient.py"
) ; then
log_info "OK, PyNUT did not complain"
PASSED="`expr $PASSED + 1`"
else
log_error "PyNUT complained, check above"
FAILED="`expr $FAILED + 1`"
fi
}
testcase_sandbox_python_with_credentials() {
isTestablePython || return 0
# That script says it expects data/evolution500.seq (as the UPS1 dummy)
# but the dummy data does not currently let issue the commands and
# setvars tested from python script.
log_separator
log_info "Call Python module test suite: PyNUT (NUT Python bindings) with login credentials"
if (
NUT_USER='admin'
NUT_PASS="${TESTPASS_ADMIN}"
export NUT_USER NUT_PASS
"${TOP_BUILDDIR}/scripts/python/module/test_nutclient.py"
) ; then
log_info "OK, PyNUT did not complain"
PASSED="`expr $PASSED + 1`"
else
log_error "PyNUT complained, check above"
FAILED="`expr $FAILED + 1`"
fi
}
testcases_sandbox_python() {
isTestablePython || return 0
testcase_sandbox_python_without_credentials
testcase_sandbox_python_with_credentials
}
####################################
isTestableCppNIT() {
# We optionally make and here can run C++ client tests:
if [ x"${TOP_BUILDDIR}" = x ] \
|| [ ! -x "${TOP_BUILDDIR}/tests/cppnit" ] \
; then
return 1
fi
return 0
}
testcase_sandbox_cppnit_without_creds() {
isTestableCppNIT || return 0
log_separator
log_info "Call libnutclient test suite: cppnit without login credentials"
if ( unset NUT_USER || true
unset NUT_PASS || true
"${TOP_BUILDDIR}/tests/cppnit"
) ; then
log_info "OK, cppnit did not complain"
PASSED="`expr $PASSED + 1`"
else
log_error "cppnit complained, check above"
FAILED="`expr $FAILED + 1`"
fi
}
testcase_sandbox_cppnit_simple_admin() {
isTestableCppNIT || return 0
log_separator
log_info "Call libnutclient test suite: cppnit with login credentials: simple admin"
if (
NUT_USER='admin'
NUT_PASS="${TESTPASS_ADMIN}"
if [ x"${TOP_SRCDIR}" != x ]; then
# Avoid dummies with TIMER flip-flops
NUT_SETVAR_DEVICE='UPS2'
else
# Risks failure when lauching sub-test at the wrong second
NUT_SETVAR_DEVICE='dummy'
fi
unset NUT_PRIMARY_DEVICE
export NUT_USER NUT_PASS NUT_SETVAR_DEVICE
"${TOP_BUILDDIR}/tests/cppnit"
) ; then
log_info "OK, cppnit did not complain"
PASSED="`expr $PASSED + 1`"
else
log_error "cppnit complained, check above"
FAILED="`expr $FAILED + 1`"
fi
}
testcase_sandbox_cppnit_upsmon_primary() {
isTestableCppNIT || return 0
log_separator
log_info "Call libnutclient test suite: cppnit with login credentials: upsmon-primary"
if (
NUT_USER='dummy-admin'
NUT_PASS="${TESTPASS_UPSMON_PRIMARY}"
NUT_PRIMARY_DEVICE='dummy'
unset NUT_SETVAR_DEVICE
export NUT_USER NUT_PASS NUT_PRIMARY_DEVICE
"${TOP_BUILDDIR}/tests/cppnit"
) ; then
log_info "OK, cppnit did not complain"
PASSED="`expr $PASSED + 1`"
else
log_error "cppnit complained, check above"
FAILED="`expr $FAILED + 1`"
fi
}
testcase_sandbox_cppnit_upsmon_master() {
isTestableCppNIT || return 0
log_separator
log_info "Call libnutclient test suite: cppnit with login credentials: upsmon-master"
if (
NUT_USER='dummy-admin-m'
NUT_PASS="${TESTPASS_UPSMON_PRIMARY}"
NUT_PRIMARY_DEVICE='dummy'
unset NUT_SETVAR_DEVICE
export NUT_USER NUT_PASS NUT_PRIMARY_DEVICE
"${TOP_BUILDDIR}/tests/cppnit"
) ; then
log_info "OK, cppnit did not complain"
PASSED="`expr $PASSED + 1`"
else
log_error "cppnit complained, check above"
FAILED="`expr $FAILED + 1`"
fi
}
testcases_sandbox_cppnit() {
isTestableCppNIT || return 0
testcase_sandbox_cppnit_without_creds
testcase_sandbox_cppnit_upsmon_primary
testcase_sandbox_cppnit_upsmon_master
testcase_sandbox_cppnit_simple_admin
}
# TODO: Some upsmon tests?
testgroup_sandbox() {
testcase_sandbox_start_drivers_after_upsd
testcase_sandbox_upsc_query_model
testcase_sandbox_upsc_query_bogus
testcase_sandbox_upsc_query_timer
testcases_sandbox_python
testcases_sandbox_cppnit
sandbox_forget_configs
}
testgroup_sandbox_python() {
# Arrange for quick test iterations
testcase_sandbox_start_drivers_after_upsd
testcases_sandbox_python
sandbox_forget_configs
}
testgroup_sandbox_cppnit() {
# Arrange for quick test iterations
testcase_sandbox_start_drivers_after_upsd
testcases_sandbox_cppnit
sandbox_forget_configs
}
testgroup_sandbox_cppnit_simple_admin() {
# Arrange for quick test iterations
testcase_sandbox_start_drivers_after_upsd
testcase_sandbox_cppnit_simple_admin
sandbox_forget_configs
}
################################################################
case "${NIT_CASE}" in
cppnit) testgroup_sandbox_cppnit ;;
python) testgroup_sandbox_python ;;
testcase_*|testgroup_*|testcases_*|testgroups_*)
"${NIT_CASE}" ;;
"") # Default test groups:
testgroup_upsd_invalid_configs
testgroup_upsd_questionable_configs
testgroup_sandbox
;;
*) die "Unsupported NIT_CASE='$NIT_CASE' was requested" ;;
esac
log_separator
log_info "OVERALL: PASSED=$PASSED FAILED=$FAILED"
# Allow to leave the sandbox daemons running for a while,
# to experiment with them interactively:
if [ -n "${DEBUG_SLEEP-}" ] ; then
log_separator
log_info "Sleeping now as asked, so you can play with the driver and server running; hint: export NUT_PORT=$NUT_PORT"
log_separator
if [ "${DEBUG_SLEEP-}" -gt 0 ] ; then
sleep "${DEBUG_SLEEP}"
else
sleep 60
fi
log_info "Sleep finished"
log_separator
fi
if [ "$PASSED" = 0 ] || [ "$FAILED" != 0 ] ; then
die "Some test scenarios failed!"
else
log_info "SUCCESS"
fi