qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Thomas Huth <thuth@redhat.com>
To: "Alex Bennée" <alex.bennee@linaro.org>,
	qemu-devel@nongnu.org,
	"Philippe Mathieu-Daudé" <philmd@linaro.org>,
	"Daniel P . Berrange" <berrange@redhat.com>
Cc: Ani Sinha <anisinha@redhat.com>,
	Richard Henderson <richard.henderson@linaro.org>,
	John Snow <jsnow@redhat.com>,
	qemu-ppc@nongnu.org, Fabiano Rosas <farosas@suse.de>
Subject: [PATCH v4 35/35] docs/devel/testing: Add documentation for functional tests
Date: Wed, 21 Aug 2024 10:27:36 +0200	[thread overview]
Message-ID: <20240821082748.65853-36-thuth@redhat.com> (raw)
In-Reply-To: <20240821082748.65853-1-thuth@redhat.com>

Document the new functional testing framework. The text is originally
based on the Avocado documentation, but heavily modified to match the
new framework.

Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 docs/devel/testing/functional.rst | 269 ++++++++++++++++++++++++++++++
 docs/devel/testing/index.rst      |   1 +
 docs/devel/testing/main.rst       |  12 ++
 3 files changed, 282 insertions(+)
 create mode 100644 docs/devel/testing/functional.rst

