| #!/bin/bash |
| # SPDX-License-Identifier: GPL-3.0+ |
| # Copyright (C) 2017 Omar Sandoval |
| |
| set -e |
| shopt -s extglob |
| |
| _error() { |
| echo "$0: $*" >&2 |
| exit 1 |
| } |
| |
| prompt_yes_no() { |
| if [[ $2 =~ ^[Yy] ]]; then |
| local default=0 |
| local prompt="$1 [Y/n] " |
| else |
| local default=1 |
| local prompt="$1 [y/N] " |
| fi |
| |
| local yn |
| read -r -n 1 -p "${prompt}" yn |
| if [[ -n "${yn}" ]]; then |
| echo |
| fi |
| if [[ "${yn}" =~ ^[Yy] ]]; then |
| return 0 |
| elif [[ "${yn}" =~ ^[Nn] ]]; then |
| return 1 |
| else |
| return $default |
| fi |
| } |
| |
| echo "Available test groups:" |
| find tests -mindepth 1 -maxdepth 1 -type d -not -name meta -printf ' %P\n' | sort |
| |
| read -r -p "Category for new test (pick one of the above or create a new one): " group |
| |
| if [[ -z $group ]]; then |
| exit 1 |
| fi |
| |
| if [[ $group =~ [[:space:]/] ]]; then |
| _error 'group name must not contain whitespace or "/"' |
| fi |
| |
| if [[ ! -e tests/${group} ]]; then |
| if ! prompt_yes_no "Category does not exist; create it?"; then |
| exit 1 |
| fi |
| mkdir -p "tests/${group}" |
| cat << EOF > "tests/${group}/rc" |
| #!/bin/bash |
| # SPDX-License-Identifier: GPL-3.0+ |
| # Copyright (C) $(date +%Y) TODO YOUR NAME HERE |
| # |
| # TODO: provide a brief description of the group here. |
| |
| . common/rc |
| # TODO: source any more common helpers needed for this group. |
| # . common/foo |
| |
| # TODO: if this test group has any extra requirements, it should define a |
| # group_requires() function. If tests in this group cannot be run, |
| # group_requires() should add strings to the \$SKIP_REASONS array which |
| # describe why the group cannot be run. |
| # |
| # Usually, group_requires() just needs to check that any necessary programs and |
| # kernel features are available using the _have_foo helpers. If |
| # group_requires() adds strings to \$SKIP_REASONS, all tests in this group will |
| # be skipped. |
| group_requires() { |
| _have_root |
| } |
| |
| # TODO: if this test group has extra requirements for what devices it can be |
| # run on, it should define a group_device_requires() function. If tests in this |
| # group cannot be run on the test device, it should add strings to |
| # \$SKIP_REASONS. \$TEST_DEV is the full path of the block device (e.g., |
| # /dev/nvme0n1 or /dev/sda1), and \$TEST_DEV_SYSFS is the sysfs path of the |
| # disk (not the partition, e.g., /sys/block/nvme0n1 or /sys/block/sda). If |
| # the target device is a partition device, \$TEST_DEV_PART_SYSFS is the sysfs |
| # path of the partition device (e.g., /sys/block/nvme0n1/nvme0n1p1 or |
| # /sys/block/sda/sda1). Otherwise, \$TEST_DEV_PART_SYSFS is an empty string. |
| # |
| # Usually, group_device_requires() just needs to check that the test device is |
| # the right type of hardware or supports any necessary features using the |
| # _require_test_dev_foo helpers. If group_device_requires() adds strings to |
| # \$SKIP_REASONS, all tests in this group will be skipped on that device. |
| # group_device_requires() { |
| # _require_test_dev_is_foo && _require_test_dev_supports_bar |
| # } |
| |
| # TODO: define any helpers that are specific to this group. |
| EOF |
| echo "Created tests/${group}/rc" |
| fi |
| |
| seq=0 |
| for test in tests/"$group"/+([0-9]); do |
| if [[ -e $test ]]; then |
| seq=${test##tests/"${group}"/+(0)} |
| fi |
| done |
| |
| test_name="${group}/$(printf "%03d" $((seq + 1)))" |
| |
| cat << EOF > "tests/${test_name}" |
| #!/bin/bash |
| # SPDX-License-Identifier: GPL-3.0+ |
| # Copyright (C) $(date +%Y) TODO YOUR NAME HERE |
| # |
| # TODO: provide a description of the test here, i.e., what it tests and how. If |
| # this is a regression test for a patch, reference the patch title: |
| # |
| # Regression test for patch "blk-stat: fix blk_stat_sum() if all samples are |
| # batched". |
| # |
| # For a commit, use the first 12 characters of the commit hash and the one-line |
| # commit summary: |
| # |
| # Regression test for commit efd4b81abbe1 ("blk-stat: fix blk_stat_sum() if all |
| # samples are batched"). |
| |
| . tests/${group}/rc |
| # TODO: source any more common helpers needed for this test. |
| |
| # TODO: fill in a very brief description of what this test does. The |
| # description should complete the sentence "This test will...". For example, |
| # "run a mixed read/write workload" would be a good description. |
| DESCRIPTION="" |
| |
| # TODO: if this test completes quickly (i.e., in ~30 seconds or less on |
| # reasonable hardware), uncomment the line below. |
| # QUICK=1 |
| |
| # TODO: if this test honors the configured \$TIMEOUT, uncomment the line below. |
| # This is for tests that can potentially run for a long time but where it's |
| # possible to limit the runtime (e.g., with the \`timeout\` command or with |
| # fio --runtime, which is what the _run_fio helper does). A test shouldn't be |
| # both QUICK and TIMED. |
| # TIMED=1 |
| |
| # TODO: dmesg is checked for oopses, warnings, etc. after each test run by |
| # default. You can suppress this by defining: |
| # CHECK_DMESG=0 |
| # Alternatively, you can filter out any unimportant messages in dmesg like so: |
| # DMESG_FILTER="grep -v sysfs" |
| |
| # TODO: if this test can be run for both regular block devices and zoned block |
| # devices, uncomment the line below. |
| # CAN_BE_ZONED=1 |
| |
| # TODO: if this test has any extra requirements, it should define a requires() |
| # function. If the test cannot be run, requires() should add strings to |
| # \$SKIP_REASONS. Usually, requires() just needs to check that any necessary |
| # programs and kernel features are available using the _have_foo helpers. |
| # If requires() adds strings to \$SKIP_REASONS, the test is skipped. |
| # requires() { |
| # _have_foo |
| # } |
| |
| # TODO: if this test has extra requirements for what devices it can be run on, |
| # it should define a device_requires() function. If this test cannot be run on |
| # the test device, it should add strings to \$SKIP_REASONS. \$TEST_DEV is the |
| # full path of the block device (e.g., /dev/nvme0n1 or /dev/sda1), and |
| # \$TEST_DEV_SYSFS is the sysfs path of the disk (not the partition, e.g., |
| # /sys/block/nvme0n1 or /sys/block/sda). If the target device is a partition |
| # device, \$TEST_DEV_PART_SYSFS is the sysfs path of the partition device |
| # (e.g., /sys/block/nvme0n1/nvme0n1p1 or /sys/block/sda/sda1). Otherwise, |
| # \$TEST_DEV_PART_SYSFS is an empty string. |
| # |
| # Usually, device_requires() just needs to check that the test device is the |
| # right type of hardware or supports any necessary features using the |
| # _require_test_dev_foo helpers. If device_requires() adds strings to |
| # \$SKIP_REASONS, the test will be skipped on that device. |
| # device_requires() { |
| # _require_test_dev_is_foo && _require_test_dev_supports_bar |
| # } |
| |
| # TODO: if the test case can run the same test for different conditions, define |
| # the helper function "set_conditions". When no argument is specified, return |
| # the number of condition variations. Blktests repeats the test case as many |
| # times as the returned number. When its argument is specified, refer to it as |
| # the condition variation index and set up the conditions for it. Also set the |
| # global variable COND_DESC which is printed at the test case run and used for |
| # the result directory name. Blktests calls set_conditions() before each run of |
| # the test case incrementing the argument index from 0. |
| # set_conditions() { |
| # local index=\$1 |
| # |
| # if [[ -z \$index ]]; then |
| # echo 2 # return number of condition variations |
| # return |
| # fi |
| # |
| # # Set test conditions based on the $index |
| # ... |
| # COND_DESC="Describe the conditions shortly" |
| # } |
| |
| # TODO: define the test. The output of this function (stdout and stderr) will |
| # be compared to tests/\${TEST_NAME}.out. If it does not match, the test is |
| # considered a failure. If the test runs a command which has unnecessary |
| # output, either redirect that output to \$FULL or /dev/null, or filter out the |
| # unimportant parts (e.g., with grep or the _filter_foo helpers). |
| # |
| # Additionally, if the test function returns non-zero, it is considered a |
| # failure. You should prefer letting the test fail because of broken output |
| # over, say, checking the exit status of every command you run. |
| # |
| # If the test cannot be run, this function may add strings to \$SKIP_REASONS |
| # and return. In that case, the return value and output are ignored, and the |
| # test is considered skipped. This should only be done when the requirements |
| # can only be detected with a non-trivial amount of setup; use |
| # group_requires(), requires(), and/or device_requires() instead when possible. |
| # |
| # Various variables are defined for the test: |
| # - \$TEST_NAME -- the full name of the test. |
| # - \$TMPDIR -- a temporary directory deleted after the test is run. |
| # - \$SRCDIR -- absolute path of the src/ subdirectory |
| # - \$FULL -- a file where the test may log verbose output (e.g., the output |
| # of fio or mkfs). |
| # - \$TEST_RUN -- an associative array of additional test data to display |
| # after the test is run and store for comparison on future |
| # test runs. Use like TEST_RUN[iops]="\$(measure_iops)". |
| # - \$TIMEOUT -- an optional timeout configured by the user. If possible, limit |
| # the runtime of the entire test to this value if it is set. |
| # |
| # Many tests do not need a test device (usually because they set up their own |
| # virtual devices, like null-blk or loop). These tests should define the test() |
| # function. |
| # |
| # Tests that require a test device should rename test() to test_device(). These |
| # tests will be run with a few more variables defined: |
| # - \$TEST_DEV -- the block device to run the test on (e.g., /dev/sda1). |
| # - \$TEST_DEV_SYSFS -- the sysfs directory of the device (e.g., |
| # /sys/block/sda). In general, you should use the |
| # _test_dev_queue_{get,set} helpers. If the device is a |
| # partition, this is the directory of its holder |
| # device. |
| # - \$TEST_DEV_PART_SYSFS -- the sysfs directory of the device if the device |
| # is a partition device (e.g., |
| # /sys/block/sda/sda1). If the device is not a |
| # partition, this is an empty string. |
| test() { |
| echo "Running \${TEST_NAME}" |
| |
| # TODO: fill in the test case. |
| |
| echo "Test complete" |
| } |
| |
| # Finally, some coding style guidelines: |
| # - Indent with tabs. |
| # - Don't add a space before the parentheses or a newline before the curly brace |
| # in function definitions. |
| # - Variables set and used by the testing framework are in caps with underscores. |
| # E.g., TEST_NAME and GROUPS. Variables local to the test are lowercase |
| # with underscores. |
| # - Functions defined by the testing framework or group scripts, including |
| # helpers, have a leading underscore. E.g., _have_scsi_debug. Functions local |
| # to the test should not have a leading underscore. |
| # - Both [[ ]] form and [ ] form are fine for tests. [[ ]] is preferred. |
| # - Always quote variable expansions unless the variable is a number or inside of |
| # a [[ ]] test. |
| # - Use the \$() form of command substitution instead of backticks. |
| # - Use bash for loops instead of seq. E.g., for ((i = 0; i < 10; i++)), not |
| # for i in \$(seq 0 9). |
| # |
| # Please run \`make check\` after your test is done to check for shell |
| # scripting errors and other mistakes. |
| EOF |
| chmod +x "tests/${test_name}" |
| echo "Created tests/${test_name}" |
| |
| cat << EOF > "tests/${test_name}.out" |
| Running ${test_name} |
| Test complete |
| EOF |
| echo "Created tests/${test_name}.out" |