ctdb-tests: Don't print summary on failure if -e option is specified
[vlendec/samba-autobuild/.git] / ctdb / tests / run_tests.sh
1 #!/usr/bin/env bash
2
3 usage() {
4     cat <<EOF
5 Usage: $0 [OPTIONS] [TESTS]
6
7 Options:
8   -A            Use "cat -A" to print test output (only some tests)
9   -c            Run integration tests on a cluster
10   -C            Remove TEST_VAR_DIR when done
11   -d            Print descriptions of tests instead of filenames (dodgy!)
12   -D            Show diff between failed/expected test output (some tests only)
13   -e            Exit on the first test failure
14   -H            No headers - for running single test with other wrapper
15   -I <count>    Iterate tests <count> times, exiting on failure (implies -e, -N)
16   -N            Don't print summary of tests results after running all tests
17   -q            Quiet - don't show tests being run (still displays summary)
18   -S <lib>      Use socket wrapper library <lib> for local integration tests
19   -v            Verbose - print test output for non-failures (only some tests)
20   -V <dir>      Use <dir> as TEST_VAR_DIR
21   -x            Trace this script with the -x option
22   -X            Trace certain scripts run by tests using -x (only some tests)
23 EOF
24     exit 1
25 }
26
27 # Print a message and exit.
28 die ()
29 {
30     echo "$1" >&2 ; exit "${2:-1}"
31 }
32
33 ######################################################################
34
35 with_summary=true
36 with_desc=false
37 quiet=false
38 exit_on_fail=false
39 max_iterations=1
40 no_header=false
41
42 export TEST_VERBOSE=false
43 export TEST_COMMAND_TRACE=false
44 export TEST_CAT_RESULTS_OPTS=""
45 export TEST_DIFF_RESULTS=false
46 export TEST_LOCAL_DAEMONS
47 [ -n "$TEST_LOCAL_DAEMONS" ] || TEST_LOCAL_DAEMONS=3
48 export TEST_VAR_DIR=""
49 export TEST_CLEANUP=false
50 export TEST_TIMEOUT=3600
51 export TEST_SOCKET_WRAPPER_SO_PATH=""
52
53 while getopts "AcCdDehHI:NqS:T:vV:xX?" opt ; do
54         case "$opt" in
55         A) TEST_CAT_RESULTS_OPTS="-A" ;;
56         c) TEST_LOCAL_DAEMONS="" ;;
57         C) TEST_CLEANUP=true ;;
58         d) with_desc=true ;;  # 4th line of output is description
59         D) TEST_DIFF_RESULTS=true ;;
60         e) exit_on_fail=true ;;
61         H) no_header=true ;;
62         I) max_iterations="$OPTARG" ; exit_on_fail=true ; with_summary=false ;;
63         N) with_summary=false ;;
64         q) quiet=true ;;
65         S) TEST_SOCKET_WRAPPER_SO_PATH="$OPTARG" ;;
66         T) TEST_TIMEOUT="$OPTARG" ;;
67         v) TEST_VERBOSE=true ;;
68         V) TEST_VAR_DIR="$OPTARG" ;;
69         x) set -x ;;
70         X) TEST_COMMAND_TRACE=true ;;
71         \?|h) usage ;;
72         esac
73 done
74 shift $((OPTIND - 1))
75
76 case $(basename "$0") in
77     *run_cluster_tests*)
78         # Running on a cluster...  same as -c
79         TEST_LOCAL_DAEMONS=""
80         ;;
81 esac
82
83 if $quiet ; then
84     show_progress() { cat >/dev/null ; }
85 else
86     show_progress() { cat ; }
87 fi
88
89 ######################################################################
90
91 ctdb_test_begin ()
92 {
93     local name="$1"
94
95     teststarttime=$(date '+%s')
96     testduration=0
97
98     echo "--==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--"
99     echo "Running test $name ($(date '+%T'))"
100     echo "--==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--"
101 }
102
103 ctdb_test_end ()
104 {
105     local name="$1" ; shift
106     local status="$1" ; shift
107     # "$@" is command-line
108
109     local interp="SKIPPED"
110     local statstr=" (reason $*)"
111     if [ -n "$status" ] ; then
112         if [ "$status" -eq 0 ] ; then
113             interp="PASSED"
114             statstr=""
115             echo "ALL OK: $*"
116         elif [ "$status" -eq 124 ] ; then
117             interp="TIMEOUT"
118             statstr=" (status $status)"
119         else
120             interp="FAILED"
121             statstr=" (status $status)"
122         fi
123     fi
124
125     testduration=$(($(date +%s) - teststarttime))
126
127     echo "=========================================================================="
128     echo "TEST ${interp}: ${name}${statstr} (duration: ${testduration}s)"
129     echo "=========================================================================="
130
131 }
132
133 ctdb_test_run ()
134 {
135     local name="$1" ; shift
136
137     [ -n "$1" ] || set -- "$name"
138
139     $no_header || ctdb_test_begin "$name"
140
141     local status=0
142     if [ -x "$1" ] ; then
143             timeout "$TEST_TIMEOUT" "$@" || status=$?
144     else
145             echo "TEST IS NOT EXECUTABLE"
146             status=1
147     fi
148
149     $no_header || ctdb_test_end "$name" "$status" "$*"
150
151     return $status
152 }
153
154 ######################################################################
155
156 tests_total=0
157 tests_passed=0
158 tests_failed=0
159
160 if ! type mktemp >/dev/null 2>&1 ; then
161     # Not perfect, but it will do...
162     mktemp ()
163     {
164         local dir=false
165         if [ "$1" = "-d" ] ; then
166             dir=true
167         fi
168         local t="${TMPDIR:-/tmp}/tmp.$$.$RANDOM"
169         (
170             umask 077
171             if $dir ; then
172                 mkdir "$t"
173             else
174                 : >"$t"
175             fi
176         )
177         echo "$t"
178     }
179 fi
180
181 tf=$(mktemp) || die "mktemp failed for tf - is TMPDIR missing?"
182 sf=$(mktemp) || die "mktemp failed for sf - is TMPDIR missing?"
183
184 set -o pipefail
185
186 run_one_test ()
187 {
188     local f="$1"
189
190     tests_total=$((tests_total + 1))
191
192     ctdb_test_run "$f" | tee "$tf" | show_progress
193     status=$?
194     if [ $status -eq 0 ] ; then
195         tests_passed=$((tests_passed + 1))
196     else
197         tests_failed=$((tests_failed + 1))
198     fi
199     if $with_summary ; then
200         local t
201         if [ $status -eq 0 ] ; then
202             t=" PASSED "
203         else
204             t="*FAILED*"
205         fi
206         if $with_desc ; then
207             desc=$(tail -n +4 "$tf" | head -n 1)
208             f="$desc"
209         fi
210         echo "$t $f" >>"$sf"
211     fi
212 }
213
214 find_and_run_one_test ()
215 {
216     local t="$1"
217     local dir="$2"
218
219     local f="${dir}${dir:+/}${t}"
220
221     if [ -d "$f" ] ; then
222         local i
223         for i in "${f%/}/"*".sh" ; do
224             # Only happens if test removed (unlikely) or empty directory
225             if [ ! -f "$i" ] ; then
226                 break
227             fi
228             run_one_test "$i"
229             if $exit_on_fail && [ $status -ne 0 ] ; then
230                 break
231             fi
232         done
233         # No tests found?  Not a tests directory!  Not found...
234         [ -n "$status" ] || status=127
235     elif [ -f "$f" ] ; then
236         run_one_test "$f"
237     else
238         status=127
239     fi
240 }
241
242 run_tests ()
243 {
244         local tests=("$@")
245
246         for f in "${tests[@]}" ; do
247                 find_and_run_one_test "$f"
248
249                 if [ $status -eq 127 ] ; then
250                         # Find the the top-level tests directory
251                         d=$(cd "$TEST_SCRIPTS_DIR" && echo "$PWD")
252                         if [ -z "$d" ] ; then
253                                 local t="$TEST_SCRIPTS_DIR"
254                                 die "Unable to find TEST_SCRIPTS_DIR=\"${t}\""
255                         fi
256                         tests_dir=$(dirname "$d")
257                         # Strip off current directory from beginning,
258                         # if there, just to make paths more friendly.
259                         tests_dir="${tests_dir#${PWD}/}"
260                         find_and_run_one_test "$f" "$tests_dir"
261                 fi
262
263                 if [ $status -eq 127 ] ; then
264                         die "test \"$f\" is not recognised"
265                 fi
266
267                 if $exit_on_fail && [ $status -ne 0 ] ; then
268                         return $status
269                 fi
270         done
271 }
272
273 export CTDB_TEST_MODE="yes"
274
275 # Following 2 lines may be modified by installation script
276 CTDB_TESTS_ARE_INSTALLED=false
277 CTDB_TEST_DIR=$(dirname "$0")
278 export CTDB_TESTS_ARE_INSTALLED CTDB_TEST_DIR
279
280 if [ -z "$TEST_VAR_DIR" ] ; then
281     if $CTDB_TESTS_ARE_INSTALLED ; then
282         TEST_VAR_DIR=$(mktemp -d)
283     else
284         TEST_VAR_DIR="${CTDB_TEST_DIR}/var"
285     fi
286 fi
287 mkdir -p "$TEST_VAR_DIR"
288
289 export TEST_SCRIPTS_DIR="${CTDB_TEST_DIR}/scripts"
290
291 unit_tests="
292         cunit
293         eventd
294         eventscripts
295         onnode
296         shellcheck
297         takeover
298         takeover_helper
299         tool
300 "
301
302 # If no tests specified then run some defaults
303 if [ -z "$1" ] ; then
304         if [ -n "$TEST_LOCAL_DAEMONS" ] ; then
305                 set -- UNIT simple
306         else
307                 set -- simple complex
308     fi
309 fi
310
311 do_cleanup ()
312 {
313     if $TEST_CLEANUP ; then
314         echo "Removing TEST_VAR_DIR=$TEST_VAR_DIR"
315         rm -rf "$TEST_VAR_DIR"
316     else
317         echo "Not cleaning up TEST_VAR_DIR=$TEST_VAR_DIR"
318     fi
319 }
320
321 trap "do_cleanup ; exit 130" SIGINT
322 trap "do_cleanup ; exit 143" SIGTERM
323
324 declare -a tests
325 i=0
326 for f ; do
327         if [ "$f" = "UNIT" ] ; then
328                 for t in $unit_tests ; do
329                         tests[i++]="$t"
330                 done
331         else
332                 tests[i++]="$f"
333         fi
334 done
335
336 iterations=0
337 # Special case: -I 0 means iterate forever (until failure)
338 while [ "$max_iterations" -eq 0 ] || [ $iterations -lt "$max_iterations" ] ; do
339         iterations=$((iterations + 1))
340
341         if [ "$max_iterations" -ne 1 ] ; then
342                 echo
343                 echo "##################################################"
344                 echo "ITERATION ${iterations}"
345                 echo "##################################################"
346                 echo
347         fi
348
349         run_tests "${tests[@]}"
350         status=$?
351
352         if [ $status -ne 0 ] ; then
353                 break
354         fi
355 done
356
357 rm -f "$tf"
358
359 if $with_summary ; then
360         if [ $status -eq 0 ] || ! $exit_on_fail ; then
361                 echo
362                 cat "$sf"
363                 echo
364                 echo "${tests_passed}/${tests_total} tests passed"
365         fi
366 fi
367
368 rm -f "$sf"
369
370 echo
371
372 do_cleanup
373
374 if $no_header || $exit_on_fail ; then
375     exit $status
376 elif [ $tests_failed -gt 0 ] ; then
377     exit 1
378 else
379     exit 0
380 fi