315 lines
12 KiB
Bash
315 lines
12 KiB
Bash
|
#!/bin/sh
|
||
|
|
||
|
# Copyright (C) 2018 Eaton
|
||
|
#
|
||
|
# This program is free software; you can redistribute it and/or modify
|
||
|
# it under the terms of the GNU General Public License as published by
|
||
|
# the Free Software Foundation; either version 2 of the License, or
|
||
|
# (at your option) any later version.
|
||
|
#
|
||
|
# This program is distributed in the hope that it will be useful,
|
||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
# GNU General Public License for more details.
|
||
|
#
|
||
|
# You should have received a copy of the GNU General Public License along
|
||
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||
|
#
|
||
|
#! \file nut-driver-enumerator-test.sh
|
||
|
# \author Jim Klimov <EvgenyKlimov@eaton.com>
|
||
|
# \brief Self-test for nut-driver-enumerator.sh utility
|
||
|
# \details Automated sanity test for nut-driver-enumerator.sh(.in)
|
||
|
# using different shells (per $SHELL_PROGS) and CLI requests
|
||
|
# for regression and compatibility tests as well as for TDD
|
||
|
# fueled by pre-decided expected outcomes.
|
||
|
|
||
|
### Use a standard locale setup so sorting in expected results is not confused
|
||
|
LANG=C
|
||
|
LC_ALL=C
|
||
|
TZ=UTC
|
||
|
export LANG LC_ALL TZ
|
||
|
|
||
|
### Note: These are relative to where the selftest script lives,
|
||
|
### not the NUT top_srcdir etc. They can be exported by a Makefile.
|
||
|
[ -n "${BUILDDIR-}" ] || BUILDDIR="`dirname $0`"
|
||
|
[ -n "${SRCDIR-}" ] || SRCDIR="`dirname $0`"
|
||
|
[ -n "${SHELL_PROGS-}" ] || SHELL_PROGS="/bin/sh"
|
||
|
case "${DEBUG-}" in
|
||
|
[Yy]|[Yy][Ee][Ss]) DEBUG=yes ;;
|
||
|
[Tt][Rr][Aa][Cc][Ee]) DEBUG=trace ;;
|
||
|
*) DEBUG="" ;;
|
||
|
esac
|
||
|
|
||
|
SYSTEMD_CONFPATH="${BUILDDIR}/selftest-rw/systemd-units"
|
||
|
export SYSTEMD_CONFPATH
|
||
|
|
||
|
NUT_CONFPATH="${BUILDDIR}/selftest-rw/nut"
|
||
|
export NUT_CONFPATH
|
||
|
|
||
|
[ -n "${UPSCONF-}" ] || UPSCONF="${SRCDIR}/nut-driver-enumerator-test--ups.conf"
|
||
|
[ ! -s "${UPSCONF-}" ] && echo "FATAL : testing ups.conf not found as '$UPSCONF'" >&2 && exit 1
|
||
|
export UPSCONF
|
||
|
|
||
|
if [ ! -n "${NDE-}" ] ; then
|
||
|
for NDE in \
|
||
|
"${BUILDDIR}/../scripts/upsdrvsvcctl/nut-driver-enumerator.sh" \
|
||
|
"${SRCDIR}/../scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in" \
|
||
|
; do [ -s "$NDE" ] && break ; done
|
||
|
fi
|
||
|
[ ! -s "${NDE-}" ] && echo "FATAL : testing nut-driver-enumerator.sh implementation not found as '$NDE'" >&2 && exit 1
|
||
|
|
||
|
# TODO : Add tests that generate configuration files for units
|
||
|
#mkdir -p "${NUT_CONFPATH}" "${SYSTEMD_CONFPATH}" || exit
|
||
|
|
||
|
FAIL_COUNT=0
|
||
|
GOOD_COUNT=0
|
||
|
callNDE() {
|
||
|
case "$DEBUG" in
|
||
|
yes) time $USE_SHELL $NDE "$@" ;;
|
||
|
trace) time $USE_SHELL -x $NDE "$@" ;;
|
||
|
*) $USE_SHELL $NDE "$@" 2>/dev/null ;;
|
||
|
esac
|
||
|
}
|
||
|
|
||
|
run_testcase() {
|
||
|
# First 3 args are required as defined below; the rest are
|
||
|
# CLI arg(s) to nut-driver-enumerator.sh
|
||
|
CASE_DESCR="$1"
|
||
|
EXPECT_CODE="$2"
|
||
|
EXPECT_TEXT="$3"
|
||
|
shift 3
|
||
|
|
||
|
printf "Testing : SHELL='%s'\tCASE='%s'\t" "$USE_SHELL" "$CASE_DESCR"
|
||
|
OUT="`callNDE "$@"`" ; RESCODE=$?
|
||
|
printf "Got : RESCODE='%s'\t" "$RESCODE"
|
||
|
|
||
|
RES=0
|
||
|
if [ "$RESCODE" = "$EXPECT_CODE" ]; then
|
||
|
printf "STATUS_CODE='MATCHED'\t"
|
||
|
GOOD_COUNT="`expr $GOOD_COUNT + 1`"
|
||
|
else
|
||
|
printf "STATUS_CODE='MISMATCH' expect_code=%s received_code=%s\t" "$EXPECT_CODE" "$RESCODE" >&2
|
||
|
FAIL_COUNT="`expr $FAIL_COUNT + 1`"
|
||
|
RES="`expr $RES + 1`"
|
||
|
fi
|
||
|
|
||
|
if [ "$OUT" = "$EXPECT_TEXT" ]; then
|
||
|
printf "STATUS_TEXT='MATCHED'\n"
|
||
|
GOOD_COUNT="`expr $GOOD_COUNT + 1`"
|
||
|
else
|
||
|
printf "STATUS_TEXT='MISMATCH'\n"
|
||
|
printf '\t--- expected ---\n%s\n\t--- received ---\n%s\n\t--- MISMATCH ABOVE\n\n' "$EXPECT_TEXT" "$OUT" >&2
|
||
|
# Give a nice output to help track the problem:
|
||
|
( rm -f "/tmp/.nde.text.expected.$$" "/tmp/.nde.text.actual.$$" \
|
||
|
&& echo "$EXPECT_TEXT" > "/tmp/.nde.text.expected.$$" \
|
||
|
&& echo "$OUT" > "/tmp/.nde.text.actual.$$" \
|
||
|
&& diff -u "/tmp/.nde.text.expected.$$" "/tmp/.nde.text.actual.$$" ) 2>/dev/null || true
|
||
|
rm -f "/tmp/.nde.text.expected.$$" "/tmp/.nde.text.actual.$$"
|
||
|
FAIL_COUNT="`expr $FAIL_COUNT + 1`"
|
||
|
RES="`expr $RES + 2`"
|
||
|
fi
|
||
|
if [ "$RES" != 0 ] || [ -n "$DEBUG" ] ; then echo "" ; fi
|
||
|
return $RES
|
||
|
}
|
||
|
|
||
|
##################################################################
|
||
|
# Note: expectations in test cases below are tightly connected #
|
||
|
# to both the current code in the script and content of the test #
|
||
|
# configuration file. #
|
||
|
##################################################################
|
||
|
|
||
|
testcase_bogus_args() {
|
||
|
run_testcase "Reject unknown args" 1 "" \
|
||
|
--some-bogus-arg
|
||
|
}
|
||
|
|
||
|
testcase_list_all_devices() {
|
||
|
# We expect a list of unbracketed names from the device sections
|
||
|
# Note: unlike other outputs, this list is alphabetically sorted
|
||
|
run_testcase "List all device names from sections" 0 \
|
||
|
"dummy-proxy
|
||
|
dummy-proxy-localhost
|
||
|
dummy1
|
||
|
epdu-2
|
||
|
epdu-2-snmp
|
||
|
qx-serial
|
||
|
qx-usb1
|
||
|
qx-usb2
|
||
|
sectionWithComment
|
||
|
sectionWithCommentWhitespace
|
||
|
serial.4
|
||
|
usb_3
|
||
|
valueHasEquals
|
||
|
valueHasHashtag
|
||
|
valueHasQuotedHashtag" \
|
||
|
--list-devices
|
||
|
}
|
||
|
|
||
|
testcase_show_all_configs() {
|
||
|
# We expect whitespace trimmed, comment-only lines removed
|
||
|
run_testcase "Show all configs" 0 \
|
||
|
'maxstartdelay=180
|
||
|
globalflag
|
||
|
[dummy1]
|
||
|
driver=dummy-ups
|
||
|
port=file1.dev
|
||
|
desc="This is ups-1"
|
||
|
[epdu-2]
|
||
|
driver=netxml-ups
|
||
|
port=http://172.16.1.2
|
||
|
synchronous=yes
|
||
|
[epdu-2-snmp]
|
||
|
driver=snmp-ups
|
||
|
port=172.16.1.2
|
||
|
synchronous=no
|
||
|
[usb_3]
|
||
|
driver=usbhid-ups
|
||
|
port=auto
|
||
|
[serial.4]
|
||
|
driver=serial-ups
|
||
|
driverflag
|
||
|
port=/dev/ttyS1 # some path
|
||
|
[dummy-proxy]
|
||
|
driver="dummy-ups "
|
||
|
port=remoteUPS@RemoteHost.local
|
||
|
[dummy-proxy-localhost]
|
||
|
driver='"'dummy-ups '"'
|
||
|
port=localUPS@127.0.0.1
|
||
|
[valueHasEquals]
|
||
|
driver=dummy=ups
|
||
|
port=file1.dev # key = val, right?
|
||
|
[valueHasHashtag]
|
||
|
driver=dummy-ups
|
||
|
port=file#1.dev
|
||
|
[valueHasQuotedHashtag]
|
||
|
driver=dummy-ups
|
||
|
port=file#1.dev
|
||
|
[qx-serial]
|
||
|
driver=nutdrv_qx
|
||
|
port=/dev/ttyb
|
||
|
[qx-usb1]
|
||
|
driver=nutdrv_qx
|
||
|
port=auto
|
||
|
[qx-usb2]
|
||
|
driver=nutdrv_qx
|
||
|
port=/dev/usb/8
|
||
|
[sectionWithComment]
|
||
|
driver=nutdrv_qx#comment
|
||
|
port=/dev/usb/8
|
||
|
desc="value with [brackets]"
|
||
|
[brackets with spaces are not sections] # but rather an invalid mess as binary parser may think
|
||
|
[sectionWithCommentWhitespace]
|
||
|
driver=nutdrv_qx # comment
|
||
|
port=/dev/usb/8 # comment
|
||
|
commentedDriverFlag # This flag gotta mean something' \
|
||
|
--show-all-configs
|
||
|
}
|
||
|
|
||
|
testcase_upslist_debug() {
|
||
|
# We expect a list of names, ports and decided MEDIA type (for dependencies)
|
||
|
run_testcase "List decided MEDIA and config checksums for all devices" 0 \
|
||
|
"INST: 68b329da9893e34099c7d8ad5cb9c940~[]: DRV='' PORT='' MEDIA='' SECTIONMD5='9a1f372a850f1ee3ab1fc08b185783e0'
|
||
|
INST: 010cf0aed6dd49865bb49b70267946f5~[dummy-proxy]: DRV='dummy-ups ' PORT='remoteUPS@RemoteHost.local' MEDIA='network' SECTIONMD5='aff543fc07d7fbf83e81001b181c8b97'
|
||
|
INST: 1ea79c6eea3681ba73cc695f3253e605~[dummy-proxy-localhost]: DRV='dummy-ups ' PORT='localUPS@127.0.0.1' MEDIA='network-localhost' SECTIONMD5='73e6b7e3e3b73558dc15253d8cca51b2'
|
||
|
INST: 76b645e28b0b53122b4428f4ab9eb4b9~[dummy1]: DRV='dummy-ups' PORT='file1.dev' MEDIA='' SECTIONMD5='9e0a326b67e00d455494f8b4258a01f1'
|
||
|
INST: a293d65e62e89d6cc3ac6cb88bc312b8~[epdu-2]: DRV='netxml-ups' PORT='http://172.16.1.2' MEDIA='network' SECTIONMD5='0d9a0147dcf87c7c720e341170f69ed4'
|
||
|
INST: 9a5561464ff8c78dd7cb544740ce2adc~[epdu-2-snmp]: DRV='snmp-ups' PORT='172.16.1.2' MEDIA='network' SECTIONMD5='2631b6c21140cea0dd30bb88b942ce3f'
|
||
|
INST: 16adbdafb22d9fdff1d09038520eb32e~[qx-serial]: DRV='nutdrv_qx' PORT='/dev/ttyb' MEDIA='serial' SECTIONMD5='e3e6e586fbe5b3c0a89432f4b993f4ad'
|
||
|
INST: a21bd2b786228b9619f6adba6db8fa83~[qx-usb1]: DRV='nutdrv_qx' PORT='auto' MEDIA='usb' SECTIONMD5='a6139c5da35bef89dc5b96e2296f5369'
|
||
|
INST: 0066605e07c66043a17eccecbeea1ac5~[qx-usb2]: DRV='nutdrv_qx' PORT='/dev/usb/8' MEDIA='usb' SECTIONMD5='5722dd9c21d07a1f5bcb516dbc458deb'
|
||
|
INST: 1280a731e03116f77290e51dd2a2f37e~[sectionWithComment]: DRV='nutdrv_qx#comment' PORT='/dev/usb/8' MEDIA='' SECTIONMD5='be30e15e17d0579c85eecaf176b4a064'
|
||
|
INST: 770abd5659061a29ed3ae4f7c0b00915~[sectionWithCommentWhitespace]: DRV='nutdrv_qx # comment' PORT='/dev/usb/8 # comment' MEDIA='' SECTIONMD5='c757822a331521cdc97310d0241eba28'
|
||
|
INST: efdb1b4698215fdca36b9bc06d24661d~[serial.4]: DRV='serial-ups' PORT='/dev/ttyS1 # some path' MEDIA='' SECTIONMD5='9c485f733aa6d6c85c1724f162929443'
|
||
|
INST: f4a1c33db201c2ca897a3337993c10fc~[usb_3]: DRV='usbhid-ups' PORT='auto' MEDIA='usb' SECTIONMD5='1f6a24becde9bd31c9852610658ef84a'
|
||
|
INST: 8e5686f92a5ba11901996c813e7bb23d~[valueHasEquals]: DRV='dummy=ups' PORT='file1.dev # key = val, right?' MEDIA='' SECTIONMD5='2f04d65da53e3b13771bb65422f0f4c0'
|
||
|
INST: 99da99b1e301e84f34f349443aac545b~[valueHasHashtag]: DRV='dummy-ups' PORT='file#1.dev' MEDIA='' SECTIONMD5='6029bda216de0cf1e81bd55ebd4a0fff'
|
||
|
INST: d50c3281f9b68a94bf9df72a115fbb5c~[valueHasQuotedHashtag]: DRV='dummy-ups' PORT='file#1.dev' MEDIA='' SECTIONMD5='af59c3c0caaa68dcd796d7145ae403ee'" \
|
||
|
upslist_debug
|
||
|
|
||
|
# FIXME : in [valueHasEquals] and [serial.4] the PORT value is quite bogus
|
||
|
# with its embedded comments. Check vs. binary config parser, whether in
|
||
|
# unquoted case only first token is the valid value, and how comments are
|
||
|
# handled in general?
|
||
|
# FIXME : in [valueHasHashtag] the line after "#" should likely be dropped
|
||
|
# (check in binary config parser first) while in [valueHasQuotedHashtag]
|
||
|
# it should stay.
|
||
|
}
|
||
|
|
||
|
testcase_getValue() {
|
||
|
run_testcase "Query a configuration key (SDP)" 0 \
|
||
|
"file1.dev" \
|
||
|
--show-device-config-value dummy1 port
|
||
|
|
||
|
run_testcase "Query a configuration key (other)" 0 \
|
||
|
"yes" \
|
||
|
--show-device-config-value epdu-2 synchronous
|
||
|
|
||
|
run_testcase "Query a configuration key (originally quoted)" 0 \
|
||
|
'This is ups-1' \
|
||
|
--show-device-config-value dummy1 desc
|
||
|
|
||
|
run_testcase "Query a configuration flag (driver)" 0 \
|
||
|
"driverflag" \
|
||
|
--show-config-value 'serial.4' driverflag
|
||
|
|
||
|
run_testcase "Query a missing configuration flag (driver)" 1 \
|
||
|
"" \
|
||
|
--show-config-value 'valueHasQuotedHashtag' nosuchflag
|
||
|
|
||
|
run_testcase "Query multiple configuration keys (originally quoted)" 0 \
|
||
|
'This is ups-1
|
||
|
file1.dev' \
|
||
|
--show-device-config-value dummy1 desc port
|
||
|
|
||
|
run_testcase "Query multiple configuration keys with some missing (originally quoted)" 1 \
|
||
|
'This is ups-1
|
||
|
|
||
|
file1.dev' \
|
||
|
--show-device-config-value dummy1 desc unknownkey port
|
||
|
}
|
||
|
|
||
|
testcase_globalSection() {
|
||
|
run_testcase "Display global config" 0 \
|
||
|
"maxstartdelay=180
|
||
|
globalflag" \
|
||
|
--show-config ''
|
||
|
|
||
|
run_testcase "Query a configuration key (global)" 0 \
|
||
|
"180" \
|
||
|
--show-config-value '' maxstartdelay
|
||
|
|
||
|
run_testcase "Query a configuration flag (global)" 0 \
|
||
|
"globalflag" \
|
||
|
--show-config-value '' globalflag
|
||
|
|
||
|
run_testcase "Query a missing configuration flag (global)" 1 \
|
||
|
"" \
|
||
|
--show-config-value '' nosuchflag
|
||
|
}
|
||
|
|
||
|
|
||
|
# Combine the cases above into a stack
|
||
|
testsuite() {
|
||
|
testcase_bogus_args
|
||
|
testcase_list_all_devices
|
||
|
testcase_show_all_configs
|
||
|
testcase_getValue
|
||
|
testcase_globalSection
|
||
|
# This one can take a while, put it last
|
||
|
testcase_upslist_debug
|
||
|
}
|
||
|
|
||
|
# If no args...
|
||
|
for USE_SHELL in $SHELL_PROGS ; do
|
||
|
case "$USE_SHELL" in
|
||
|
busybox|busybox_sh) USE_SHELL="busybox sh" ;;
|
||
|
esac
|
||
|
testsuite
|
||
|
done
|
||
|
# End of loop over shells
|
||
|
|
||
|
echo "Test suite for nut-driver-enumerator has completed with $FAIL_COUNT failed cases and $GOOD_COUNT good cases" >&2
|
||
|
|
||
|
[ "$FAIL_COUNT" = 0 ] || { echo "As a developer, you may want to export DEBUG=trace or export DEBUG=yes and re-run the test; also make sure you meant the nut-driver-enumerator.sh implementation as NDE='$NDE'" >&2 ; exit 1; }
|