xref: /qemu/docs/devel/testing/functional.rst (revision 897c68fb795cf03b89b6688a6f945d68a765c3e4)
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