Home | History | Annotate | Download | only in lib
      1 #!/bin/sh
      2 #
      3 # Copyright (c) Linux Test Project, 2014-2017
      4 #
      5 # This program is free software; you can redistribute it and/or modify
      6 # it under the terms of the GNU General Public License as published by
      7 # the Free Software Foundation; either version 2 of the License, or
      8 # (at your option) any later version.
      9 #
     10 # This program is distributed in the hope that it will be useful,
     11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
     12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13 # GNU General Public License for more details.
     14 #
     15 # You should have received a copy of the GNU General Public License along
     16 # with this program; if not, write to the Free Software Foundation, Inc.,
     17 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
     18 #
     19 # Written by Cyril Hrubis <chrubis (at] suse.cz>
     20 #
     21 # This is a LTP test library for shell.
     22 #
     23 
     24 export TST_PASS=0
     25 export TST_FAIL=0
     26 export TST_BROK=0
     27 export TST_WARN=0
     28 export TST_CONF=0
     29 export TST_COUNT=1
     30 export TST_ITERATIONS=1
     31 export TST_TMPDIR_RHOST=0
     32 
     33 . tst_ansi_color.sh
     34 
     35 tst_do_exit()
     36 {
     37 	local ret=0
     38 
     39 	if [ -n "$TST_SETUP_STARTED" -a -n "$TST_CLEANUP" -a \
     40 	     -z "$TST_NO_CLEANUP" ]; then
     41 		$TST_CLEANUP
     42 	fi
     43 
     44 	if [ "$TST_NEEDS_DEVICE" = 1 -a "$TST_DEVICE_FLAG" = 1 ]; then
     45 		if ! tst_device release "$TST_DEVICE"; then
     46 			tst_res TWARN "Failed to release device '$TST_DEVICE'"
     47 		fi
     48 	fi
     49 
     50 	if [ "$TST_NEEDS_TMPDIR" = 1 -a -n "$TST_TMPDIR" ]; then
     51 		cd "$LTPROOT"
     52 		rm -r "$TST_TMPDIR"
     53 		[ "$TST_TMPDIR_RHOST" = 1 ] && tst_cleanup_rhost
     54 	fi
     55 
     56 	if [ $TST_FAIL -gt 0 ]; then
     57 		ret=$((ret|1))
     58 	fi
     59 
     60 	if [ $TST_BROK -gt 0 ]; then
     61 		ret=$((ret|2))
     62 	fi
     63 
     64 	if [ $TST_WARN -gt 0 ]; then
     65 		ret=$((ret|4))
     66 	fi
     67 
     68 	if [ $TST_CONF -gt 0 ]; then
     69 		ret=$((ret|32))
     70 	fi
     71 
     72 	echo
     73 	echo "Summary:"
     74 	echo "passed   $TST_PASS"
     75 	echo "failed   $TST_FAIL"
     76 	echo "skipped  $TST_CONF"
     77 	echo "warnings $TST_WARN"
     78 
     79 	exit $ret
     80 }
     81 
     82 tst_inc_res()
     83 {
     84 	case "$1" in
     85 	TPASS) TST_PASS=$((TST_PASS+1));;
     86 	TFAIL) TST_FAIL=$((TST_FAIL+1));;
     87 	TBROK) TST_BROK=$((TST_BROK+1));;
     88 	TWARN) TST_WARN=$((TST_WARN+1));;
     89 	TCONF) TST_CONF=$((TST_CONF+1));;
     90 	TINFO) ;;
     91 	*) tst_brk TBROK "Invalid resm type '$1'";;
     92 	esac
     93 }
     94 
     95 tst_res()
     96 {
     97 	local res=$1
     98 	shift
     99 
    100 	tst_color_enabled
    101 	local color=$?
    102 
    103 	tst_inc_res "$res"
    104 
    105 	printf "$TCID $TST_COUNT "
    106 	tst_print_colored $res "$res: "
    107 	echo "$@"
    108 }
    109 
    110 tst_brk()
    111 {
    112 	local res=$1
    113 	shift
    114 
    115 	tst_res "$res" "$@"
    116 	tst_do_exit
    117 }
    118 
    119 ROD_SILENT()
    120 {
    121 	tst_rod $@ > /dev/null 2>&1
    122 	if [ $? -ne 0 ]; then
    123 		tst_brk TBROK "$@ failed"
    124 	fi
    125 }
    126 
    127 ROD()
    128 {
    129 	tst_rod "$@"
    130 	if [ $? -ne 0 ]; then
    131 		tst_brk TBROK "$@ failed"
    132 	fi
    133 }
    134 
    135 EXPECT_PASS()
    136 {
    137 	tst_rod "$@"
    138 	if [ $? -eq 0 ]; then
    139 		tst_res TPASS "$@ passed as expected"
    140 	else
    141 		tst_res TFAIL "$@ failed unexpectedly"
    142 	fi
    143 }
    144 
    145 EXPECT_FAIL()
    146 {
    147 	# redirect stderr since we expect the command to fail
    148 	tst_rod "$@" 2> /dev/null
    149 	if [ $? -ne 0 ]; then
    150 		tst_res TPASS "$@ failed as expected"
    151 	else
    152 		tst_res TFAIL "$@ passed unexpectedly"
    153 	fi
    154 }
    155 
    156 tst_umount()
    157 {
    158 	local device="$1"
    159 	local i=0
    160 
    161 	if ! grep -q "$device" /proc/mounts; then
    162 		tst_res TINFO "The $device is not mounted, skipping umount"
    163 		return
    164 	fi
    165 
    166 	while [ "$i" -lt 50 ]; do
    167 		if umount "$device" > /dev/null; then
    168 			return
    169 		fi
    170 
    171 		i=$((i+1))
    172 
    173 		tst_res TINFO "umount($device) failed, try $i ..."
    174 		tst_res TINFO "Likely gvfsd-trash is probing newly mounted "\
    175 		              "fs, kill it to speed up tests."
    176 
    177 		tst_sleep 100ms
    178 	done
    179 
    180 	tst_res TWARN "Failed to umount($device) after 50 retries"
    181 }
    182 
    183 tst_mkfs()
    184 {
    185 	local fs_type=$1
    186 	local device=$2
    187 	shift 2
    188 	local fs_opts="$@"
    189 
    190 	if [ -z "$fs_type" ]; then
    191 		tst_brk TBROK "No fs_type specified"
    192 	fi
    193 
    194 	if [ -z "$device" ]; then
    195 		tst_brk TBROK "No device specified"
    196 	fi
    197 
    198 	tst_res TINFO "Formatting $device with $fs_type extra opts='$fs_opts'"
    199 
    200 	ROD_SILENT mkfs.$fs_type $fs_opts $device
    201 }
    202 
    203 tst_check_cmds()
    204 {
    205 	local cmd
    206 	for cmd in $*; do
    207 		if ! command -v $cmd > /dev/null 2>&1; then
    208 			tst_brk TCONF "'$cmd' not found"
    209 		fi
    210 	done
    211 }
    212 
    213 tst_is_int()
    214 {
    215 	[ "$1" -eq "$1" ] 2>/dev/null
    216 	return $?
    217 }
    218 
    219 tst_usage()
    220 {
    221 	if [ -n "$TST_USAGE" ]; then
    222 		$TST_USAGE
    223 	else
    224 		echo "usage: $0"
    225 		echo "OPTIONS"
    226 	fi
    227 
    228 	echo "-h      Prints this help"
    229 	echo "-i n    Execute test n times"
    230 }
    231 
    232 tst_resstr()
    233 {
    234 	echo "$TST_PASS$TST_FAIL$TST_CONF"
    235 }
    236 
    237 tst_rescmp()
    238 {
    239 	local res=$(tst_resstr)
    240 
    241 	if [ "$1" = "$res" ]; then
    242 		tst_brk TBROK "Test didn't report any results"
    243 	fi
    244 }
    245 
    246 tst_run()
    247 {
    248 	local tst_i
    249 
    250 	if [ -n "$TST_TEST_PATH" ]; then
    251 		for tst_i in $(grep TST_ "$TST_TEST_PATH" | sed 's/.*TST_//; s/[="} \t\/:`].*//'); do
    252 			case "$tst_i" in
    253 			SETUP|CLEANUP|TESTFUNC|ID|CNT);;
    254 			OPTS|USAGE|PARSE_ARGS|POS_ARGS);;
    255 			NEEDS_ROOT|NEEDS_TMPDIR|NEEDS_DEVICE|DEVICE);;
    256 			NEEDS_CMDS|NEEDS_MODULE|MODPATH|DATAROOT);;
    257 			*) tst_res TWARN "Reserved variable TST_$tst_i used!";;
    258 			esac
    259 		done
    260 	fi
    261 
    262 	local name
    263 
    264 	OPTIND=1
    265 
    266 	while getopts "hi:$TST_OPTS" name $TST_ARGS; do
    267 		case $name in
    268 		'h') tst_usage; exit 0;;
    269 		'i') TST_ITERATIONS=$OPTARG;;
    270 		'?') tst_usage; exit 2;;
    271 		*) $TST_PARSE_ARGS "$name" "$OPTARG";;
    272 		esac
    273 	done
    274 
    275 	if ! tst_is_int "$TST_ITERATIONS"; then
    276 		tst_brk TBROK "Expected number (-i) not '$TST_ITERATIONS'"
    277 	fi
    278 
    279 	if [ "$TST_ITERATIONS" -le 0 ]; then
    280 		tst_brk TBROK "Number of iterations (-i) must be > 0"
    281 	fi
    282 
    283 	if [ "$TST_NEEDS_ROOT" = 1 ]; then
    284 		if [ "$(id -ru)" != 0 ]; then
    285 			tst_brk TCONF "Must be super/root for this test!"
    286 		fi
    287 	fi
    288 
    289 	tst_check_cmds $TST_NEEDS_CMDS
    290 
    291 	if [ "$TST_NEEDS_TMPDIR" = 1 ]; then
    292 		if [ -z "$TMPDIR" ]; then
    293 			export TMPDIR="/tmp"
    294 		fi
    295 
    296 		TST_TMPDIR=$(mktemp -d "$TMPDIR/LTP_$TST_ID.XXXXXXXXXX")
    297 
    298 		chmod 777 "$TST_TMPDIR"
    299 
    300 		TST_STARTWD=$(pwd)
    301 
    302 		cd "$TST_TMPDIR"
    303 	fi
    304 
    305 	if [ "$TST_NEEDS_DEVICE" = 1 ]; then
    306 		if [ -z ${TST_TMPDIR} ]; then
    307 			tst_brk "Use TST_NEEDS_TMPDIR must be set for TST_NEEDS_DEVICE"
    308 		fi
    309 
    310 		TST_DEVICE=$(tst_device acquire)
    311 
    312 		if [ -z "$TST_DEVICE" ]; then
    313 			tst_brk "Failed to acquire device"
    314 		fi
    315 
    316 		TST_DEVICE_FLAG=1
    317 	fi
    318 
    319 	if [ -n "$TST_NEEDS_MODULE" ]; then
    320 		for tst_module in "$TST_NEEDS_MODULE" \
    321 		                  "$LTPROOT/testcases/bin/$TST_NEEDS_MODULE" \
    322 		                  "$TST_STARTWD/$TST_NEEDS_MODULE"; do
    323 
    324 				if [ -f "$tst_module" ]; then
    325 					TST_MODPATH="$tst_module"
    326 					break
    327 				fi
    328 		done
    329 
    330 		if [ -z "$TST_MODPATH" ]; then
    331 			tst_brk TCONF "Failed to find module '$TST_NEEDS_MODULE'"
    332 		else
    333 			tst_res TINFO "Found module at '$TST_MODPATH'"
    334 		fi
    335 	fi
    336 
    337 	if [ -n "$TST_SETUP" ]; then
    338 		TST_SETUP_STARTED=1
    339 		$TST_SETUP
    340 	fi
    341 
    342 	#TODO check that test reports some results for each test function call
    343 	while [ $TST_ITERATIONS -gt 0 ]; do
    344 		if [ -n "$TST_CNT" ]; then
    345 			if type test1 > /dev/null 2>&1; then
    346 				for tst_i in $(seq $TST_CNT); do
    347 					local res=$(tst_resstr)
    348 					$TST_TESTFUNC$tst_i
    349 					tst_rescmp "$res"
    350 					TST_COUNT=$((TST_COUNT+1))
    351 				done
    352 			else
    353 				for tst_i in $(seq $TST_CNT); do
    354 					local res=$(tst_resstr)
    355 					$TST_TESTFUNC $tst_i
    356 					tst_rescmp "$res"
    357 					TST_COUNT=$((TST_COUNT+1))
    358 				done
    359 			fi
    360 		else
    361 			local res=$(tst_resstr)
    362 			$TST_TESTFUNC
    363 			tst_rescmp "$res"
    364 			TST_COUNT=$((TST_COUNT+1))
    365 		fi
    366 		TST_ITERATIONS=$((TST_ITERATIONS-1))
    367 	done
    368 
    369 	tst_do_exit
    370 }
    371 
    372 if TST_TEST_PATH=$(which $0) 2>/dev/null; then
    373 	if ! grep -q tst_run "$TST_TEST_PATH"; then
    374 		tst_brk TBROK "Test $0 must call tst_run!"
    375 	fi
    376 fi
    377 
    378 if [ -z "$TST_ID" ]; then
    379 	filename=$(basename $0)
    380 	TST_ID=${filename%%.*}
    381 fi
    382 export TST_ID="$TST_ID"
    383 
    384 if [ -z "$TST_TESTFUNC" ]; then
    385 	tst_brk TBROK "TST_TESTFUNC is not defined"
    386 fi
    387 
    388 if [ -n "$TST_CNT" ]; then
    389 	if ! tst_is_int "$TST_CNT"; then
    390 		tst_brk TBROK "TST_CNT must be integer"
    391 	fi
    392 
    393 	if [ "$TST_CNT" -le 0 ]; then
    394 		tst_brk TBROK "TST_CNT must be > 0"
    395 	fi
    396 fi
    397 
    398 if [ -n "$TST_POS_ARGS" ]; then
    399 	if ! tst_is_int "$TST_POS_ARGS"; then
    400 		tst_brk TBROK "TST_POS_ARGS must be integer"
    401 	fi
    402 
    403 	if [ "$TST_POS_ARGS" -le 0 ]; then
    404 		tst_brk TBROK "TST_POS_ARGS must be > 0"
    405 	fi
    406 fi
    407 
    408 if [ -z "$LTPROOT" ]; then
    409 	export LTPROOT="$PWD"
    410 	export TST_DATAROOT="$LTPROOT/datafiles"
    411 else
    412 	export TST_DATAROOT="$LTPROOT/testcases/data/$TST_ID"
    413 fi
    414 
    415 TST_ARGS="$@"
    416 
    417 while getopts ":hi:$TST_OPTS" tst_name; do
    418 	case $tst_name in
    419 	'h') TST_PRINT_HELP=1;;
    420 	*);;
    421 	esac
    422 done
    423 
    424 shift $((OPTIND - 1))
    425 
    426 if [ -n "$TST_POS_ARGS" ]; then
    427 	if [ -z "$TST_PRINT_HELP" -a $# -ne "$TST_POS_ARGS" ]; then
    428 		tst_brk TBROK "Invalid number of positional paramters:"\
    429 			      "have ($@) $#, expected ${TST_POS_ARGS}"
    430 	fi
    431 else
    432 	if [ -z "$TST_PRINT_HELP" -a $# -ne 0 ]; then
    433 		tst_brk TBROK "Unexpected positional arguments '$@'"
    434 	fi
    435 fi
    436