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