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]
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.
41 _printline ASSERTION: "$@"
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
61 log_neg_expect "" "$@"
64 # Execute a positive test and exit $STF_FAIL is test fails
66 # $@ - command to execute
70 log_pos "$@" || log_fail
73 # Execute a positive test (expecting no stderr) and exit $STF_FAIL
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.
88 # $3-$@ - command to execute
90 function log_must_retry
92 typeset logfile="/tmp/log.$$"
99 while [[ -e $logfile ]]; do
100 logfile="$logfile.$$"
103 while (( $retry > 0 )); do
107 if (( $status == 0 )); then
108 if grep -qEi "internal error|assertion failed" $logfile; then
110 _printerror "$@" "internal error or" \
111 " assertion failure exited $status"
114 [[ -n $LOGAPI_DEBUG ]] && cat $logfile
119 if grep -qi "$expect" $logfile; then
121 _printerror "$@" "Retry in $delay seconds"
124 (( retry=retry - 1 ))
125 (( delay=delay * 2 ))
132 if (( $status != 0 )) ; then
134 _printerror "$@" "exited $status"
137 _recursive_output $logfile "false"
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
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
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,
196 function log_neg_expect
198 typeset logfile="/tmp/log.$$"
203 while [[ -e $logfile ]]; do
204 logfile="$logfile.$$"
211 if (( $status == EXIT_SUCCESS )); then
213 _printerror "$@" "unexpectedly exited $status"
215 elif (( $status == EXIT_NOTFOUND )); then
217 _printerror "$@" "unexpectedly exited $status (File not found)"
218 # bus error - core dump
219 elif (( $status == EXIT_SIGBUS )); then
221 _printerror "$@" "unexpectedly exited $status (Bus Error)"
222 # segmentation violation - core dump
223 elif (( $status == EXIT_SIGSEGV )); then
225 _printerror "$@" "unexpectedly exited $status (SEGV)"
227 if grep -qEi "internal error|assertion failed" $logfile; then
229 _printerror "$@" "internal error or assertion failure" \
231 elif [[ -n $expect ]] ; then
232 if grep -qi "$expect" $logfile; then
236 _printerror "$@" "unexpectedly exited $status"
242 if (( $ret == 0 )); then
243 [[ -n $LOGAPI_DEBUG ]] && cat $logfile
244 _printsuccess "$@" "exited $status"
247 _recursive_output $logfile "false"
251 # Execute and print command with status where success equals zero result
253 # $@ command to execute
255 # return command exit status
259 typeset logfile="/tmp/log.$$"
261 while [[ -e $logfile ]]; do
262 logfile="$logfile.$$"
268 if (( $status != 0 )) ; then
270 _printerror "$@" "exited $status"
272 if grep -qEi "internal error|assertion failed" $logfile; then
274 _printerror "$@" "internal error or assertion failure" \
278 [[ -n $LOGAPI_DEBUG ]] && cat $logfile
282 _recursive_output $logfile "false"
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
294 function log_pos_nostderr
296 typeset logfile="/tmp/log.$$"
298 while [[ -e $logfile ]]; do
299 logfile="$logfile.$$"
305 if (( $status != 0 )) ; then
307 _printerror "$@" "exited $status"
309 if [ -s "$logfile" ]; then
311 _printerror "$@" "message in stderr" \
315 [[ -n $LOGAPI_DEBUG ]] && cat $logfile
319 _recursive_output $logfile "false"
323 # Set an exit handler
325 # $@ - function(s) to perform on exit
332 # Push an exit handler on the cleanup stack
334 # $@ - function(s) to perform on exit
336 function log_onexit_push
341 # Pop an exit handler off the cleanup stack
343 function log_onexit_pop
345 _CLEANUP=("${_CLEANUP[@]:0:${#_CLEANUP[@]}-1}")
352 # Perform cleanup and exit $STF_PASS
358 _endlog $STF_PASS "$@"
361 # Perform cleanup and exit $STF_FAIL
367 _endlog $STF_FAIL "$@"
370 # Perform cleanup and exit $STF_UNRESOLVED
374 function log_unresolved
376 _endlog $STF_UNRESOLVED "$@"
379 # Perform cleanup and exit $STF_UNSUPPORTED
383 function log_unsupported
385 _endlog $STF_UNSUPPORTED "$@"
388 # Perform cleanup and exit $STF_UNTESTED
392 function log_untested
394 _endlog $STF_UNTESTED "$@"
397 function set_main_pid
406 # Execute custom callback scripts on test failure
408 # callback script paths are stored in TESTFAIL_CALLBACKS, delimited by ':'.
410 function _execute_testfail_callbacks
414 while read -d ":" callback; do
415 if [[ -n "$callback" ]] ; then
416 log_note "Performing test-fail callback ($callback)"
419 done <<<"$TESTFAIL_CALLBACKS:"
422 # Perform cleanup and exit
425 # $2-$n - message text
429 typeset logfile="/tmp/log.$$"
430 _recursive_output $logfile
434 (( ${#@} > 0 )) && _printline "$@"
437 # If we're running in a subshell then just exit and let
438 # the parent handle the failures
440 if [[ -n "$_MAINPID" && $$ != "$_MAINPID" ]]; then
441 log_note "subshell exited: "$_MAINPID
445 if [[ $exitcode == $STF_FAIL ]] ; then
446 _execute_testfail_callbacks
449 typeset stack=("${_CLEANUP[@]}")
451 typeset i=${#stack[@]}
453 typeset cleanup="${stack[i]}"
454 log_note "Performing local cleanup via log_onexit ($cleanup)"
461 # Output a formatted line
470 # Output an error message
476 _printline ERROR: "$@"
479 # Output a success message
483 function _printsuccess
485 _printline SUCCESS: "$@"
488 # Output logfiles recursively
491 # $2 - indicate whether output the start file itself, default as yes.
493 function _recursive_output #logfile
497 while [[ -e $logfile ]]; do
498 if [[ -z $2 || $logfile != $1 ]]; then
502 logfile="$logfile.$$"