|  | .. _checkavocado-ref: | 
|  |  | 
|  |  | 
|  | Integration testing with Avocado | 
|  | ================================ | 
|  |  | 
|  | The ``tests/avocado`` directory hosts integration tests. They're usually | 
|  | higher level tests, and may interact with external resources and with | 
|  | various guest operating systems. | 
|  |  | 
|  | These tests are written using the Avocado Testing Framework (which must be | 
|  | installed separately) in conjunction with a the ``avocado_qemu.QemuSystemTest`` | 
|  | class, implemented at ``tests/avocado/avocado_qemu``. | 
|  |  | 
|  | Tests based on ``avocado_qemu.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) | 
|  |  | 
|  | * Interact with external data files that accompany the test itself | 
|  | (see ``self.get_data()``) | 
|  |  | 
|  | * Download (and cache) remote data files, such as firmware and kernel | 
|  | images | 
|  |  | 
|  | * Have access to a library of guest OS images (by means of the | 
|  | ``avocado.utils.vmimage`` library) | 
|  |  | 
|  | * Make use of various other test related utilities available at the | 
|  | test class itself and at the utility library: | 
|  |  | 
|  | - http://avocado-framework.readthedocs.io/en/latest/api/test/avocado.html#avocado.Test | 
|  | - http://avocado-framework.readthedocs.io/en/latest/api/utils/avocado.utils.html | 
|  |  | 
|  | Running tests | 
|  | ------------- | 
|  |  | 
|  | You can run the avocado tests simply by executing: | 
|  |  | 
|  | .. code:: | 
|  |  | 
|  | make check-avocado | 
|  |  | 
|  | This involves the automatic installation, from PyPI, of all the | 
|  | necessary avocado-framework dependencies into the QEMU venv within the | 
|  | build tree (at ``./pyvenv``). Test results are also saved within the | 
|  | build tree (at ``tests/results``). | 
|  |  | 
|  | Note: the build environment must be using a Python 3 stack, and have | 
|  | the ``venv`` and ``pip`` packages installed.  If necessary, make sure | 
|  | ``configure`` is called with ``--python=`` and that those modules are | 
|  | available.  On Debian and Ubuntu based systems, depending on the | 
|  | specific version, they may be on packages named ``python3-venv`` and | 
|  | ``python3-pip``. | 
|  |  | 
|  | It is also possible to run tests based on tags using the | 
|  | ``make check-avocado`` command and the ``AVOCADO_TAGS`` environment | 
|  | variable: | 
|  |  | 
|  | .. code:: | 
|  |  | 
|  | make check-avocado AVOCADO_TAGS=quick | 
|  |  | 
|  | Note that tags separated with commas have an AND behavior, while tags | 
|  | separated by spaces have an OR behavior. For more information on Avocado | 
|  | tags, see: | 
|  |  | 
|  | https://avocado-framework.readthedocs.io/en/latest/guides/user/chapters/tags.html | 
|  |  | 
|  | To run a single test file, a couple of them, or a test within a file | 
|  | using the ``make check-avocado`` command, set the ``AVOCADO_TESTS`` | 
|  | environment variable with the test files or test names. To run all | 
|  | tests from a single file, use: | 
|  |  | 
|  | .. code:: | 
|  |  | 
|  | make check-avocado AVOCADO_TESTS=$FILEPATH | 
|  |  | 
|  | The same is valid to run tests from multiple test files: | 
|  |  | 
|  | .. code:: | 
|  |  | 
|  | make check-avocado AVOCADO_TESTS='$FILEPATH1 $FILEPATH2' | 
|  |  | 
|  | To run a single test within a file, use: | 
|  |  | 
|  | .. code:: | 
|  |  | 
|  | make check-avocado AVOCADO_TESTS=$FILEPATH:$TESTCLASS.$TESTNAME | 
|  |  | 
|  | The same is valid to run single tests from multiple test files: | 
|  |  | 
|  | .. code:: | 
|  |  | 
|  | make check-avocado AVOCADO_TESTS='$FILEPATH1:$TESTCLASS1.$TESTNAME1 $FILEPATH2:$TESTCLASS2.$TESTNAME2' | 
|  |  | 
|  | The scripts installed inside the virtual environment may be used | 
|  | without an "activation".  For instance, the Avocado test runner | 
|  | may be invoked by running: | 
|  |  | 
|  | .. code:: | 
|  |  | 
|  | pyvenv/bin/avocado run $OPTION1 $OPTION2 tests/avocado/ | 
|  |  | 
|  | Note that if ``make check-avocado`` was not executed before, it is | 
|  | possible to create the Python virtual environment with the dependencies | 
|  | needed running: | 
|  |  | 
|  | .. code:: | 
|  |  | 
|  | make check-venv | 
|  |  | 
|  | It is also possible to run tests from a single file or a single test within | 
|  | a test file. To run tests from a single file within the build tree, use: | 
|  |  | 
|  | .. code:: | 
|  |  | 
|  | pyvenv/bin/avocado run tests/avocado/$TESTFILE | 
|  |  | 
|  | To run a single test within a test file, use: | 
|  |  | 
|  | .. code:: | 
|  |  | 
|  | pyvenv/bin/avocado run tests/avocado/$TESTFILE:$TESTCLASS.$TESTNAME | 
|  |  | 
|  | Valid test names are visible in the output from any previous execution | 
|  | of Avocado or ``make check-avocado``, and can also be queried using: | 
|  |  | 
|  | .. code:: | 
|  |  | 
|  | pyvenv/bin/avocado list tests/avocado | 
|  |  | 
|  | Manual Installation | 
|  | ------------------- | 
|  |  | 
|  | To manually install Avocado and its dependencies, run: | 
|  |  | 
|  | .. code:: | 
|  |  | 
|  | pip install --user avocado-framework | 
|  |  | 
|  | Alternatively, follow the instructions on this link: | 
|  |  | 
|  | https://avocado-framework.readthedocs.io/en/latest/guides/user/chapters/installing.html | 
|  |  | 
|  | Overview | 
|  | -------- | 
|  |  | 
|  | The ``tests/avocado/avocado_qemu`` directory provides the | 
|  | ``avocado_qemu`` Python module, containing the ``avocado_qemu.QemuSystemTest`` | 
|  | class.  Here's a simple usage example: | 
|  |  | 
|  | .. code:: | 
|  |  | 
|  | from avocado_qemu import QemuSystemTest | 
|  |  | 
|  |  | 
|  | class Version(QemuSystemTest): | 
|  | """ | 
|  | :avocado: tags=quick | 
|  | """ | 
|  | 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)') | 
|  |  | 
|  | To execute your test, run: | 
|  |  | 
|  | .. code:: | 
|  |  | 
|  | avocado run version.py | 
|  |  | 
|  | Tests may be classified according to a convention by using docstring | 
|  | directives such as ``:avocado: tags=TAG1,TAG2``.  To run all tests | 
|  | in the current directory, tagged as "quick", run: | 
|  |  | 
|  | .. code:: | 
|  |  | 
|  | avocado run -t quick . | 
|  |  | 
|  | The ``avocado_qemu.QemuSystemTest`` base test class | 
|  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | 
|  |  | 
|  | The ``avocado_qemu.QemuSystemTest`` class has a number of characteristics | 
|  | that are worth being mentioned right away. | 
|  |  | 
|  | 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 avocado_qemu 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", ``avocado_qemu.QemuSystemTest`` handles all the | 
|  | QEMUMachines shutdown. | 
|  |  | 
|  | The ``avocado_qemu.LinuxTest`` base test class | 
|  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | 
|  |  | 
|  | The ``avocado_qemu.LinuxTest`` is further specialization of the | 
|  | ``avocado_qemu.QemuSystemTest`` class, so it contains all the characteristics | 
|  | of the later plus some extra features. | 
|  |  | 
|  | First of all, this base class is intended for tests that need to | 
|  | interact with a fully booted and operational Linux guest.  At this | 
|  | time, it uses a Fedora 31 guest image.  The most basic example looks | 
|  | like this: | 
|  |  | 
|  | .. code:: | 
|  |  | 
|  | from avocado_qemu import LinuxTest | 
|  |  | 
|  |  | 
|  | class SomeTest(LinuxTest): | 
|  |  | 
|  | def test(self): | 
|  | self.launch_and_wait() | 
|  | self.ssh_command('some_command_to_be_run_in_the_guest') | 
|  |  | 
|  | Please refer to tests that use ``avocado_qemu.LinuxTest`` under | 
|  | ``tests/avocado`` for more examples. | 
|  |  | 
|  | 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`` parameter.  If it's | 
|  | not explicitly set, its default value will be the result of a dynamic | 
|  | probe in the same source tree.  A suitable binary will be one that | 
|  | targets the architecture matching host machine. | 
|  |  | 
|  | Based on this description, test writers will usually rely on one of | 
|  | the following approaches: | 
|  |  | 
|  | 1) Set ``qemu_bin``, and use the given binary | 
|  |  | 
|  | 2) Do not set ``qemu_bin``, and use a QEMU binary named like | 
|  | "qemu-system-${arch}", either in the current | 
|  | working directory, or in the current source tree. | 
|  |  | 
|  | The resulting ``qemu_bin`` value will be preserved in the | 
|  | ``avocado_qemu.QemuSystemTest`` as an attribute with the same name. | 
|  |  | 
|  | Attribute reference | 
|  | ------------------- | 
|  |  | 
|  | Test | 
|  | ^^^^ | 
|  |  | 
|  | Besides the attributes and methods that are part of the base | 
|  | ``avocado.Test`` class, the following attributes are available on any | 
|  | ``avocado_qemu.QemuSystemTest`` instance. | 
|  |  | 
|  | vm | 
|  | "" | 
|  |  | 
|  | A QEMUMachine instance, initially configured according to the given | 
|  | ``qemu_bin`` parameter. | 
|  |  | 
|  | arch | 
|  | """" | 
|  |  | 
|  | The architecture can be used on different levels of the stack, e.g. by | 
|  | the framework or by the test itself.  At the framework level, it will | 
|  | currently influence the selection of a QEMU binary (when one is not | 
|  | explicitly given). | 
|  |  | 
|  | Tests are also free to use this attribute value, for their own needs. | 
|  | A test may, for instance, use the same value when selecting the | 
|  | architecture of a kernel or disk image to boot a VM with. | 
|  |  | 
|  | The ``arch`` attribute will be set to the test parameter of the same | 
|  | name.  If one is not given explicitly, it will either be set to | 
|  | ``None``, or, if the test is tagged with one (and only one) | 
|  | ``:avocado: tags=arch:VALUE`` tag, it will be set to ``VALUE``. | 
|  |  | 
|  | cpu | 
|  | """ | 
|  |  | 
|  | The cpu model that will be set to all QEMUMachine instances created | 
|  | by the test. | 
|  |  | 
|  | The ``cpu`` attribute will be set to the test parameter of the same | 
|  | name. If one is not given explicitly, it will either be set to | 
|  | ``None ``, or, if the test is tagged with one (and only one) | 
|  | ``:avocado: tags=cpu:VALUE`` tag, it will be set to ``VALUE``. | 
|  |  | 
|  | machine | 
|  | """"""" | 
|  |  | 
|  | The machine type that will be set to all QEMUMachine instances created | 
|  | by the test. | 
|  |  | 
|  | The ``machine`` attribute will be set to the test parameter of the same | 
|  | name.  If one is not given explicitly, it will either be set to | 
|  | ``None``, or, if the test is tagged with one (and only one) | 
|  | ``:avocado: tags=machine:VALUE`` tag, it will be set to ``VALUE``. | 
|  |  | 
|  | qemu_bin | 
|  | """""""" | 
|  |  | 
|  | The preserved value of the ``qemu_bin`` parameter or the result of the | 
|  | dynamic probe for a QEMU binary in the current working directory or | 
|  | source tree. | 
|  |  | 
|  | LinuxTest | 
|  | ^^^^^^^^^ | 
|  |  | 
|  | Besides the attributes present on the ``avocado_qemu.QemuSystemTest`` base | 
|  | class, the ``avocado_qemu.LinuxTest`` adds the following attributes: | 
|  |  | 
|  | distro | 
|  | """""" | 
|  |  | 
|  | The name of the Linux distribution used as the guest image for the | 
|  | test.  The name should match the **Provider** column on the list | 
|  | of images supported by the avocado.utils.vmimage library: | 
|  |  | 
|  | https://avocado-framework.readthedocs.io/en/latest/guides/writer/libs/vmimage.html#supported-images | 
|  |  | 
|  | distro_version | 
|  | """""""""""""" | 
|  |  | 
|  | The version of the Linux distribution as the guest image for the | 
|  | test.  The name should match the **Version** column on the list | 
|  | of images supported by the avocado.utils.vmimage library: | 
|  |  | 
|  | https://avocado-framework.readthedocs.io/en/latest/guides/writer/libs/vmimage.html#supported-images | 
|  |  | 
|  | distro_checksum | 
|  | """"""""""""""" | 
|  |  | 
|  | The sha256 hash of the guest image file used for the test. | 
|  |  | 
|  | If this value is not set in the code or by a test parameter (with the | 
|  | same name), no validation on the integrity of the image will be | 
|  | performed. | 
|  |  | 
|  | Parameter reference | 
|  | ------------------- | 
|  |  | 
|  | To understand how Avocado parameters are accessed by tests, and how | 
|  | they can be passed to tests, please refer to:: | 
|  |  | 
|  | https://avocado-framework.readthedocs.io/en/latest/guides/writer/chapters/writing.html#accessing-test-parameters | 
|  |  | 
|  | Parameter values can be easily seen in the log files, and will look | 
|  | like the following: | 
|  |  | 
|  | .. code:: | 
|  |  | 
|  | PARAMS (key=qemu_bin, path=*, default=./qemu-system-x86_64) => './qemu-system-x86_64 | 
|  |  | 
|  | Test | 
|  | ^^^^ | 
|  |  | 
|  | arch | 
|  | """" | 
|  |  | 
|  | The architecture that will influence the selection of a QEMU binary | 
|  | (when one is not explicitly given). | 
|  |  | 
|  | Tests are also free to use this parameter value, for their own needs. | 
|  | A test may, for instance, use the same value when selecting the | 
|  | architecture of a kernel or disk image to boot a VM with. | 
|  |  | 
|  | This parameter has a direct relation with the ``arch`` attribute.  If | 
|  | not given, it will default to None. | 
|  |  | 
|  | 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. | 
|  |  | 
|  | qemu_bin | 
|  | """""""" | 
|  |  | 
|  | The exact QEMU binary to be used on QEMUMachine. | 
|  |  | 
|  | LinuxTest | 
|  | ^^^^^^^^^ | 
|  |  | 
|  | Besides the parameters present on the ``avocado_qemu.QemuSystemTest`` base | 
|  | class, the ``avocado_qemu.LinuxTest`` adds the following parameters: | 
|  |  | 
|  | distro | 
|  | """""" | 
|  |  | 
|  | The name of the Linux distribution used as the guest image for the | 
|  | test.  The name should match the **Provider** column on the list | 
|  | of images supported by the avocado.utils.vmimage library: | 
|  |  | 
|  | https://avocado-framework.readthedocs.io/en/latest/guides/writer/libs/vmimage.html#supported-images | 
|  |  | 
|  | distro_version | 
|  | """""""""""""" | 
|  |  | 
|  | The version of the Linux distribution as the guest image for the | 
|  | test.  The name should match the **Version** column on the list | 
|  | of images supported by the avocado.utils.vmimage library: | 
|  |  | 
|  | https://avocado-framework.readthedocs.io/en/latest/guides/writer/libs/vmimage.html#supported-images | 
|  |  | 
|  | distro_checksum | 
|  | """"""""""""""" | 
|  |  | 
|  | The sha256 hash of the guest image file used for the test. | 
|  |  | 
|  | If this value is not set in the code or by this parameter no | 
|  | validation on the integrity of the image will be performed. | 
|  |  | 
|  | Skipping tests | 
|  | -------------- | 
|  |  | 
|  | The Avocado framework provides Python decorators which allow for easily skip | 
|  | 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://avocado-framework.readthedocs.io/en/latest/guides/writer/chapters/writing.html#skipping-tests | 
|  |  | 
|  | 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: | 
|  |  | 
|  | AVOCADO_ALLOW_LARGE_STORAGE | 
|  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | 
|  | Tests which are going to fetch or produce assets considered *large* are not | 
|  | going to run unless that ``AVOCADO_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. | 
|  |  | 
|  | SPEED | 
|  | ^^^^^ | 
|  | Tests which have a long runtime will not be run unless ``SPEED=slow`` is | 
|  | exported on the environment. | 
|  |  | 
|  | The definition of *long* is a bit arbitrary here, and it depends on the | 
|  | usefulness of the test too. A unique test is worth spending more time on, | 
|  | small variations on existing tests perhaps less so. As a rough guide, | 
|  | a test or set of similar tests which take more than 100 seconds to | 
|  | complete. | 
|  |  | 
|  | AVOCADO_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 ``AVOCADO_ALLOW_UNTRUSTED_CODE=1`` on the environment in | 
|  | order to allow tests which make use of those kind of assets. | 
|  |  | 
|  | AVOCADO_TIMEOUT_EXPECTED | 
|  | ^^^^^^^^^^^^^^^^^^^^^^^^ | 
|  | The Avocado framework has a timeout mechanism which interrupts tests to avoid the | 
|  | test suite of getting stuck. The timeout value can be set via test parameter or | 
|  | property defined in the test class, for further details:: | 
|  |  | 
|  | https://avocado-framework.readthedocs.io/en/latest/guides/writer/chapters/writing.html#setting-a-test-timeout | 
|  |  | 
|  | Even though the timeout can be set by the test developer, there are some tests | 
|  | that may not have a well-defined limit of time to finish under certain | 
|  | conditions. For example, tests that take longer to execute when QEMU is | 
|  | compiled with debug flags. Therefore, the ``AVOCADO_TIMEOUT_EXPECTED`` variable | 
|  | has been used to determine whether those tests should run or not. | 
|  |  | 
|  | 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() | 
|  |  | 
|  | You can also add ``:avocado: tags=flaky`` to the test meta-data so | 
|  | only the flaky tests can be run as a group: | 
|  |  | 
|  | .. code:: | 
|  |  | 
|  | env QEMU_TEST_FLAKY_TESTS=1 ./pyvenv/bin/avocado \ | 
|  | run tests/avocado -filter-by-tags=flaky | 
|  |  | 
|  | Tests should not live in this state forever and should either be fixed | 
|  | or eventually removed. | 
|  |  | 
|  |  | 
|  | Uninstalling Avocado | 
|  | -------------------- | 
|  |  | 
|  | If you've followed the manual installation instructions above, you can | 
|  | easily uninstall Avocado.  Start by listing the packages you have | 
|  | installed:: | 
|  |  | 
|  | pip list --user | 
|  |  | 
|  | And remove any package you want with:: | 
|  |  | 
|  | pip uninstall <package_name> | 
|  |  | 
|  | If you've used ``make check-avocado``, the Python virtual environment where | 
|  | Avocado is installed will be cleaned up as part of ``make check-clean``. |