diff --git a/docs/devel/testing/functional.rst b/docs/devel/testing/functional.rst
new file mode 100644
index 0000000000..c1f4bbf224
--- /dev/null
+++ b/docs/devel/testing/functional.rst
@@ -0,0 +1,269 @@
+.. _checkfunctional-ref:
+
+Functional testing with Python
+==============================
+
+The ``tests/functional`` directory hosts functional tests written in
+Python. They are usually higher level tests, and may interact with
+external resources and with various guest operating systems.
+The functional tests have initially evolved from the Avocado tests, so there
+is a lot of similarity to those tests here (see :ref:`checkavocado-ref` for
+details about the Avocado tests).
+
+The tests should be written in the style of the Python `unittest`_
+framework, using stdio for the TAP protocol. The folder
+``tests/functional/qemu_test`` provides classes (e.g. the ``QemuBaseTest``
+and the ``QemuSystemTest`` classes) and utility functions that help
+to get your test into the right shape.
+
+Tests based on ``qemu_test.QemuSystemTest`` can easily:
+
+ * Customize the command line arguments given to the convenience
+   ``self.vm`` attribute (a QEMUMachine instance)
+
+ * Interact with the QEMU monitor, send QMP commands and check
+   their results
+
+ * Interact with the guest OS, using the convenience console device
+   (which may be useful to assert the effectiveness and correctness of
+   command line arguments or QMP commands)
+
+ * Download (and cache) remote data files, such as firmware and kernel
+   images
+
+Running tests
+-------------
+
+You can run the functional tests simply by executing:
+
+.. code::
+
+  make check-functional
+
+It is also possible to run tests for a certain target only, for example
+the following line will only run the tests for the x86_64 target:
+
+.. code::
+
+  make check-functional-x86_64
+
+To run a single test file without the meson test runner, you can also
+execute the file directly by specifying two environment variables first,
+the PYTHONPATH that has to include the python folder and the tests/functional
+folder of the source tree, and QEMU_TEST_QEMU_BINARY that has to point
+to the QEMU binary that should be used for the test, for example::
+
+  $ export PYTHONPATH=../python:../tests/functional
+  $ export QEMU_TEST_QEMU_BINARY=$PWD/qemu-system-x86_64
+  $ python3 ../tests/functional/test_file.py
+
+Overview
+--------
+
+The ``tests/functional/qemu_test`` directory provides the ``qemu_test``
+Python module, containing the ``qemu_test.QemuSystemTest`` class.
+Here is a simple usage example:
+
+.. code::
+
+  #!/usr/bin/env python3
+
+  from qemu_test import QemuSystemTest
+
+  class Version(QemuSystemTest):
+
+      def test_qmp_human_info_version(self):
+          self.vm.launch()
+          res = self.vm.cmd('human-monitor-command',
+                            command_line='info version')
+          self.assertRegex(res, r'^(\d+\.\d+\.\d)')
+
+  if __name__ == '__main__':
+      QemuSystemTest.main()
+
+By providing the "hash bang" line at the beginning of the script,
+and by calling into QemuSystemTest.main() when it is run directly,
+the test framework makes sure to run all test_*() functions in the
+right fassion (e.g. with TAP output that is required by the meson test
+runner).
+
+The ``qemu_test.QemuSystemTest`` base test class
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The ``qemu_test.QemuSystemTest`` class has a number of characteristics
+that are worth being mentioned.
+
+First of all, it attempts to give each test a ready to use QEMUMachine
+instance, available at ``self.vm``.  Because many tests will tweak the
+QEMU command line, launching the QEMUMachine (by using ``self.vm.launch()``)
+is left to the test writer.
+
+The base test class has also support for tests with more than one
+QEMUMachine. The way to get machines is through the ``self.get_vm()``
+method which will return a QEMUMachine instance. The ``self.get_vm()``
+method accepts arguments that will be passed to the QEMUMachine creation
+and also an optional ``name`` attribute so you can identify a specific
+machine and get it more than once through the tests methods. A simple
+and hypothetical example follows:
+
+.. code::
+
+  from qemu_test import QemuSystemTest
+
+  class MultipleMachines(QemuSystemTest):
+      def test_multiple_machines(self):
+          first_machine = self.get_vm()
+          second_machine = self.get_vm()
+          self.get_vm(name='third_machine').launch()
+
+          first_machine.launch()
+          second_machine.launch()
+
+          first_res = first_machine.cmd(
+              'human-monitor-command',
+              command_line='info version')
+
+          second_res = second_machine.cmd(
+              'human-monitor-command',
+              command_line='info version')
+
+          third_res = self.get_vm(name='third_machine').cmd(
+              'human-monitor-command',
+              command_line='info version')
+
+          self.assertEqual(first_res, second_res, third_res)
+
+At test "tear down", ``qemu_test.QemuSystemTest`` handles all the QEMUMachines
+shutdown.
+
+QEMUMachine
+-----------
+
+The QEMUMachine API is already widely used in the Python iotests,
+device-crash-test and other Python scripts.  It's a wrapper around the
+execution of a QEMU binary, giving its users:
+
+ * the ability to set command line arguments to be given to the QEMU
+   binary
+
+ * a ready to use QMP connection and interface, which can be used to
+   send commands and inspect its results, as well as asynchronous
+   events
+
+ * convenience methods to set commonly used command line arguments in
+   a more succinct and intuitive way
+
+QEMU binary selection
+^^^^^^^^^^^^^^^^^^^^^
+
+The QEMU binary used for the ``self.vm`` QEMUMachine instance will
+primarily depend on the value of the ``qemu_bin`` class attribute.
+If it is not explicitly set by the test code, its default value will
+be the result the QEMU_TEST_QEMU_BINARY environment variable.
+
+Attribute reference
+-------------------
+
+QemuBaseTest
+^^^^^^^^^^^^
+
+The following attributes are available on any ``qemu_test.QemuBaseTest``
+instance.
+
+arch
+""""
+
+The target architecture of the QEMU binary.
+
+Tests are also free to use this attribute value, for their own needs.
+A test may, for instance, use this value when selecting the architecture
+of a kernel or disk image to boot a VM with.
+
+qemu_bin
+""""""""
+
+The preserved value of the ``QEMU_TEST_QEMU_BINARY`` environment
+variable.
+
+QemuSystemTest
+^^^^^^^^^^^^^^
+
+vm
+""
+
+A QEMUMachine instance, initially configured according to the given
+``qemu_bin`` parameter.
+
+cpu
+"""
+
+The cpu model that will be set to all QEMUMachine instances created
+by the test.
+
+machine
+"""""""
+
+The machine type that will be set to all QEMUMachine instances created
+by the test. By using the set_machine() function of the QemuSystemTest
+class to set this attribute, you can automatically check whether the
+machine is available to skip the test in case it is not built into the
+QEMU binary.
+
+Skipping tests
+--------------
+
+Since the test framework is based on the common Python unittest framework,
+you can use the usual Python decorators which allow for easily skipping
+tests running under certain conditions, for example, on the lack of a binary
+on the test system or when the running environment is a CI system. For further
+information about those decorators, please refer to::
+
+  https://docs.python.org/3/library/unittest.html#skipping-tests-and-expected-failures
+
+While the conditions for skipping tests are often specifics of each one, there
+are recurring scenarios identified by the QEMU developers and the use of
+environment variables became a kind of standard way to enable/disable tests.
+
+Here is a list of the most used variables:
+
+QEMU_TEST_ALLOW_LARGE_STORAGE
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Tests which are going to fetch or produce assets considered *large* are not
+going to run unless that ``QEMU_TEST_ALLOW_LARGE_STORAGE=1`` is exported on
+the environment.
+
+The definition of *large* is a bit arbitrary here, but it usually means an
+asset which occupies at least 1GB of size on disk when uncompressed.
+
+QEMU_TEST_ALLOW_UNTRUSTED_CODE
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+There are tests which will boot a kernel image or firmware that can be
+considered not safe to run on the developer's workstation, thus they are
+skipped by default. The definition of *not safe* is also arbitrary but
+usually it means a blob which either its source or build process aren't
+public available.
+
+You should export ``QEMU_TEST_ALLOW_UNTRUSTED_CODE=1`` on the environment in
+order to allow tests which make use of those kind of assets.
+
+QEMU_TEST_FLAKY_TESTS
+^^^^^^^^^^^^^^^^^^^^^
+Some tests are not working reliably and thus are disabled by default.
+This includes tests that don't run reliably on GitLab's CI which
+usually expose real issues that are rarely seen on developer machines
+due to the constraints of the CI environment. If you encounter a
+similar situation then raise a bug and then mark the test as shown on
+the code snippet below:
+
+.. code::
+
+  # See https://gitlab.com/qemu-project/qemu/-/issues/nnnn
+  @skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab')
+  def test(self):
+      do_something()
+
+Tests should not live in this state forever and should either be fixed
+or eventually removed.
+
+
+.. _unittest: https://docs.python.org/3/library/unittest.html
diff --git a/docs/devel/testing/index.rst b/docs/devel/testing/index.rst
index cdf7ba1f8b..45eb4a7181 100644
--- a/docs/devel/testing/index.rst
+++ b/docs/devel/testing/index.rst
@@ -9,6 +9,7 @@ testing infrastructure.
 
    main
    qtest
