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