ctdb-protocol: Fix marshalling for ctdb_uptime
[vlendec/samba-autobuild/.git] / ctdb / tests / run_tests.sh
index 5fcd89d5dee9e76799bb9195c0f0a80be5305cd5..ffc81d405a6760bc4a1aa33d8c1b287c7d4a6206 100755 (executable)
-#!/bin/sh
+#!/bin/bash
 
-test_dir=$(dirname "$0")
+usage() {
+    cat <<EOF
+Usage: $0 [OPTIONS] [TESTS]
+
+Options:
+  -A           Use "cat -A" to print test output (only some tests)
+  -c           Run integration tests on a cluster
+  -C           Clean up - kill daemons and remove TEST_VAR_DIR when done
+  -d           Print descriptions of tests instead of filenames (dodgy!)
+  -D           Show diff between failed/expected test output (some tests only)
+  -e           Exit on the first test failure
+  -H           No headers - for running single test with other wrapper
+  -N           Don't print summary of tests results after running all tests
+  -q           Quiet - don't show tests being run (hint: use with -s)
+  -S            Enable socket wrapper
+  -v           Verbose - print test output for non-failures (only some tests)
+  -V <dir>     Use <dir> as TEST_VAR_DIR
+  -x           Trace this script with the -x option
+  -X           Trace certain scripts run by tests using -x (only some tests)
+EOF
+    exit 1
+}
+
+# Print a message and exit.
+die ()
+{
+    echo "$1" >&2 ; exit ${2:-1}
+}
+
+######################################################################
+
+with_summary=true
+with_desc=false
+quiet=false
+exit_on_fail=false
+no_header=false
+socket_wrapper=false
+
+export TEST_VERBOSE=false
+export TEST_COMMAND_TRACE=false
+export TEST_CAT_RESULTS_OPTS=""
+export TEST_DIFF_RESULTS=false
+export TEST_LOCAL_DAEMONS
+[ -n "$TEST_LOCAL_DAEMONS" ] || TEST_LOCAL_DAEMONS=3
+export TEST_VAR_DIR=""
+export TEST_CLEANUP=false
+
+temp=$(getopt -n "$prog" -o "AcCdDehHNqSvV:xX" -l help -- "$@")
+
+[ $? != 0 ] && usage
+
+eval set -- "$temp"
+
+while true ; do
+    case "$1" in
+       -A) TEST_CAT_RESULTS_OPTS="-A" ; shift ;;
+       -c) TEST_LOCAL_DAEMONS="" ; shift ;;
+       -C) TEST_CLEANUP=true ; shift ;;
+       -d) with_desc=true ; shift ;;  # 4th line of output is description
+       -D) TEST_DIFF_RESULTS=true ; shift ;;
+       -e) exit_on_fail=true ; shift ;;
+       -H) no_header=true ; shift ;;
+       -N) with_summary=false ; shift ;;
+       -q) quiet=true ; shift ;;
+       -S) socket_wrapper=true ; shift ;;
+       -v) TEST_VERBOSE=true ; shift ;;
+       -V) TEST_VAR_DIR="$2" ; shift 2 ;;
+       -x) set -x; shift ;;
+       -X) TEST_COMMAND_TRACE=true ; shift ;;
+       --) shift ; break ;;
+       *) usage ;;
+    esac
+done
 
 case $(basename "$0") in
     *run_cluster_tests*)
-       # Running on a cluster:
-       # * print summary, run any integration tests against cluster
-       # * default to running: all integration tests, no unit tests
-       opts="-s"
-       tests="simple complex"
+       # Running on a cluster...  same as -c
+       TEST_LOCAL_DAEMONS=""
        ;;
-    *)
-       # Running on local machine:
-       # * print summary, run any integration tests against local daemons
-       # * default to running: all unit tests, simple integration tests
-       opts="-s -l"
-       tests="onnode takeover tool eventscripts simple"
-       # If running in the source tree then use a fixed TEST_VAR_DIR.
-       # If this script is installed using the INSTALL script then
-       # TEST_BIN_DIR will be set, so use this as the test.
-       if [ -z "$TEST_BIN_DIR" ] ; then
-           opts="${opts} -V ${test_dir}/var"
-       fi
 esac
 
