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, for example:: 63 64 $ export PYTHONPATH=../python:../tests/functional 65 $ export QEMU_TEST_QEMU_BINARY=$PWD/qemu-system-x86_64 66 $ python3 ../tests/functional/test_file.py 67 68Overview 69-------- 70 71The ``tests/functional/qemu_test`` directory provides the ``qemu_test`` 72Python module, containing the ``qemu_test.QemuSystemTest`` class. 73Here is a simple usage example: 74 75.. code:: 76 77 #!/usr/bin/env python3 78 79 from qemu_test import QemuSystemTest 80 81 class Version(QemuSystemTest): 82 83 def test_qmp_human_info_version(self): 84 self.vm.launch() 85 res = self.vm.cmd('human-monitor-command', 86 command_line='info version') 87 self.assertRegex(res, r'^(\d+\.\d+\.\d)') 88 89 if __name__ == '__main__': 90 QemuSystemTest.main() 91 92By providing the "hash bang" line at the beginning of the script, marking 93the file as executable and by calling into QemuSystemTest.main(), the test 94can also be run stand-alone, without a test runner. OTOH when run via a test 95runner, the QemuSystemTest.main() function takes care of running the test 96functions in the right fassion (e.g. with TAP output that is required by the 97meson test runner). 98 99The ``qemu_test.QemuSystemTest`` base test class 100^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 101 102The ``qemu_test.QemuSystemTest`` class has a number of characteristics 103that are worth being mentioned. 104 105First of all, it attempts to give each test a ready to use QEMUMachine 106instance, available at ``self.vm``. Because many tests will tweak the 107QEMU command line, launching the QEMUMachine (by using ``self.vm.launch()``) 108is left to the test writer. 109 110The base test class has also support for tests with more than one 111QEMUMachine. The way to get machines is through the ``self.get_vm()`` 112method which will return a QEMUMachine instance. The ``self.get_vm()`` 113method accepts arguments that will be passed to the QEMUMachine creation 114and also an optional ``name`` attribute so you can identify a specific 115machine and get it more than once through the tests methods. A simple 116and hypothetical example follows: 117 118.. code:: 119 120 from qemu_test import QemuSystemTest 121 122 class MultipleMachines(QemuSystemTest): 123 def test_multiple_machines(self): 124 first_machine = self.get_vm() 125 second_machine = self.get_vm() 126 self.get_vm(name='third_machine').launch() 127 128 first_machine.launch() 129 second_machine.launch() 130 131 first_res = first_machine.cmd( 132 'human-monitor-command', 133 command_line='info version') 134 135 second_res = second_machine.cmd( 136 'human-monitor-command', 137 command_line='info version') 138 139 third_res = self.get_vm(name='third_machine').cmd( 140 'human-monitor-command', 141 command_line='info version') 142 143 self.assertEqual(first_res, second_res, third_res) 144 145At test "tear down", ``qemu_test.QemuSystemTest`` handles all the QEMUMachines 146shutdown. 147 148QEMUMachine 149----------- 150 151The QEMUMachine API is already widely used in the Python iotests, 152device-crash-test and other Python scripts. It's a wrapper around the 153execution of a QEMU binary, giving its users: 154 155 * the ability to set command line arguments to be given to the QEMU 156 binary 157 158 * a ready to use QMP connection and interface, which can be used to 159 send commands and inspect its results, as well as asynchronous 160 events 161 162 * convenience methods to set commonly used command line arguments in 163 a more succinct and intuitive way 164 165QEMU binary selection 166^^^^^^^^^^^^^^^^^^^^^ 167 168The QEMU binary used for the ``self.vm`` QEMUMachine instance will 169primarily depend on the value of the ``qemu_bin`` class attribute. 170If it is not explicitly set by the test code, its default value will 171be the result the QEMU_TEST_QEMU_BINARY environment variable. 172 173Attribute reference 174------------------- 175 176QemuBaseTest 177^^^^^^^^^^^^ 178 179The following attributes are available on any ``qemu_test.QemuBaseTest`` 180instance. 181 182arch 183"""" 184 185The target architecture of the QEMU binary. 186 187Tests are also free to use this attribute value, for their own needs. 188A test may, for instance, use this value when selecting the architecture 189of a kernel or disk image to boot a VM with. 190 191qemu_bin 192"""""""" 193 194The preserved value of the ``QEMU_TEST_QEMU_BINARY`` environment 195variable. 196 197QemuUserTest 198^^^^^^^^^^^^ 199 200The QemuUserTest class can be used for running an executable via the 201usermode emulation binaries. 202 203QemuSystemTest 204^^^^^^^^^^^^^^ 205 206The QemuSystemTest class can be used for running tests via one of the 207qemu-system-* binaries. 208 209vm 210"" 211 212A QEMUMachine instance, initially configured according to the given 213``qemu_bin`` parameter. 214 215cpu 216""" 217 218The cpu model that will be set to all QEMUMachine instances created 219by the test. 220 221machine 222""""""" 223 224The machine type that will be set to all QEMUMachine instances created 225by the test. By using the set_machine() function of the QemuSystemTest 226class to set this attribute, you can automatically check whether the 227machine is available to skip the test in case it is not built into the 228QEMU binary. 229 230Asset handling 231-------------- 232 233Many functional tests download assets (e.g. Linux kernels, initrds, 234firmware images, etc.) from the internet to be able to run tests with 235them. This imposes additional challenges to the test framework. 236 237First there is the the problem that some people might not have an 238unconstrained internet connection, so such tests should not be run by 239default when running ``make check``. To accomplish this situation, 240the tests that download files should only be added to the "thorough" 241speed mode in the meson.build file, while the "quick" speed mode is 242fine for functional tests that can be run without downloading files. 243``make check`` then only runs the quick functional tests along with 244the other quick tests from the other test suites. If you choose to 245run only run ``make check-functional``, the "thorough" tests will be 246executed, too. And to run all functional tests along with the others, 247you can use something like:: 248 249 make -j$(nproc) check SPEED=thorough 250 251The second problem with downloading files from the internet are time 252constraints. The time for downloading files should not be taken into 253account when the test is running and the timeout of the test is ticking 254(since downloading can be very slow, depending on the network bandwidth). 255This problem is solved by downloading the assets ahead of time, before 256the tests are run. This pre-caching is done with the qemu_test.Asset 257class. To use it in your test, declare an asset in your test class with 258its URL and SHA256 checksum like this:: 259 260 ASSET_somename = ( 261 ('https://www.qemu.org/assets/images/qemu_head_200.png'), 262 '34b74cad46ea28a2966c1d04e102510daf1fd73e6582b6b74523940d5da029dd') 263 264In your test function, you can then get the file name of the cached 265asset like this:: 266 267 def test_function(self): 268 file_path = self.ASSET_somename.fetch() 269 270The pre-caching will be done automatically when running 271``make check-functional`` (but not when running e.g. 272``make check-functional-<target>``). In case you just want to download 273the assets without running the tests, you can do so by running:: 274 275 make precache-functional 276 277The cache is populated in the ``~/.cache/qemu/download`` directory by 278default, but the location can be changed by setting the 279``QEMU_TEST_CACHE_DIR`` environment variable. 280 281Skipping tests 282-------------- 283 284Since the test framework is based on the common Python unittest framework, 285you can use the usual Python decorators which allow for easily skipping 286tests running under certain conditions, for example, on the lack of a binary 287on the test system or when the running environment is a CI system. For further 288information about those decorators, please refer to: 289 290 https://docs.python.org/3/library/unittest.html#skipping-tests-and-expected-failures 291 292While the conditions for skipping tests are often specifics of each one, there 293are recurring scenarios identified by the QEMU developers and the use of 294environment variables became a kind of standard way to enable/disable tests. 295 296Here is a list of the most used variables: 297 298QEMU_TEST_ALLOW_LARGE_STORAGE 299^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 300Tests which are going to fetch or produce assets considered *large* are not 301going to run unless that ``QEMU_TEST_ALLOW_LARGE_STORAGE=1`` is exported on 302the environment. 303 304The definition of *large* is a bit arbitrary here, but it usually means an 305asset which occupies at least 1GB of size on disk when uncompressed. 306 307QEMU_TEST_ALLOW_UNTRUSTED_CODE 308^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 309There are tests which will boot a kernel image or firmware that can be 310considered not safe to run on the developer's workstation, thus they are 311skipped by default. The definition of *not safe* is also arbitrary but 312usually it means a blob which either its source or build process aren't 313public available. 314 315You should export ``QEMU_TEST_ALLOW_UNTRUSTED_CODE=1`` on the environment in 316order to allow tests which make use of those kind of assets. 317 318QEMU_TEST_FLAKY_TESTS 319^^^^^^^^^^^^^^^^^^^^^ 320Some tests are not working reliably and thus are disabled by default. 321This includes tests that don't run reliably on GitLab's CI which 322usually expose real issues that are rarely seen on developer machines 323due to the constraints of the CI environment. If you encounter a 324similar situation then raise a bug and then mark the test as shown on 325the code snippet below: 326 327.. code:: 328 329 # See https://gitlab.com/qemu-project/qemu/-/issues/nnnn 330 @skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab') 331 def test(self): 332 do_something() 333 334Tests should not live in this state forever and should either be fixed 335or eventually removed. 336 337 338.. _unittest: https://docs.python.org/3/library/unittest.html 339