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