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