All pastes #1987795 Raw Edit

test001

public text v1 · immutable
#1987795 ·published 2010-11-11 04:12 UTC
rendered paste body
## 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 (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.### Written by Roland Mainz <roland.mainz@nrubsig.org>## HACK BEGIN# this is a HACK to disable the VM* debugging, otherwise the test runs for# two hour on our SPARCif [[ ! -v NOVMDEBUG ]] ; then	unset VMALLOC_OPTIONS VMDEBUG	NOVMDEBUG=1 exec ${SHELL} "$0" "$@"fi# HACK END# test setupfunction err_exit{	print -u2 -n "\t"	print -u2 -r ${Command}[$1]: "${@:2}"	(( Errors < 127 && Errors++ ))}alias err_exit='err_exit $LINENO'set -o nounsetCommand=${0##*/}integer Errors=0typeset ocwdtypeset tmpdirtypeset out# create temporary test directoryocwd="$PWD"tmpdir="$(mktemp -t -d "test_sun_solaris_command_substitution.XXXXXXXX")" || err_exit "Cannot create temporary directory"cd "${tmpdir}" || { err_exit "cd ${tmpdir} failed." ; exit $((Errors)) ; }function isvalidpid{        kill -0 ${1} 2>/dev/null && return 0        return 1}function pretests{	cat <<EOF >'myseq'#!${SHELL}# script version of "seq"function main{	integer i	integer arg1=\$1	integer arg2=\$2	integer arg3=\$3	case \$# in		1)			for (( i=1. ; i <= arg1 ; i=i+1. )) ; do				printf '%d\n' i			done			;;		2)			for (( i=arg1 ; i <= arg2 ; i=i+1. )) ; do				printf '%d\n' i			done			;;		3)			for (( i=arg1 ; i <= arg3 ; i+=arg2 )) ; do				printf '%d\n' i			done			;;		*)			print -u2 -f '%s: Illegal number of arguments %d\n' "\$0" \$#			return 1			;;	esac		return 0}set -o noglobIFS=''main "\$@"exit \$?EOF	chmod a+rx 'myseq'	return 0}function posttests{	rm 'myseq'}# test1: run loop and check various temp filesizes# (Please keep this test syncted with sun_solaris_cr_6800929_large_command_substitution_hang.sh)function test1{	integer childpid	integer maxwait	integer i	integer testfilesize	typeset tmpfile='test1tmpfile'	integer testid		compound -r test1=(		compound -r -a testcases=(			# test 1a: Run test child for $(...)			# (note the pipe chain has to end in a builtin command, an external command may not trigger the bug)			( name="test1a" cmd="builtin cat ; print -- \"\$(cat \"${tmpfile}\" | cat)\" ; true" )			# test 1b: Same as test1a but uses ${... ; } instead if $(...)			( name="test1b" cmd="builtin cat ; print -- \"\${ cat \"${tmpfile}\" | cat ; }\" ; true" )			# test 1c: Same as test1a but does not use a pipe			( name="test1c" cmd="builtin cat ; print -- \"\$(cat \"${tmpfile}\" ; true)\" ; true" )			# test 1d: Same as test1a but does not use a pipe			( name="test1d" cmd="builtin cat ; print -- \"\${ cat \"${tmpfile}\" ; true ; }\" ; true" )				# test 1e: Same as test1a but uses an external "cat" command			( name="test1e" cmd="builtin -d cat /bin/cat ; print -- \"\$(cat \"${tmpfile}\" | cat)\" ; true" )			# test 1f: Same as test1a but uses an external "cat" command			( name="test1f" cmd="builtin -d cat /bin/cat ; print -- \"\${ cat \"${tmpfile}\" | cat ; }\" ; true" )			# test 1g: Same as test1a but uses an external "cat" command			( name="test1g" cmd="builtin -d cat /bin/cat ; print -- \"\$(cat \"${tmpfile}\" ; true)\" ; true" )			# test 1h: Same as test1a but uses an external "cat" command			( name="test1h" cmd="builtin -d cat /bin/cat ; print -- \"\${ cat \"${tmpfile}\" ; true ; }\" ; true" )		)	)		for (( testfilesize=1*1024 ; testfilesize <= 1024*1024 ; testfilesize*=2 )) ; do		# Create temp file		{			for (( i=0 ; i < testfilesize ; i+=64 )) ; do				print '0123456789abcdef01234567890ABCDEF0123456789abcdef01234567890ABCDE'			done		} >"${tmpfile}"			# wait up to log2(i) seconds for the child to terminate		# (this is 10 seconds for 1KB and 19 seconds for 512KB)		(( maxwait=log2(testfilesize) ))					for testid in "${!test1.testcases[@]}" ; do			nameref currtst=test1.testcases[testid]			${SHELL} -o errexit -c "${currtst.cmd}" >"${tmpfile}.out" &			(( childpid=$! ))				for (( i=0 ; i < maxwait ; i++ )) ; do				isvalidpid ${childpid} || break				sleep 0.25			done				if isvalidpid ${childpid} ; then				err_exit "${currtst.name}: child (pid=${childpid}) still busy, filesize=${testfilesize}."				kill -KILL ${childpid} 2>/dev/null			fi			wait || err_exit "${currtst.name}: Child returned non-zero exit code." # wait for child (and/or avoid zombies/slime)				# compare input/output			cmp -s "${tmpfile}" "${tmpfile}.out" || err_exit "${currtst.name}: ${tmpfile} and ${tmpfile}.out differ, filesize=${testfilesize}."			rm "${tmpfile}.out"		done			# Cleanup		rm "${tmpfile}"	done	return 0}# test2: If a command substitution calls a function and that function contains# a command substitution which contains a piped command, the original# command substitution calling the function will return 127 instead of 0.# This is causing problems in several VSC tests.# If we remove the piped command from the simple case in the attached script,# it returns 0.function test2{	typeset str	typeset testbody	typeset testout	testbody=$(# <CS> means command substitution start, <CE> means command substitution endcat <<EOFmyfunc (){ 	pipedcmd=<CS> printf "hi" | tr "h" "H" <CE>	echo \$pipedcmd	return 0}foo=<CS>myfunc<CE>retval=\$?if [ "\$foo"X != "HiX" ]; then	echo "myfunc returned '\${foo}'; expected 'Hi'"fiif [ \$retval -ne 0 ]; then	echo "command substitution calling myfunc returned \"\${retval}\"; expected 0"else	echo "command substitution calling myfunc successfully returned 0"fiEOF)			# Test 002/a: Plain test	testout=${ printf "%B\n" testbody | sed 's/<CS>/$(/g;s/<CE>/)/g' | ${SHELL} 2>&1 || err_exit "command returned exit code $?" }	[[ "${testout}" == "command substitution calling myfunc successfully returned 0" ]] || err_exit "Expected 'command substitution calling myfunc successfully returned 0', got ${testout}"		# Test 002/b: Same as test002/a but replaces "$(" with "${"	testout=${ printf "%B\n" testbody | sed 's/<CS>/${ /g;s/<CE>/ ; }/g' | ${SHELL} 2>&1 || err_exit "command returned exit code $?" }	[[ "${testout}" == "command substitution calling myfunc successfully returned 0" ]] || err_exit "Expected 'command substitution calling myfunc successfully returned 0', got ${testout}"		# Test 002/c: Same as test002/a but forces |fork()| for a subshell via "ulimit -c 0"	testout=${ printf "%B\n" testbody | sed 's/<CS>/$( ulimit -c 0 ; /g;s/<CE>/)/g' | ${SHELL} 2>&1 || err_exit "command returned exit code $?" }	[[ "${testout}" == "command substitution calling myfunc successfully returned 0" ]] || err_exit "Expected 'command substitution calling myfunc successfully returned 0', got ${testout}"		# Test 002/d: Same as test002/a but uses extra subshell	testout=${ printf "%B\n" testbody | sed 's/<CS>/$( ( /g;s/<CE>/) )/g' | ${SHELL} 2>&1 || err_exit "command returned exit code $?" }	[[ "${testout}" == "command substitution calling myfunc successfully returned 0" ]] || err_exit "Expected 'command substitution calling myfunc successfully returned 0', got ${testout}"		# Test 002/e: Same as test002/b but uses extra subshell after "${ " 	testout=${ printf "%B\n" testbody | sed 's/<CS>/${ ( /g;s/<CE>/) ; }/g' | ${SHELL} 2>&1 || err_exit "command returned exit code $?" }	[[ "${testout}" == "command substitution calling myfunc successfully returned 0" ]] || err_exit "Expected 'command substitution calling myfunc successfully returned 0', got ${testout}"	return 0}# test3: An expression within backticks which should return false, instead# returns true (0).function test3{	typeset str	typeset testbody	typeset testout	testbody=$(# <CS> means command substitution start, <CE> means command substitution endcat <<EOFif <CS>expr "NOMATCH" : ".*Z" > /dev/null<CE> ; then        echo "xerror"else        echo "xok"fiEOF)		# Test 003/a: Plain test	testout=${ printf "%B\n" testbody | sed 's/<CS>/$(/g;s/<CE>/)/g' | ${SHELL} 2>&1 || err_exit "command returned exit code $?" }	[[ "${testout}" == 'xok' ]] || err_exit "Expected 'xok', got ${testout}"		# Test 003/b: Same as test003/a but replaces "$(" with "${"	testout=${ printf "%B\n" testbody | sed 's/<CS>/${ /g;s/<CE>/ ; }/g' | ${SHELL} 2>&1 || err_exit "command returned exit code $?" }	[[ "${testout}" == 'xok' ]] || err_exit "Expected 'xok', got ${testout}"		# Test 003/c: Same as test003/a but forces |fork()| for a subshell via "ulimit -c 0"	testout=${ printf "%B\n" testbody | sed 's/<CS>/$( ulimit -c 0 ; /g;s/<CE>/)/g' | ${SHELL} 2>&1 || err_exit "command returned exit code $?" }	[[ "${testout}" == 'xok' ]] || err_exit "Expected 'xok', got ${testout}"		# Test 003/d: Same as test003/a but uses extra subshell	testout=${ printf "%B\n" testbody | sed 's/<CS>/$( ( /g;s/<CE>/) )/g' | ${SHELL} 2>&1 || err_exit "command returned exit code $?" }	[[ "${testout}" == 'xok' ]] || err_exit "Expected 'xok', got ${testout}"		# Test 003/e: Same as test003/b but uses extra subshell after "${ " 	testout=${ printf "%B\n" testbody | sed 's/<CS>/${ ( /g;s/<CE>/) ; }/g' | ${SHELL} 2>&1 || err_exit "command returned exit code $?" }	[[ "${testout}" == 'xok' ]] || err_exit "Expected 'xok', got ${testout}"	return 0	}	############################################################################ test set 004:# test pipe within ${... ; } command subtitution ending in a# non-builtin command (therefore we use "/bin/cat" instead of "cat" below# to force the use of the external "cat" command). ast-ksh.2009-01-20# had a bug which caused this test to fail.function test4{	typeset testout	testout=$( ${SHELL} -c 'pipedcmd=${ printf "hi" | /bin/cat ; } ; print $pipedcmd' )	[[ "${testout}" == 'hi' ]] || err_exit "test004: Expected 'hi', got '${testout}'"	return 0}############################################################################ test set 005:# Test whether the shell may hang in a# 'exec 5>/dev/null; print $(eval ls -d . 2>&1 1>&5)'# Originally discovered with ast-ksh.2009-05-05 which hung in# the "configure" script of postgresql-8.3.7.tar.gz (e.g. # configure --enable-thread-safety --without-readline)function test5{	integer testid	integer maxwait	integer i	integer childpid	typeset tmpfile='test5_tmpfile'	compound -r -a testcases=(		# gsf's reduced testcase		( name='test5_a' cmd='exec 5>/dev/null; print $(eval ls -d . 2>&1 1>&5)done' )		# gisburn's reduced testcase		( name='test5_b' cmd='exec 5>/dev/null; print $(eval "/bin/printf hello\n" 2>&1 1>&5)done' )			## The following tests do not trigger the problem but are included here for completeness		## and to make sure we don't get other incarnations of the same problem later...			# same as test5_a but uses ${ ... ; } instead of $(...)		( name='test5_c' cmd='exec 5>/dev/null; print "${ eval ls -d . 2>&1 1>&5 ;}done"' )		# same as test5_b but uses ${ ... ; } instead of $(...)		( name='test5_d' cmd='exec 5>/dev/null; print "${ eval "/bin/printf hello\n" 2>&1 1>&5 ;}done"' )		# same as test5_a but uses "ulimit -c 0" to force the shell to use a seperare process for $(...)		( name='test5_e' cmd='exec 5>/dev/null; print $(ulimit -c 0 ; eval ls -d . 2>&1 1>&5)done' )		# same as test5_b but uses "ulimit -c 0" to force the shell to use a seperare process for $(...)		( name='test5_f' cmd='exec 5>/dev/null; print $(ulimit -c 0 ; eval "/bin/printf hello\n" 2>&1 1>&5)done' )	)		maxwait=5	for testid in "${!testcases[@]}" ; do		nameref currtst=testcases[testid]		${SHELL} -o errexit -c "${currtst.cmd}" >"${tmpfile}.out" &		(( childpid=$! ))			for (( i=0 ; i < maxwait ; i++ )) ; do			isvalidpid ${childpid} || break			sleep 0.25		done			if isvalidpid ${childpid} ; then			err_exit "${currtst.name}: child (pid=${childpid}) still busy."			kill -KILL ${childpid} 2>/dev/null		fi		wait || err_exit "${currtst.name}: Child returned non-zero exit code." # wait for child (and/or avoid zombies/slime)			testout="$( < "${tmpfile}.out" )"		rm "${tmpfile}.out" || err_exit "File '${tmpfile}.out' could not be removed."		[[ "${testout}" == 'done' ]] || err_exit "test '${currtst.name}' failed, expected 'done', got '${testout}'"	done	return 0}# left/right typetypeset -T lr_t=(	typeset left	typeset right)# test6: Programatically iterate over all combinations of tested# command substitutions with large amounts of datafunction test6{	integer childpid	integer i	typeset cmd	typeset child_killed # bool	typeset -a test_list	integer tli # test_list index	# basic test command (this should be "myseq 30000" but the "cat" below is faster)	typeset -r basecmd='/bin/cat "tmpfile.expected"'	integer cl	typeset -r -a cmdlist=(		# plain		" ${basecmd} "		" exec ${basecmd} "		" ${basecmd} ; true "		# plain pipe		" ${basecmd} | cat "		" ${basecmd} | cat ; true "		" ${basecmd} | /bin/cat "		" ${basecmd} | /bin/cat ; true "		# pipe in subshell		# ("ulimit -c 0" is used to force the a subshell to call |fork()|)		" ${basecmd} | ( cat ) "		" ${basecmd} | ( cat ; true ) "		" ${basecmd} | ( /bin/cat ) "		" ${basecmd} | ( exec /bin/cat ) "		" ${basecmd} | ( ulimit -c 0 ; /bin/true ; exec /bin/cat ) "		" ${basecmd} | ( /bin/cat ; true ) "		# extra (operators not part of original problem but we cover then here to be sure)		' /bin/cat <( /bin/cat "tmpfile.expected" ) '		' /bin/cat <( /bin/cat <( /bin/cat "tmpfile.expected" ) ) '		' cat <( cat "tmpfile.expected" ) '		' cat <( cat <( /bin/cat "tmpfile.expected" ) ) '		' print -- "$( < "tmpfile.expected" )" '	)		integer l1	lr_t -r -a level1=(		( left='print -- "$( '			right=' )"'				)		( left='print -- "$( ulimit -c 0 ; '	right=' )"'				)		( left='print -- "${ '			right=' ; }"'				)		( left='print -- "${ ulimit -c 0 ; '	right=' ; }"'				)		( left='s="${ '				right=' ; }" ; /bin/cat <<<"${s}"'	)	)	integer l2	lr_t -r -a level2=(		( left=' '				right=' '				)		( left='( '				right=' )'				)		( left='print -- "$( '			right=' )"'				)		( left='print -- "$( ulimit -c 0 ; '	right=' )"'				)		( left='print -- "${ '			right=' ; }"'				)		( left='print -- "${ ulimit -c 0 ; '	right=' ; }"'				)		( left='s="${ '				right=' ; }" ; /bin/cat <<<"${s}"'	)	)	integer l3	lr_t -r -a level3=(		( left=' '				right=' '				)		( left='( '				right=' )'				)		( left='print -- "$( '			right=' )"'				)		( left='print -- "$( ulimit -c 0 ; '	right=' )"'				)		( left='print -- "${ '			right=' ; }"'				)		( left='print -- "${ ulimit -c 0 ; '	right=' ; }"'				)		( left='s="${ '				right=' ; }" ; /bin/cat <<<"${s}"'  	)	)	myseq 30000 >'tmpfile.expected'	# build a list of tests...	for (( l1=0 ; l1 < ${#level1[@]} ; l1++ )) ; do		for (( l2=0 ; l2 < ${#level2[@]} ; l2++ )) ; do			for (( l3=0 ; l3 < ${#level3[@]} ; l3++ )) ; do				for (( cl=0 ; cl < ${#cmdlist[@]} ; cl++ )) ; do					cmd=''					cmd+="${level1[l1].left}"					cmd+="${level2[l2].left}"					cmd+="${level3[l3].left}"					cmd+="${cmdlist[cl]}"					cmd+="${level3[l3].right}"					cmd+="${level2[l2].right}"					cmd+="${level1[l1].right}"										# make sure "cat" is a builtin not bound to a PATH element if we use it					[[ "${cmd}" == ~(E)[^/]cat ]] && cmd="builtin cat ; ${cmd}"										# append test to list					test_list+=( "${cmd}" )				done			done		done	done	#	print -u2 -f "# got %d tests\n" "${#test_list[@]}"	# run tests...	for (( tli=0 ; tli < ${#test_list[@]} ; tli++ )) ; do#		(( tli % 100 == 0 )) && print -u2 -f "# mark %d, %f\n" tli SECONDS		cmd="${test_list[tli]}"		testname="${0}/'${cmd}'"				#print -u2 -f "## Running %T: %s\n" "now" "${testname}" # debug				child_killed='false'		${SHELL} -o errexit -c "${cmd}" >'tmpfile.out' 2>'tmpfile.err' &		(( childpid=$! ))				# wait 20 seconds		for (( i=0 ; i < 80 ; i++ )) ; do			isvalidpid ${childpid} || break			sleep 0.25		done				# kill child if neccesary...		if isvalidpid ${childpid} ; then			err_exit "${testname}: child (pid=${childpid}) still busy, sending SIGTERM"			kill -TERM ${childpid} 2>/dev/null			child_killed='true'					sleep 2					if isvalidpid ${childpid} ; then				err_exit "${testname}: child (pid=${childpid}) still busy, sending SIGKILL"				kill -KILL ${childpid} 2>/dev/null			fi		fi		wait || err_exit "${testname}: Child returned non-zero exit code $?." # wait for child (and/or avoid zombies/slime)				# process output...		[[ "$( < 'tmpfile.err' )" == '' ]] || err_exit "${testname}: Expected empty stderr, got $(printf "%q\n" "$( < "tmpfile.err" )")"				if ! ${child_killed} ; then			cmp -s 'tmpfile.expected' 'tmpfile.out' || err_exit "${testname}: tmpfile.expected and tmpfile.out differ."		fi				rm 'tmpfile.out' 'tmpfile.err'	done	rm 'tmpfile.expected'	return 0}# test7: Test if command substitution of external and internal# utilities results in the same datafunction test7{        compound out=( typeset stdout stderr ; integer res )	integer i		compound -r -a tests=(		# original testcase		(			cmd='builtin cat ;  myseq 11 >"tmp11" ; LC_ALL="C" diff -u <(print -- "$(/bin/cat  <( /bin/cat  "tmp11" ) )") <(print -- "$(cat  <( cat "tmp11" ) )")'			expected_output='No differences encountered'		)		# same testcase as above but uses "head" instead of "cat"		(			cmd='builtin head ; myseq 11 >"tmp11" ; LC_ALL="C" diff -u <(print -- "$(/usr/bin/head <( /usr/bin/head "tmp11" ) )") <(print -- "$(head <( cat "tmp11" ) )")'			expected_output='No differences encountered'		)		# Glenn Fowlers testcase		(			cmd='print 1 | : "$(/bin/cat <(/bin/cat))"'			expected_output=''		)	)		for (( i=0 ; i < ${#tests[@]} ; i++ )) ; do		nameref ts=tests[i]		out.stderr="${ { out.stdout="${ ${SHELL} -o nounset -c "${ts.cmd}" ; (( out.res=$? )) ; }" ; } 2>&1 ; }"		[[ "${out.stdout}" == "${ts.expected_output}" ]] || err_exit "${0}/${i}: Expected stdout to match $(printf '%q\n' "${ts.expected_output}"), got ${ printf '%q\n' "${out.stdout}" ; }"		[[ "${out.stderr}" == ''                      ]] || err_exit "${0}/${i}: Expected empty stderr, got ${ printf '%q\n' "${out.stderr}" ; }"	done		rm 'tmp11'	return 0}# test8: One-time issue which came up during development for# CR #6946957 ("Nested sub shell in command substitution with lots of data hangs")function test8{	typeset testname="${0}/hang"	integer childpid	# original test, do _NOT_ edit!!	typeset -r cmd=$'		for (( i=0 ; i < 10 ; i++ )) ; do		set -x		(			typeset base=`line`			print "generating ${base}.c"			(				true			) >/dev/null		) <<<"a"	done	'	${SHELL} -o errexit -c "${cmd}" >'tmpfile.out' 2>'tmpfile.err' &	(( childpid=$! ))		# wait 10 seconds	for (( i=0 ; i < 40 ; i++ )) ; do		isvalidpid ${childpid} || break		sleep 0.25	done		# kill child if neccesary...	if isvalidpid ${childpid} ; then		err_exit "${testname}: child (pid=${childpid}) still busy, sending SIGTERM"		kill -TERM ${childpid} 2>/dev/null			sleep 2			if isvalidpid ${childpid} ; then			err_exit "${testname}: child (pid=${childpid}) still busy, sending SIGKILL"			kill -KILL ${childpid} 2>/dev/null		fi	fi	wait || err_exit "${testname}: Child returned non-zero exit code $?." # wait for child (and/or avoid zombies/slime)				rm 'tmpfile.out' 'tmpfile.err'	return 0}# prepare for testsexport PATH="${PWD}:${PATH}"builtin cmpbuiltin rmunset VMALLOC_OPTIONS VMDEBUG # no debug for helper scriptspretests# run teststest1test2test3test4test5test6test7test8# cleanupposttestscd "${ocwd}"rmdir "${tmpdir}" || err_exit "Cannot remove temporary directory ${tmpdir}."# tests doneexit $((Errors))