1#!/bin/bash 2# Copyright (C) 2017 Luis R. Rodriguez <mcgrof@kernel.org> 3# 4# This program is free software; you can redistribute it and/or modify it 5# under the terms of the GNU General Public License as published by the Free 6# Software Foundation; either version 2 of the License, or at your option any 7# later version; or, when distributed separately from the Linux kernel or 8# when incorporated into other software packages, subject to the following 9# license: 10# 11# This program is free software; you can redistribute it and/or modify it 12# under the terms of copyleft-next (version 0.3.1 or later) as published 13# at http://copyleft-next.org/. 14 15# This performs a series tests against the proc sysctl interface. 16 17# Kselftest framework requirement - SKIP code is 4. 18ksft_skip=4 19 20TEST_NAME="sysctl" 21TEST_DRIVER="test_${TEST_NAME}" 22TEST_DIR=$(dirname $0) 23TEST_FILE=$(mktemp) 24 25# This represents 26# 27# TEST_ID:TEST_COUNT:ENABLED:TARGET 28# 29# TEST_ID: is the test id number 30# TEST_COUNT: number of times we should run the test 31# ENABLED: 1 if enabled, 0 otherwise 32# TARGET: test target file required on the test_sysctl module 33# 34# Once these are enabled please leave them as-is. Write your own test, 35# we have tons of space. 36ALL_TESTS="0001:1:1:int_0001" 37ALL_TESTS="$ALL_TESTS 0002:1:1:string_0001" 38ALL_TESTS="$ALL_TESTS 0003:1:1:int_0002" 39ALL_TESTS="$ALL_TESTS 0004:1:1:uint_0001" 40ALL_TESTS="$ALL_TESTS 0005:3:1:int_0003" 41ALL_TESTS="$ALL_TESTS 0006:50:1:bitmap_0001" 42ALL_TESTS="$ALL_TESTS 0007:1:1:boot_int" 43 44function allow_user_defaults() 45{ 46 if [ -z $DIR ]; then 47 DIR="/sys/module/test_sysctl/" 48 fi 49 if [ -z $DEFAULT_NUM_TESTS ]; then 50 DEFAULT_NUM_TESTS=50 51 fi 52 if [ -z $SYSCTL ]; then 53 SYSCTL="/proc/sys/debug/test_sysctl" 54 fi 55 if [ -z $PROD_SYSCTL ]; then 56 PROD_SYSCTL="/proc/sys" 57 fi 58 if [ -z $WRITES_STRICT ]; then 59 WRITES_STRICT="${PROD_SYSCTL}/kernel/sysctl_writes_strict" 60 fi 61} 62 63function check_production_sysctl_writes_strict() 64{ 65 echo -n "Checking production write strict setting ... " 66 if [ ! -e ${WRITES_STRICT} ]; then 67 echo "FAIL, but skip in case of old kernel" >&2 68 else 69 old_strict=$(cat ${WRITES_STRICT}) 70 if [ "$old_strict" = "1" ]; then 71 echo "ok" 72 else 73 echo "FAIL, strict value is 0 but force to 1 to continue" >&2 74 echo "1" > ${WRITES_STRICT} 75 fi 76 fi 77 78 if [ -z $PAGE_SIZE ]; then 79 PAGE_SIZE=$(getconf PAGESIZE) 80 fi 81 if [ -z $MAX_DIGITS ]; then 82 MAX_DIGITS=$(($PAGE_SIZE/8)) 83 fi 84 if [ -z $INT_MAX ]; then 85 INT_MAX=$(getconf INT_MAX) 86 fi 87 if [ -z $UINT_MAX ]; then 88 UINT_MAX=$(getconf UINT_MAX) 89 fi 90} 91 92test_reqs() 93{ 94 uid=$(id -u) 95 if [ $uid -ne 0 ]; then 96 echo $msg must be run as root >&2 97 exit $ksft_skip 98 fi 99 100 if ! which perl 2> /dev/null > /dev/null; then 101 echo "$0: You need perl installed" 102 exit $ksft_skip 103 fi 104 if ! which getconf 2> /dev/null > /dev/null; then 105 echo "$0: You need getconf installed" 106 exit $ksft_skip 107 fi 108 if ! which diff 2> /dev/null > /dev/null; then 109 echo "$0: You need diff installed" 110 exit $ksft_skip 111 fi 112} 113 114function load_req_mod() 115{ 116 if [ ! -d $SYSCTL ]; then 117 if ! modprobe -q -n $TEST_DRIVER; then 118 echo "$0: module $TEST_DRIVER not found [SKIP]" 119 echo "You must set CONFIG_TEST_SYSCTL=m in your kernel" >&2 120 exit $ksft_skip 121 fi 122 modprobe $TEST_DRIVER 123 if [ $? -ne 0 ]; then 124 echo "$0: modprobe $TEST_DRIVER failed." 125 exit 126 fi 127 fi 128} 129 130reset_vals() 131{ 132 VAL="" 133 TRIGGER=$(basename ${TARGET}) 134 case "$TRIGGER" in 135 int_0001) 136 VAL="60" 137 ;; 138 int_0002) 139 VAL="1" 140 ;; 141 uint_0001) 142 VAL="314" 143 ;; 144 string_0001) 145 VAL="(none)" 146 ;; 147 bitmap_0001) 148 VAL="" 149 ;; 150 *) 151 ;; 152 esac 153 echo -n $VAL > $TARGET 154} 155 156set_orig() 157{ 158 if [ ! -z $TARGET ] && [ ! -z $ORIG ]; then 159 if [ -f ${TARGET} ]; then 160 echo "${ORIG}" > "${TARGET}" 161 fi 162 fi 163} 164 165set_test() 166{ 167 echo "${TEST_STR}" > "${TARGET}" 168} 169 170verify() 171{ 172 local seen 173 seen=$(cat "$1") 174 if [ "${seen}" != "${TEST_STR}" ]; then 175 return 1 176 fi 177 return 0 178} 179 180# proc files get read a page at a time, which can confuse diff, 181# and get you incorrect results on proc files with long data. To use 182# diff against them you must first extract the output to a file, and 183# then compare against that file. 184verify_diff_proc_file() 185{ 186 TMP_DUMP_FILE=$(mktemp) 187 cat $1 > $TMP_DUMP_FILE 188 189 if ! diff -w -q $TMP_DUMP_FILE $2; then 190 return 1 191 else 192 return 0 193 fi 194} 195 196verify_diff_w() 197{ 198 echo "$TEST_STR" | diff -q -w -u - $1 > /dev/null 199 return $? 200} 201 202test_rc() 203{ 204 if [[ $rc != 0 ]]; then 205 echo "Failed test, return value: $rc" >&2 206 exit $rc 207 fi 208} 209 210test_finish() 211{ 212 set_orig 213 rm -f "${TEST_FILE}" 214 215 if [ ! -z ${old_strict} ]; then 216 echo ${old_strict} > ${WRITES_STRICT} 217 fi 218 exit $rc 219} 220 221run_numerictests() 222{ 223 echo "== Testing sysctl behavior against ${TARGET} ==" 224 225 rc=0 226 227 echo -n "Writing test file ... " 228 echo "${TEST_STR}" > "${TEST_FILE}" 229 if ! verify "${TEST_FILE}"; then 230 echo "FAIL" >&2 231 exit 1 232 else 233 echo "ok" 234 fi 235 236 echo -n "Checking sysctl is not set to test value ... " 237 if verify "${TARGET}"; then 238 echo "FAIL" >&2 239 exit 1 240 else 241 echo "ok" 242 fi 243 244 echo -n "Writing sysctl from shell ... " 245 set_test 246 if ! verify "${TARGET}"; then 247 echo "FAIL" >&2 248 exit 1 249 else 250 echo "ok" 251 fi 252 253 echo -n "Resetting sysctl to original value ... " 254 set_orig 255 if verify "${TARGET}"; then 256 echo "FAIL" >&2 257 exit 1 258 else 259 echo "ok" 260 fi 261 262 # Now that we've validated the sanity of "set_test" and "set_orig", 263 # we can use those functions to set starting states before running 264 # specific behavioral tests. 265 266 echo -n "Writing entire sysctl in single write ... " 267 set_orig 268 dd if="${TEST_FILE}" of="${TARGET}" bs=4096 2>/dev/null 269 if ! verify "${TARGET}"; then 270 echo "FAIL" >&2 271 rc=1 272 else 273 echo "ok" 274 fi 275 276 echo -n "Writing middle of sysctl after synchronized seek ... " 277 set_test 278 dd if="${TEST_FILE}" of="${TARGET}" bs=1 seek=1 skip=1 2>/dev/null 279 if ! verify "${TARGET}"; then 280 echo "FAIL" >&2 281 rc=1 282 else 283 echo "ok" 284 fi 285 286 echo -n "Writing beyond end of sysctl ... " 287 set_orig 288 dd if="${TEST_FILE}" of="${TARGET}" bs=20 seek=2 2>/dev/null 289 if verify "${TARGET}"; then 290 echo "FAIL" >&2 291 rc=1 292 else 293 echo "ok" 294 fi 295 296 echo -n "Writing sysctl with multiple long writes ... " 297 set_orig 298 (perl -e 'print "A" x 50;'; echo "${TEST_STR}") | \ 299 dd of="${TARGET}" bs=50 2>/dev/null 300 if verify "${TARGET}"; then 301 echo "FAIL" >&2 302 rc=1 303 else 304 echo "ok" 305 fi 306 test_rc 307} 308 309check_failure() 310{ 311 echo -n "Testing that $1 fails as expected..." 312 reset_vals 313 TEST_STR="$1" 314 orig="$(cat $TARGET)" 315 echo -n "$TEST_STR" > $TARGET 2> /dev/null 316 317 # write should fail and $TARGET should retain its original value 318 if [ $? = 0 ] || [ "$(cat $TARGET)" != "$orig" ]; then 319 echo "FAIL" >&2 320 rc=1 321 else 322 echo "ok" 323 fi 324 test_rc 325} 326 327run_wideint_tests() 328{ 329 # sysctl conversion functions receive a boolean sign and ulong 330 # magnitude; here we list the magnitudes we want to test (each of 331 # which will be tested in both positive and negative forms). Since 332 # none of these values fit in 32 bits, writing them to an int- or 333 # uint-typed sysctl should fail. 334 local magnitudes=( 335 # common boundary-condition values (zero, +1, -1, INT_MIN, 336 # and INT_MAX respectively) if truncated to lower 32 bits 337 # (potential for being falsely deemed in range) 338 0x0000000100000000 339 0x0000000100000001 340 0x00000001ffffffff 341 0x0000000180000000 342 0x000000017fffffff 343 344 # these look like negatives, but without a leading '-' are 345 # actually large positives (should be rejected as above 346 # despite being zero/+1/-1/INT_MIN/INT_MAX in the lower 32) 347 0xffffffff00000000 348 0xffffffff00000001 349 0xffffffffffffffff 350 0xffffffff80000000 351 0xffffffff7fffffff 352 ) 353 354 for sign in '' '-'; do 355 for mag in "${magnitudes[@]}"; do 356 check_failure "${sign}${mag}" 357 done 358 done 359} 360 361# Your test must accept digits 3 and 4 to use this 362run_limit_digit() 363{ 364 echo -n "Checking ignoring spaces up to PAGE_SIZE works on write ..." 365 reset_vals 366 367 LIMIT=$((MAX_DIGITS -1)) 368 TEST_STR="3" 369 (perl -e 'print " " x '$LIMIT';'; echo "${TEST_STR}") | \ 370 dd of="${TARGET}" 2>/dev/null 371 372 if ! verify "${TARGET}"; then 373 echo "FAIL" >&2 374 rc=1 375 else 376 echo "ok" 377 fi 378 test_rc 379 380 echo -n "Checking passing PAGE_SIZE of spaces fails on write ..." 381 reset_vals 382 383 LIMIT=$((MAX_DIGITS)) 384 TEST_STR="4" 385 (perl -e 'print " " x '$LIMIT';'; echo "${TEST_STR}") | \ 386 dd of="${TARGET}" 2>/dev/null 387 388 if verify "${TARGET}"; then 389 echo "FAIL" >&2 390 rc=1 391 else 392 echo "ok" 393 fi 394 test_rc 395} 396 397# You are using an int 398run_limit_digit_int() 399{ 400 echo -n "Testing INT_MAX works ..." 401 reset_vals 402 TEST_STR="$INT_MAX" 403 echo -n $TEST_STR > $TARGET 404 405 if ! verify "${TARGET}"; then 406 echo "FAIL" >&2 407 rc=1 408 else 409 echo "ok" 410 fi 411 test_rc 412 413 echo -n "Testing INT_MAX + 1 will fail as expected..." 414 reset_vals 415 let TEST_STR=$INT_MAX+1 416 echo -n $TEST_STR > $TARGET 2> /dev/null 417 418 if verify "${TARGET}"; then 419 echo "FAIL" >&2 420 rc=1 421 else 422 echo "ok" 423 fi 424 test_rc 425 426 echo -n "Testing negative values will work as expected..." 427 reset_vals 428 TEST_STR="-3" 429 echo -n $TEST_STR > $TARGET 2> /dev/null 430 if ! verify "${TARGET}"; then 431 echo "FAIL" >&2 432 rc=1 433 else 434 echo "ok" 435 fi 436 test_rc 437} 438 439# You used an int array 440run_limit_digit_int_array() 441{ 442 echo -n "Testing array works as expected ... " 443 TEST_STR="4 3 2 1" 444 echo -n $TEST_STR > $TARGET 445 446 if ! verify_diff_w "${TARGET}"; then 447 echo "FAIL" >&2 448 rc=1 449 else 450 echo "ok" 451 fi 452 test_rc 453 454 echo -n "Testing skipping trailing array elements works ... " 455 # Do not reset_vals, carry on the values from the last test. 456 # If we only echo in two digits the last two are left intact 457 TEST_STR="100 101" 458 echo -n $TEST_STR > $TARGET 459 # After we echo in, to help diff we need to set on TEST_STR what 460 # we expect the result to be. 461 TEST_STR="100 101 2 1" 462 463 if ! verify_diff_w "${TARGET}"; then 464 echo "FAIL" >&2 465 rc=1 466 else 467 echo "ok" 468 fi 469 test_rc 470 471 echo -n "Testing PAGE_SIZE limit on array works ... " 472 # Do not reset_vals, carry on the values from the last test. 473 # Even if you use an int array, you are still restricted to 474 # MAX_DIGITS, this is a known limitation. Test limit works. 475 LIMIT=$((MAX_DIGITS -1)) 476 TEST_STR="9" 477 (perl -e 'print " " x '$LIMIT';'; echo "${TEST_STR}") | \ 478 dd of="${TARGET}" 2>/dev/null 479 480 TEST_STR="9 101 2 1" 481 if ! verify_diff_w "${TARGET}"; then 482 echo "FAIL" >&2 483 rc=1 484 else 485 echo "ok" 486 fi 487 test_rc 488 489 echo -n "Testing exceeding PAGE_SIZE limit fails as expected ... " 490 # Do not reset_vals, carry on the values from the last test. 491 # Now go over limit. 492 LIMIT=$((MAX_DIGITS)) 493 TEST_STR="7" 494 (perl -e 'print " " x '$LIMIT';'; echo "${TEST_STR}") | \ 495 dd of="${TARGET}" 2>/dev/null 496 497 TEST_STR="7 101 2 1" 498 if verify_diff_w "${TARGET}"; then 499 echo "FAIL" >&2 500 rc=1 501 else 502 echo "ok" 503 fi 504 test_rc 505} 506 507# You are using an unsigned int 508run_limit_digit_uint() 509{ 510 echo -n "Testing UINT_MAX works ..." 511 reset_vals 512 TEST_STR="$UINT_MAX" 513 echo -n $TEST_STR > $TARGET 514 515 if ! verify "${TARGET}"; then 516 echo "FAIL" >&2 517 rc=1 518 else 519 echo "ok" 520 fi 521 test_rc 522 523 echo -n "Testing UINT_MAX + 1 will fail as expected..." 524 reset_vals 525 TEST_STR=$(($UINT_MAX+1)) 526 echo -n $TEST_STR > $TARGET 2> /dev/null 527 528 if verify "${TARGET}"; then 529 echo "FAIL" >&2 530 rc=1 531 else 532 echo "ok" 533 fi 534 test_rc 535 536 echo -n "Testing negative values will not work as expected ..." 537 reset_vals 538 TEST_STR="-3" 539 echo -n $TEST_STR > $TARGET 2> /dev/null 540 541 if verify "${TARGET}"; then 542 echo "FAIL" >&2 543 rc=1 544 else 545 echo "ok" 546 fi 547 test_rc 548} 549 550run_stringtests() 551{ 552 echo -n "Writing entire sysctl in short writes ... " 553 set_orig 554 dd if="${TEST_FILE}" of="${TARGET}" bs=1 2>/dev/null 555 if ! verify "${TARGET}"; then 556 echo "FAIL" >&2 557 rc=1 558 else 559 echo "ok" 560 fi 561 562 echo -n "Writing middle of sysctl after unsynchronized seek ... " 563 set_test 564 dd if="${TEST_FILE}" of="${TARGET}" bs=1 seek=1 2>/dev/null 565 if verify "${TARGET}"; then 566 echo "FAIL" >&2 567 rc=1 568 else 569 echo "ok" 570 fi 571 572 echo -n "Checking sysctl maxlen is at least $MAXLEN ... " 573 set_orig 574 perl -e 'print "A" x ('"${MAXLEN}"'-2), "B";' | \ 575 dd of="${TARGET}" bs="${MAXLEN}" 2>/dev/null 576 if ! grep -q B "${TARGET}"; then 577 echo "FAIL" >&2 578 rc=1 579 else 580 echo "ok" 581 fi 582 583 echo -n "Checking sysctl keeps original string on overflow append ... " 584 set_orig 585 perl -e 'print "A" x ('"${MAXLEN}"'-1), "B";' | \ 586 dd of="${TARGET}" bs=$(( MAXLEN - 1 )) 2>/dev/null 587 if grep -q B "${TARGET}"; then 588 echo "FAIL" >&2 589 rc=1 590 else 591 echo "ok" 592 fi 593 594 echo -n "Checking sysctl stays NULL terminated on write ... " 595 set_orig 596 perl -e 'print "A" x ('"${MAXLEN}"'-1), "B";' | \ 597 dd of="${TARGET}" bs="${MAXLEN}" 2>/dev/null 598 if grep -q B "${TARGET}"; then 599 echo "FAIL" >&2 600 rc=1 601 else 602 echo "ok" 603 fi 604 605 echo -n "Checking sysctl stays NULL terminated on overwrite ... " 606 set_orig 607 perl -e 'print "A" x ('"${MAXLEN}"'-1), "BB";' | \ 608 dd of="${TARGET}" bs=$(( $MAXLEN + 1 )) 2>/dev/null 609 if grep -q B "${TARGET}"; then 610 echo "FAIL" >&2 611 rc=1 612 else 613 echo "ok" 614 fi 615 616 test_rc 617} 618 619target_exists() 620{ 621 TARGET="${SYSCTL}/$1" 622 TEST_ID="$2" 623 624 if [ ! -f ${TARGET} ] ; then 625 echo "Target for test $TEST_ID: $TARGET not exist, skipping test ..." 626 return 0 627 fi 628 return 1 629} 630 631run_bitmaptest() { 632 # Total length of bitmaps string to use, a bit under 633 # the maximum input size of the test node 634 LENGTH=$((RANDOM % 65000)) 635 636 # First bit to set 637 BIT=$((RANDOM % 1024)) 638 639 # String containing our list of bits to set 640 TEST_STR=$BIT 641 642 # build up the string 643 while [ "${#TEST_STR}" -le "$LENGTH" ]; do 644 # Make sure next entry is discontiguous, 645 # skip ahead at least 2 646 BIT=$((BIT + $((2 + RANDOM % 10)))) 647 648 # Add new bit to the list 649 TEST_STR="${TEST_STR},${BIT}" 650 651 # Randomly make it a range 652 if [ "$((RANDOM % 2))" -eq "1" ]; then 653 RANGE_END=$((BIT + $((1 + RANDOM % 10)))) 654 TEST_STR="${TEST_STR}-${RANGE_END}" 655 BIT=$RANGE_END 656 fi 657 done 658 659 echo -n "Checking bitmap handler... " 660 TEST_FILE=$(mktemp) 661 echo -n "$TEST_STR" > $TEST_FILE 662 663 cat $TEST_FILE > $TARGET 2> /dev/null 664 if [ $? -ne 0 ]; then 665 echo "FAIL" >&2 666 rc=1 667 test_rc 668 fi 669 670 if ! verify_diff_proc_file "$TARGET" "$TEST_FILE"; then 671 echo "FAIL" >&2 672 rc=1 673 else 674 echo "ok" 675 rc=0 676 fi 677 test_rc 678} 679 680sysctl_test_0001() 681{ 682 TARGET="${SYSCTL}/$(get_test_target 0001)" 683 reset_vals 684 ORIG=$(cat "${TARGET}") 685 TEST_STR=$(( $ORIG + 1 )) 686 687 run_numerictests 688 run_wideint_tests 689 run_limit_digit 690} 691 692sysctl_test_0002() 693{ 694 TARGET="${SYSCTL}/$(get_test_target 0002)" 695 reset_vals 696 ORIG=$(cat "${TARGET}") 697 TEST_STR="Testing sysctl" 698 # Only string sysctls support seeking/appending. 699 MAXLEN=65 700 701 run_numerictests 702 run_stringtests 703} 704 705sysctl_test_0003() 706{ 707 TARGET="${SYSCTL}/$(get_test_target 0003)" 708 reset_vals 709 ORIG=$(cat "${TARGET}") 710 TEST_STR=$(( $ORIG + 1 )) 711 712 run_numerictests 713 run_wideint_tests 714 run_limit_digit 715 run_limit_digit_int 716} 717 718sysctl_test_0004() 719{ 720 TARGET="${SYSCTL}/$(get_test_target 0004)" 721 reset_vals 722 ORIG=$(cat "${TARGET}") 723 TEST_STR=$(( $ORIG + 1 )) 724 725 run_numerictests 726 run_wideint_tests 727 run_limit_digit 728 run_limit_digit_uint 729} 730 731sysctl_test_0005() 732{ 733 TARGET="${SYSCTL}/$(get_test_target 0005)" 734 reset_vals 735 ORIG=$(cat "${TARGET}") 736 737 run_limit_digit_int_array 738} 739 740sysctl_test_0006() 741{ 742 TARGET="${SYSCTL}/bitmap_0001" 743 reset_vals 744 ORIG="" 745 run_bitmaptest 746} 747 748sysctl_test_0007() 749{ 750 TARGET="${SYSCTL}/boot_int" 751 if [ ! -f $TARGET ]; then 752 echo "Skipping test for $TARGET as it is not present ..." 753 return $ksft_skip 754 fi 755 756 if [ -d $DIR ]; then 757 echo "Boot param test only possible sysctl_test is built-in, not module:" 758 cat $TEST_DIR/config >&2 759 return $ksft_skip 760 fi 761 762 echo -n "Testing if $TARGET is set to 1 ..." 763 ORIG=$(cat "${TARGET}") 764 765 if [ x$ORIG = "x1" ]; then 766 echo "ok" 767 return 0 768 fi 769 echo "FAIL" 770 echo "Checking if /proc/cmdline contains setting of the expected parameter ..." 771 if [ ! -f /proc/cmdline ]; then 772 echo "/proc/cmdline does not exist, test inconclusive" 773 return 0 774 fi 775 776 FOUND=$(grep -c "sysctl[./]debug[./]test_sysctl[./]boot_int=1" /proc/cmdline) 777 if [ $FOUND = "1" ]; then 778 echo "Kernel param found but $TARGET is not 1, TEST FAILED" 779 rc=1 780 test_rc 781 fi 782 783 echo "Skipping test, expected kernel parameter missing." 784 echo "To perform this test, make sure kernel is booted with parameter: sysctl.debug.test_sysctl.boot_int=1" 785 return $ksft_skip 786} 787 788list_tests() 789{ 790 echo "Test ID list:" 791 echo 792 echo "TEST_ID x NUM_TEST" 793 echo "TEST_ID: Test ID" 794 echo "NUM_TESTS: Number of recommended times to run the test" 795 echo 796 echo "0001 x $(get_test_count 0001) - tests proc_dointvec_minmax()" 797 echo "0002 x $(get_test_count 0002) - tests proc_dostring()" 798 echo "0003 x $(get_test_count 0003) - tests proc_dointvec()" 799 echo "0004 x $(get_test_count 0004) - tests proc_douintvec()" 800 echo "0005 x $(get_test_count 0005) - tests proc_douintvec() array" 801 echo "0006 x $(get_test_count 0006) - tests proc_do_large_bitmap()" 802 echo "0007 x $(get_test_count 0007) - tests setting sysctl from kernel boot param" 803} 804 805usage() 806{ 807 NUM_TESTS=$(grep -o ' ' <<<"$ALL_TESTS" | grep -c .) 808 let NUM_TESTS=$NUM_TESTS+1 809 MAX_TEST=$(printf "%04d\n" $NUM_TESTS) 810 echo "Usage: $0 [ -t <4-number-digit> ] | [ -w <4-number-digit> ] |" 811 echo " [ -s <4-number-digit> ] | [ -c <4-number-digit> <test- count>" 812 echo " [ all ] [ -h | --help ] [ -l ]" 813 echo "" 814 echo "Valid tests: 0001-$MAX_TEST" 815 echo "" 816 echo " all Runs all tests (default)" 817 echo " -t Run test ID the number amount of times is recommended" 818 echo " -w Watch test ID run until it runs into an error" 819 echo " -c Run test ID once" 820 echo " -s Run test ID x test-count number of times" 821 echo " -l List all test ID list" 822 echo " -h|--help Help" 823 echo 824 echo "If an error every occurs execution will immediately terminate." 825 echo "If you are adding a new test try using -w <test-ID> first to" 826 echo "make sure the test passes a series of tests." 827 echo 828 echo Example uses: 829 echo 830 echo "$TEST_NAME.sh -- executes all tests" 831 echo "$TEST_NAME.sh -t 0002 -- Executes test ID 0002 number of times is recomended" 832 echo "$TEST_NAME.sh -w 0002 -- Watch test ID 0002 run until an error occurs" 833 echo "$TEST_NAME.sh -s 0002 -- Run test ID 0002 once" 834 echo "$TEST_NAME.sh -c 0002 3 -- Run test ID 0002 three times" 835 echo 836 list_tests 837 exit 1 838} 839 840function test_num() 841{ 842 re='^[0-9]+$' 843 if ! [[ $1 =~ $re ]]; then 844 usage 845 fi 846} 847 848function get_test_count() 849{ 850 test_num $1 851 TEST_DATA=$(echo $ALL_TESTS | awk '{print $'$1'}') 852 echo ${TEST_DATA} | awk -F":" '{print $2}' 853} 854 855function get_test_enabled() 856{ 857 test_num $1 858 TEST_DATA=$(echo $ALL_TESTS | awk '{print $'$1'}') 859 echo ${TEST_DATA} | awk -F":" '{print $3}' 860} 861 862function get_test_target() 863{ 864 test_num $1 865 TEST_DATA=$(echo $ALL_TESTS | awk '{print $'$1'}') 866 echo ${TEST_DATA} | awk -F":" '{print $4}' 867} 868 869function run_all_tests() 870{ 871 for i in $ALL_TESTS ; do 872 TEST_ID=${i%:*:*:*} 873 ENABLED=$(get_test_enabled $TEST_ID) 874 TEST_COUNT=$(get_test_count $TEST_ID) 875 TEST_TARGET=$(get_test_target $TEST_ID) 876 if target_exists $TEST_TARGET $TEST_ID; then 877 continue 878 fi 879 if [[ $ENABLED -eq "1" ]]; then 880 test_case $TEST_ID $TEST_COUNT $TEST_TARGET 881 fi 882 done 883} 884 885function watch_log() 886{ 887 if [ $# -ne 3 ]; then 888 clear 889 fi 890 date 891 echo "Running test: $2 - run #$1" 892} 893 894function watch_case() 895{ 896 i=0 897 while [ 1 ]; do 898 899 if [ $# -eq 1 ]; then 900 test_num $1 901 watch_log $i ${TEST_NAME}_test_$1 902 ${TEST_NAME}_test_$1 903 else 904 watch_log $i all 905 run_all_tests 906 fi 907 let i=$i+1 908 done 909} 910 911function test_case() 912{ 913 NUM_TESTS=$2 914 915 i=0 916 917 if target_exists $3 $1; then 918 continue 919 fi 920 921 while [ $i -lt $NUM_TESTS ]; do 922 test_num $1 923 watch_log $i ${TEST_NAME}_test_$1 noclear 924 RUN_TEST=${TEST_NAME}_test_$1 925 $RUN_TEST 926 let i=$i+1 927 done 928} 929 930function parse_args() 931{ 932 if [ $# -eq 0 ]; then 933 run_all_tests 934 else 935 if [[ "$1" = "all" ]]; then 936 run_all_tests 937 elif [[ "$1" = "-w" ]]; then 938 shift 939 watch_case $@ 940 elif [[ "$1" = "-t" ]]; then 941 shift 942 test_num $1 943 test_case $1 $(get_test_count $1) $(get_test_target $1) 944 elif [[ "$1" = "-c" ]]; then 945 shift 946 test_num $1 947 test_num $2 948 test_case $1 $2 $(get_test_target $1) 949 elif [[ "$1" = "-s" ]]; then 950 shift 951 test_case $1 1 $(get_test_target $1) 952 elif [[ "$1" = "-l" ]]; then 953 list_tests 954 elif [[ "$1" = "-h" || "$1" = "--help" ]]; then 955 usage 956 else 957 usage 958 fi 959 fi 960} 961 962test_reqs 963allow_user_defaults 964check_production_sysctl_writes_strict 965load_req_mod 966 967trap "test_finish" EXIT 968 969parse_args $@ 970 971exit 0 972