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 https://opensource.org/licenses/CDDL-1.0.
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_PASS=0
30 STF_FAIL=1
31 STF_UNRESOLVED=2
32 STF_UNSUPPORTED=4
33 STF_UNTESTED=5
34
35 # Output an assertion
36 #
37 # $@ - assertion text
38
39 function log_assert
40 {
41 _printline ASSERTION: "$@"
42 }
43
44 # Output a comment
45 #
46 # $@ - comment text
47
48 function log_note
49 {
50 _printline NOTE: "$@"
51 }
52
53 # Execute and print command with status where success equals non-zero result
54 #
55 # $@ - command to execute
56 #
57 # return 0 if command fails, otherwise return 1
58
59 function log_neg
60 {
61 log_neg_expect "" "$@"
62 }
63
64 # Execute a positive test and exit $STF_FAIL is test fails
65 #
66 # $@ - command to execute
67
68 function log_must
69 {
70 log_pos "$@" || log_fail
71 }
72
73 # Execute a positive test (expecting no stderr) and exit $STF_FAIL
74 # if test fails
75 # $@ - command to execute
76
77 function log_must_nostderr
78 {
79 log_pos_nostderr "$@" || log_fail
80 }
81
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.
85 #
86 # $1 - retry keyword
87 # $2 - retry attempts
88 # $3-$@ - command to execute
89 #
90 function log_must_retry
91 {
92 typeset logfile="/tmp/log.$$"
93 typeset status=1
94 typeset expect=$1
95 typeset retry=$2
96 typeset delay=1
97 shift 2
98
99 while [[ -e $logfile ]]; do
100 logfile="$logfile.$$"
101 done
102
103 while (( $retry > 0 )); do
104 "$@" 2>$logfile
105 status=$?
106
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
123
124 (( retry=retry - 1 ))
125 (( delay=delay * 2 ))
126 else
127 break;
128 fi
129 fi
130 done
131
132 if (( $status != 0 )) ; then
133 cat $logfile >&2
134 _printerror "$@" "exited $status"
135 fi
136
137 _recursive_output $logfile "false"
138 return $status
139 }
140
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".
143 #
144 # $@ - command to execute
145 function log_must_busy
146 {
147 log_must_retry "busy" 5 "$@" || log_fail
148 }
149
150 # Execute a negative test and exit $STF_FAIL if test passes
151 #
152 # $@ - command to execute
153
154 function log_mustnot
155 {
156 log_neg "$@" || log_fail
157 }
158
159 # Execute a negative test with keyword expected, and exit
160 # $STF_FAIL if test passes
161 #
162 # $1 - keyword expected
163 # $2-$@ - command to execute
164
165 function log_mustnot_expect
166 {
167 log_neg_expect "$@" || log_fail
168 }
169
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))
186
187 # Execute and print command with status where success equals non-zero result
188 # or output includes expected keyword
189 #
190 # $1 - keyword expected
191 # $2-$@ - command to execute
192 #
193 # return 0 if command fails, or the output contains the keyword expected,
194 # return 1 otherwise
195
196 function log_neg_expect
197 {
198 typeset logfile="/tmp/log.$$"
199 typeset ret=1
200 typeset expect=$1
201 shift
202
203 while [[ -e $logfile ]]; do
204 logfile="$logfile.$$"
205 done
206
207 "$@" 2>$logfile
208 typeset status=$?
209
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
241
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
249 }
250
251 # Execute and print command with status where success equals zero result
252 #
253 # $@ command to execute
254 #
255 # return command exit status
256
257 function log_pos
258 {
259 typeset logfile="/tmp/log.$$"
260
261 while [[ -e $logfile ]]; do
262 logfile="$logfile.$$"
263 done
264
265 "$@" 2>$logfile
266 typeset status=$?
267
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
284 }
285
286 # Execute and print command with status where success equals zero result
287 # and no stderr output
288 #
289 # $@ command to execute
290 #
291 # return 0 if command succeeds and no stderr output
292 # return 1 othersie
293
294 function log_pos_nostderr
295 {
296 typeset logfile="/tmp/log.$$"
297
298 while [[ -e $logfile ]]; do
299 logfile="$logfile.$$"
300 done
301
302 "$@" 2>$logfile
303 typeset status=$?
304
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
321 }
322
323 # Set an exit handler
324 #
325 # $@ - function(s) to perform on exit
326
327 function log_onexit
328 {
329 _CLEANUP=("$*")
330 }
331
332 # Push an exit handler on the cleanup stack
333 #
334 # $@ - function(s) to perform on exit
335
336 function log_onexit_push
337 {
338 _CLEANUP+=("$*")
339 }
340
341 # Pop an exit handler off the cleanup stack
342
343 function log_onexit_pop
344 {
345 _CLEANUP=("${_CLEANUP[@]:0:${#_CLEANUP[@]}-1}")
346 }
347
348 #
349 # Exit functions
350 #
351
352 # Perform cleanup and exit $STF_PASS
353 #
354 # $@ - message text
355
356 function log_pass
357 {
358 _endlog $STF_PASS "$@"
359 }
360
361 # Perform cleanup and exit $STF_FAIL
362 #
363 # $@ - message text
364
365 function log_fail
366 {
367 _endlog $STF_FAIL "$@"
368 }
369
370 # Perform cleanup and exit $STF_UNRESOLVED
371 #
372 # $@ - message text
373
374 function log_unresolved
375 {
376 _endlog $STF_UNRESOLVED "$@"
377 }
378
379 # Perform cleanup and exit $STF_UNSUPPORTED
380 #
381 # $@ - message text
382
383 function log_unsupported
384 {
385 _endlog $STF_UNSUPPORTED "$@"
386 }
387
388 # Perform cleanup and exit $STF_UNTESTED
389 #
390 # $@ - message text
391
392 function log_untested
393 {
394 _endlog $STF_UNTESTED "$@"
395 }
396
397 function set_main_pid
398 {
399 _MAINPID=$1
400 }
401
402 #
403 # Internal functions
404 #
405
406 # Execute custom callback scripts on test failure
407 #
408 # callback script paths are stored in TESTFAIL_CALLBACKS, delimited by ':'.
409
410 function _execute_testfail_callbacks
411 {
412 typeset callback
413
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:"
420 }
421
422 # Perform cleanup and exit
423 #
424 # $1 - stf exit code
425 # $2-$n - message text
426
427 function _endlog
428 {
429 typeset logfile="/tmp/log.$$"
430 _recursive_output $logfile
431
432 typeset exitcode=$1
433 shift
434 (( ${#@} > 0 )) && _printline "$@"
435
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
444
445 if [[ $exitcode == $STF_FAIL ]] ; then
446 _execute_testfail_callbacks
447 fi
448
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
457
458 exit $exitcode
459 }
460
461 # Output a formatted line
462 #
463 # $@ - message text
464
465 function _printline
466 {
467 echo "$@"
468 }
469
470 # Output an error message
471 #
472 # $@ - message text
473
474 function _printerror
475 {
476 _printline ERROR: "$@"
477 }
478
479 # Output a success message
480 #
481 # $@ - message text
482
483 function _printsuccess
484 {
485 _printline SUCCESS: "$@"
486 }
487
488 # Output logfiles recursively
489 #
490 # $1 - start file
491 # $2 - indicate whether output the start file itself, default as yes.
492
493 function _recursive_output #logfile
494 {
495 typeset logfile=$1
496
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
504 }
Cache object: 08b2800f1adab01bdbb1ca2d17469bf9
|