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