Skip snapshot in zfs_iter_mounted()
[freebsd.git] / tests / test-runner / include / logapi.shlib
1 #
2 # CDDL HEADER START
3 #
4 # The contents of this file are subject to the terms of the
5 # Common Development and Distribution License (the "License").
6 # You may not use this file except in compliance with the License.
7 #
8 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 # or http://www.opensolaris.org/os/licensing.
10 # See the License for the specific language governing permissions
11 # and limitations under the License.
12 #
13 # When distributing Covered Code, include this CDDL HEADER in each
14 # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 # If applicable, add the following below this CDDL HEADER, with the
16 # fields enclosed by brackets "[]" replaced with your own identifying
17 # information: Portions Copyright [yyyy] [name of copyright owner]
18 #
19 # CDDL HEADER END
20 #
21
22 #
23 # Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24 # Use is subject to license terms.
25 #
26 # Copyright (c) 2012, 2020 by Delphix. All rights reserved.
27 #
28
29 . ${STF_TOOLS}/include/stf.shlib
30
31 # Output an assertion
32 #
33 # $@ - assertion text
34
35 function log_assert
36 {
37         _printline ASSERTION: "$@"
38 }
39
40 # Output a comment
41 #
42 # $@ - comment text
43
44 function log_note
45 {
46         _printline NOTE: "$@"
47 }
48
49 # Execute and print command with status where success equals non-zero result
50 #
51 # $@ - command to execute
52 #
53 # return 0 if command fails, otherwise return 1
54
55 function log_neg
56 {
57         log_neg_expect ""  "$@"
58         return $?
59 }
60
61 # Execute a positive test and exit $STF_FAIL is test fails
62 #
63 # $@ - command to execute
64
65 function log_must
66 {
67         log_pos "$@"
68         (( $? != 0 )) && log_fail
69 }
70
71 # Execute a positive test (expecting no stderr) and exit $STF_FAIL
72 # if test fails
73 # $@ - command to execute
74
75 function log_must_nostderr
76 {
77         log_pos_nostderr "$@"
78         (( $? != 0 )) && log_fail
79 }
80
81 # Execute a positive test but retry the command on failure if the output
82 # matches an expected pattern.  Otherwise behave like log_must and exit
83 # $STF_FAIL is test fails.
84 #
85 # $1 - retry keyword
86 # $2 - retry attempts
87 # $3-$@ - command to execute
88 #
89 function log_must_retry
90 {
91         typeset out=""
92         typeset logfile="/tmp/log.$$"
93         typeset status=1
94         typeset expect=$1
95         typeset retry=$2
96         typeset delay=1
97         shift 2
98
99         while [[ -e $logfile ]]; do
100                 logfile="$logfile.$$"
101         done
102
103         while (( $retry > 0 )); do
104                 "$@" 2>$logfile
105                 status=$?
106                 out="cat $logfile"
107
108                 if (( $status == 0 )); then
109                         $out | egrep -i "internal error|assertion failed" \
110                                 > /dev/null 2>&1
111                         # internal error or assertion failed
112                         if [[ $? -eq 0 ]]; then
113                                 print -u2 $($out)
114                                 _printerror "$@" "internal error or" \
115                                         " assertion failure exited $status"
116                                 status=1
117                         else
118                                 [[ -n $LOGAPI_DEBUG ]] && cat $logfile
119                                 _printsuccess "$@"
120                         fi
121                         break
122                 else
123                         $out | grep -i "$expect" > /dev/null 2>&1
124                         if (( $? == 0 )); then
125                                 print -u2 $($out)
126                                 _printerror "$@" "Retry in $delay seconds"
127                                 sleep $delay
128
129                                 (( retry=retry - 1 ))
130                                 (( delay=delay * 2 ))
131                         else
132                                 break;
133                         fi
134                 fi
135         done
136
137         if (( $status != 0 )) ; then
138                 print -u2 $($out)
139                 _printerror "$@" "exited $status"
140         fi
141
142         _recursive_output $logfile "false"
143         return $status
144 }
145
146 # Execute a positive test and exit $STF_FAIL is test fails after being
147 # retried up to 5 times when the command returns the keyword "busy".
148 #
149 # $@ - command to execute
150 function log_must_busy
151 {
152         log_must_retry "busy" 5 "$@"
153         (( $? != 0 )) && log_fail
154 }
155
156 # Execute a negative test and exit $STF_FAIL if test passes
157 #
158 # $@ - command to execute
159
160 function log_mustnot
161 {
162         log_neg "$@"
163         (( $? != 0 )) && log_fail
164 }
165
166 # Execute a negative test with keyword expected, and exit
167 # $STF_FAIL if test passes
168 #
169 # $1 - keyword expected
170 # $2-$@ - command to execute
171
172 function log_mustnot_expect
173 {
174         log_neg_expect "$@"
175         (( $? != 0 )) && log_fail
176 }
177
178 # Signal numbers are platform-dependent
179 case $(uname) in
180 Darwin|FreeBSD)
181         SIGBUS=10
182         SIGSEGV=11
183         ;;
184 illumos|Linux|*)
185         SIGBUS=7
186         SIGSEGV=11
187         ;;
188 esac
189 EXIT_SUCCESS=0
190 EXIT_NOTFOUND=127
191 EXIT_SIGNAL=256
192 EXIT_SIGBUS=$((EXIT_SIGNAL + SIGBUS))
193 EXIT_SIGSEGV=$((EXIT_SIGNAL + SIGSEGV))
194
195 # Execute and print command with status where success equals non-zero result
196 # or output includes expected keyword
197 #
198 # $1 - keyword expected
199 # $2-$@ - command to execute
200 #
201 # return 0 if command fails, or the output contains the keyword expected,
202 # return 1 otherwise
203
204 function log_neg_expect
205 {
206         typeset out=""
207         typeset logfile="/tmp/log.$$"
208         typeset ret=1
209         typeset expect=$1
210         shift
211
212         while [[ -e $logfile ]]; do
213                 logfile="$logfile.$$"
214         done
215
216         "$@" 2>$logfile
217         typeset status=$?
218         out="cat $logfile"
219
220         # unexpected status
221         if (( $status == EXIT_SUCCESS )); then
222                  print -u2 $($out)
223                 _printerror "$@" "unexpectedly exited $status"
224         # missing binary
225         elif (( $status == EXIT_NOTFOUND )); then
226                 print -u2 $($out)
227                 _printerror "$@" "unexpectedly exited $status (File not found)"
228         # bus error - core dump
229         elif (( $status == EXIT_SIGBUS )); then
230                 print -u2 $($out)
231                 _printerror "$@" "unexpectedly exited $status (Bus Error)"
232         # segmentation violation - core dump
233         elif (( $status == EXIT_SIGSEGV )); then
234                 print -u2 $($out)
235                 _printerror "$@" "unexpectedly exited $status (SEGV)"
236         else
237                 $out | egrep -i "internal error|assertion failed" \
238                         > /dev/null 2>&1
239                 # internal error or assertion failed
240                 if (( $? == 0 )); then
241                         print -u2 $($out)
242                         _printerror "$@" "internal error or assertion failure" \
243                                 " exited $status"
244                 elif [[ -n $expect ]] ; then
245                         $out | grep -i "$expect" > /dev/null 2>&1
246                         if (( $? == 0 )); then
247                                 ret=0
248                         else
249                                 print -u2 $($out)
250                                 _printerror "$@" "unexpectedly exited $status"
251                         fi
252                 else
253                         ret=0
254                 fi
255
256                 if (( $ret == 0 )); then
257                         [[ -n $LOGAPI_DEBUG ]] && cat $logfile
258                         _printsuccess "$@" "exited $status"
259                 fi
260         fi
261         _recursive_output $logfile "false"
262         return $ret
263 }
264
265 # Execute and print command with status where success equals zero result
266 #
267 # $@ command to execute
268 #
269 # return command exit status
270
271 function log_pos
272 {
273         typeset out=""
274         typeset logfile="/tmp/log.$$"
275
276         while [[ -e $logfile ]]; do
277                 logfile="$logfile.$$"
278         done
279
280         "$@" 2>$logfile
281         typeset status=$?
282         out="cat $logfile"
283
284         if (( $status != 0 )) ; then
285                 print -u2 $($out)
286                 _printerror "$@" "exited $status"
287         else
288                 $out | egrep -i "internal error|assertion failed" \
289                         > /dev/null 2>&1
290                 # internal error or assertion failed
291                 if [[ $? -eq 0 ]]; then
292                         print -u2 $($out)
293                         _printerror "$@" "internal error or assertion failure" \
294                                 " exited $status"
295                         status=1
296                 else
297                         [[ -n $LOGAPI_DEBUG ]] && cat $logfile
298                         _printsuccess "$@"
299                 fi
300         fi
301         _recursive_output $logfile "false"
302         return $status
303 }
304
305 # Execute and print command with status where success equals zero result
306 # and no stderr output
307 #
308 # $@ command to execute
309 #
310 # return 0 if command succeeds and no stderr output
311 # return 1 othersie
312
313 function log_pos_nostderr
314 {
315         typeset out=""
316         typeset logfile="/tmp/log.$$"
317
318         while [[ -e $logfile ]]; do
319                 logfile="$logfile.$$"
320         done
321
322         "$@" 2>$logfile
323         typeset status=$?
324         out="cat $logfile"
325         typeset out_msg=$($out)
326
327         if (( $status != 0 )) ; then
328                 print -u2 $out_msg
329                 _printerror "$@" "exited $status"
330         else
331                 if [[ ! -z "$out_msg" ]]; then
332                         print -u2 $out_msg
333                         _printerror "$@" "message in stderr" \
334                                 " exited $status"
335                         status=1
336                 else
337                         [[ -n $LOGAPI_DEBUG ]] && cat $logfile
338                         _printsuccess "$@"
339                 fi
340         fi
341         _recursive_output $logfile "false"
342         return $status
343 }
344
345 # Set an exit handler
346 #
347 # $@ - function(s) to perform on exit
348
349 function log_onexit
350 {
351         _CLEANUP=("$*")
352 }
353
354 # Push an exit handler on the cleanup stack
355 #
356 # $@ - function(s) to perform on exit
357
358 function log_onexit_push
359 {
360         _CLEANUP+=("$*")
361 }
362
363 # Pop an exit handler off the cleanup stack
364
365 function log_onexit_pop
366 {
367         _CLEANUP=("${_CLEANUP[@]:0:${#_CLEANUP[@]}-1}")
368 }
369
370 #
371 # Exit functions
372 #
373
374 # Perform cleanup and exit $STF_PASS
375 #
376 # $@ - message text
377
378 function log_pass
379 {
380         _endlog $STF_PASS "$@"
381 }
382
383 # Perform cleanup and exit $STF_FAIL
384 #
385 # $@ - message text
386
387 function log_fail
388 {
389         _endlog $STF_FAIL "$@"
390 }
391
392 # Perform cleanup and exit $STF_UNRESOLVED
393 #
394 # $@ - message text
395
396 function log_unresolved
397 {
398         _endlog $STF_UNRESOLVED "$@"
399 }
400
401 # Perform cleanup and exit $STF_NOTINUSE
402 #
403 # $@ - message text
404
405 function log_notinuse
406 {
407         _endlog $STF_NOTINUSE "$@"
408 }
409
410 # Perform cleanup and exit $STF_UNSUPPORTED
411 #
412 # $@ - message text
413
414 function log_unsupported
415 {
416         _endlog $STF_UNSUPPORTED "$@"
417 }
418
419 # Perform cleanup and exit $STF_UNTESTED
420 #
421 # $@ - message text
422
423 function log_untested
424 {
425         _endlog $STF_UNTESTED "$@"
426 }
427
428 # Perform cleanup and exit $STF_UNINITIATED
429 #
430 # $@ - message text
431
432 function log_uninitiated
433 {
434         _endlog $STF_UNINITIATED "$@"
435 }
436
437 # Perform cleanup and exit $STF_NORESULT
438 #
439 # $@ - message text
440
441 function log_noresult
442 {
443         _endlog $STF_NORESULT "$@"
444 }
445
446 # Perform cleanup and exit $STF_WARNING
447 #
448 # $@ - message text
449
450 function log_warning
451 {
452         _endlog $STF_WARNING "$@"
453 }
454
455 # Perform cleanup and exit $STF_TIMED_OUT
456 #
457 # $@ - message text
458
459 function log_timed_out
460 {
461         _endlog $STF_TIMED_OUT "$@"
462 }
463
464 # Perform cleanup and exit $STF_OTHER
465 #
466 # $@ - message text
467
468 function log_other
469 {
470         _endlog $STF_OTHER "$@"
471 }
472
473 function set_main_pid
474 {
475         _MAINPID=$1
476 }
477
478 #
479 # Internal functions
480 #
481
482 # Execute custom callback scripts on test failure
483 #
484 # callback script paths are stored in TESTFAIL_CALLBACKS, delimited by ':'.
485
486 function _execute_testfail_callbacks
487 {
488         typeset callback
489
490         print "$TESTFAIL_CALLBACKS:" | while read -d ":" callback; do
491                 if [[ -n "$callback" ]] ; then
492                         log_note "Performing test-fail callback ($callback)"
493                         $callback
494                 fi
495         done
496 }
497
498 # Perform cleanup and exit
499 #
500 # $1 - stf exit code
501 # $2-$n - message text
502
503 function _endlog
504 {
505         typeset logfile="/tmp/log.$$"
506         _recursive_output $logfile
507
508         typeset exitcode=$1
509         shift
510         (( ${#@} > 0 )) && _printline "$@"
511
512         #
513         # If we're running in a subshell then just exit and let
514         # the parent handle the failures
515         #
516         if [[ -n "$_MAINPID" && $$ != "$_MAINPID" ]]; then
517                 log_note "subshell exited: "$_MAINPID
518                 exit $exitcode
519         fi
520
521         if [[ $exitcode == $STF_FAIL ]] ; then
522                 _execute_testfail_callbacks
523         fi
524
525         typeset stack=("${_CLEANUP[@]}")
526         log_onexit ""
527         typeset i=${#stack[@]}
528         while (( i-- )); do
529                 typeset cleanup="${stack[i]}"
530                 log_note "Performing local cleanup via log_onexit ($cleanup)"
531                 $cleanup
532         done
533
534         exit $exitcode
535 }
536
537 # Output a formatted line
538 #
539 # $@ - message text
540
541 function _printline
542 {
543         print "$@"
544 }
545
546 # Output an error message
547 #
548 # $@ - message text
549
550 function _printerror
551 {
552         _printline ERROR: "$@"
553 }
554
555 # Output a success message
556 #
557 # $@ - message text
558
559 function _printsuccess
560 {
561         _printline SUCCESS: "$@"
562 }
563
564 # Output logfiles recursively
565 #
566 # $1 - start file
567 # $2 - indicate whether output the start file itself, default as yes.
568
569 function _recursive_output #logfile
570 {
571         typeset logfile=$1
572
573         while [[ -e $logfile ]]; do
574                 if [[ -z $2 || $logfile != $1 ]]; then
575                         cat $logfile
576                 fi
577                 rm -f $logfile
578                 logfile="$logfile.$$"
579         done
580 }