1d201506cSStephen Warren# U-Boot pytest suite 2d201506cSStephen Warren 3d201506cSStephen Warren## Introduction 4d201506cSStephen Warren 5d201506cSStephen WarrenThis tool aims to test U-Boot by executing U-Boot shell commands using the 6d201506cSStephen Warrenconsole interface. A single top-level script exists to execute or attach to the 7d201506cSStephen WarrenU-Boot console, run the entire script of tests against it, and summarize the 8d201506cSStephen Warrenresults. Advantages of this approach are: 9d201506cSStephen Warren 10d201506cSStephen Warren- Testing is performed in the same way a user or script would interact with 11d201506cSStephen Warren U-Boot; there can be no disconnect. 12d201506cSStephen Warren- There is no need to write or embed test-related code into U-Boot itself. 13d201506cSStephen Warren It is asserted that writing test-related code in Python is simpler and more 14d201506cSStephen Warren flexible that writing it all in C. 15d201506cSStephen Warren- It is reasonably simple to interact with U-Boot in this way. 16d201506cSStephen Warren 17d201506cSStephen Warren## Requirements 18d201506cSStephen Warren 19d201506cSStephen WarrenThe test suite is implemented using pytest. Interaction with the U-Boot console 20d201506cSStephen Warreninvolves executing some binary and interacting with its stdin/stdout. You will 21d201506cSStephen Warrenneed to implement various "hook" scripts that are called by the test suite at 22d201506cSStephen Warrenthe appropriate time. 23d201506cSStephen Warren 24d201506cSStephen WarrenOn Debian or Debian-like distributions, the following packages are required. 25d201506cSStephen WarrenSimilar package names should exist in other distributions. 26d201506cSStephen Warren 27d201506cSStephen Warren| Package | Version tested (Ubuntu 14.04) | 28d201506cSStephen Warren| -------------- | ----------------------------- | 29d201506cSStephen Warren| python | 2.7.5-5ubuntu3 | 30d201506cSStephen Warren| python-pytest | 2.5.1-1 | 31d201506cSStephen Warren 32d201506cSStephen WarrenThe test script supports either: 33d201506cSStephen Warren 34d201506cSStephen Warren- Executing a sandbox port of U-Boot on the local machine as a sub-process, 35d201506cSStephen Warren and interacting with it over stdin/stdout. 36d201506cSStephen Warren- Executing an external "hook" scripts to flash a U-Boot binary onto a 37d201506cSStephen Warren physical board, attach to the board's console stream, and reset the board. 38d201506cSStephen Warren Further details are described later. 39d201506cSStephen Warren 40d201506cSStephen Warren### Using `virtualenv` to provide requirements 41d201506cSStephen Warren 42d201506cSStephen WarrenOlder distributions (e.g. Ubuntu 10.04) may not provide all the required 43d201506cSStephen Warrenpackages, or may provide versions that are too old to run the test suite. One 44d201506cSStephen Warrencan use the Python `virtualenv` script to locally install more up-to-date 45d201506cSStephen Warrenversions of the required packages without interfering with the OS installation. 46d201506cSStephen WarrenFor example: 47d201506cSStephen Warren 48d201506cSStephen Warren```bash 49d201506cSStephen Warren$ cd /path/to/u-boot 50d201506cSStephen Warren$ sudo apt-get install python python-virtualenv 51d201506cSStephen Warren$ virtualenv venv 52d201506cSStephen Warren$ . ./venv/bin/activate 53d201506cSStephen Warren$ pip install pytest 54d201506cSStephen Warren``` 55d201506cSStephen Warren 56d201506cSStephen Warren## Testing sandbox 57d201506cSStephen Warren 58d201506cSStephen WarrenTo run the testsuite on the sandbox port (U-Boot built as a native user-space 59d201506cSStephen Warrenapplication), simply execute: 60d201506cSStephen Warren 61d201506cSStephen Warren``` 62d201506cSStephen Warren./test/py/test.py --bd sandbox --build 63d201506cSStephen Warren``` 64d201506cSStephen Warren 65d201506cSStephen WarrenThe `--bd` option tells the test suite which board type is being tested. This 66d201506cSStephen Warrenlets the test suite know which features the board has, and hence exactly what 67d201506cSStephen Warrencan be tested. 68d201506cSStephen Warren 69d201506cSStephen WarrenThe `--build` option tells U-Boot to compile U-Boot. Alternatively, you may 70d201506cSStephen Warrenomit this option and build U-Boot yourself, in whatever way you choose, before 71d201506cSStephen Warrenrunning the test script. 72d201506cSStephen Warren 73d201506cSStephen WarrenThe test script will attach to U-Boot, execute all valid tests for the board, 74d201506cSStephen Warrenthen print a summary of the test process. A complete log of the test session 75d201506cSStephen Warrenwill be written to `${build_dir}/test-log.html`. This is best viewed in a web 76d201506cSStephen Warrenbrowser, but may be read directly as plain text, perhaps with the aid of the 77d201506cSStephen Warren`html2text` utility. 78d201506cSStephen Warren 79d70facf8SStephen Warren### Testing under a debugger 80d70facf8SStephen Warren 81d70facf8SStephen WarrenIf you need to run sandbox under a debugger, you may pass the command-line 82d70facf8SStephen Warrenoption `--gdbserver COMM`. This causes two things to happens: 83d70facf8SStephen Warren 84d70facf8SStephen Warren- Instead of running U-Boot directly, it will be run under gdbserver, with 85d70facf8SStephen Warren debug communication via the channel `COMM`. You can attach a debugger to the 86d70facf8SStephen Warren sandbox process in order to debug it. See `man gdbserver` and the example 87d70facf8SStephen Warren below for details of valid values for `COMM`. 88d70facf8SStephen Warren- All timeouts in tests are disabled, allowing U-Boot an arbitrary amount of 89d70facf8SStephen Warren time to execute commands. This is useful if U-Boot is stopped at a breakpoint 90d70facf8SStephen Warren during debugging. 91d70facf8SStephen Warren 92d70facf8SStephen WarrenA usage example is: 93d70facf8SStephen Warren 94d70facf8SStephen WarrenWindow 1: 95d70facf8SStephen Warren```shell 96d70facf8SStephen Warren./test/py/test.py --bd sandbox --gdbserver localhost:1234 97d70facf8SStephen Warren``` 98d70facf8SStephen Warren 99d70facf8SStephen WarrenWindow 2: 100d70facf8SStephen Warren```shell 101d70facf8SStephen Warrengdb ./build-sandbox/u-boot -ex 'target remote localhost:1234' 102d70facf8SStephen Warren``` 103d70facf8SStephen Warren 104d70facf8SStephen WarrenAlternatively, you could leave off the `-ex` option and type the command 105d70facf8SStephen Warrenmanually into gdb once it starts. 106d70facf8SStephen Warren 107d70facf8SStephen WarrenYou can use any debugger you wish, so long as it speaks the gdb remote 108d70facf8SStephen Warrenprotocol, or any graphical wrapper around gdb. 109d70facf8SStephen Warren 110d70facf8SStephen WarrenSome tests deliberately cause the sandbox process to exit, e.g. to test the 111d70facf8SStephen Warrenreset command, or sandbox's CTRL-C handling. When this happens, you will need 112d70facf8SStephen Warrento attach the debugger to the new sandbox instance. If these tests are not 113d70facf8SStephen Warrenrelevant to your debugging session, you can skip them using pytest's -k 114d70facf8SStephen Warrencommand-line option; see the next section. 115d70facf8SStephen Warren 116d201506cSStephen Warren## Command-line options 117d201506cSStephen Warren 118d201506cSStephen Warren- `--board-type`, `--bd`, `-B` set the type of the board to be tested. For 119d201506cSStephen Warren example, `sandbox` or `seaboard`. 120d201506cSStephen Warren- `--board-identity`, `--id` set the identity of the board to be tested. 121d201506cSStephen Warren This allows differentiation between multiple instances of the same type of 122d201506cSStephen Warren physical board that are attached to the same host machine. This parameter is 123d201506cSStephen Warren not interpreted by the test script in any way, but rather is simply passed 124d201506cSStephen Warren to the hook scripts described below, and may be used in any site-specific 125d201506cSStephen Warren way deemed necessary. 126d201506cSStephen Warren- `--build` indicates that the test script should compile U-Boot itself 127d201506cSStephen Warren before running the tests. If using this option, make sure that any 128d201506cSStephen Warren environment variables required by the build process are already set, such as 129d201506cSStephen Warren `$CROSS_COMPILE`. 130d201506cSStephen Warren- `--build-dir` sets the directory containing the compiled U-Boot binaries. 131d201506cSStephen Warren If omitted, this is `${source_dir}/build-${board_type}`. 132d201506cSStephen Warren- `--result-dir` sets the directory to write results, such as log files, 133d201506cSStephen Warren into. If omitted, the build directory is used. 134d201506cSStephen Warren- `--persistent-data-dir` sets the directory used to store persistent test 135d201506cSStephen Warren data. This is test data that may be re-used across test runs, such as file- 136d201506cSStephen Warren system images. 137d201506cSStephen Warren 138d70facf8SStephen Warren`pytest` also implements a number of its own command-line options. Commonly used 139d70facf8SStephen Warrenoptions are mentioned below. Please see `pytest` documentation for complete 140d70facf8SStephen Warrendetails. Execute `py.test --version` for a brief summary. Note that U-Boot's 141d70facf8SStephen Warrentest.py script passes all command-line arguments directly to `pytest` for 142d70facf8SStephen Warrenprocessing. 143d70facf8SStephen Warren 144d70facf8SStephen Warren- `-k` selects which tests to run. The default is to run all known tests. This 145d70facf8SStephen Warren option takes a single argument which is used to filter test names. Simple 146d70facf8SStephen Warren logical operators are supported. For example: 147d70facf8SStephen Warren - `'ums'` runs only tests with "ums" in their name. 148d70facf8SStephen Warren - ``ut_dm'` runs only tests with "ut_dm" in their name. Note that in this 149d70facf8SStephen Warren case, "ut_dm" is a parameter to a test rather than the test name. The full 150d70facf8SStephen Warren test name is e.g. "test_ut[ut_dm_leak]". 151d70facf8SStephen Warren - `'not reset'` runs everything except tests with "reset" in their name. 152d70facf8SStephen Warren - `'ut or hush'` runs only tests with "ut" or "hush" in their name. 153d70facf8SStephen Warren - `'not (ut or hush)'` runs everything except tests with "ut" or "hush" in 154d70facf8SStephen Warren their name. 155d70facf8SStephen Warren- `-s` prevents pytest from hiding a test's stdout. This allows you to see 156d70facf8SStephen Warren U-Boot's console log in real time on pytest's stdout. 157d201506cSStephen Warren 158d201506cSStephen Warren## Testing real hardware 159d201506cSStephen Warren 160d201506cSStephen WarrenThe tools and techniques used to interact with real hardware will vary 161d201506cSStephen Warrenradically between different host and target systems, and the whims of the user. 162d201506cSStephen WarrenFor this reason, the test suite does not attempt to directly interact with real 163d201506cSStephen Warrenhardware in any way. Rather, it executes a standardized set of "hook" scripts 164d201506cSStephen Warrenvia `$PATH`. These scripts implement certain actions on behalf of the test 165d201506cSStephen Warrensuite. This keeps the test suite simple and isolated from system variances 166d201506cSStephen Warrenunrelated to U-Boot features. 167d201506cSStephen Warren 168d201506cSStephen Warren### Hook scripts 169d201506cSStephen Warren 170d201506cSStephen Warren#### Environment variables 171d201506cSStephen Warren 172d201506cSStephen WarrenThe following environment variables are set when running hook scripts: 173d201506cSStephen Warren 174d201506cSStephen Warren- `UBOOT_BOARD_TYPE` the board type being tested. 175d201506cSStephen Warren- `UBOOT_BOARD_IDENTITY` the board identity being tested, or `na` if none was 176d201506cSStephen Warren specified. 177d201506cSStephen Warren- `UBOOT_SOURCE_DIR` the U-Boot source directory. 178d201506cSStephen Warren- `UBOOT_TEST_PY_DIR` the full path to `test/py/` in the source directory. 179d201506cSStephen Warren- `UBOOT_BUILD_DIR` the U-Boot build directory. 180d201506cSStephen Warren- `UBOOT_RESULT_DIR` the test result directory. 181d201506cSStephen Warren- `UBOOT_PERSISTENT_DATA_DIR` the test peristent data directory. 182d201506cSStephen Warren 183d201506cSStephen Warren#### `u-boot-test-console` 184d201506cSStephen Warren 185d201506cSStephen WarrenThis script provides access to the U-Boot console. The script's stdin/stdout 186d201506cSStephen Warrenshould be connected to the board's console. This process should continue to run 187d201506cSStephen Warrenindefinitely, until killed. The test suite will run this script in parallel 188d201506cSStephen Warrenwith all other hooks. 189d201506cSStephen Warren 190d201506cSStephen WarrenThis script may be implemented e.g. by exec()ing `cu`, `kermit`, `conmux`, etc. 191d201506cSStephen Warren 192d201506cSStephen WarrenIf you are able to run U-Boot under a hardware simulator such as qemu, then 193d201506cSStephen Warrenyou would likely spawn that simulator from this script. However, note that 194d201506cSStephen Warren`u-boot-test-reset` may be called multiple times per test script run, and must 195d201506cSStephen Warrencause U-Boot to start execution from scratch each time. Hopefully your 196d201506cSStephen Warrensimulator includes a virtual reset button! If not, you can launch the 197d201506cSStephen Warrensimulator from `u-boot-test-reset` instead, while arranging for this console 198d201506cSStephen Warrenprocess to always communicate with the current simulator instance. 199d201506cSStephen Warren 200d201506cSStephen Warren#### `u-boot-test-flash` 201d201506cSStephen Warren 202d201506cSStephen WarrenPrior to running the test suite against a board, some arrangement must be made 203d201506cSStephen Warrenso that the board executes the particular U-Boot binary to be tested. Often, 204d201506cSStephen Warrenthis involves writing the U-Boot binary to the board's flash ROM. The test 205d201506cSStephen Warrensuite calls this hook script for that purpose. 206d201506cSStephen Warren 207d201506cSStephen WarrenThis script should perform the entire flashing process synchronously; the 208d201506cSStephen Warrenscript should only exit once flashing is complete, and a board reset will 209d201506cSStephen Warrencause the newly flashed U-Boot binary to be executed. 210d201506cSStephen Warren 211d201506cSStephen WarrenIt is conceivable that this script will do nothing. This might be useful in 212d201506cSStephen Warrenthe following cases: 213d201506cSStephen Warren 214d201506cSStephen Warren- Some other process has already written the desired U-Boot binary into the 215d201506cSStephen Warren board's flash prior to running the test suite. 216d201506cSStephen Warren- The board allows U-Boot to be downloaded directly into RAM, and executed 217d201506cSStephen Warren from there. Use of this feature will reduce wear on the board's flash, so 218d201506cSStephen Warren may be preferable if available, and if cold boot testing of U-Boot is not 219d201506cSStephen Warren required. If this feature is used, the `u-boot-test-reset` script should 220d201506cSStephen Warren peform this download, since the board could conceivably be reset multiple 221d201506cSStephen Warren times in a single test run. 222d201506cSStephen Warren 223d201506cSStephen WarrenIt is up to the user to determine if those situations exist, and to code this 224d201506cSStephen Warrenhook script appropriately. 225d201506cSStephen Warren 226d201506cSStephen WarrenThis script will typically be implemented by calling out to some SoC- or 227d201506cSStephen Warrenboard-specific vendor flashing utility. 228d201506cSStephen Warren 229d201506cSStephen Warren#### `u-boot-test-reset` 230d201506cSStephen Warren 231d201506cSStephen WarrenWhenever the test suite needs to reset the target board, this script is 232d201506cSStephen Warrenexecuted. This is guaranteed to happen at least once, prior to executing the 233d201506cSStephen Warrenfirst test function. If any test fails, the test infra-structure will execute 234d201506cSStephen Warrenthis script again to restore U-Boot to an operational state before running the 235d201506cSStephen Warrennext test function. 236d201506cSStephen Warren 237d201506cSStephen WarrenThis script will likely be implemented by communicating with some form of 238d201506cSStephen Warrenrelay or electronic switch attached to the board's reset signal. 239d201506cSStephen Warren 240d201506cSStephen WarrenThe semantics of this script require that when it is executed, U-Boot will 241d201506cSStephen Warrenstart running from scratch. If the U-Boot binary to be tested has been written 242d201506cSStephen Warrento flash, pulsing the board's reset signal is likely all this script need do. 243d201506cSStephen WarrenHowever, in some scenarios, this script may perform other actions. For 244d201506cSStephen Warrenexample, it may call out to some SoC- or board-specific vendor utility in order 245d201506cSStephen Warrento download the U-Boot binary directly into RAM and execute it. This would 246d201506cSStephen Warrenavoid the need for `u-boot-test-flash` to actually write U-Boot to flash, thus 247d201506cSStephen Warrensaving wear on the flash chip(s). 248d201506cSStephen Warren 249*5b2beab5SStephen Warren#### Examples 250*5b2beab5SStephen Warren 251*5b2beab5SStephen Warrenhttps://github.com/swarren/uboot-test-hooks contains some working example hook 252*5b2beab5SStephen Warrenscripts, and may be useful as a reference when implementing hook scripts for 253*5b2beab5SStephen Warrenyour platform. These scripts are not considered part of U-Boot itself. 254*5b2beab5SStephen Warren 255d201506cSStephen Warren### Board-type-specific configuration 256d201506cSStephen Warren 257d201506cSStephen WarrenEach board has a different configuration and behaviour. Many of these 258d201506cSStephen Warrendifferences can be automatically detected by parsing the `.config` file in the 259d201506cSStephen Warrenbuild directory. However, some differences can't yet be handled automatically. 260d201506cSStephen Warren 261d201506cSStephen WarrenFor each board, an optional Python module `u_boot_board_${board_type}` may exist 262d201506cSStephen Warrento provide board-specific information to the test script. Any global value 263d201506cSStephen Warrendefined in these modules is available for use by any test function. The data 264d201506cSStephen Warrencontained in these scripts must be purely derived from U-Boot source code. 265d201506cSStephen WarrenHence, these configuration files are part of the U-Boot source tree too. 266d201506cSStephen Warren 267d201506cSStephen Warren### Execution environment configuration 268d201506cSStephen Warren 269d201506cSStephen WarrenEach user's hardware setup may enable testing different subsets of the features 270d201506cSStephen Warrenimplemented by a particular board's configuration of U-Boot. For example, a 271d201506cSStephen WarrenU-Boot configuration may support USB device mode and USB Mass Storage, but this 272d201506cSStephen Warrencan only be tested if a USB cable is connected between the board and the host 273d201506cSStephen Warrenmachine running the test script. 274d201506cSStephen Warren 275d201506cSStephen WarrenFor each board, optional Python modules `u_boot_boardenv_${board_type}` and 276d201506cSStephen Warren`u_boot_boardenv_${board_type}_${board_identity}` may exist to provide 277d201506cSStephen Warrenboard-specific and board-identity-specific information to the test script. Any 278d201506cSStephen Warrenglobal value defined in these modules is available for use by any test 279d201506cSStephen Warrenfunction. The data contained in these is specific to a particular user's 280d201506cSStephen Warrenhardware configuration. Hence, these configuration files are not part of the 281d201506cSStephen WarrenU-Boot source tree, and should be installed outside of the source tree. Users 282d201506cSStephen Warrenshould set `$PYTHONPATH` prior to running the test script to allow these 283d201506cSStephen Warrenmodules to be loaded. 284d201506cSStephen Warren 285d201506cSStephen Warren### Board module parameter usage 286d201506cSStephen Warren 287d201506cSStephen WarrenThe test scripts rely on the following variables being defined by the board 288d201506cSStephen Warrenmodule: 289d201506cSStephen Warren 290d201506cSStephen Warren- None at present. 291d201506cSStephen Warren 292d201506cSStephen Warren### U-Boot `.config` feature usage 293d201506cSStephen Warren 294d201506cSStephen WarrenThe test scripts rely on various U-Boot `.config` features, either directly in 295d201506cSStephen Warrenorder to test those features, or indirectly in order to query information from 296d201506cSStephen Warrenthe running U-Boot instance in order to test other features. 297d201506cSStephen Warren 298d201506cSStephen WarrenOne example is that testing of the `md` command requires knowledge of a RAM 299d201506cSStephen Warrenaddress to use for the test. This data is parsed from the output of the 300d201506cSStephen Warren`bdinfo` command, and hence relies on CONFIG_CMD_BDI being enabled. 301d201506cSStephen Warren 302d201506cSStephen WarrenFor a complete list of dependencies, please search the test scripts for 303d201506cSStephen Warreninstances of: 304d201506cSStephen Warren 305d201506cSStephen Warren- `buildconfig.get(...` 306d201506cSStephen Warren- `@pytest.mark.buildconfigspec(...` 307d201506cSStephen Warren 308d201506cSStephen Warren### Complete invocation example 309d201506cSStephen Warren 310d201506cSStephen WarrenAssuming that you have installed the hook scripts into $HOME/ubtest/bin, and 311d201506cSStephen Warrenany required environment configuration Python modules into $HOME/ubtest/py, 312d201506cSStephen Warrenthen you would likely invoke the test script as follows: 313d201506cSStephen Warren 314d201506cSStephen WarrenIf U-Boot has already been built: 315d201506cSStephen Warren 316d201506cSStephen Warren```bash 317d201506cSStephen WarrenPATH=$HOME/ubtest/bin:$PATH \ 318d201506cSStephen Warren PYTHONPATH=${HOME}/ubtest/py:${PYTHONPATH} \ 319d201506cSStephen Warren ./test/py/test.py --bd seaboard 320d201506cSStephen Warren``` 321d201506cSStephen Warren 322d201506cSStephen WarrenIf you want the test script to compile U-Boot for you too, then you likely 323d201506cSStephen Warrenneed to set `$CROSS_COMPILE` to allow this, and invoke the test script as 324d201506cSStephen Warrenfollow: 325d201506cSStephen Warren 326d201506cSStephen Warren```bash 327d201506cSStephen WarrenCROSS_COMPILE=arm-none-eabi- \ 328d201506cSStephen Warren PATH=$HOME/ubtest/bin:$PATH \ 329d201506cSStephen Warren PYTHONPATH=${HOME}/ubtest/py:${PYTHONPATH} \ 330d201506cSStephen Warren ./test/py/test.py --bd seaboard --build 331d201506cSStephen Warren``` 332d201506cSStephen Warren 333d201506cSStephen Warren## Writing tests 334d201506cSStephen Warren 335d201506cSStephen WarrenPlease refer to the pytest documentation for details of writing pytest tests. 336d201506cSStephen WarrenDetails specific to the U-Boot test suite are described below. 337d201506cSStephen Warren 338d201506cSStephen WarrenA test fixture named `u_boot_console` should be used by each test function. This 339d201506cSStephen Warrenprovides the means to interact with the U-Boot console, and retrieve board and 340d201506cSStephen Warrenenvironment configuration information. 341d201506cSStephen Warren 342d201506cSStephen WarrenThe function `u_boot_console.run_command()` executes a shell command on the 343d201506cSStephen WarrenU-Boot console, and returns all output from that command. This allows 344d201506cSStephen Warrenvalidation or interpretation of the command output. This function validates 345d201506cSStephen Warrenthat certain strings are not seen on the U-Boot console. These include shell 346d201506cSStephen Warrenerror messages and the U-Boot sign-on message (in order to detect unexpected 347d201506cSStephen Warrenboard resets). See the source of `u_boot_console_base.py` for a complete list of 348d201506cSStephen Warren"bad" strings. Some test scenarios are expected to trigger these strings. Use 349d201506cSStephen Warren`u_boot_console.disable_check()` to temporarily disable checking for specific 350d201506cSStephen Warrenstrings. See `test_unknown_cmd.py` for an example. 351d201506cSStephen Warren 352d201506cSStephen WarrenBoard- and board-environment configuration values may be accessed as sub-fields 353d201506cSStephen Warrenof the `u_boot_console.config` object, for example 354d201506cSStephen Warren`u_boot_console.config.ram_base`. 355d201506cSStephen Warren 356d201506cSStephen WarrenBuild configuration values (from `.config`) may be accessed via the dictionary 357d201506cSStephen Warren`u_boot_console.config.buildconfig`, with keys equal to the Kconfig variable 358d201506cSStephen Warrennames. 359