ctdb-tests: Rationalise node stop/start/restart
[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            Clean up when done by removing test state directory (see -V)
11   -D            Show diff between failed/expected test output (some tests only)
12   -e            Exit on the first test failure
13   -H            No headers - for running single test with other wrapper
14   -I <count>    Iterate tests <count> times, exiting on failure (implies -e, -N)
15   -l <count>    Use <count> daemons for local daemon integration tests
16   -L            Print daemon logs on test failure (only some tests)
17   -N            Don't print summary of tests results after running all tests
18   -q            Quiet - don't show tests being run (still displays summary)
19   -S <lib>      Use socket wrapper library <lib> for local integration tests
20   -v            Verbose - print test output for non-failures (only some tests)
21   -V <dir>      Use <dir> as test state directory
22   -x            Trace this script with the -x option
23   -X            Trace certain scripts run by tests using -x (only some tests)
24 EOF
25     exit 1
26 }
27
28 # Print a message and exit.
29 die ()
30 {
31     echo "$1" >&2 ; exit "${2:-1}"
32 }
33
34 ######################################################################
35
36 with_summary=true
37 quiet=false
38 exit_on_fail=false
39 max_iterations=1
40 no_header=false
41 test_state_dir=""
42 cleanup=false
43 test_time_limit=3600
44
45 export CTDB_TEST_VERBOSE=false
46 export CTDB_TEST_COMMAND_TRACE=false
47 export CTDB_TEST_CAT_RESULTS_OPTS=""
48 export CTDB_TEST_DIFF_RESULTS=false
49 export CTDB_TEST_PRINT_LOGS_ON_ERROR=false
50 export CTDB_TEST_LOCAL_DAEMONS=3
51 export CTDB_TEST_SWRAP_SO_PATH=""
52
53 while getopts "AcCDehHI:l:LNqS:T:vV:xX?" opt ; do
54         case "$opt" in
55         A) CTDB_TEST_CAT_RESULTS_OPTS="-A" ;;
56         c) CTDB_TEST_LOCAL_DAEMONS="" ;;
57         C) cleanup=true ;;
58         D) CTDB_TEST_DIFF_RESULTS=true ;;
59         e) exit_on_fail=true ;;
60         H) no_header=true ;;
61         I) max_iterations="$OPTARG" ; exit_on_fail=true ; with_summary=false ;;
62         l) CTDB_TEST_LOCAL_DAEMONS="$OPTARG" ;;
63         L) CTDB_TEST_PRINT_LOGS_ON_ERROR=true ;;
64         N) with_summary=false ;;
65         q) quiet=true ;;
66         S) CTDB_TEST_SWRAP_SO_PATH="$OPTARG" ;;
67         T) test_time_limit="$OPTARG" ;;
68         v) CTDB_TEST_VERBOSE=true ;;
69         V) test_state_dir="$OPTARG" ;;
70         x) set -x ;;
71         X) CTDB_TEST_COMMAND_TRACE=true ;;
72         \?|h) usage ;;
73         esac
74 done
75 shift $((OPTIND - 1))
76
77 case $(basename "$0") in
78     *run_cluster_tests*)
79         # Running on a cluster...  same as -c
80         CTDB_TEST_LOCAL_DAEMONS=""
81         ;;
82 esac
83
84 if $quiet ; then
85     show_progress() { cat >/dev/null ; }
86 else
87     show_progress() { cat ; }
88 fi
89
90 ######################################################################
91
92 test_header ()
93 {
94         local name="$1"
95
96         echo "--==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--"
97         echo "Running test $name ($(date '+%T'))"
98         echo "--==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--"
99 }
100
101 test_footer ()
102 {
103         local f="$1"
104         local status="$2"
105         local interp="$3"
106         local duration="$4"
107
108         local statstr=""
109         if [ "$status" -eq 0 ] ; then
110                 statstr=""
111         else
112                 statstr=" (status $status)"
113         fi
114
115         echo "=========================================================================="
116         echo "TEST ${interp}: ${f}${statstr} (duration: ${duration}s)"
117         echo "=========================================================================="
118 }
119
120 ctdb_test_run ()
121 {
122         local f="$1"
123
124         $no_header || test_header "$f"
125
126         local status=0
127         local start_time
128
129         start_time=$(date '+%s')
130
131         if [ -x "$f" ] ; then
132                 timeout "$test_time_limit" "$f" </dev/null | show_progress
133                 status=$?
134         else
135                 echo "TEST IS NOT EXECUTABLE"
136                 status=99
137         fi
138
139         local duration=$(($(date +%s) - start_time))
140
141         tests_total=$((tests_total + 1))
142
143         local interp
144         case "$status" in
145         0)
146                 interp="PASSED"
147                 tests_passed=$((tests_passed + 1))
148                 ;;
149         77)
150                 interp="SKIPPED"
151                 tests_skipped=$((tests_skipped + 1))
152                 ;;
153         99)
154                 interp="ERROR"
155                 tests_failed=$((tests_failed + 1))
156                 ;;
157         124)
158                 interp="TIMEDOUT"
159                 tests_failed=$((tests_failed + 1))
160                 ;;
161         *)
162                 interp="FAILED"
163                 tests_failed=$((tests_failed + 1))
164                 ;;
165         esac
166
167         $no_header || test_footer "$f" "$status" "$interp" "$duration"
168
169         if $with_summary ; then
170                 local t
171                 if [ $status -eq 0 ] ; then
172                         t=" ${interp}"
173                 else
174                         t="*${interp}*"
175                 fi
176                 printf '%-10s %s\n' "$t" "$f" >>"$summary_file"
177         fi
178
179         return $status
180 }
181
182 ######################################################################
183
184 tests_total=0
185 tests_passed=0
186 tests_skipped=0
187 tests_failed=0
188
189 if ! type mktemp >/dev/null 2>&1 ; then
190     # Not perfect, but it will do...
191     mktemp ()
192     {
193         local dir=false
194         if [ "$1" = "-d" ] ; then
195             dir=true
196         fi
197         local t="${TMPDIR:-/tmp}/tmp.$$.$RANDOM"
198         (
199             umask 077
200             if $dir ; then
201                 mkdir "$t"
202             else
203                 : >"$t"
204             fi
205         )
206         echo "$t"
207     }
208 fi
209
210 set -o pipefail
211
212 run_one_test ()
213 {
214     local f="$1"
215
216     CTDB_TEST_SUITE_DIR=$(dirname "$f")
217     export CTDB_TEST_SUITE_DIR
218     # This expands the most probable problem cases like "." and "..".
219     if [ "$(dirname "$CTDB_TEST_SUITE_DIR")" = "." ] ; then
220             CTDB_TEST_SUITE_DIR=$(cd "$CTDB_TEST_SUITE_DIR" && pwd)
221     fi
222
223     # Set CTDB_TEST_TMP_DIR
224     #
225     # Determine the relative test suite subdirectory.  The top-level
226     # test directory needs to be a prefix of the test suite directory,
227     # so make absolute versions of both.
228     local test_dir test_suite_dir reldir
229     test_dir=$(cd "$CTDB_TEST_DIR" && pwd)
230     test_suite_dir=$(cd "$CTDB_TEST_SUITE_DIR" && pwd)
231     reldir="${test_suite_dir#${test_dir}/}"
232
233     export CTDB_TEST_TMP_DIR="${test_state_dir}/${reldir}"
234     rm -rf "$CTDB_TEST_TMP_DIR"
235     mkdir -p "$CTDB_TEST_TMP_DIR"
236
237     ctdb_test_run "$f"
238     status=$?
239 }
240
241 run_tests ()
242 {
243         local f
244
245         for f ; do
246                 case "$f" in
247                 */README|*/README.md)
248                         continue
249                         ;;
250                 esac
251
252                 if [ ! -e "$f" ] ; then
253                         # Can't find it?  Check relative to CTDB_TEST_DIR.
254                         # Strip off current directory from beginning,
255                         # if there, just to make paths more friendly.
256                         f="${CTDB_TEST_DIR#${PWD}/}/${f}"
257                 fi
258
259                 if [ -d "$f" ] ; then
260                         local test_dir dir reldir subtests
261
262                         test_dir=$(cd "$CTDB_TEST_DIR" && pwd)
263                         dir=$(cd "$f" && pwd)
264                         reldir="${dir#${test_dir}/}"
265
266                         case "$reldir" in
267                         */*/*)
268                                 die "test \"$f\" is not recognised"
269                                 ;;
270                         */*)
271                                 # This is a test suite
272                                 subtests=$(echo "${f%/}/"*".sh")
273                                 if [ "$subtests" = "${f%/}/*.sh" ] ; then
274                                         # Probably empty directory
275                                         die "test \"$f\" is not recognised"
276                                 fi
277                                 ;;
278                         CLUSTER|INTEGRATION|UNIT)
279                                 # A collection of test suites
280                                 subtests=$(echo "${f%/}/"*)
281                                 ;;
282                         *)
283                                 die "test \"$f\" is not recognised"
284                         esac
285
286                         # Recurse - word-splitting wanted
287                         # shellcheck disable=SC2086
288                         run_tests $subtests
289                 elif [ -f "$f" ] ; then
290                         run_one_test "$f"
291                 else
292                         # Time to give up
293                         die "test \"$f\" is not recognised"
294                 fi
295
296                 if $exit_on_fail && [ $status -ne 0 ] ; then
297                         return $status
298                 fi
299         done
300 }
301
302 export CTDB_TEST_MODE="yes"
303
304 # Following 2 lines may be modified by installation script
305 CTDB_TESTS_ARE_INSTALLED=false
306 CTDB_TEST_DIR=$(dirname "$0")
307 export CTDB_TESTS_ARE_INSTALLED CTDB_TEST_DIR
308
309 if [ -z "$test_state_dir" ] ; then
310     if $CTDB_TESTS_ARE_INSTALLED ; then
311         test_state_dir=$(mktemp -d)
312     else
313         test_state_dir="${CTDB_TEST_DIR}/var"
314     fi
315 fi
316 mkdir -p "$test_state_dir"
317
318 summary_file="${test_state_dir}/.summary"
319 : >"$summary_file"
320
321 export TEST_SCRIPTS_DIR="${CTDB_TEST_DIR}/scripts"
322
323 # If no tests specified then run some defaults
324 if [ -z "$1" ] ; then
325         if [ -n "$CTDB_TEST_LOCAL_DAEMONS" ] ; then
326                 set -- UNIT INTEGRATION
327         else
328                 set -- INTEGRATION CLUSTER
329     fi
330 fi
331
332 do_cleanup ()
333 {
334     if $cleanup ; then
335         echo "Removing test state directory: ${test_state_dir}"
336         rm -rf "$test_state_dir"
337     else
338         echo "Not cleaning up test state directory: ${test_state_dir}"
339     fi
340 }
341
342 trap "do_cleanup ; exit 130" SIGINT
343 trap "do_cleanup ; exit 143" SIGTERM
344
345 iterations=0
346 # Special case: -I 0 means iterate forever (until failure)
347 while [ "$max_iterations" -eq 0 ] || [ $iterations -lt "$max_iterations" ] ; do
348         iterations=$((iterations + 1))
349
350         if [ "$max_iterations" -ne 1 ] ; then
351                 echo
352                 echo "##################################################"
353                 echo "ITERATION ${iterations}"
354                 echo "##################################################"
355                 echo
356         fi
357
358         run_tests "$@"
359         status=$?
360
361         if [ $status -ne 0 ] ; then
362                 break
363         fi
364 done
365
366 if $with_summary ; then
367         if [ $status -eq 0 ] || ! $exit_on_fail ; then
368                 echo
369                 cat "$summary_file"
370
371                 echo
372                 tests_run=$((tests_total - tests_skipped))
373                 printf '%d/%d tests passed' $tests_passed $tests_run
374                 if [ $tests_skipped -gt 0 ] ; then
375                         printf ' (%d skipped)' $tests_skipped
376                 fi
377                 printf '\n'
378         fi
379 fi
380 rm -f "$summary_file"
381
382 echo
383
384 do_cleanup
385
386 if $no_header || $exit_on_fail ; then
387     exit $status
388 elif [ $tests_failed -gt 0 ] ; then
389     exit 1
390 else
391     exit 0
392 fi