-# Allow options to be passed to this script.  However, if any options
-# are passed there must be a "--" between the options and the tests.
-# This makes it easy to handle options that take arguments.
-case "$1" in
-    -*)
-       while [ -n "$1" ] ; do
-           case "$1" in
-               --) shift ; break ;;
-               *) opts="$opts $1" ; shift ;;
-           esac
+if $quiet ; then
+    show_progress() { cat >/dev/null ; }
+else
+    show_progress() { cat ; }
+fi
+
+######################################################################
+
+ctdb_test_begin ()
+{
+    local name="$1"
+
+    teststarttime=$(date '+%s')
+    testduration=0
+
+    echo "--==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--"
+    echo "Running test $name ($(date '+%T'))"
+    echo "--==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--"
+}
+
+ctdb_test_end ()
+{
+    local name="$1" ; shift
+    local status="$1" ; shift
+    # "$@" is command-line
+
+    local interp="SKIPPED"
+    local statstr=" (reason $*)"
+    if [ -n "$status" ] ; then
+       if [ $status -eq 0 ] ; then
+           interp="PASSED"
+           statstr=""
+           echo "ALL OK: $*"
+       else
+           interp="FAILED"
+           statstr=" (status $status)"
+       fi
+    fi
+
+    testduration=$(($(date +%s)-$teststarttime))
+
+    echo "=========================================================================="
+    echo "TEST ${interp}: ${name}${statstr} (duration: ${testduration}s)"
+    echo "=========================================================================="
+
+}
+
+ctdb_test_run ()
+{
+    local name="$1" ; shift
+
+    [ -n "$1" ] || set -- "$name"
+
+    $no_header || ctdb_test_begin "$name"
+
+    local status=0
+    "$@" || status=$?
+
+    $no_header || ctdb_test_end "$name" "$status" "$*"
+
+    return $status
+}
+
+######################################################################
+
+tests_total=0
+tests_passed=0
+tests_failed=0
+summary=""
+
+if ! which mktemp >/dev/null 2>&1 ; then
+    # Not perfect, but it will do...
+    mktemp ()
+    {
+       local dir=false
+       if [ "$1" = "-d" ] ; then
+           dir=true
+       fi
+       local t="${TMPDIR:-/tmp}/tmp.$$.$RANDOM"
+       (
+           umask 077
+           if $dir ; then
+               mkdir "$t"
+           else
+               >"$t"
+           fi
+       )
+       echo "$t"
+    }
+fi
+
+tf=$(mktemp) || die "mktemp failed for tf - is TMPDIR missing?"
+sf=$(mktemp) || die "mktemp failed for sf - is TMPDIR missing?"
+
+set -o pipefail
+
+run_one_test ()
+{
+    local f="$1"
+
+    [ -x "$f" ] || die "test \"$f\" is not executable"
+    tests_total=$(($tests_total + 1))
+
+    ctdb_test_run "$f" | tee "$tf" | show_progress
+    status=$?
+    if [ $status -eq 0 ] ; then
+       tests_passed=$(($tests_passed + 1))
+    else
+       tests_failed=$(($tests_failed + 1))
+    fi
+    if $with_summary ; then
+       local t
+       if [ $status -eq 0 ] ; then
+           t=" PASSED "
+       else
+           t="*FAILED*"
+       fi
+       if $with_desc ; then
+           desc=$(tail -n +4 $tf | head -n 1)
+           f="$desc"
+       fi
+       echo "$t $f" >>"$sf"
+    fi
+}
+
+find_and_run_one_test ()
+{
+    local t="$1"
+    local dir="$2"
+
+    local f="${dir}${dir:+/}${t}"
+
+    if [ -d "$f" ] ; then
+       local i
+       for i in $(ls "${f%/}/"*".sh" 2>/dev/null) ; do
+           run_one_test "$i"
+           if $exit_on_fail && [ $status -ne 0 ] ; then
+               break
+           fi
        done
-esac
+       # No tests found?  Not a tests directory!  Not found...
+       [ -n "$status" ] || status=127
+    elif [ -f "$f" ] ; then
+       run_one_test "$f"
+    else
+       status=127
+    fi
+}
+
+# Following 2 lines may be modified by installation script
+export CTDB_TESTS_ARE_INSTALLED=false
+export CTDB_TEST_DIR=$(dirname "$0")
+
+if [ -z "$TEST_VAR_DIR" ] ; then
+    if $CTDB_TESTS_ARE_INSTALLED ; then
+       TEST_VAR_DIR=$(mktemp -d)
+    else
+       TEST_VAR_DIR="${CTDB_TEST_DIR}/var"
+    fi
+fi
+mkdir -p "$TEST_VAR_DIR"
+
+# Must be absolute
+TEST_VAR_DIR=$(cd "$TEST_VAR_DIR"; echo "$PWD")
+echo "TEST_VAR_DIR=$TEST_VAR_DIR"
+
+if $socket_wrapper ; then
+    export SOCKET_WRAPPER_DIR="${TEST_VAR_DIR}/sw"
+    mkdir -p "$SOCKET_WRAPPER_DIR"
+fi
+
+export TEST_SCRIPTS_DIR="${CTDB_TEST_DIR}/scripts"
+
+# If no tests specified then run some defaults
+if [ -z "$1" ] ; then
+    if [ -n "$TEST_LOCAL_DAEMONS" ] ; then
+       set -- onnode takeover takeover_helper tool eventscripts \
+           cunit eventd shellcheck simple
+    else
+       set -- simple complex
+    fi
+fi
+
+do_cleanup ()
+{
+    if $TEST_CLEANUP ; then
+       echo "Removing TEST_VAR_DIR=$TEST_VAR_DIR"
+       rm -rf "$TEST_VAR_DIR"
+    else
+       echo "Not cleaning up TEST_VAR_DIR=$TEST_VAR_DIR"
+    fi
+}
+
+cleanup_handler ()
+{
+    if $TEST_CLEANUP ; then
+       if [ -n "$TEST_LOCAL_DAEMONS" -a "$f" = "simple" ] ; then
+           echo "***** shutting down daemons *****"
+           find_and_run_one_test simple/99_daemons_shutdown.sh "$tests_dir"
+       fi
+    fi
+    do_cleanup
+}
+
+trap cleanup_handler SIGINT SIGTERM
+
+for f ; do
+    find_and_run_one_test "$f"
+
+    if [ $status -eq 127 ] ; then
+       # Find the the top-level tests directory
+       tests_dir=$(dirname $(cd $TEST_SCRIPTS_DIR; echo $PWD))
+       # Strip off current directory from beginning, if there, just
+       # to make paths more friendly.
+       tests_dir=${tests_dir#$PWD/}
+       find_and_run_one_test "$f" "$tests_dir"
+    fi
+
+    if [ $status -eq 127 ] ; then
+           die "test \"$f\" is not recognised"
+    fi
+
+    if $exit_on_fail && [ $status -ne 0 ] ; then
+           break
+    fi
+done
+
+rm -f "$tf"
+
+if $with_summary ; then
+    echo
+    cat "$sf"
+    echo
+    echo "${tests_passed}/${tests_total} tests passed"
+fi
+
+rm -f "$sf"
 
-# If no tests are specified, then run the defaults.
-[ -n "$1" ] || set -- $tests
+echo
 
-"${test_dir}/scripts/run_tests" $opts "$@" || exit 1
+do_cleanup
 
-echo "All OK"
-exit 0
+if $no_header || $exit_on_fail ; then
+    exit $status
+elif [ $tests_failed -gt 0 ] ; then
+    exit 1
+else
+    exit 0
+fi