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