Aller directement au contenu

openQA pour les équipement de développement et de maintenance

KDE Linux utilise openQA pour tester automatiquement chaque image système avant sa publication. openQA démarre chaque image dans une machine virtuelle et vérifie qu'elle peut être installée, mise à niveau et utilisée avec succès.

openQA possède une terminologie spécifique : une tâche est une exécution d'une suite de tests sur une image, tandis qu'un processus est la machine ou le conteneur exécutant la tâche. La documentation sur openQA explique ces concepts ainsi que d'autres, notamment les modules de test, les groupes de tâches, les actifs et l'interface utilisateur Internet.

Comment fonctionnent les tests

La tâche de tests s'exécute parallèlement au pipeline d'intégration continue (CI), afin de pouvoir utiliser les images et les disques virtuels produits par la compilation sans télécharger ces fichiers volumineux ailleurs. Les tests sont fournis à la machine virtuelle grâce à une extension système et communiquant avec elle grâce à SSH.

Les tests sur le bureau utilisent l'API d'accessibilité grâce à « selenium-webdriver-at-spi », lui permettant d'interagir avec les applications et de vérifier leur état sans se fier uniquement à la correspondance de captures d'écran. La suite vérifie également les services système défaillants, les processus de bureau défaillants, les problèmes de réseau et les régressions dans les commandes de KDE Linux.

Cycle d'intégration continue (CI) et flux de travail de l'équipe de maintenance

Sur la branche protégée par défaut du dépôt amont de KDE Linux, le pipeline fonctionne comme suit :

  1. La tâche imaging compile, signe et valide l'image et son canal « sysupdate » sur « storage.kde.org ».
  2. La tâche trigger-openqa démarre le pipeline dans os-autoinst-distri-kdelinux, en lui transmettant l'URL de l'image validée et l'URL du canal « sysupdate ».
  3. The downstream pipeline runs the install and upgrade flows declared in tests/tests.toml, each with plain and encrypted installations.
  4. La tâche publish amont ne s'exécute qu'après la réussite du pipeline pour openQA. Il fait la promotion de l'image déjà mise en ligne auprès du public.

Cela fait d'un échec sous openQA un point bloquant pour la publication d'images. Veuillez démarrer par l'ouverture du pipeline en aval à partir de la tâche « trigger-openqa », puis l'ouverture de la tâche de openQA défaillante à partir de son journal d'intégration continue (CI). La page de la tâche affiche les modules de test dans l'ordre et vous permet d'identifier si l'échec concerne l'installation, les tests d'intégrité du système installé ou l'emplacement de la mise à niveau.

Télécharger une image préparée

The link provided after the log message “In case of failure, inspect and download the image and sysupdate tree at…” opens a storage browser for the build under test. Download the .iso there to boot it manually or give it to a local openQA stack. The sysupdate tree contains the staged update artifacts used by the upgrade test.

Investiguer sur une tâche en erreur

Ouvrez la tâche dans l'interface utilisateur Internet de openQA et sélectionnez d'abord le module défaillant. Le lien vers l'interface utilisateur Internet apparaîtra après que le message de journal « La tâche de tests est en cours d'exécution. ». Ses détails précisent le résultat du module, des captures d'écran ou une vidéo, selon le cas, et la sortie de diagnostics. Dans l'onglet Journaux et ressources, téléchargez ou consultez le fichier « autoinst-log.txt » pour le journal du processus pour openQA et du moteur de test. Il s'agit du journal principal pour la tâche elle-même.

Pour les tests exécutant des commandes sur le système en tests, KDE Linux les exécute dans des services « systemd » transitoires et enregistre le journal des services comme sortie de diagnostic dans le résultat du test. Veuillez regarder le fichier « autoinst-log.txt » pour la sortie de la commande et le journal. Vous pouvez également télécharger le fichier « *kde-linux-collected-logs.tar.zst » pour les journaux capturés par l'outil collect-logs.

Exécutez des tests localement

Vous pouvez utiliser openQA pour tester une image construite localement avant de soumettre une modification. Ceci est requis lorsque vous travaillez à partir d'un fork en dehors de « kde-linux/kde-linux » - son pipeline d'intégration continue (CI) construit une image de tests, mais ne déclenche pas le pipeline de openQA. C'est également utile lors du développement de tests pour vos propres modifications.

