| #!/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 can be run, |
| # group_requires() should return 0. Otherwise, it should return non-zero and |
| # set the \$SKIP_REASON variable. |
| # |
| # Usually, group_requires() just needs to check that any necessary programs and |
| # kernel features are available using the _have_foo helpers. If |
| # group_requires() returns non-zero, 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 can be run on the test device, it should return zero. Otherwise, it |
| # should return non-zero and set the \$SKIP_REASON variable. \$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 |
| # _test_dev_foo helpers. If group_device_requires() returns non-zero, all tests |
| # in this group will be skipped on that device. |
| # group_device_requires() { |
| # _test_dev_is_foo && _test_dev_supports_bar |
| # } |
| |
| # TODO: define any helpers that are specific to this group. |
| EOF |
| echo "Created tests/${group}/rc" |
| fi |
| |
| for ((i = 1; ; i++)); do |
| seq="$(printf "%03d" $i)" |
| test_name="${group}/${seq}" |
| if [[ ! -e tests/${test_name} ]]; then |
| break |
| fi |
| done |
| |
| 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 can be run, requires() should return 0. Otherwise, it |
| # should return non-zero and set the \$SKIP_REASON variable. Usually, |
| # requires() just needs to check that any necessary programs and kernel |
| # features are available using the _have_foo helpers. If requires() returns |
| # non-zero, 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 can be run on the |
| # test device, it should return zero. Otherwise, it should return non-zero and |
| # set the \$SKIP_REASON variable. \$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 |
| # _test_dev_foo helpers. If device_requires() returns non-zero, the test will |
| # be skipped on that device. |
| # device_requires() { |
| # _test_dev_is_foo && _test_dev_supports_bar |
| # } |
| |
| # 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. |
| # |
| # 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 guidlines: |
| # - 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. |
| # - Use the bash [[ ]] form of tests instead of [ ]. |
| # - 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" |