1.. _checkfunctional-ref: 2 3Functional testing with Python 4============================== 5 6The ``tests/functional`` directory hosts functional tests written in 7Python. They are usually higher level tests, and may interact with 8external resources and with various guest operating systems. 9The functional tests have initially evolved from the Avocado tests, so there 10is a lot of similarity to those tests here (see :ref:`checkavocado-ref` for 11details about the Avocado tests). 12 13The tests should be written in the style of the Python `unittest`_ framework, 14using stdio for the TAP protocol. The folder ``tests/functional/qemu_test`` 15provides classes (e.g. the ``QemuBaseTest``, ``QemuUserTest`` and the 16``QemuSystemTest`` classes) and utility functions that help to get your test 17into the right shape, e.g. by replacing the 'stdout' python object to redirect 18the normal output of your test to stderr instead. 19 20Note that if you don't use one of the QemuBaseTest based classes for your 21test, or if you spawn subprocesses from your test, you have to make sure 22that there is no TAP-incompatible output written to stdio, e.g. either by 23prefixing every line with a "# " to mark the output as a TAP comment, or 24e.g. by capturing the stdout output of subprocesses (redirecting it to 25stderr is OK). 26 27Tests based on ``qemu_test.QemuSystemTest`` can easily: 28 29 * Customize the command line arguments given to the convenience 30 ``self.vm`` attribute (a QEMUMachine instance) 31 32 * Interact with the QEMU monitor, send QMP commands and check 33 their results 34 35 * Interact with the guest OS, using the convenience console device 36 (which may be useful to assert the effectiveness and correctness of 37 command line arguments or QMP commands) 38 39 * Download (and cache) remote data files, such as firmware and kernel 40 images 41 42Running tests 43------------- 44 45You can run the functional tests simply by executing: 46 47.. code:: 48 49 make check-functional 50 51It is also possible to run tests for a certain target only, for example 52the following line will only run the tests for the x86_64 target: 53 54.. code:: 55 56 make check-functional-x86_64 57 58To run a single test file without the meson test runner, you can also 59execute the file directly by specifying two environment variables first, 60the PYTHONPATH that has to include the python folder and the tests/functional 61folder of the source tree, and QEMU_TEST_QEMU_BINARY that has to point 62to the QEMU binary that should be used for the test. The current working 63directory should be your build folder. For example:: 64 65 $ export PYTHONPATH=../python:../tests/functional 66 $ export QEMU_TEST_QEMU_BINARY=$PWD/qemu-system-x86_64 67 $ pyvenv/bin/python3 ../tests/functional/test_file.py 68 69The test framework will automatically purge any scratch files created during 70the tests. If needing to debug a failed test, it is possible to keep these 71files around on disk by setting ```QEMU_TEST_KEEP_SCRATCH=1``` as an env 72variable. Any preserved files will be deleted the next time the test is run 73without this variable set. 74 75Logging 76------- 77 78The framework collects log files for each test in the build directory 79in the following subfolder:: 80 81 <builddir>/tests/functional/<arch>/<fileid>.<classid>.<testname>/ 82 83There are usually three log files: 84 85* ``base.log`` contains the generic logging information that is written 86 by the calls to the logging functions in the test code (e.g. by calling 87 the ``self.log.info()`` or ``self.log.debug()`` functions). 88* ``console.log`` contains the output of the serial console of the guest. 89* ``default.log`` contains the output of QEMU. This file could be named 90 differently if the test chooses to use a different identifier for 91 the guest VM (e.g. when the test spins up multiple VMs). 92 93Introduction to writing tests 94----------------------------- 95 96The ``tests/functional/qemu_test`` directory provides the ``qemu_test`` 97Python module, containing the ``qemu_test.QemuSystemTest`` class. 98Here is a simple usage example: 99 100.. code:: 101 102 #!/usr/bin/env python3 103 104 from qemu_test import QemuSystemTest 105 106 class Version(QemuSystemTest): 107 108 def test_qmp_human_info_version(self): 109 self.vm.launch() 110 res = self.vm.cmd('human-monitor-command', 111 command_line='info version') 112 self.assertRegex(res, r'^(\d+\.\d+\.\d)') 113 114 if __name__ == '__main__': 115 QemuSystemTest.main() 116 117By providing the "hash bang" line at the beginning of the script, marking 118the file as executable and by calling into QemuSystemTest.main(), the test 119can also be run stand-alone, without a test runner. OTOH when run via a test 120runner, the QemuSystemTest.main() function takes care of running the test 121functions in the right fassion (e.g. with TAP output that is required by the 122meson test runner). 123 124The ``qemu_test.QemuSystemTest`` base test class 125^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 126 127The ``qemu_test.QemuSystemTest`` class has a number of characteristics 128that are worth being mentioned. 129 130First of all, it attempts to give each test a ready to use QEMUMachine 131instance, available at ``self.vm``. Because many tests will tweak the 132QEMU command line, launching the QEMUMachine (by using ``self.vm.launch()``) 133is left to the test writer. 134 135The base test class has also support for tests with more than one 136QEMUMachine. The way to get machines is through the ``self.get_vm()`` 137method which will return a QEMUMachine instance. The ``self.get_vm()`` 138method accepts arguments that will be passed to the QEMUMachine creation 139and also an optional ``name`` attribute so you can identify a specific 140machine and get it more than once through the tests methods. A simple 141and hypothetical example follows: 142 143.. code:: 144 145 from qemu_test import QemuSystemTest 146 147 class MultipleMachines(QemuSystemTest): 148 def test_multiple_machines(self): 149 first_machine = self.get_vm() 150 second_machine = self.get_vm() 151 self.get_vm(name='third_machine').launch() 152 153 first_machine.launch() 154 second_machine.launch() 155 156 first_res = first_machine.cmd( 157 'human-monitor-command', 158 command_line='info version') 159 160 second_res = second_machine.cmd( 161 'human-monitor-command', 162 command_line='info version') 163 164 third_res = self.get_vm(name='third_machine').cmd( 165 'human-monitor-command', 166 command_line='info version') 167 168 self.assertEqual(first_res, second_res, third_res) 169 170At test "tear down", ``qemu_test.QemuSystemTest`` handles all the QEMUMachines 171shutdown. 172 173QEMUMachine 174----------- 175 176The QEMUMachine API is already widely used in the Python iotests, 177device-crash-test and other Python scripts. It's a wrapper around the 178execution of a QEMU binary, giving its users: 179 180 * the ability to set command line arguments to be given to the QEMU 181 binary 182 183 * a ready to use QMP connection and interface, which can be used to 184 send commands and inspect its results, as well as asynchronous 185 events 186 187 * convenience methods to set commonly used command line arguments in 188 a more succinct and intuitive way 189 190QEMU binary selection 191^^^^^^^^^^^^^^^^^^^^^ 192 193The QEMU binary used for the ``self.vm`` QEMUMachine instance will 194primarily depend on the value of the ``qemu_bin`` instance attribute. 195If it is not explicitly set by the test code, its default value will 196be the result the QEMU_TEST_QEMU_BINARY environment variable. 197 198Debugging hung QEMU 199^^^^^^^^^^^^^^^^^^^ 200 201When test cases go wrong it may be helpful to debug a stalled QEMU 202process. While the QEMUMachine class owns the primary QMP monitor 203socket, it is possible to request a second QMP monitor be created 204by setting the ``QEMU_TEST_QMP_BACKDOOR`` env variable to refer 205to a UNIX socket name. The ``qmp-shell`` command can then be 206attached to the stalled QEMU to examine its live state. 207 208Attribute reference 209------------------- 210 211QemuBaseTest 212^^^^^^^^^^^^ 213 214The following attributes are available on any ``qemu_test.QemuBaseTest`` 215instance. 216 217arch 218"""" 219 220The target architecture of the QEMU binary. 221 222Tests are also free to use this attribute value, for their own needs. 223A test may, for instance, use this value when selecting the architecture 224of a kernel or disk image to boot a VM with. 225 226qemu_bin 227"""""""" 228 229The preserved value of the ``QEMU_TEST_QEMU_BINARY`` environment 230variable. 231 232QemuUserTest 233^^^^^^^^^^^^ 234 235The QemuUserTest class can be used for running an executable via the 236usermode emulation binaries. 237 238QemuSystemTest 239^^^^^^^^^^^^^^ 240 241The QemuSystemTest class can be used for running tests via one of the 242qemu-system-* binaries. 243 244vm 245"" 246 247A QEMUMachine instance, initially configured according to the given 248``qemu_bin`` parameter. 249 250cpu 251""" 252 253The cpu model that will be set to all QEMUMachine instances created 254by the test. 255 256machine 257""""""" 258 259The machine type that will be set to all QEMUMachine instances created 260by the test. By using the set_machine() function of the QemuSystemTest 261class to set this attribute, you can automatically check whether the 262machine is available to skip the test in case it is not built into the 263QEMU binary. 264 265Asset handling 266-------------- 267 268Many functional tests download assets (e.g. Linux kernels, initrds, 269firmware images, etc.) from the internet to be able to run tests with 270them. This imposes additional challenges to the test framework. 271 272First there is the problem that some people might not have an 273unconstrained internet connection, so such tests should not be run by 274default when running ``make check``. To accomplish this situation, 275the tests that download files should only be added to the "thorough" 276speed mode in the meson.build file, while the "quick" speed mode is 277fine for functional tests that can be run without downloading files. 278``make check`` then only runs the quick functional tests along with 279the other quick tests from the other test suites. If you choose to 280run only run ``make check-functional``, the "thorough" tests will be 281executed, too. And to run all functional tests along with the others, 282you can use something like:: 283 284 make -j$(nproc) check SPEED=thorough 285 286The second problem with downloading files from the internet are time 287constraints. The time for downloading files should not be taken into 288account when the test is running and the timeout of the test is ticking 289(since downloading can be very slow, depending on the network bandwidth). 290This problem is solved by downloading the assets ahead of time, before 291the tests are run. This pre-caching is done with the qemu_test.Asset 292class. To use it in your test, declare an asset in your test class with 293its URL and SHA256 checksum like this:: 294 295 from qemu_test import Asset 296 297 ASSET_somename = Asset( 298 ('https://www.qemu.org/assets/images/qemu_head_200.png'), 299 '34b74cad46ea28a2966c1d04e102510daf1fd73e6582b6b74523940d5da029dd') 300 301In your test function, you can then get the file name of the cached 302asset like this:: 303 304 def test_function(self): 305 file_path = self.ASSET_somename.fetch() 306 307The pre-caching will be done automatically when running 308``make check-functional`` (but not when running e.g. 309``make check-functional-<target>``). In case you just want to download 310the assets without running the tests, you can do so by running:: 311 312 make precache-functional 313 314The cache is populated in the ``~/.cache/qemu/download`` directory by 315default, but the location can be changed by setting the 316``QEMU_TEST_CACHE_DIR`` environment variable. 317 318Skipping tests 319-------------- 320 321Since the test framework is based on the common Python unittest framework, 322you can use the usual Python decorators which allow for easily skipping 323tests running under certain conditions, for example, on the lack of a binary 324on the test system or when the running environment is a CI system. For further 325information about those decorators, please refer to: 326 327 https://docs.python.org/3/library/unittest.html#skipping-tests-and-expected-failures 328 329While the conditions for skipping tests are often specifics of each one, there 330are recurring scenarios identified by the QEMU developers and the use of 331environment variables became a kind of standard way to enable/disable tests. 332 333Here is a list of the most used variables: 334 335QEMU_TEST_ALLOW_LARGE_STORAGE 336^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 337Tests which are going to fetch or produce assets considered *large* are not 338going to run unless that ``QEMU_TEST_ALLOW_LARGE_STORAGE=1`` is exported on 339the environment. 340 341The definition of *large* is a bit arbitrary here, but it usually means an 342asset which occupies at least 1GB of size on disk when uncompressed. 343 344QEMU_TEST_ALLOW_UNTRUSTED_CODE 345^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 346There are tests which will boot a kernel image or firmware that can be 347considered not safe to run on the developer's workstation, thus they are 348skipped by default. The definition of *not safe* is also arbitrary but 349usually it means a blob which either its source or build process aren't 350public available. 351 352You should export ``QEMU_TEST_ALLOW_UNTRUSTED_CODE=1`` on the environment in 353order to allow tests which make use of those kind of assets. 354 355QEMU_TEST_FLAKY_TESTS 356^^^^^^^^^^^^^^^^^^^^^ 357Some tests are not working reliably and thus are disabled by default. 358This includes tests that don't run reliably on GitLab's CI which 359usually expose real issues that are rarely seen on developer machines 360due to the constraints of the CI environment. If you encounter a 361similar situation then raise a bug and then mark the test as shown on 362the code snippet below: 363 364.. code:: 365 366 # See https://gitlab.com/qemu-project/qemu/-/issues/nnnn 367 @skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab') 368 def test(self): 369 do_something() 370 371Tests should not live in this state forever and should either be fixed 372or eventually removed. 373 374QEMU_TEST_ALLOW_SLOW 375^^^^^^^^^^^^^^^^^^^^ 376Tests that have a very long runtime and might run into timeout issues 377e.g. if the QEMU binary has been compiled with debugging options enabled. 378To avoid these timeout issues by default and to save some precious CPU 379cycles during normal testing, such tests are disabled by default unless 380the QEMU_TEST_ALLOW_SLOW environment variable has been set. 381 382 383.. _unittest: https://docs.python.org/3/library/unittest.html 384