1#!/bin/sh 2# 3# Copyright (c) Linux Test Project, 2014-2018 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@suse.cz> 20# 21# This is a LTP test library for shell. 22# 23 24[ -n "$TST_LIB_LOADED" ] && return 0 25 26export TST_PASS=0 27export TST_FAIL=0 28export TST_BROK=0 29export TST_WARN=0 30export TST_CONF=0 31export TST_COUNT=1 32export TST_ITERATIONS=1 33export TST_TMPDIR_RHOST=0 34export TST_LIB_LOADED=1 35 36. tst_ansi_color.sh 37 38# default trap function 39trap "tst_brk TBROK 'test interrupted'" INT 40 41_tst_do_exit() 42{ 43 local ret=0 44 TST_DO_EXIT=1 45 46 if [ -n "$TST_SETUP_STARTED" -a -n "$TST_CLEANUP" -a \ 47 -z "$TST_NO_CLEANUP" ]; then 48 $TST_CLEANUP 49 fi 50 51 if [ "$TST_NEEDS_DEVICE" = 1 -a "$TST_DEVICE_FLAG" = 1 ]; then 52 if ! tst_device release "$TST_DEVICE"; then 53 tst_res TWARN "Failed to release device '$TST_DEVICE'" 54 fi 55 fi 56 57 if [ "$TST_NEEDS_TMPDIR" = 1 -a -n "$TST_TMPDIR" ]; then 58 cd "$LTPROOT" 59 rm -r "$TST_TMPDIR" 60 [ "$TST_TMPDIR_RHOST" = 1 ] && tst_cleanup_rhost 61 fi 62 63 if [ -n "$_tst_setup_timer_pid" ]; then 64 kill $_tst_setup_timer_pid 2>/dev/null 65 wait $_tst_setup_timer_pid 2>/dev/null 66 fi 67 68 if [ $TST_FAIL -gt 0 ]; then 69 ret=$((ret|1)) 70 fi 71 72 if [ $TST_BROK -gt 0 ]; then 73 ret=$((ret|2)) 74 fi 75 76 if [ $TST_WARN -gt 0 ]; then 77 ret=$((ret|4)) 78 fi 79 80 if [ $TST_CONF -gt 0 ]; then 81 ret=$((ret|32)) 82 fi 83 84 echo 85 echo "Summary:" 86 echo "passed $TST_PASS" 87 echo "failed $TST_FAIL" 88 echo "skipped $TST_CONF" 89 echo "warnings $TST_WARN" 90 91 exit $ret 92} 93 94_tst_inc_res() 95{ 96 case "$1" in 97 TPASS) TST_PASS=$((TST_PASS+1));; 98 TFAIL) TST_FAIL=$((TST_FAIL+1));; 99 TBROK) TST_BROK=$((TST_BROK+1));; 100 TWARN) TST_WARN=$((TST_WARN+1));; 101 TCONF) TST_CONF=$((TST_CONF+1));; 102 TINFO) ;; 103 *) tst_brk TBROK "Invalid res type '$1'";; 104 esac 105} 106 107tst_res() 108{ 109 local res=$1 110 shift 111 112 tst_color_enabled 113 local color=$? 114 115 _tst_inc_res "$res" 116 117 printf "$TST_ID $TST_COUNT " 118 tst_print_colored $res "$res: " 119 echo "$@" 120} 121 122tst_brk() 123{ 124 local res=$1 125 shift 126 127 if [ "$TST_DO_EXIT" = 1 ]; then 128 tst_res TWARN "$@" 129 return 130 fi 131 132 tst_res "$res" "$@" 133 _tst_do_exit 134} 135 136ROD_SILENT() 137{ 138 local tst_out="$(tst_rod $@ 2>&1)" 139 if [ $? -ne 0 ]; then 140 echo "$tst_out" 141 tst_brk TBROK "$@ failed" 142 fi 143} 144 145ROD() 146{ 147 tst_rod "$@" 148 if [ $? -ne 0 ]; then 149 tst_brk TBROK "$@ failed" 150 fi 151} 152 153EXPECT_PASS() 154{ 155 tst_rod "$@" 156 if [ $? -eq 0 ]; then 157 tst_res TPASS "$@ passed as expected" 158 else 159 tst_res TFAIL "$@ failed unexpectedly" 160 fi 161} 162 163EXPECT_FAIL() 164{ 165 # redirect stderr since we expect the command to fail 166 tst_rod "$@" 2> /dev/null 167 if [ $? -ne 0 ]; then 168 tst_res TPASS "$@ failed as expected" 169 else 170 tst_res TFAIL "$@ passed unexpectedly" 171 fi 172} 173 174TST_RETRY_FN_EXP_BACKOFF() 175{ 176 local tst_fun="$1" 177 local tst_exp=$2 178 local tst_sec=$(expr $3 \* 1000000) 179 local tst_delay=1 180 181 if [ $# -ne 3 ]; then 182 tst_brk TBROK "TST_RETRY_FN_EXP_BACKOFF expects 3 parameters" 183 fi 184 185 if ! tst_is_int "$tst_sec"; then 186 tst_brk TBROK "TST_RETRY_FN_EXP_BACKOFF: tst_sec must be integer ('$tst_sec')" 187 fi 188 189 while true; do 190 $tst_fun 191 if [ "$?" = "$tst_exp" ]; then 192 break 193 fi 194 195 if [ $tst_delay -lt $tst_sec ]; then 196 tst_sleep ${tst_delay}us 197 tst_delay=$((tst_delay*2)) 198 else 199 tst_brk TBROK "\"$tst_fun\" timed out" 200 fi 201 done 202 203 return $tst_exp 204} 205 206TST_RETRY_FUNC() 207{ 208 if [ $# -ne 2 ]; then 209 tst_brk TBROK "TST_RETRY_FUNC expects 2 parameters" 210 fi 211 212 TST_RETRY_FN_EXP_BACKOFF "$1" "$2" 1 213 return $2 214} 215 216TST_RTNL_CHK() 217{ 218 local msg1="RTNETLINK answers: Function not implemented" 219 local msg2="RTNETLINK answers: Operation not supported" 220 local msg3="RTNETLINK answers: Protocol not supported" 221 local output="$($@ 2>&1 || echo 'LTP_ERR')" 222 local msg 223 224 echo "$output" | grep -q "LTP_ERR" || return 0 225 226 for msg in "$msg1" "$msg2" "$msg3"; do 227 echo "$output" | grep -q "$msg" && tst_brk TCONF "'$@': $msg" 228 done 229 230 tst_brk TBROK "$@ failed: $output" 231} 232 233tst_umount() 234{ 235 local device="$1" 236 local i=0 237 238 if ! grep -q "$device" /proc/mounts; then 239 tst_res TINFO "The $device is not mounted, skipping umount" 240 return 241 fi 242 243 while [ "$i" -lt 50 ]; do 244 if umount "$device" > /dev/null; then 245 return 246 fi 247 248 i=$((i+1)) 249 250 tst_res TINFO "umount($device) failed, try $i ..." 251 tst_res TINFO "Likely gvfsd-trash is probing newly mounted "\ 252 "fs, kill it to speed up tests." 253 254 tst_sleep 100ms 255 done 256 257 tst_res TWARN "Failed to umount($device) after 50 retries" 258} 259 260tst_mkfs() 261{ 262 local fs_type=$1 263 local device=$2 264 shift 2 265 local fs_opts="$@" 266 267 if [ -z "$fs_type" ]; then 268 tst_brk TBROK "No fs_type specified" 269 fi 270 271 if [ -z "$device" ]; then 272 tst_brk TBROK "No device specified" 273 fi 274 275 tst_res TINFO "Formatting $device with $fs_type extra opts='$fs_opts'" 276 277 ROD_SILENT mkfs.$fs_type $fs_opts $device 278} 279 280tst_cmd_available() 281{ 282 if type command > /dev/null 2>&1; then 283 command -v $1 > /dev/null 2>&1 || return 1 284 else 285 which $1 > /dev/null 2>&1 286 if [ $? -eq 0 ]; then 287 return 0 288 elif [ $? -eq 127 ]; then 289 tst_brk TCONF "missing which command" 290 else 291 return 1 292 fi 293 fi 294} 295 296tst_test_cmds() 297{ 298 local cmd 299 for cmd in $*; do 300 tst_cmd_available $cmd || tst_brk TCONF "'$cmd' not found" 301 done 302} 303 304tst_check_cmds() 305{ 306 local cmd 307 for cmd; do 308 if ! tst_cmd_available $cmd; then 309 tst_res TCONF "'$cmd' not found" 310 return 1 311 fi 312 done 313 return 0 314} 315 316tst_test_drivers() 317{ 318 [ $# -eq 0 ] && return 0 319 320 local drv 321 322 drv="$(tst_check_drivers $@ 2>&1)" 323 324 [ $? -ne 0 ] && tst_brk TCONF "$drv driver not available" 325 return 0 326} 327 328tst_is_int() 329{ 330 [ "$1" -eq "$1" ] 2>/dev/null 331 return $? 332} 333 334tst_usage() 335{ 336 if [ -n "$TST_USAGE" ]; then 337 $TST_USAGE 338 else 339 echo "usage: $0" 340 echo "OPTIONS" 341 fi 342 343 echo "-h Prints this help" 344 echo "-i n Execute test n times" 345} 346 347_tst_resstr() 348{ 349 echo "$TST_PASS$TST_FAIL$TST_CONF" 350} 351 352_tst_rescmp() 353{ 354 local res=$(_tst_resstr) 355 356 if [ "$1" = "$res" ]; then 357 tst_brk TBROK "Test didn't report any results" 358 fi 359} 360 361 362_tst_setup_timer() 363{ 364 LTP_TIMEOUT_MUL=${LTP_TIMEOUT_MUL:-1} 365 366 local sec=$((300 * LTP_TIMEOUT_MUL)) 367 local h=$((sec / 3600)) 368 local m=$((sec / 60 % 60)) 369 local s=$((sec % 60)) 370 local pid=$$ 371 372 tst_res TINFO "timeout per run is ${h}h ${m}m ${s}s" 373 374 sleep $sec && tst_res TBROK "test killed, timeout! If you are running on slow machine, try exporting LTP_TIMEOUT_MUL > 1" && kill -9 -$pid & 375 376 _tst_setup_timer_pid=$! 377} 378 379tst_run() 380{ 381 local _tst_i 382 local _tst_data 383 local _tst_max 384 local _tst_name 385 386 if [ -n "$TST_TEST_PATH" ]; then 387 for _tst_i in $(grep TST_ "$TST_TEST_PATH" | sed 's/.*TST_//; s/[="} \t\/:`].*//'); do 388 case "$_tst_i" in 389 SETUP|CLEANUP|TESTFUNC|ID|CNT|MIN_KVER);; 390 OPTS|USAGE|PARSE_ARGS|POS_ARGS);; 391 NEEDS_ROOT|NEEDS_TMPDIR|TMPDIR|NEEDS_DEVICE|DEVICE);; 392 NEEDS_CMDS|NEEDS_MODULE|MODPATH|DATAROOT);; 393 NEEDS_DRIVERS);; 394 IPV6|IPVER|TEST_DATA|TEST_DATA_IFS);; 395 RETRY_FUNC|RETRY_FN_EXP_BACKOFF);; 396 *) tst_res TWARN "Reserved variable TST_$_tst_i used!";; 397 esac 398 done 399 400 for _tst_i in $(grep _tst_ "$TST_TEST_PATH" | sed 's/.*_tst_//; s/[="} \t\/:`].*//'); do 401 tst_res TWARN "Private variable or function _tst_$_tst_i used!" 402 done 403 fi 404 405 OPTIND=1 406 407 while getopts ":hi:$TST_OPTS" _tst_name $TST_ARGS; do 408 case $_tst_name in 409 'h') tst_usage; exit 0;; 410 'i') TST_ITERATIONS=$OPTARG;; 411 '?') tst_usage; exit 2;; 412 *) $TST_PARSE_ARGS "$_tst_name" "$OPTARG";; 413 esac 414 done 415 416 if ! tst_is_int "$TST_ITERATIONS"; then 417 tst_brk TBROK "Expected number (-i) not '$TST_ITERATIONS'" 418 fi 419 420 if [ "$TST_ITERATIONS" -le 0 ]; then 421 tst_brk TBROK "Number of iterations (-i) must be > 0" 422 fi 423 424 if [ "$TST_NEEDS_ROOT" = 1 ]; then 425 if [ "$(id -ru)" != 0 ]; then 426 tst_brk TCONF "Must be super/root for this test!" 427 fi 428 fi 429 430 tst_test_cmds $TST_NEEDS_CMDS 431 tst_test_drivers $TST_NEEDS_DRIVERS 432 433 if [ -n "$TST_MIN_KVER" ]; then 434 tst_kvcmp -lt "$TST_MIN_KVER" && \ 435 tst_brk TCONF "test requires kernel $TST_MIN_KVER+" 436 fi 437 438 _tst_setup_timer 439 440 if [ "$TST_NEEDS_TMPDIR" = 1 ]; then 441 if [ -z "$TMPDIR" ]; then 442 export TMPDIR="/tmp" 443 fi 444 445 TST_TMPDIR=$(mktemp -d "$TMPDIR/LTP_$TST_ID.XXXXXXXXXX") 446 447 chmod 777 "$TST_TMPDIR" 448 449 TST_STARTWD=$(pwd) 450 451 cd "$TST_TMPDIR" 452 fi 453 454 if [ "$TST_NEEDS_DEVICE" = 1 ]; then 455 if [ -z ${TST_TMPDIR} ]; then 456 tst_brk TBROK "Use TST_NEEDS_TMPDIR must be set for TST_NEEDS_DEVICE" 457 fi 458 459 TST_DEVICE=$(tst_device acquire) 460 461 if [ ! -b "$TST_DEVICE" -o $? -ne 0 ]; then 462 tst_brk TBROK "Failed to acquire device" 463 fi 464 465 TST_DEVICE_FLAG=1 466 fi 467 468 if [ -n "$TST_NEEDS_MODULE" ]; then 469 for tst_module in "$TST_NEEDS_MODULE" \ 470 "$LTPROOT/testcases/bin/$TST_NEEDS_MODULE" \ 471 "$TST_STARTWD/$TST_NEEDS_MODULE"; do 472 473 if [ -f "$tst_module" ]; then 474 TST_MODPATH="$tst_module" 475 break 476 fi 477 done 478 479 if [ -z "$TST_MODPATH" ]; then 480 tst_brk TCONF "Failed to find module '$TST_NEEDS_MODULE'" 481 else 482 tst_res TINFO "Found module at '$TST_MODPATH'" 483 fi 484 fi 485 486 if [ -n "$TST_SETUP" ]; then 487 TST_SETUP_STARTED=1 488 $TST_SETUP 489 fi 490 491 #TODO check that test reports some results for each test function call 492 while [ $TST_ITERATIONS -gt 0 ]; do 493 if [ -n "$TST_TEST_DATA" ]; then 494 tst_test_cmds cut tr wc 495 _tst_max=$(( $(echo $TST_TEST_DATA | tr -cd "$TST_TEST_DATA_IFS" | wc -c) +1)) 496 for _tst_i in $(seq $_tst_max); do 497 _tst_data="$(echo "$TST_TEST_DATA" | cut -d"$TST_TEST_DATA_IFS" -f$_tst_i)" 498 _tst_run_tests "$_tst_data" 499 done 500 else 501 _tst_run_tests 502 fi 503 TST_ITERATIONS=$((TST_ITERATIONS-1)) 504 done 505 506 _tst_do_exit 507} 508 509_tst_run_tests() 510{ 511 local _tst_data="$1" 512 local _tst_i 513 514 for _tst_i in $(seq ${TST_CNT:-1}); do 515 if type ${TST_TESTFUNC}1 > /dev/null 2>&1; then 516 _tst_run_test "$TST_TESTFUNC$_tst_i" $_tst_i "$_tst_data" 517 else 518 _tst_run_test "$TST_TESTFUNC" $_tst_i "$_tst_data" 519 fi 520 done 521} 522 523_tst_run_test() 524{ 525 local _tst_res=$(_tst_resstr) 526 local _tst_fnc="$1" 527 shift 528 529 $_tst_fnc "$@" 530 _tst_rescmp "$_tst_res" 531 TST_COUNT=$((TST_COUNT+1)) 532} 533 534if [ -z "$TST_ID" ]; then 535 _tst_filename=$(basename $0) || \ 536 tst_brk TCONF "Failed to set TST_ID from \$0 ('$0'), fix it with setting TST_ID before sourcing tst_test.sh" 537 TST_ID=${_tst_filename%%.*} 538fi 539export TST_ID="$TST_ID" 540 541if [ -z "$LTPROOT" ]; then 542 export LTPROOT="$PWD" 543 export TST_DATAROOT="$LTPROOT/datafiles" 544else 545 export TST_DATAROOT="$LTPROOT/testcases/data/$TST_ID" 546fi 547 548if [ -z "$TST_NO_DEFAULT_RUN" ]; then 549 if TST_TEST_PATH=$(which $0) 2>/dev/null; then 550 if ! grep -q tst_run "$TST_TEST_PATH"; then 551 tst_brk TBROK "Test $0 must call tst_run!" 552 fi 553 fi 554 555 if [ -z "$TST_TESTFUNC" ]; then 556 tst_brk TBROK "TST_TESTFUNC is not defined" 557 fi 558 559 TST_TEST_DATA_IFS="${TST_TEST_DATA_IFS:- }" 560 561 if [ -n "$TST_CNT" ]; then 562 if ! tst_is_int "$TST_CNT"; then 563 tst_brk TBROK "TST_CNT must be integer" 564 fi 565 566 if [ "$TST_CNT" -le 0 ]; then 567 tst_brk TBROK "TST_CNT must be > 0" 568 fi 569 fi 570 571 if [ -n "$TST_POS_ARGS" ]; then 572 if ! tst_is_int "$TST_POS_ARGS"; then 573 tst_brk TBROK "TST_POS_ARGS must be integer" 574 fi 575 576 if [ "$TST_POS_ARGS" -le 0 ]; then 577 tst_brk TBROK "TST_POS_ARGS must be > 0" 578 fi 579 fi 580 581 TST_ARGS="$@" 582 583 while getopts ":hi:$TST_OPTS" tst_name; do 584 case $tst_name in 585 'h') TST_PRINT_HELP=1;; 586 *);; 587 esac 588 done 589 590 shift $((OPTIND - 1)) 591 592 if [ -n "$TST_POS_ARGS" ]; then 593 if [ -z "$TST_PRINT_HELP" -a $# -ne "$TST_POS_ARGS" ]; then 594 tst_brk TBROK "Invalid number of positional parameters:"\ 595 "have ($@) $#, expected ${TST_POS_ARGS}" 596 fi 597 else 598 if [ -z "$TST_PRINT_HELP" -a $# -ne 0 ]; then 599 tst_brk TBROK "Unexpected positional arguments '$@'" 600 fi 601 fi 602fi 603