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