Chase Qi | 840edf2 | 2016-09-02 16:24:58 +0800 | [diff] [blame] | 1 | ======================= |
| 2 | Test Writing Guidelines |
| 3 | ======================= |
| 4 | |
Nicolas Dechesne | c4c736a | 2017-01-24 21:15:11 +0100 | [diff] [blame] | 5 | This document describes guidelines and is intended for anybody who wants to write |
Chase Qi | 840edf2 | 2016-09-02 16:24:58 +0800 | [diff] [blame] | 6 | or modify a test case. It's not a definitive guide and it's not, by any means, a |
| 7 | substitute for common sense. |
| 8 | |
| 9 | General Rules |
| 10 | ============= |
| 11 | |
| 12 | 1. Simplicity |
| 13 | ------------- |
| 14 | |
Nicolas Dechesne | c4c736a | 2017-01-24 21:15:11 +0100 | [diff] [blame] | 15 | It's worth keeping test cases as simple as possible. |
Chase Qi | 840edf2 | 2016-09-02 16:24:58 +0800 | [diff] [blame] | 16 | |
| 17 | 2. Code duplication |
| 18 | ------------------- |
| 19 | |
| 20 | Whenever you are about to copy a large part of the code from one test case to |
| 21 | another, think if it is possible to move it to a library to reduce code |
| 22 | duplication and the cost of maintenance. |
| 23 | |
| 24 | 3. Coding style |
| 25 | --------------- |
| 26 | |
| 27 | Use common sense and BE CONSISTENT. |
| 28 | |
| 29 | If you are editing code, take a few minutes to look at the code around you and |
| 30 | determine its style. |
| 31 | |
| 32 | The point of having style guidelines is to have a common vocabulary of coding so |
| 33 | people can concentrate on what you are saying, rather than on how you are saying |
| 34 | it. |
| 35 | |
| 36 | 3.1 Shell coding style |
| 37 | ~~~~~~~~~~~~~~~~~~~~~~ |
| 38 | When writing test cases in shell write in *portable shell* only. |
| 39 | |
| 40 | You can either try to run the test cases on Debian which has '/bin/sh' pointing |
| 41 | to 'dash' by default or install 'dash' on your favorite distribution and use |
| 42 | it to run the tests. |
| 43 | |
| 44 | Ref: `Shell Style Guide <https://google.github.io/styleguide/shell.xml>`_ |
| 45 | |
| 46 | 3.2 Python coding style |
| 47 | ~~~~~~~~~~~~~~~~~~~~~~~ |
| 48 | Please follow PEP 8 style guide whenever possible. |
| 49 | |
| 50 | Ref: `PEP 8 <https://www.python.org/dev/peps/pep-0008/>`_ |
| 51 | Easy-to-read version of PEP 8 available at `pep8.org <http://pep8.org>`_ |
| 52 | |
| 53 | 4. Commenting code |
| 54 | ------------------ |
| 55 | |
| 56 | Use useful comments in your program to explain: |
| 57 | |
Chase Qi | 6d96a9f | 2019-01-23 17:17:48 +0800 | [diff] [blame] | 58 | - assumptions |
| 59 | - important decisions |
| 60 | - important details |
| 61 | - problems you're trying to solve |
| 62 | - problems you're trying to overcome in your program, etc. |
Chase Qi | 840edf2 | 2016-09-02 16:24:58 +0800 | [diff] [blame] | 63 | |
| 64 | Code tells you how, comments should tell you why. |
| 65 | |
| 66 | 5. License |
| 67 | ---------- |
| 68 | Code contributed to this repository should be licensed under GPLv2+ (GNU GPL |
| 69 | version 2 or any later version). |
| 70 | |
| 71 | Writing a test case |
| 72 | =================== |
| 73 | |
| 74 | Linux |
| 75 | ------ |
| 76 | |
| 77 | 1. Structure |
| 78 | ~~~~~~~~~~~~ |
| 79 | |
Nicolas Dechesne | c4c736a | 2017-01-24 21:15:11 +0100 | [diff] [blame] | 80 | Tests are generally placed under 'linux/' directory. Everything that relates to |
Chase Qi | 840edf2 | 2016-09-02 16:24:58 +0800 | [diff] [blame] | 81 | the test goes under the same folder named with test case name. |
| 82 | |
| 83 | Define 'linux/test-case-name/output' folder in test case to save test output and |
| 84 | result. Using a dedicated folder is helpful to distinguish between test script |
| 85 | and test output. |
| 86 | |
Nicolas Dechesne | c4c736a | 2017-01-24 21:15:11 +0100 | [diff] [blame] | 87 | 2. Installing dependencies |
| 88 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ |
Chase Qi | 840edf2 | 2016-09-02 16:24:58 +0800 | [diff] [blame] | 89 | |
Nicolas Dechesne | c4c736a | 2017-01-24 21:15:11 +0100 | [diff] [blame] | 90 | The same test case should work on Debian/Ubuntu, Fedora/CentOS and OE based |
| 91 | distributions whenever possible. This can be achieved with install_deps() |
Chase Qi | c246bb4 | 2017-01-13 16:12:35 +0800 | [diff] [blame] | 92 | function. The following is a simple example. "${SKIP_INSTALL}" should be set to |
Nicolas Dechesne | c4c736a | 2017-01-24 21:15:11 +0100 | [diff] [blame] | 93 | 'true' on distributions that do not supported install_deps(). In the unsupported |
| 94 | case, if "${SKIP_INSTALL}" is 'true', install_deps() still will skip package |
Chase Qi | c246bb4 | 2017-01-13 16:12:35 +0800 | [diff] [blame] | 95 | installation. |
Chase Qi | 840edf2 | 2016-09-02 16:24:58 +0800 | [diff] [blame] | 96 | |
Chase Qi | c246bb4 | 2017-01-13 16:12:35 +0800 | [diff] [blame] | 97 | Example 1:: |
Chase Qi | 840edf2 | 2016-09-02 16:24:58 +0800 | [diff] [blame] | 98 | |
Chase Qi | c246bb4 | 2017-01-13 16:12:35 +0800 | [diff] [blame] | 99 | install_deps "${pkgs}" "${SKIP_INSTALL}" |
Chase Qi | 840edf2 | 2016-09-02 16:24:58 +0800 | [diff] [blame] | 100 | |
Chase Qi | c246bb4 | 2017-01-13 16:12:35 +0800 | [diff] [blame] | 101 | Package name may vary by distribution. In this case, you will need to handle |
Nicolas Dechesne | c4c736a | 2017-01-24 21:15:11 +0100 | [diff] [blame] | 102 | package installation with separate lines. dist_name() function is designed to |
Chase Qi | c246bb4 | 2017-01-13 16:12:35 +0800 | [diff] [blame] | 103 | detect the distribution ID at running time so that you can define package name |
| 104 | by distribution. Refer to the following example. |
Chase Qi | 840edf2 | 2016-09-02 16:24:58 +0800 | [diff] [blame] | 105 | |
Chase Qi | c246bb4 | 2017-01-13 16:12:35 +0800 | [diff] [blame] | 106 | Example 2:: |
Chase Qi | 840edf2 | 2016-09-02 16:24:58 +0800 | [diff] [blame] | 107 | |
| 108 | dist_name |
| 109 | case "${dist}" in |
Nicolas Dechesne | b7e3876 | 2017-01-25 12:07:08 +0100 | [diff] [blame] | 110 | debian|ubuntu) install_deps "lsb-release" "${SKIP_INSTALL}" ;; |
| 111 | fedora|centos) install_deps "redhat-lsb-core" "${SKIP_INSTALL}" ;; |
Chase Qi | 475120c | 2017-02-06 12:06:01 +0800 | [diff] [blame] | 112 | *) warn_msg "Unsupported distro: ${dist}! Package installation skipped." ;; |
Chase Qi | 840edf2 | 2016-09-02 16:24:58 +0800 | [diff] [blame] | 113 | esac |
Chase Qi | c246bb4 | 2017-01-13 16:12:35 +0800 | [diff] [blame] | 114 | |
| 115 | Except automated package installation, you may also need to download and install |
| 116 | software manually. If you want to make these steps skippable, here is an |
| 117 | example. |
| 118 | |
| 119 | Example 3:: |
| 120 | |
| 121 | if [ "${SKIP_INSTALL}" = "true" ] || [ "${SKIP_INSTALL}" = "True" ]; then |
| 122 | dist_name |
| 123 | case "${dist}" in |
Nicolas Dechesne | b7e3876 | 2017-01-25 12:07:08 +0100 | [diff] [blame] | 124 | debian|ubuntu) install_deps "${pkgs}" ;; |
| 125 | fedora|centos) install_deps "${pkgs}" ;; |
Chase Qi | 475120c | 2017-02-06 12:06:01 +0800 | [diff] [blame] | 126 | *) warn_msg "Unsupported distro: ${dist}! Package installation skipped." ;; |
Chase Qi | c246bb4 | 2017-01-13 16:12:35 +0800 | [diff] [blame] | 127 | esac |
| 128 | |
| 129 | # manually install steps. |
| 130 | git clone "${repo}" |
| 131 | cd "${dir}" |
Nicolas Dechesne | c4c736a | 2017-01-24 21:15:11 +0100 | [diff] [blame] | 132 | ./configure && make install |
Chase Qi | c246bb4 | 2017-01-13 16:12:35 +0800 | [diff] [blame] | 133 | fi |
| 134 | |
Nicolas Dechesne | c4c736a | 2017-01-24 21:15:11 +0100 | [diff] [blame] | 135 | Hopefully, the above 3 examples cover most of the user cases. When |
| 136 | writing test cases, in general: |
Chase Qi | c246bb4 | 2017-01-13 16:12:35 +0800 | [diff] [blame] | 137 | |
Chase Qi | 6d96a9f | 2019-01-23 17:17:48 +0800 | [diff] [blame] | 138 | - Define 'SKIP_INSTALL' variable with 'false' as default. |
| 139 | - Add parameter '-s <True|False>', so that user can modify 'SKIP_INSTALL'. |
| 140 | - Try to use the above functions, and give unknown distributions more care. |
Chase Qi | 840edf2 | 2016-09-02 16:24:58 +0800 | [diff] [blame] | 141 | |
| 142 | 3. Saving output |
| 143 | ~~~~~~~~~~~~~~~~~ |
| 144 | |
| 145 | 'test-case-name/output' directory is recommended to save test log and result |
| 146 | files. |
| 147 | |
| 148 | 4. Parsing result |
| 149 | ~~~~~~~~~~~~~~~~~ |
| 150 | |
| 151 | Saving parsed result in the same format is important for post process such as |
Chase Qi | 6d96a9f | 2019-01-23 17:17:48 +0800 | [diff] [blame] | 152 | sending to LAVA. The following result format should be followed:: |
Chase Qi | 840edf2 | 2016-09-02 16:24:58 +0800 | [diff] [blame] | 153 | |
Chase Qi | fd13645 | 2019-03-04 11:06:45 +0800 | [diff] [blame] | 154 | test-case-id pass/fail/skip |
Nicolas Dechesne | c4c736a | 2017-01-24 21:15:11 +0100 | [diff] [blame] | 155 | test-case-id pass/fail/skip measurement |
Chase Qi | 840edf2 | 2016-09-02 16:24:58 +0800 | [diff] [blame] | 156 | test-case-id pass/fail/skip measurement units |
| 157 | |
| 158 | 'output/result.txt' file is recommended to save result. |
| 159 | |
Nicolas Dechesne | c4c736a | 2017-01-24 21:15:11 +0100 | [diff] [blame] | 160 | We encourage test writers to use the functions defined in 'sh-test-lib' to format |
Chase Qi | 840edf2 | 2016-09-02 16:24:58 +0800 | [diff] [blame] | 161 | test result. |
| 162 | |
| 163 | Print "test-case pass/fail" by checking exit code:: |
| 164 | |
| 165 | check_return "${test_case_id}" |
| 166 | |
| 167 | Add a metric for performance test:: |
| 168 | |
Nicolas Dechesne | c4c736a | 2017-01-24 21:15:11 +0100 | [diff] [blame] | 169 | add_metic "${test-case-id}" "pass/fail/skip" "${measurement}" "${units}" |
Chase Qi | 840edf2 | 2016-09-02 16:24:58 +0800 | [diff] [blame] | 170 | |
| 171 | |
| 172 | 5. Running in LAVA |
| 173 | ~~~~~~~~~~~~~~~~~~ |
| 174 | |
| 175 | LAVA is the foundation of test automation in Linaro. It is able to handle image |
| 176 | deployment and boot, and provides a test shell for test run. To run a test case |
| 177 | in LAVA, a definition file in YAML format is required. |
| 178 | |
| 179 | Bear in mind, do all the LAVA-specific steps in test definition file, and do not |
| 180 | use any LAVA-specific steps in test script, otherwise you may lock yourself out |
| 181 | of your own test case when LAVA isn't available or the board you want to test |
| 182 | wasn't deployed in LAVA. |
| 183 | |
| 184 | Test script should handle dependencies installation, test execution, result |
| 185 | parsing and other work in a self-contained way, and produce result.txt file with |
| 186 | a format that can be easily parsed and sent to LAVA. This is a more robust way. |
| 187 | Test case works with/without LAVA and can be tested locally. |
| 188 | |
| 189 | A general test definition file should contain the below keywords and steps:: |
| 190 | |
| 191 | metadata: |
| 192 | # Define parameters required by test case with default values. |
| 193 | params: |
| 194 | SKIP_INSTALL: False |
| 195 | run: |
| 196 | # A typical test run in LAVA requires the below steps. |
| 197 | steps: |
| 198 | # Enter the directory of the test case. |
| 199 | - cd ./automated/linux/smoke/ |
| 200 | # Run the test. |
| 201 | - ./smoke.sh -s "${SKIP_INSTALL}" |
| 202 | # Send the results in result.txt to LAVA. |
| 203 | - ../../utils/send-to-lava.sh ./output/result.txt |
| 204 | |
| 205 | Android specific |
| 206 | ---------------- |
| 207 | |
| 208 | The above test writing guidelines also apply to Android test cases. The major |
| 209 | difference is that we run all Android test cases through adb shell. Compare with |
| 210 | local run, adb and adb shell enable us to do more. And this model is well |
| 211 | supported by LAVA V2 LXC protocol. |
| 212 | |
| 213 | A typical Android test case can be written with the following steps:: |
| 214 | |
| 215 | # Check adb connect with initialize_adb funtion |
| 216 | initialize_adb |
| 217 | # Install binaries and scripts |
| 218 | detect_abi |
| 219 | install "../../bin/${abi}/busybox" |
| 220 | install "./device-script.sh" |
| 221 | # Run test script through adb shell. |
| 222 | adb -s "${SN}" shell device-script.sh |
| 223 | # Pull output from device for parsing. |
| 224 | pull_output "${DEVICE_OUTPUT}" "${HOST_OUTPUT}" |
| 225 | |
Milosz Wasilewski | 05b2d38 | 2017-04-18 16:36:41 +0100 | [diff] [blame] | 226 | |
| 227 | 6. Using test-runner |
| 228 | ~~~~~~~~~~~~~~~~~~~~ |
| 229 | |
| 230 | Using test-runner to run tests locally |
| 231 | -------------------------------------- |
| 232 | |
| 233 | The tests can be run directly on the board, assuming you have installed basic |
| 234 | tools such as git, gcc, ... `test-runner` is written in Python and requires |
| 235 | `pexpect` and `yaml` modules to be installed as well. To run tests directly |
| 236 | on the board, get a prompt and run:: |
| 237 | |
| 238 | git clone http://git.linaro.org/qa/test-definitions.git |
| 239 | cd test-definitions |
| 240 | source automated/bin/setenv.sh |
| 241 | test-runner -p plans/rpb_ee/rpb_ee_functional.yaml |
| 242 | |
| 243 | By default the test output are stored in `$HOME/output/`, and the output folder |
| 244 | can be configured with `-o` argument. |
| 245 | |
| 246 | Using test-runner to run tests from host PC |
| 247 | ------------------------------------------- |
| 248 | |
| 249 | It is also possible to run tests from a host PC if the board is available on |
| 250 | the network. In that case `test-runner` will connect to the board over SSH, and |
| 251 | you need to setup the board so that the host PC can connect to the board over |
| 252 | SSH without any prompt (password less connection). To run from the host, run |
| 253 | the following commands from the host command prompt:: |
| 254 | |
| 255 | git clone http://git.linaro.org/qa/test-definitions.git |
| 256 | cd test-definitions |
| 257 | source automated/bin/setenv.sh |
| 258 | test-runner -g root@ip -p plans/rpb_ee/rpb_ee_functional.yaml |
| 259 | |
| 260 | Where `root@ip` is the credential to connect to the board over SSH. |
| 261 | |
| 262 | By default the test output are stored in `$HOME/output/root@ip`, and the output |
| 263 | folder can be configured with `-o` argument. |
| 264 | |
| 265 | Running individual tests |
| 266 | ------------------------ |
| 267 | |
| 268 | Instead of running a test plan with `-p` argument, it is possible to run a single |
| 269 | test only using `-d` argument. |
| 270 | |
| 271 | Test output |
| 272 | ----------- |
| 273 | |
| 274 | At the end of the test run, the following artefact are available in the output |
| 275 | folder: |
| 276 | |
Chase Qi | 6d96a9f | 2019-01-23 17:17:48 +0800 | [diff] [blame] | 277 | - `result.csv` and `result.json` which contain summary of test results |
| 278 | (including test name, test case ID, test results such as pass, fail, skip, |
| 279 | test measurement, if any, with the associated measurement unit, and the test |
| 280 | argument used |
| 281 | - For each test executed, there is a folder which contains the console output |
| 282 | of the test run, `stdout.log` as well as all test scripts/data |
Milosz Wasilewski | 05b2d38 | 2017-04-18 16:36:41 +0100 | [diff] [blame] | 283 | |
Chase Qi | 840edf2 | 2016-09-02 16:24:58 +0800 | [diff] [blame] | 284 | Test Contribution Checklist |
| 285 | =========================== |
| 286 | |
Chase Qi | 6d96a9f | 2019-01-23 17:17:48 +0800 | [diff] [blame] | 287 | - When applicable, check test cases with the following tools with line length |
Chase Qi | 840edf2 | 2016-09-02 16:24:58 +0800 | [diff] [blame] | 288 | rule relaxed. |
| 289 | |
Chase Qi | 6d96a9f | 2019-01-23 17:17:48 +0800 | [diff] [blame] | 290 | - shellcheck: Shell script analysis tool. |
| 291 | - pycodestyle: check Python code against the style conventions in PEP 8. |
| 292 | - php: check syntax with 'php -l file'. |
Chase Qi | 840edf2 | 2016-09-02 16:24:58 +0800 | [diff] [blame] | 293 | |
Chase Qi | 6d96a9f | 2019-01-23 17:17:48 +0800 | [diff] [blame] | 294 | - Run test cases on local system without LAVA. |
| 295 | - Optionally, run test cases in LAVA and provide job example. |