The KDE Linux openQA test repository includes a local stack containing both an openQA web UI and a worker. It requires Python 3.14, Podman, and podman-compose, which are included in KDE Linux.

Veuillez cloner le dépôt de tests, puis placer l'image .iso de KDE Linux que vous souhaitez tester dans son dossier racine. Si aucune image n'est présente, le programme d'exécution des tests télécharge à la place la dernière image disponible de façon publique.

Start the local stack from the repository root:

./qa-mock up

Once it is ready, open http://localhost:1080 to inspect the openQA web UI. Jobs are not submitted automatically, so open a shell in the container and submit the install flow. Run flow, job, and build-sysext commands inside this container.

./qa-mock enter
./qa flow install

To run the upgrade flow instead:

./qa flow upgrade

For an encrypted installation, pass FDE_INSTALL=1 as an openQA setting. The flavor suffix distinguishes encrypted jobs in the web UI:

./qa flow install --var FDE_INSTALL=1 --flavor-suffix=-encrypted
./qa flow upgrade --var FDE_INSTALL=1 --flavor-suffix=-encrypted

--var NAME=VALUE can be repeated, but each variable must be declared in the selected flow's variables list in tests/tests.toml.

The sanity-test suite uses the virtual disk created by install-system. To concentrate on particular tests, edit the suite's tests list in tests/tests.toml, or declare another suite and flow there. You can also run an individual suite with ./qa job --name <suite> while keeping its disk dependencies in mind. The flow, job, and build-sysext commands accept --manifest-path <path> to use a manifest other than tests/tests.toml. Test paths within the manifest are relative to that manifest's directory. Run ./qa job --help for its required options.

For example, build the system extension and run an install-system job with an .iso in the repository directory. Replace the build ID and variant with those of your image:

./qa build-sysext
./qa job \
    --live ./kde-linux_<build-id>.iso \
    --hdd kde-linux_<build-id>.qcow2 \
    --sysext ./openqa-sysext.img \
    --build <build-id> \
    --variant <variant> \
    --name install-system \
    --flavor live

When you are finished, exit the container shell, then stop the stack and remove its local volumes from the host.

./qa-mock down -v

./qa-mock passes through arguments to podman-compose. For example, use ./qa-mock up -d to start the stack in the background.

Test upgrades between local builds

Place the base ISO in the test repository root. When starting the stack from the host, set KDE_LINUX_OUTPUT to the mkosi.output directory containing the build you want to upgrade to:

KDE_LINUX_OUTPUT=~/Repositories/kde-linux/mkosi.output ./qa-mock up

Enter the container and run the upgrade flow, replacing &lt;build-id&gt; with the build ID of your base ISO:

./qa-mock enter
./qa flow upgrade \
    --upgrade-from /casedir/kde-linux_<build-id>.iso \
    --upgrade-to /kde-linux-output

Both options must be supplied together. The repository is mounted at /casedir, and the selected mkosi.output directory is mounted read-only at /kde-linux-output. The newest build in that directory is served to the virtual machine as a temporary sysupdate source and must be newer than the base ISO. Add --var FDE_INSTALL=1 --flavor-suffix=-encrypted to test an encrypted installation.

Declare suites and flows

tests/tests.toml defines the distribution (name and distri), suites, and flows. A suite is an ordered list of tests run in one openQA job. Its action determines how the job uses the virtual disk:

  • install boots the live image and creates the installed disk.
  • upgrade boots the installed disk and sets DO_UPGRADE for tests that perform the upgrade.
  • test boots the installed disk for validation.

A flow runs suites in the declared order, passing the installed disk between jobs. KDE Linux defines these flows:

[flows.install]
suites = ["install-system", "sanity-test"]
variables = ["FDE_INSTALL"]

[flows.upgrade]
suites = ["install-system", "upgrade-system", "sanity-test"]
variables = ["FDE_INSTALL"]

The install flow installs and checks the build under test. The upgrade flow first installs an older image, upgrades it to the build under test, and then runs sanity tests. For a staged CI build, the base is the latest published image. Without --upgrade-from and --upgrade-to, a local upgrade run will default to the latest public build as its target, using an older local ISO if one is available or downloading the previous image.

Before each job, the worker generates a temporary test directory (CASEDIR) with a main.pm schedule for the selected suite. Tests run in manifest order, including repeated entries. Edit the manifest to change the schedule.

Écrire un test

