# Common variables and functions for CTDB unit tests.
+trap -- '' PIPE
+
# Set the required result for a test.
# - Argument 1 is exit code.
# - Argument 2, if present is the required test output but "--"
# indicates empty output.
# If argument 2 is not present or null then read required test output
# from stdin.
-required_result ()
+required_result()
{
- required_rc="${1:-0}"
- if [ -n "$2" ] ; then
- if [ "$2" = "--" ] ; then
- required_output=""
- else
- required_output="$2"
- fi
- else
- if ! tty -s ; then
- required_output=$(cat)
+ required_rc="${1:-0}"
+ if [ -n "$2" ]; then
+ if [ "$2" = "--" ]; then
+ required_output=""
+ else
+ # Use a sub-shell to strip trailing newlines.
+ # They can't be matched anyway because the
+ # test is run in a sub-shell, which strips
+ # trailing newlines.
+ # shellcheck disable=SC2116
+ required_output=$(echo "$2")
+ fi
else
- required_output=""
+ if ! tty -s; then
+ required_output=$(cat)
+ else
+ required_output=""
+ fi
fi
- fi
}
-ok ()
+required_error()
{
- required_result 0 "$@"
+ rc=$(errcode "$1")
+ shift
+ required_result "$rc" "$@"
}
-ok_null ()
+ok()
{
- ok --
+ required_result 0 "$@"
}
-result_print ()
+ok_null()
{
- _passed="$1"
- _out="$2"
- _rc="$3"
- _extra_header="$4"
+ ok --
+}
- if "$TEST_VERBOSE" || ! $_passed ; then
- if [ -n "$_extra_header" ] ; then
- cat <<EOF
+reset_extra_header()
+{
+ # Re-define this function to output extra header information
+ extra_header()
+ {
+ :
+ }
+}
-##################################################
-$_extra_header
-EOF
- fi
+reset_extra_footer()
+{
+ # Re-define this function to output extra footer information
+ extra_footer()
+ {
+ :
+ }
+}
+
+reset_extra_header
+reset_extra_footer
+
+result_print()
+{
+ _passed="$1"
+ _out="$2"
+ _rc="$3"
+
+ if "$CTDB_TEST_VERBOSE" || ! $_passed; then
+ extra_header
-cat <<EOF
+ cat <<EOF
--------------------------------------------------
Output (Exit status: ${_rc}):
--------------------------------------------------
EOF
- echo "$_out" | cat $TEST_CAT_RESULTS_OPTS
- fi
+ # Avoid echo, which might expand unintentional escapes
+ printf '%s\n' "$_out" |
+ result_filter |
+ cat "${CTDB_TEST_CAT_RESULTS_OPTS:--}"
+ fi
- if ! $_passed ; then
- cat <<EOF
+ if ! $_passed; then
+ cat <<EOF
--------------------------------------------------
Required output (Exit status: ${required_rc}):
--------------------------------------------------
EOF
- echo "$required_output" | cat $TEST_CAT_RESULTS_OPTS
+ # Avoid echo, which might expand unintentional escapes
+ printf '%s\n' "$required_output" |
+ cat "${CTDB_TEST_CAT_RESULTS_OPTS:--}"
- if $TEST_DIFF_RESULTS ; then
- _outr=$(mktemp)
- echo "$required_output" >"$_outr"
+ if $CTDB_TEST_DIFF_RESULTS; then
+ _outr=$(mktemp)
+ # Avoid echo, which might expand unintentional escapes
+ printf '%s\n' "$required_output" >"$_outr"
- _outf=$(mktemp)
- echo "$_fout" >"$_outf"
+ _outf=$(mktemp)
+ # Avoid echo, which might expand unintentional escapes
+ printf '%s\n' "$_fout" >"$_outf"
- cat <<EOF
+ cat <<EOF
--------------------------------------------------
Diff:
--------------------------------------------------
EOF
- diff -u "$_outr" "$_outf" | cat -A
- rm "$_outr" "$_outf"
+ diff -u "$_outr" "$_outf" | cat -A
+ rm "$_outr" "$_outf"
+ fi
fi
- fi
}
-result_footer ()
+result_footer()
{
- _passed="$1"
- _extra_footer="$2"
+ _passed="$1"
- if "$TEST_VERBOSE" || ! $_passed ; then
- if [ -n "$_extra_footer" ] ; then
- cat <<EOF
---------------------------------------------------
-$_extra_footer
---------------------------------------------------
-EOF
+ if "$CTDB_TEST_VERBOSE" || ! $_passed; then
+ extra_footer
+ fi
+
+ if $_passed; then
+ echo "PASSED"
+ return 0
+ else
+ echo
+ echo "FAILED"
+ return 1
fi
- fi
-
- if $_passed ; then
- echo "PASSED"
- return 0
- else
- echo
- echo "FAILED"
- return 1
- fi
}
# Result filtering is (usually) used to replace the date/time/PID
# prefix on some CTDB tool/client log messages with the literal string
# "DATE TIME [PID]". This allows tests to loosely match this output,
# since it can't otherwise be matched.
-result_filter_default ()
+result_filter_default()
{
- _date_time_pid='[0-9/][0-9/]*\ [0-9:\.][0-9:\.]*\ \[[\ 0-9][\ 0-9]*\]'
- sed -e "s@^${_date_time_pid}:@DATE\ TIME\ \[PID\]:@"
+ _date_time_pid='[0-9/][0-9/]*\ [0-9:\.][0-9:\.]*\ \[[\ 0-9][\ 0-9]*\]'
+ sed -e "s@^${_date_time_pid}:@DATE\ TIME\ \[PID\]:@"
}
+# Used in testcases
+# shellcheck disable=SC2034
+TEST_DATE_STAMP=""
# Override this function to customise output filtering.
-result_filter ()
+result_filter()
{
- result_filter_default
+ result_filter_default
}
-result_check ()
+result_check()
{
- _rc=$?
+ _rc=$?
- _extra_header="$1"
+ # Avoid echo, which might expand unintentional escapes
+ _fout=$(printf '%s\n' "$_out" | result_filter)
- _fout=$(echo "$_out" | result_filter)
+ if [ "$_fout" = "$required_output" ] &&
+ [ "$_rc" = "$required_rc" ]; then
+ _passed=true
+ else
+ _passed=false
+ fi
- if [ "$_fout" = "$required_output" -a $_rc = $required_rc ] ; then
- _passed=true
- else
+ result_print "$_passed" "$_out" "$_rc"
+ result_footer "$_passed"
+}
+
+test_fail()
+{
_passed=false
- fi
+ return 1
+}
+
+test_case_string=""
+test_case()
+{
+ test_case_string="$*"
+}
+
+test_header_default()
+{
+ echo "=================================================="
+ if [ -n "$test_case_string" ]; then
+ echo "Summary: ${test_case_string}"
+ test_case_string=""
+ fi
+ echo "Running: $*"
+}
+
+reset_test_header()
+{
+ # Re-define this function to get different header
+ test_header()
+ {
+ test_header_default "$@"
+ }
+}
- result_print "$_passed" "$_out" "$_rc" "$_extra_header"
- result_footer "$_passed"
+reset_test_header
+
+# Simple test harness for running binary unit tests
+unit_test()
+{
+ test_header "$@"
+
+ _wrapper="$VALGRIND"
+ if $CTDB_TEST_COMMAND_TRACE; then
+ _wrapper="strace"
+ fi
+ _out=$($_wrapper "$@" 2>&1)
+
+ result_check || exit $?
}
-local="${TEST_SUBDIR}/scripts/local.sh"
-if [ -r "$local" ] ; then
- . "$local"
+# Simple test harness for running shell script unit tests
+script_test()
+{
+ test_header "$@"
+
+ _shell=""
+ if ${CTDB_TEST_COMMAND_TRACE}; then
+ _shell="sh -x"
+ else
+ _shell="sh"
+ fi
+
+ _out=$($_shell "$@" 2>&1)
+
+ result_check || exit $?
+}
+
+# Simple test harness for running tests without tracing
+unit_test_notrace()
+{
+ test_header "$@"
+
+ _out=$("$@" 2>&1)
+
+ result_check || exit $?
+}
+
+test_cleanup_hooks=""
+
+test_cleanup()
+{
+ test_cleanup_hooks="${test_cleanup_hooks}${test_cleanup_hooks:+ ; }$*"
+}
+
+trap 'eval $test_cleanup_hooks' 0
+
+local="${CTDB_TEST_SUITE_DIR}/scripts/local.sh"
+if [ -r "$local" ]; then
+ . "$local"
fi