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