Passa al contenuto

openQA per sviluppatori e responsabili

KDE Linux usa openQA per eseguire test automatici su ogni immagine di sistema prima della sua pubblicazione. openQA avvia ciascuna immagine in una macchina virtuale e controlla che possa essere installata, aggiornata e utilizzata correttamente.

openQA possiede una sua terminologia specifica (che verrà mantenuta): un job è una esecuzione di una suite di test su un'immagine, mentre un worker è la macchina o il contenitore che esegue il job. La documentazione openQA spiega tutti i concetti, inclusi moduli dei test, gruppi di job, risorse e interfaccia web.

Come funzionano i test

Il worker del test viene eseguito insieme alla pipeline CI, in modo che possa usare le immagini e i dischi virtuali prodotti dalla generazione senza caricare quei file di grandi dimensioni altrove. I test sono inviati alla macchina virtuale tramite un'estensione del sistema e comunicano con essa su SSH.

I test desktop usano l'API di accessibilità attraverso selenium-webdriver-at-spi, che permette loro di interagire con le applicazioni e verificare il loro stato senza dover fare affidamento esclusivamente sulla corrispondenza delle schermate (screenshot). La suite controlla anche gli errori dei servizi di sistema, i processi desktop con crash, i problemi di rete e le regressioni nei comandi di KDE Linux.

Pipeline CI e flusso di lavoro dei responsabili

Nel ramo predefinito protetto del deposito upstream di KDE Linux, la pipeline funziona come segue:

  1. Il job di creazione dell'immagine genera, firma e crea le fasi dell'immagine e del suo canale sysupdate su storage.kde.org.
  2. Il job trigger-openqa avvia la pipeline in os-autoinst-distri-kdelinux, passandogli l'URL dell'immagine modificata e l'URL del canale sysupdate.
  3. The downstream pipeline runs the install and upgrade flows declared in tests/tests.toml, each with plain and encrypted installations.
  4. Il job upstream publish viene eseguito solo dopo che la pipeline openQA è stata completata correttamente. Promuove l'immagine già modificata per l'utilizzo pubblico.

Questo fa sì che un errore di openQA diventi un ostacolo alla pubblicazione dell'immagine. Inizia aprendo la pipeline downstream dal job trigger-openqa, quindi apri il job openQA che ha restituito l'errore dal relativo registro CI. La pagina del job mostra i moduli di test in ordine e ti permette di identificare se l'errore è nell'installazione, nei test di integrità del sistema installato o nel percorso di aggiornamento.

Scaricare un'immagine modificata

Il link fornito dopo il messaggio di log “In case of failure, inspect and download the image and sysupdate tree at…” apre un browser di archiviazione per la build in fase di test. Scarica il file .iso da lì per avviarlo manualmente o forniscilo a uno stack openQA locale. L'albero sysupdate contiene gli artefatti di aggiornamento modificati utilizzati dal test di aggiornamento.

Investigare un job con errore

Apri il job nell'interfaccia web di openQA e seleziona prima il modulo che ha generato l'errore. Il collegamento all'interfaccia web comparirà dopo il messaggio di registro del “job del test ora in esecuzione.”. I suoi dettagli includono i risultati del modulo, le schermate o i video (dove applicabile) e l'output diagnostico. Nella scheda Logs & Assets, scarica o visualizza autoinst-log.txt per il worker openQA e il registro test-engine. Questo è il registro principale per lo stesso job.

Per i test che eseguono comandi sul sistema in esame, KDE Linux li esegue in servizi systemd temporanei e registra il registro (journal) del servizio come output diagnostico nel risultato del test. Esamina il file autoinst-log.txt per visualizzare l'output del comando e il registro. Puoi anche scaricare il file *kde-linux-collected-logs.tar.zst per i registri acquisiti dallo strumento collect-logs.

Eseguire i test localmente

Prima di inviare una modifica, puoi usare openQA per un'immagine generata localmente. Ciò è richiesto quando lavori da un fork esterno a kde-linux/kde-linux - la sua pipeline CI genera un'immagine di test ma non attiva la pipeline openQA. È anche utile durante lo sviluppo di test per le tue modifiche personali.

Il deposito dei test openQA di KDE Linux include uno stack locale che contiene sia un'interfaccia web openQA, sia un worker. Richiede Python 3.14, Podman e podman-compose, inclusi in KDE Linux.

Clona il deposito dei test, quindi posiziona l'immagine .iso di KDE Linux che vuoi testare nella sua cartella di root. Se non è presente alcuna immagine, l'esecutore dei test scaricherà l'ultima immagine disponibile pubblicamente.

Avvia lo stack locale dalla root del deposito:

./qa-mock up

Una volta pronta, apri http://localhost:1080 per ispezionare l'interfaccia web di openQA. I job non vengono inviati automaticamente, pertanto apri una shell nel container e invia il flusso install flow. Esegui i comandi flow, job build-sysext all'interno di questo container.

./qa-mock enter
./qa flow install

Per eseguire invece un flusso upgrade:

./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

Quando hai terminato, esci dalla shell del container, quindi ferma lo stack e rimuovi i suoi volumi locali dall'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.

Scrivere 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.

Scegli il tipo di test in base a quello che stai verificando:

  • Usa un unittest Python standard per gli strumenti a riga di comando, i servizi, lo stato del filesystem o altri comportamenti non grafici.
  • Usa Selenium tramite selenium-webdriver-at-spi quando il comportamento richiede l'interazione con un'applicazione grafica.

Test Python standard

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, "esempio")

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.

Test grafici con Selenium

I test grafici sono anch'essi classi unittest Python, ma utilizzano il driver Appium/Selenium per trovare e interagire con gli elementi di interfaccia accessibili. L'esecutore Selenium abilita l'infrastruttura per l'accessibilità e avvia il driver al posto tuo.

Per esempio, un test grafico crea un driver per la sua applicazione, interagisce con gli elementi accessibili e poi chiude il driver:

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.

Per ulteriori informazioni su come scrivere test con Selenium, vedi le pagine Appium automation testing e GUI Testing with selenium-webdriver-at-spi (in inglese).

Ulteriori informazioni

Per una spiegazione più dettagliata del flusso dei test e la sua implementazione, vedi openQA Testing in KDE Linux. L'infrastruttura dei test è sviluppata nel deposito os-autoinst-distri-kdelinux.


Articolo scritto da sotto licenza CC-BY-4.0.