482 lines
8.7 KiB
Text
482 lines
8.7 KiB
Text
|
#
|
||
|
# CDDL HEADER START
|
||
|
#
|
||
|
# The contents of this file are subject to the terms of the
|
||
|
# Common Development and Distribution License (the "License").
|
||
|
# You may not use this file except in compliance with the License.
|
||
|
#
|
||
|
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||
|
# or http://www.opensolaris.org/os/licensing.
|
||
|
# See the License for the specific language governing permissions
|
||
|
# and limitations under the License.
|
||
|
#
|
||
|
# When distributing Covered Code, include this CDDL HEADER in each
|
||
|
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||
|
# If applicable, add the following below this CDDL HEADER, with the
|
||
|
# fields enclosed by brackets "[]" replaced with your own identifying
|
||
|
# information: Portions Copyright [yyyy] [name of copyright owner]
|
||
|
#
|
||
|
# CDDL HEADER END
|
||
|
#
|
||
|
|
||
|
#
|
||
|
# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
|
||
|
# Use is subject to license terms.
|
||
|
#
|
||
|
# Copyright (c) 2012, 2016 by Delphix. All rights reserved.
|
||
|
#
|
||
|
|
||
|
. ${STF_TOOLS}/include/stf.shlib
|
||
|
|
||
|
# Output an assertion
|
||
|
#
|
||
|
# $@ - assertion text
|
||
|
|
||
|
function log_assert
|
||
|
{
|
||
|
_printline ASSERTION: "$@"
|
||
|
}
|
||
|
|
||
|
# Output a comment
|
||
|
#
|
||
|
# $@ - comment text
|
||
|
|
||
|
function log_note
|
||
|
{
|
||
|
_printline NOTE: "$@"
|
||
|
}
|
||
|
|
||
|
# Execute and print command with status where success equals non-zero result
|
||
|
#
|
||
|
# $@ - command to execute
|
||
|
#
|
||
|
# return 0 if command fails, otherwise return 1
|
||
|
|
||
|
function log_neg
|
||
|
{
|
||
|
log_neg_expect "" "$@"
|
||
|
return $?
|
||
|
}
|
||
|
|
||
|
# Execute a positive test and exit $STF_FAIL is test fails
|
||
|
#
|
||
|
# $@ - command to execute
|
||
|
|
||
|
function log_must
|
||
|
{
|
||
|
log_pos "$@"
|
||
|
(( $? != 0 )) && log_fail
|
||
|
}
|
||
|
|
||
|
# Execute a positive test but retry the command on failure if the output
|
||
|
# matches an expected pattern. Otherwise behave like log_must and exit
|
||
|
# $STF_FAIL is test fails.
|
||
|
#
|
||
|
# $1 - retry keyword
|
||
|
# $2 - retry attempts
|
||
|
# $3-$@ - command to execute
|
||
|
#
|
||
|
function log_must_retry
|
||
|
{
|
||
|
typeset out=""
|
||
|
typeset logfile="/tmp/log.$$"
|
||
|
typeset status=1
|
||
|
typeset expect=$1
|
||
|
typeset retry=$2
|
||
|
typeset delay=1
|
||
|
shift 2
|
||
|
|
||
|
while [[ -e $logfile ]]; do
|
||
|
logfile="$logfile.$$"
|
||
|
done
|
||
|
|
||
|
while (( $retry > 0 )); do
|
||
|
"$@" 2>$logfile
|
||
|
status=$?
|
||
|
out="cat $logfile"
|
||
|
|
||
|
if (( $status == 0 )); then
|
||
|
$out | egrep -i "internal error|assertion failed" \
|
||
|
> /dev/null 2>&1
|
||
|
# internal error or assertion failed
|
||
|
if [[ $? -eq 0 ]]; then
|
||
|
print -u2 $($out)
|
||
|
_printerror "$@" "internal error or" \
|
||
|
" assertion failure exited $status"
|
||
|
status=1
|
||
|
else
|
||
|
[[ -n $LOGAPI_DEBUG ]] && print $($out)
|
||
|
_printsuccess "$@"
|
||
|
fi
|
||
|
break
|
||
|
else
|
||
|
$out | grep -i "$expect" > /dev/null 2>&1
|
||
|
if (( $? == 0 )); then
|
||
|
print -u2 $($out)
|
||
|
_printerror "$@" "Retry in $delay seconds"
|
||
|
sleep $delay
|
||
|
|
||
|
(( retry=retry - 1 ))
|
||
|
(( delay=delay * 2 ))
|
||
|
else
|
||
|
break;
|
||
|
fi
|
||
|
fi
|
||
|
done
|
||
|
|
||
|
if (( $status != 0 )) ; then
|
||
|
print -u2 $($out)
|
||
|
_printerror "$@" "exited $status"
|
||
|
fi
|
||
|
|
||
|
_recursive_output $logfile "false"
|
||
|
return $status
|
||
|
}
|
||
|
|
||
|
# Execute a positive test and exit $STF_FAIL is test fails after being
|
||
|
# retried up to 5 times when the command returns the keyword "busy".
|
||
|
#
|
||
|
# $@ - command to execute
|
||
|
function log_must_busy
|
||
|
{
|
||
|
log_must_retry "busy" 5 "$@"
|
||
|
(( $? != 0 )) && log_fail
|
||
|
}
|
||
|
|
||
|
# Execute a negative test and exit $STF_FAIL if test passes
|
||
|
#
|
||
|
# $@ - command to execute
|
||
|
|
||
|
function log_mustnot
|
||
|
{
|
||
|
log_neg "$@"
|
||
|
(( $? != 0 )) && log_fail
|
||
|
}
|
||
|
|
||
|
# Execute a negative test with keyword expected, and exit
|
||
|
# $STF_FAIL if test passes
|
||
|
#
|
||
|
# $1 - keyword expected
|
||
|
# $2-$@ - command to execute
|
||
|
|
||
|
function log_mustnot_expect
|
||
|
{
|
||
|
log_neg_expect "$@"
|
||
|
(( $? != 0 )) && log_fail
|
||
|
}
|
||
|
|
||
|
# Execute and print command with status where success equals non-zero result
|
||
|
# or output includes expected keyword
|
||
|
#
|
||
|
# $1 - keyword expected
|
||
|
# $2-$@ - command to execute
|
||
|
#
|
||
|
# return 0 if command fails, or the output contains the keyword expected,
|
||
|
# return 1 otherwise
|
||
|
|
||
|
function log_neg_expect
|
||
|
{
|
||
|
typeset out=""
|
||
|
typeset logfile="/tmp/log.$$"
|
||
|
typeset ret=1
|
||
|
typeset expect=$1
|
||
|
shift
|
||
|
|
||
|
while [[ -e $logfile ]]; do
|
||
|
logfile="$logfile.$$"
|
||
|
done
|
||
|
|
||
|
"$@" 2>$logfile
|
||
|
typeset status=$?
|
||
|
out="cat $logfile"
|
||
|
|
||
|
# unexpected status
|
||
|
if (( $status == 0 )); then
|
||
|
print -u2 $($out)
|
||
|
_printerror "$@" "unexpectedly exited $status"
|
||
|
# missing binary
|
||
|
elif (( $status == 127 )); then
|
||
|
print -u2 $($out)
|
||
|
_printerror "$@" "unexpectedly exited $status (File not found)"
|
||
|
# bus error - core dump (256+signal, SIGBUS=7)
|
||
|
elif (( $status == 263 )); then
|
||
|
print -u2 $($out)
|
||
|
_printerror "$@" "unexpectedly exited $status (Bus Error)"
|
||
|
# segmentation violation - core dump (256+signal, SIGSEGV=11)
|
||
|
elif (( $status == 267 )); then
|
||
|
print -u2 $($out)
|
||
|
_printerror "$@" "unexpectedly exited $status (SEGV)"
|
||
|
else
|
||
|
$out | egrep -i "internal error|assertion failed" \
|
||
|
> /dev/null 2>&1
|
||
|
# internal error or assertion failed
|
||
|
if (( $? == 0 )); then
|
||
|
print -u2 $($out)
|
||
|
_printerror "$@" "internal error or assertion failure" \
|
||
|
" exited $status"
|
||
|
elif [[ -n $expect ]] ; then
|
||
|
$out | grep -i "$expect" > /dev/null 2>&1
|
||
|
if (( $? == 0 )); then
|
||
|
ret=0
|
||
|
else
|
||
|
print -u2 $($out)
|
||
|
_printerror "$@" "unexpectedly exited $status"
|
||
|
fi
|
||
|
else
|
||
|
ret=0
|
||
|
fi
|
||
|
|
||
|
if (( $ret == 0 )); then
|
||
|
[[ -n $LOGAPI_DEBUG ]] && print $($out)
|
||
|
_printsuccess "$@" "exited $status"
|
||
|
fi
|
||
|
fi
|
||
|
_recursive_output $logfile "false"
|
||
|
return $ret
|
||
|
}
|
||
|
|
||
|
# Execute and print command with status where success equals zero result
|
||
|
#
|
||
|
# $@ command to execute
|
||
|
#
|
||
|
# return command exit status
|
||
|
|
||
|
function log_pos
|
||
|
{
|
||
|
typeset out=""
|
||
|
typeset logfile="/tmp/log.$$"
|
||
|
|
||
|
while [[ -e $logfile ]]; do
|
||
|
logfile="$logfile.$$"
|
||
|
done
|
||
|
|
||
|
"$@" 2>$logfile
|
||
|
typeset status=$?
|
||
|
out="cat $logfile"
|
||
|
|
||
|
if (( $status != 0 )) ; then
|
||
|
print -u2 $($out)
|
||
|
_printerror "$@" "exited $status"
|
||
|
else
|
||
|
$out | egrep -i "internal error|assertion failed" \
|
||
|
> /dev/null 2>&1
|
||
|
# internal error or assertion failed
|
||
|
if [[ $? -eq 0 ]]; then
|
||
|
print -u2 $($out)
|
||
|
_printerror "$@" "internal error or assertion failure" \
|
||
|
" exited $status"
|
||
|
status=1
|
||
|
else
|
||
|
[[ -n $LOGAPI_DEBUG ]] && print $($out)
|
||
|
_printsuccess "$@"
|
||
|
fi
|
||
|
fi
|
||
|
_recursive_output $logfile "false"
|
||
|
return $status
|
||
|
}
|
||
|
|
||
|
# Set an exit handler
|
||
|
#
|
||
|
# $@ - function(s) to perform on exit
|
||
|
|
||
|
function log_onexit
|
||
|
{
|
||
|
_CLEANUP="$@"
|
||
|
}
|
||
|
|
||
|
#
|
||
|
# Exit functions
|
||
|
#
|
||
|
|
||
|
# Perform cleanup and exit $STF_PASS
|
||
|
#
|
||
|
# $@ - message text
|
||
|
|
||
|
function log_pass
|
||
|
{
|
||
|
_endlog $STF_PASS "$@"
|
||
|
}
|
||
|
|
||
|
# Perform cleanup and exit $STF_FAIL
|
||
|
#
|
||
|
# $@ - message text
|
||
|
|
||
|
function log_fail
|
||
|
{
|
||
|
_endlog $STF_FAIL "$@"
|
||
|
}
|
||
|
|
||
|
# Perform cleanup and exit $STF_UNRESOLVED
|
||
|
#
|
||
|
# $@ - message text
|
||
|
|
||
|
function log_unresolved
|
||
|
{
|
||
|
_endlog $STF_UNRESOLVED "$@"
|
||
|
}
|
||
|
|
||
|
# Perform cleanup and exit $STF_NOTINUSE
|
||
|
#
|
||
|
# $@ - message text
|
||
|
|
||
|
function log_notinuse
|
||
|
{
|
||
|
_endlog $STF_NOTINUSE "$@"
|
||
|
}
|
||
|
|
||
|
# Perform cleanup and exit $STF_UNSUPPORTED
|
||
|
#
|
||
|
# $@ - message text
|
||
|
|
||
|
function log_unsupported
|
||
|
{
|
||
|
_endlog $STF_UNSUPPORTED "$@"
|
||
|
}
|
||
|
|
||
|
# Perform cleanup and exit $STF_UNTESTED
|
||
|
#
|
||
|
# $@ - message text
|
||
|
|
||
|
function log_untested
|
||
|
{
|
||
|
_endlog $STF_UNTESTED "$@"
|
||
|
}
|
||
|
|
||
|
# Perform cleanup and exit $STF_UNINITIATED
|
||
|
#
|
||
|
# $@ - message text
|
||
|
|
||
|
function log_uninitiated
|
||
|
{
|
||
|
_endlog $STF_UNINITIATED "$@"
|
||
|
}
|
||
|
|
||
|
# Perform cleanup and exit $STF_NORESULT
|
||
|
#
|
||
|
# $@ - message text
|
||
|
|
||
|
function log_noresult
|
||
|
{
|
||
|
_endlog $STF_NORESULT "$@"
|
||
|
}
|
||
|
|
||
|
# Perform cleanup and exit $STF_WARNING
|
||
|
#
|
||
|
# $@ - message text
|
||
|
|
||
|
function log_warning
|
||
|
{
|
||
|
_endlog $STF_WARNING "$@"
|
||
|
}
|
||
|
|
||
|
# Perform cleanup and exit $STF_TIMED_OUT
|
||
|
#
|
||
|
# $@ - message text
|
||
|
|
||
|
function log_timed_out
|
||
|
{
|
||
|
_endlog $STF_TIMED_OUT "$@"
|
||
|
}
|
||
|
|
||
|
# Perform cleanup and exit $STF_OTHER
|
||
|
#
|
||
|
# $@ - message text
|
||
|
|
||
|
function log_other
|
||
|
{
|
||
|
_endlog $STF_OTHER "$@"
|
||
|
}
|
||
|
|
||
|
#
|
||
|
# Internal functions
|
||
|
#
|
||
|
|
||
|
# Execute custom callback scripts on test failure
|
||
|
#
|
||
|
# callback script paths are stored in TESTFAIL_CALLBACKS, delimited by ':'.
|
||
|
|
||
|
function _execute_testfail_callbacks
|
||
|
{
|
||
|
typeset callback
|
||
|
|
||
|
print "$TESTFAIL_CALLBACKS:" | while read -d ":" callback; do
|
||
|
if [[ -n "$callback" ]] ; then
|
||
|
log_note "Performing test-fail callback ($callback)"
|
||
|
$callback
|
||
|
fi
|
||
|
done
|
||
|
}
|
||
|
|
||
|
# Perform cleanup and exit
|
||
|
#
|
||
|
# $1 - stf exit code
|
||
|
# $2-$n - message text
|
||
|
|
||
|
function _endlog
|
||
|
{
|
||
|
typeset logfile="/tmp/log.$$"
|
||
|
_recursive_output $logfile
|
||
|
|
||
|
typeset exitcode=$1
|
||
|
shift
|
||
|
(( ${#@} > 0 )) && _printline "$@"
|
||
|
|
||
|
if [[ $exitcode == $STF_FAIL ]] ; then
|
||
|
_execute_testfail_callbacks
|
||
|
fi
|
||
|
|
||
|
if [[ -n $_CLEANUP ]] ; then
|
||
|
typeset cleanup=$_CLEANUP
|
||
|
log_onexit ""
|
||
|
log_note "Performing local cleanup via log_onexit ($cleanup)"
|
||
|
$cleanup
|
||
|
fi
|
||
|
|
||
|
exit $exitcode
|
||
|
}
|
||
|
|
||
|
# Output a formatted line
|
||
|
#
|
||
|
# $@ - message text
|
||
|
|
||
|
function _printline
|
||
|
{
|
||
|
print "$@"
|
||
|
}
|
||
|
|
||
|
# Output an error message
|
||
|
#
|
||
|
# $@ - message text
|
||
|
|
||
|
function _printerror
|
||
|
{
|
||
|
_printline ERROR: "$@"
|
||
|
}
|
||
|
|
||
|
# Output a success message
|
||
|
#
|
||
|
# $@ - message text
|
||
|
|
||
|
function _printsuccess
|
||
|
{
|
||
|
_printline SUCCESS: "$@"
|
||
|
}
|
||
|
|
||
|
# Output logfiles recursively
|
||
|
#
|
||
|
# $1 - start file
|
||
|
# $2 - indicate whether output the start file itself, default as yes.
|
||
|
|
||
|
function _recursive_output #logfile
|
||
|
{
|
||
|
typeset logfile=$1
|
||
|
|
||
|
while [[ -e $logfile ]]; do
|
||
|
if [[ -z $2 || $logfile != $1 ]]; then
|
||
|
cat $logfile
|
||
|
fi
|
||
|
rm -f $logfile
|
||
|
logfile="$logfile.$$"
|
||
|
done
|
||
|
}
|