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. La pipeline downstream esegue i flussi (flow) install e upgrade dichiarati in tests/tests.toml, ciascuno con installazioni semplici e cifrate.
  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

Per un'installazione cifrata, passa FDE_INSTALL=1 come impostazione openQA. Il suffisso flavor distingue i job cifrati nell'interfaccia web:

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

--var NAME=VALUE può essere ripetuta, ma ciascuna variabile deve essere dichiarata nell'elenco variables del flusso selezionato in tests/tests.toml.

La suite sanity-test usa il disco virtuale creato da install-system. Per concentrarti su test specifici, modifica l'elenco tests della suite in tests/tests.toml, oppure dichiara un'altra suite ed esegui il flusso lì. Puoi anche eseguire una singola suite con ./qa job --name <suite> sempre tenendo presenti le sue dipendenze del disco. I comandi flow, job e build-sysext accettano --manifest-path <path> da usare come manifesto diverso da tests/tests.toml. I percorsi dei test all'interno del manifesto sono relativi alla cartella di quel manifesto. Esegui ./qa job --help per conoscere le opzioni richieste.

Per esempio, genera l'estensione di sistema ed esegui un job install-system con un .iso nella cartella del deposito. Sostituisci l'ID della build e la variante con quelli della tua immagine:

./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 passa gli argomenti a podman-compose. Per esempio, usa ./qa-mock up -d per avviare lo stack in background.

Aggiornamenti dei test tra build locali

Metti la ISO di base nella root del deposito di test. Quando avvii lo stack dall'host, imposta KDE_LINUX_OUTPUT alla cartella mkosi.output che contiene la build che vuoi aggiornare a:

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

Entra nel container ed esegui il flusso di aggiornamento, sostituendo &lt;build-id&gt; con l'ID della build della tua ISO di base:

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

Entrambe le opzioni devono essere fornite assieme. Il deposito è montato a /casedir, e la cartella mkosi.output selezionata è montata in sola lettura a /kde-linux-output. La build più recente in quella cartella serve alla macchina virtuale come fonte sysupdate temporanea e deve essere più recente dell'ISO di base. Aggiunti --var FDE_INSTALL=1 --flavor-suffix=-encrypted per testare un'installazione cifrata.

Dichiarare suite e flussi (flow)

tests/tests.toml definisce distribuzione (name e distri), suite e flussi. Una suite è un elenco ordinato di test eseguiti in un job openQA. La sua action determina come il job utilizza il disco virtuale:

  • install avvia l'immagine live e crea il disco installato.
  • upgrade avvia il disco installato e configura DO_UPGRADE per i test che eseguono l'aggiornamento.
  • test avvia il disco installato per la validazione.

Un flusso esegue le suite nell'ordine dichiarato, passando il disco installato tra i job. KDE Linux definisce questi flussi:

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

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

Il flusso install installa e controlla la build sotto test. Il flusso upgrade prima installa un'immagine meno recente, la aggiorna alla build sotto test, quindi esegue i test di integrità. Per una build CI a fasi, la base è l'ultima immagine pubblicata. Senza --upgrade-from e --upgrade-to, l'esecuzione di un aggiornamento locale aggiornerà all'ultima build pubblica come target, utilizzando una ISO locale meno recente, se ce n'è una disponibile, oppure scaricando l'immagine precedente.

Prima di ciascun job, il worker genera una cartella temporanea di test (CASEDIR) con una pianificazione main.pm per la suite selezionata. I test sono eseguiti nell'ordine del manifesto, incluse le voci ripetute. Modifica il manifesto per cambiare la pianificazione.

Scrivere un test

Le definizioni dei test e il codice live si trovano in os-autoinst-distri-kdelinux. Aggiungi gli scripts dei test in tests/, accanto ai testi collegati, e registrali nella corretta matrice tests del test in tests/tests.toml. Per esempio:

[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 },
]

I test openqa si eseguono sul worker e utilizzano direttamente le API di openQA. I test python e selenium si eseguono sul sistema sotto test, l'estensione del sistema impacchetta automaticamente i loro script e il worker genera i wrapper del test openQA invocandoli.

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

Crea un unittest in tests/, per esempio tests/kdelinux/system/example.py. Dovrebbe eseguire delle asserzioni sul sistema in fase di test e scrivere i risultati in un file XML JUnit, che verrà automaticamente raccolto come risorsa openQA e report di GitLab CI.

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

Aggiungi una voce alla matrice tests pertinente della suite:

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

Il wrapper generato raccoglie il risultato JUnit e l'output dei comandi in modo che gli errori vengano visualizzati nel job openQA job e negli artefatti CI.

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

Salva lo script come, per esempio, tests/kdelinux/app/esempio.py e aggiungilo alla suite attinente con type = "selenium". Seleziona l'utente del test installato per le applicazioni desktop:

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

Esegui il flusso che contiene localmente la tua suite mentre la sviluppi.

Opzioni del test e wrapper personalizzati

Per i wrapper SUT generati, le voci del manifesto possono impostare user (root, live, installed o plasma_setup), timeout in secondi (predefinito 90), artifacts come un elenco di percorsi da raccogliere e i flag openQA fatal = true o always_run = true. Imposta enabled = false per lasciare dichiarato un test mentre lo escludi dalla pianificazione.

Quando un test necessita di una qualche forma di orchestrazione personalizzata da eseguire, inserisci un wrapper accanto al suo script SUT e puntalo con override:

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

Questo wrapper personalizzato è responsabile della sua raccolta di flags, user, timeout artifact, e deve passare il percorso relativo dello script SUT a CliTest.run_python() o CliTest.run_selenium(). Vedi l'esistente collect_logs.openqa.py come esempio.

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.