zpool/zfs: restore -V & --version options
[zfs.git] / tests / test-runner / include / logapi.shlib
blob8a9ca3e87caf6a3dcedf10b954825ba47da0fa6d
2 # CDDL HEADER START
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.
8 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 # or https://opensource.org/licenses/CDDL-1.0.
10 # See the License for the specific language governing permissions
11 # and limitations under the License.
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]
19 # CDDL HEADER END
23 # Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24 # Use is subject to license terms.
26 # Copyright (c) 2012, 2020 by Delphix. All rights reserved.
29 STF_PASS=0
30 STF_FAIL=1
31 STF_UNRESOLVED=2
32 STF_UNSUPPORTED=4
33 STF_UNTESTED=5
35 # Output an assertion
37 # $@ - assertion text
39 function log_assert
41         _printline ASSERTION: "$@"
44 # Output a comment
46 # $@ - comment text
48 function log_note
50         _printline NOTE: "$@"
53 # Execute and print command with status where success equals non-zero result
55 # $@ - command to execute
57 # return 0 if command fails, otherwise return 1
59 function log_neg
61         log_neg_expect "" "$@"
64 # Execute a positive test and exit $STF_FAIL is test fails
66 # $@ - command to execute
68 function log_must
70         log_pos "$@" || log_fail
73 # Execute a positive test (expecting no stderr) and exit $STF_FAIL
74 # if test fails
75 # $@ - command to execute
77 function log_must_nostderr
79         log_pos_nostderr "$@" || log_fail
82 # Execute a positive test but retry the command on failure if the output
83 # matches an expected pattern.  Otherwise behave like log_must and exit
84 # $STF_FAIL is test fails.
86 # $1 - retry keyword
87 # $2 - retry attempts
88 # $3-$@ - command to execute
90 function log_must_retry
92         typeset logfile="/tmp/log.$$"
93         typeset status=1
94         typeset expect=$1
95         typeset retry=$2
96         typeset delay=1
97         shift 2
99         while [[ -e $logfile ]]; do
100                 logfile="$logfile.$$"
101         done
103         while (( $retry > 0 )); do
104                 "$@" 2>$logfile
105                 status=$?
107                 if (( $status == 0 )); then
108                         if grep -qEi "internal error|assertion failed" $logfile; then
109                                 cat $logfile >&2
110                                 _printerror "$@" "internal error or" \
111                                         " assertion failure exited $status"
112                                 status=1
113                         else
114                                 [[ -n $LOGAPI_DEBUG ]] && cat $logfile
115                                 _printsuccess "$@"
116                         fi
117                         break
118                 else
119                         if grep -qi "$expect" $logfile; then
120                                 cat $logfile >&2
121                                 _printerror "$@" "Retry in $delay seconds"
122                                 sleep $delay
124                                 (( retry=retry - 1 ))
125                                 (( delay=delay * 2 ))
126                         else
127                                 break;
128                         fi
129                 fi
130         done
132         if (( $status != 0 )) ; then
133                 cat $logfile >&2
134                 _printerror "$@" "exited $status"
135         fi
137         _recursive_output $logfile "false"
138         return $status
141 # Execute a positive test and exit $STF_FAIL is test fails after being
142 # retried up to 5 times when the command returns the keyword "busy".
144 # $@ - command to execute
145 function log_must_busy
147         log_must_retry "busy" 5 "$@" || log_fail
150 # Execute a negative test and exit $STF_FAIL if test passes
152 # $@ - command to execute
154 function log_mustnot
156         log_neg "$@" || log_fail
159 # Execute a negative test with keyword expected, and exit
160 # $STF_FAIL if test passes
162 # $1 - keyword expected
163 # $2-$@ - command to execute
165 function log_mustnot_expect
167         log_neg_expect "$@" || log_fail
170 # Signal numbers are platform-dependent
171 case $(uname) in
172 Darwin|FreeBSD)
173         SIGBUS=10
174         SIGSEGV=11
175         ;;
176 illumos|Linux|*)
177         SIGBUS=7
178         SIGSEGV=11
179         ;;
180 esac
181 EXIT_SUCCESS=0
182 EXIT_NOTFOUND=127
183 EXIT_SIGNAL=256
184 EXIT_SIGBUS=$((EXIT_SIGNAL + SIGBUS))
185 EXIT_SIGSEGV=$((EXIT_SIGNAL + SIGSEGV))
187 # Execute and print command with status where success equals non-zero result
188 # or output includes expected keyword
190 # $1 - keyword expected
191 # $2-$@ - command to execute
193 # return 0 if command fails, or the output contains the keyword expected,
194 # return 1 otherwise
196 function log_neg_expect
198         typeset logfile="/tmp/log.$$"
199         typeset ret=1
200         typeset expect=$1
201         shift
203         while [[ -e $logfile ]]; do
204                 logfile="$logfile.$$"
205         done
207         "$@" 2>$logfile
208         typeset status=$?
210         # unexpected status
211         if (( $status == EXIT_SUCCESS )); then
212                  cat $logfile >&2
213                 _printerror "$@" "unexpectedly exited $status"
214         # missing binary
215         elif (( $status == EXIT_NOTFOUND )); then
216                 cat $logfile >&2
217                 _printerror "$@" "unexpectedly exited $status (File not found)"
218         # bus error - core dump
219         elif (( $status == EXIT_SIGBUS )); then
220                 cat $logfile >&2
221                 _printerror "$@" "unexpectedly exited $status (Bus Error)"
222         # segmentation violation - core dump
223         elif (( $status == EXIT_SIGSEGV )); then
224                 cat $logfile >&2
225                 _printerror "$@" "unexpectedly exited $status (SEGV)"
226         else
227                 if grep -qEi "internal error|assertion failed" $logfile; then
228                         cat $logfile >&2
229                         _printerror "$@" "internal error or assertion failure" \
230                                 " exited $status"
231                 elif [[ -n $expect ]] ; then
232                         if grep -qi "$expect" $logfile; then
233                                 ret=0
234                         else
235                                 cat $logfile >&2
236                                 _printerror "$@" "unexpectedly exited $status"
237                         fi
238                 else
239                         ret=0
240                 fi
242                 if (( $ret == 0 )); then
243                         [[ -n $LOGAPI_DEBUG ]] && cat $logfile
244                         _printsuccess "$@" "exited $status"
245                 fi
246         fi
247         _recursive_output $logfile "false"
248         return $ret
251 # Execute and print command with status where success equals zero result
253 # $@ command to execute
255 # return command exit status
257 function log_pos
259         typeset logfile="/tmp/log.$$"
261         while [[ -e $logfile ]]; do
262                 logfile="$logfile.$$"
263         done
265         "$@" 2>$logfile
266         typeset status=$?
268         if (( $status != 0 )) ; then
269                 cat $logfile >&2
270                 _printerror "$@" "exited $status"
271         else
272                 if grep -qEi "internal error|assertion failed" $logfile; then
273                         cat $logfile >&2
274                         _printerror "$@" "internal error or assertion failure" \
275                                 " exited $status"
276                         status=1
277                 else
278                         [[ -n $LOGAPI_DEBUG ]] && cat $logfile
279                         _printsuccess "$@"
280                 fi
281         fi
282         _recursive_output $logfile "false"
283         return $status
286 # Execute and print command with status where success equals zero result
287 # and no stderr output
289 # $@ command to execute
291 # return 0 if command succeeds and no stderr output
292 # return 1 othersie
294 function log_pos_nostderr
296         typeset logfile="/tmp/log.$$"
298         while [[ -e $logfile ]]; do
299                 logfile="$logfile.$$"
300         done
302         "$@" 2>$logfile
303         typeset status=$?
305         if (( $status != 0 )) ; then
306                 cat $logfile >&2
307                 _printerror "$@" "exited $status"
308         else
309                 if [ -s "$logfile" ]; then
310                         cat $logfile >&2
311                         _printerror "$@" "message in stderr" \
312                                 " exited $status"
313                         status=1
314                 else
315                         [[ -n $LOGAPI_DEBUG ]] && cat $logfile
316                         _printsuccess "$@"
317                 fi
318         fi
319         _recursive_output $logfile "false"
320         return $status
323 # Set an exit handler
325 # $@ - function(s) to perform on exit
327 function log_onexit
329         _CLEANUP=("$*")
332 # Push an exit handler on the cleanup stack
334 # $@ - function(s) to perform on exit
336 function log_onexit_push
338         _CLEANUP+=("$*")
341 # Pop an exit handler off the cleanup stack
343 function log_onexit_pop
345         _CLEANUP=("${_CLEANUP[@]:0:${#_CLEANUP[@]}-1}")
349 # Exit functions
352 # Perform cleanup and exit $STF_PASS
354 # $@ - message text
356 function log_pass
358         _endlog $STF_PASS "$@"
361 # Perform cleanup and exit $STF_FAIL
363 # $@ - message text
365 function log_fail
367         _endlog $STF_FAIL "$@"
370 # Perform cleanup and exit $STF_UNRESOLVED
372 # $@ - message text
374 function log_unresolved
376         _endlog $STF_UNRESOLVED "$@"
379 # Perform cleanup and exit $STF_UNSUPPORTED
381 # $@ - message text
383 function log_unsupported
385         _endlog $STF_UNSUPPORTED "$@"
388 # Perform cleanup and exit $STF_UNTESTED
390 # $@ - message text
392 function log_untested
394         _endlog $STF_UNTESTED "$@"
397 function set_main_pid
399         _MAINPID=$1
403 # Internal functions
406 # Execute custom callback scripts on test failure
408 # callback script paths are stored in TESTFAIL_CALLBACKS, delimited by ':'.
410 function _execute_testfail_callbacks
412         typeset callback
414         while read -d ":" callback; do
415                 if [[ -n "$callback" ]] ; then
416                         log_note "Performing test-fail callback ($callback)"
417                         $callback
418                 fi
419         done <<<"$TESTFAIL_CALLBACKS:"
422 # Perform cleanup and exit
424 # $1 - stf exit code
425 # $2-$n - message text
427 function _endlog
429         typeset logfile="/tmp/log.$$"
430         _recursive_output $logfile
432         typeset exitcode=$1
433         shift
434         (( ${#@} > 0 )) && _printline "$@"
436         #
437         # If we're running in a subshell then just exit and let
438         # the parent handle the failures
439         #
440         if [[ -n "$_MAINPID" && $$ != "$_MAINPID" ]]; then
441                 log_note "subshell exited: "$_MAINPID
442                 exit $exitcode
443         fi
445         if [[ $exitcode == $STF_FAIL ]] ; then
446                 _execute_testfail_callbacks
447         fi
449         typeset stack=("${_CLEANUP[@]}")
450         log_onexit ""
451         typeset i=${#stack[@]}
452         while (( i-- )); do
453                 typeset cleanup="${stack[i]}"
454                 log_note "Performing local cleanup via log_onexit ($cleanup)"
455                 $cleanup
456         done
458         exit $exitcode
461 # Output a formatted line
463 # $@ - message text
465 function _printline
467         echo "$@"
470 # Output an error message
472 # $@ - message text
474 function _printerror
476         _printline ERROR: "$@"
479 # Output a success message
481 # $@ - message text
483 function _printsuccess
485         _printline SUCCESS: "$@"
488 # Output logfiles recursively
490 # $1 - start file
491 # $2 - indicate whether output the start file itself, default as yes.
493 function _recursive_output #logfile
495         typeset logfile=$1
497         while [[ -e $logfile ]]; do
498                 if [[ -z $2 || $logfile != $1 ]]; then
499                         cat $logfile
500                 fi
501                 rm -f $logfile
502                 logfile="$logfile.$$"
503         done