The test definitions and code live in os-autoinst-distri-kdelinux. Add test scripts under tests/, alongside related tests, and register them in the appropriate suite's tests array in tests/tests.toml. For example:

[suites.example]
action = "test"
tests = [
    { path = "common/bootup.py", type = "openqa" },
    { path = "common/basic_test.py", type = "python" },
    { path = "kdelinux/app/firefox.py", type = "selenium", user = "installed", timeout = 180 },
]

openqa tests execute on the worker and use openQA APIs directly. python and selenium tests execute on the system under test, the system extension packages their scripts automatically, and the worker generates the openQA test wrappers invoking them.

Sectionnez le type de test en fonction de ce que vous vérifiez :

  • Utilisez un « test unitaire » Python normal pour les outils en ligne de commandes, les services, l'état du système de fichiers ou tout autre comportement non graphique.
  • Utilisez Selenium grâce à « selenium-webdriver-at-spi » lorsque le comportement nécessite une interaction avec une application graphique.

Tests Python classiques

Create a unittest under tests/, for example tests/kdelinux/system/example.py. It should make assertions about the system under test and write its results to a JUnit XML file, which will be automatically collected as an openQA asset and a GitLab CI report.

import unittest
from lib.sut import openqa_junit_xml

class ExampleTests(unittest.TestCase):
    def test_expected_behaviour(self):
        self.assertTrue(True)

if __name__ == "__main__":
    openqa_junit_xml.run(ExampleTests, "example")

Add an entry to the relevant suite's tests array:

{ path = "kdelinux/system/example.py", type = "python" },

The generated wrapper collects the JUnit result and command output so that failures appear in the openQA job and CI artifacts.

Tests graphiques avec Selenium

Les tests graphiques sont également des classes Python « unittest ». Cependant, ils utilisent le pilote Appium / Selenium pour rechercher et interagir avec les éléments accessibles d'interface utilisateur. Le lanceur de Selenium active l'infrastructure d'accessibilité et démarre le pilote pour vous.

Par exemple, un test graphique crée un pilote pour son application, interagit avec les éléments accessibles et ferme ensuite le pilote :

import unittest
from appium import webdriver
from appium.options.common.base import AppiumOptions
from appium.webdriver.common.appiumby import AppiumBy
from lib.sut import openqa_junit_xml

class ExampleTests(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        options = AppiumOptions()
        options.set_capability("app", "org.kde.example.desktop")
        cls.driver = webdriver.Remote("http://127.0.0.1:4723", options=options)

    @classmethod
    def tearDownClass(cls):
        cls.driver.quit()

    def test_expected_behaviour(self):
        self.driver.find_element(AppiumBy.ACCESSIBILITY_ID, "example-control").click()

if __name__ == "__main__":
    openqa_junit_xml.run(ExampleTests, "example")

Save the script as, for example, tests/kdelinux/app/example.py, and add it to the relevant suite with type = "selenium". Select the installed test user for desktop applications:

{ path = "kdelinux/app/example.py", type = "selenium", user = "installed", timeout = 180 },

Run the flow containing your suite locally while developing it.

Test options and custom wrappers

For generated SUT wrappers, manifest entries can set user (root, live, installed, or plasma_setup), timeout in seconds (defaults to 90), artifacts as a list of paths to collect, and the openQA flags fatal = true or always_run = true. Set enabled = false to leave a test declared while excluding it from the schedule.

When a test needs some form of custom orchestration to run, put a wrapper beside its SUT script and point to it with override:

{ path = "kdelinux/system/collect_logs.py", type = "selenium", override = "kdelinux/system/collect_logs.openqa.py" },

This custom wrapper is responsible for its flags, user, timeout, and artifact collection, and must pass the SUT script's relative path to CliTest.run_python() or CliTest.run_selenium(). See the existing collect_logs.openqa.py for an example.

Pour plus d'informations sur l'écriture de tests avec Selenium, veuillez consulter la page Tests d'automatisation avec Appium et Tests d'interface graphique Utilisateur avec selenium-webdriver-at-spi.

En apprendre encore plus

Pour une explication plus détaillée du flux de tests et de sa mise en œuvre, veuillez consulter la page Exécution de tests sous openQA sous KDE Linux. L'infrastructure des tests est développée dans le dépôt os-autoinst-distri-kdelinux.


Article rédigé par sous licence CC-BY-4.0.