+   functional
    avocado
    acpi-bits
    ci
diff --git a/docs/devel/testing/main.rst b/docs/devel/testing/main.rst
index 39b965ecf6..e9921a4b10 100644
--- a/docs/devel/testing/main.rst
+++ b/docs/devel/testing/main.rst
@@ -862,6 +862,18 @@ supported. To start the fuzzer, run
 Alternatively, some command different from ``qemu-img info`` can be tested, by
 changing the ``-c`` option.
 
+Functional tests using Python
+-----------------------------
+
+The ``tests/functional`` directory hosts functional tests written in
+Python. You can run the functional tests simply by executing:
+
+.. code::
+
+  make check-functional
+
+See :ref:`checkfunctional-ref` for more details.
+
 Integration tests using the Avocado Framework
 ---------------------------------------------
 
-- 
2.46.0



  parent reply	other threads:[~2024-08-21  8:34 UTC|newest]

Thread overview: 69+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-08-21  8:27 [PATCH v4 00/35] Convert avocado tests to normal Python unittests Thomas Huth
2024-08-21  8:27 ` [PATCH v4 01/35] tests/avocado: machine aarch64: standardize location and RO access Thomas Huth
2024-08-21  9:30   ` Philippe Mathieu-Daudé
2024-08-21  8:27 ` [PATCH v4 02/35] tests/avocado/boot_xen.py: fetch kernel during test setUp() Thomas Huth
2024-08-21  8:27 ` [PATCH v4 03/35] tests/avocado/machine_aarch64_sbsaref.py: allow for rw usage of image Thomas Huth
2024-08-21  8:27 ` [PATCH v4 04/35] Bump avocado to 103.0 Thomas Huth
2024-08-21 10:34   ` Philippe Mathieu-Daudé
2024-08-29  9:45     ` Daniel P. Berrangé
2024-08-21  8:27 ` [PATCH v4 05/35] tests/avocado/avocado_qemu: Fix the "from" statements in linuxtest.py Thomas Huth
2024-08-21  9:31   ` Philippe Mathieu-Daudé
2024-08-21 10:07     ` Thomas Huth
2024-08-21 10:18       ` Philippe Mathieu-Daudé
2024-08-21  8:27 ` [PATCH v4 06/35] tests/avocado/boot_linux_console: Remove the s390x subtest Thomas Huth
2024-08-29  9:46   ` Daniel P. Berrangé
2024-08-21  8:27 ` [PATCH v4 07/35] python: Install pycotap in our venv if necessary Thomas Huth
2024-08-29  9:49   ` Daniel P. Berrangé
2024-08-21  8:27 ` [PATCH v4 08/35] tests/functional: Add base classes for the upcoming pytest-based tests Thomas Huth
2024-08-21  8:27 ` [PATCH v4 09/35] tests/functional: Set up logging Thomas Huth
2024-08-21  8:27 ` [PATCH v4 10/35] tests/Makefile.include: Increase the level of indentation in the help text Thomas Huth
2024-08-21  8:27 ` [PATCH v4 11/35] tests/functional: Prepare the meson build system for the functional tests Thomas Huth
2024-08-21 14:30   ` Philippe Mathieu-Daudé
2024-08-23 12:54   ` Philippe Mathieu-Daudé
2024-08-26  8:18     ` Thomas Huth
2024-08-29  9:54       ` Daniel P. Berrangé
2024-08-21  8:27 ` [PATCH v4 12/35] tests/functional: Convert simple avocado tests into standalone python tests Thomas Huth
2024-08-21  8:27 ` [PATCH v4 13/35] tests/functional: Convert avocado tests that just need a small adjustment Thomas Huth
2024-08-21  8:27 ` [PATCH v4 14/35] tests/functional: add a module for handling asset download & caching Thomas Huth
2024-08-21 14:49   ` Philippe Mathieu-Daudé
2024-08-29  9:57     ` Daniel P. Berrangé
2024-08-23  6:24   ` Philippe Mathieu-Daudé
2024-08-29 10:00     ` Daniel P. Berrangé
2024-08-21  8:27 ` [PATCH v4 15/35] tests/functional: enable pre-emptive caching of assets Thomas Huth
2024-08-23  7:28   ` Philippe Mathieu-Daudé
2024-08-27 13:16     ` Thomas Huth
2024-08-27 14:24       ` Thomas Huth
2024-08-29 10:15         ` Daniel P. Berrangé
2024-08-30  7:38           ` Thomas Huth
2024-08-30  7:42             ` Daniel P. Berrangé
2024-08-30 11:27               ` Thomas Huth
2024-08-30 11:37                 ` Daniel P. Berrangé
2024-08-21  8:27 ` [PATCH v4 16/35] tests/functional: Convert some tests that download files via fetch_asset() Thomas Huth
2024-08-21  8:27 ` [PATCH v4 17/35] tests/functional: Add a function for extracting files from an archive Thomas Huth
2024-08-21  8:27 ` [PATCH v4 18/35] tests/functional: Convert some avocado tests that needed avocado.utils.archive Thomas Huth
2024-08-21  8:27 ` [PATCH v4 19/35] tests/functional: Convert the s390x avocado tests into standalone tests Thomas Huth
2024-08-21  8:27 ` [PATCH v4 20/35] tests/functional: Convert the x86_cpu_model_versions test Thomas Huth
2024-08-21  8:27 ` [PATCH v4 21/35] tests/functional: Convert the microblaze avocado tests into standalone tests Thomas Huth
2024-08-21  8:27 ` [PATCH v4 22/35] tests/functional: Convert the riscv_opensbi avocado test into a standalone test Thomas Huth
2024-08-21  8:27 ` [PATCH v4 23/35] tests/functional: Convert the virtio_gpu " Thomas Huth
2024-08-21  8:27 ` [PATCH v4 24/35] tests/functional: Convert most ppc avocado tests into standalone tests Thomas Huth
2024-08-21  8:27 ` [PATCH v4 25/35] tests/functional: Convert the ppc_amiga avocado test into a standalone test Thomas Huth
2024-08-21  8:27 ` [PATCH v4 26/35] tests/functional: Convert the ppc_hv " Thomas Huth
2024-08-21  9:43   ` Philippe Mathieu-Daudé
2024-08-21 10:11     ` Thomas Huth
2024-08-21 11:47   ` Philippe Mathieu-Daudé
2024-08-21  8:27 ` [PATCH v4 27/35] tests/functional: Convert the m68k nextcube test with tesseract Thomas Huth
2024-08-21  8:27 ` [PATCH v4 28/35] tests/functional: Convert the acpi-bits test into a standalone test Thomas Huth
2024-08-21  8:27 ` [PATCH v4 29/35] tests/functional: Convert the rx_gdbsim avocado " Thomas Huth
2024-08-21  8:27 ` [PATCH v4 30/35] tests/functional: Convert the linux_initrd " Thomas Huth
2024-08-21  8:27 ` [PATCH v4 31/35] gitlab-ci: Add "check-functional" to the build tests Thomas Huth
2024-08-21  8:27 ` [PATCH v4 32/35] docs/devel: Split testing docs from the build docs and move to separate folder Thomas Huth
2024-08-21  8:27 ` [PATCH v4 33/35] docs/devel/testing: Split the Avocado documentation into a separate file Thomas Huth
2024-08-29 10:18   ` Daniel P. Berrangé
2024-08-21  8:27 ` [PATCH v4 34/35] docs/devel/testing: Rename avocado_qemu.Test class Thomas Huth
2024-08-29 10:27   ` Daniel P. Berrangé
2024-08-21  8:27 ` Thomas Huth [this message]
2024-08-29 10:34   ` [PATCH v4 35/35] docs/devel/testing: Add documentation for functional tests Daniel P. Berrangé
2024-08-29 11:35     ` Thomas Huth
2024-08-29 11:43       ` Daniel P. Berrangé
2024-08-29 10:35   ` Daniel P. Berrangé

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20240821082748.65853-36-thuth@redhat.com \
    --to=thuth@redhat.com \
    --cc=alex.bennee@linaro.org \
    --cc=anisinha@redhat.com \
    --cc=berrange@redhat.com \
    --cc=farosas@suse.de \
    --cc=jsnow@redhat.com \
    --cc=philmd@linaro.org \
    --cc=qemu-devel@nongnu.org \
    --cc=qemu-ppc@nongnu.org \
    --cc=richard.henderson@linaro.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).