openQA voor ontwikkelaars en onderhouder
KDE Linux gebruikt openQA om elk systeem-image automatisch te testen voordat het wordt gepubliceerd. openQA start elk image op in een virtuele machine en controleert of het succesvol kan worden geïnstalleerd, opgewaardeerd en gebruikt.
openQA hanteert specifieke terminologie: een job is een enkele uitvoering van een testsuite op een image, terwijl een worker de machine of container is die de job uitvoert. De openQA-documentatie licht deze en andere concepten toe, waaronder testmodules, jobgroepen, assets en de web-UI.
Hoe de testen werken
De test-worker draait parallel aan de CI-pipeline, waardoor deze gebruik kan maken van de door de build gegenereerde images en virtuele schijven zonder die grote bestanden elders te hoeven uploaden. Tests worden via een systeemextensie aan de virtuele machine aangeleverd en communiceren ermee via SSH.
Bureaubladtesten maken gebruik van de toegankelijkheids-API via selenium-webdriver-at-spi, waardoor ze met applicaties kunnen interageren en de status ervan kunnen controleren zonder uitsluitend afhankelijk te zijn van screenshot-vergelijking. Daarnaast controleert de testsuite op falende systeemdiensten, gecrashte bureaubladprocessen, netwerkproblemen en regressies in KDE Linux-commando's.
CI-pijplijn en workflow voor onderhouders
Op de beveiligde standaardbranch van de upstream KDE Linux-repository werkt de pijpelijn als volgt:
- De imaging-taak bouwt en ondertekent de image en het bijbehorende sysupdate-kanaal, en plaatst deze op
storage.kde.org. - De trigger-openqa-job start de pijplijn in os-autoinst-distri-kdelinux en geeft daarbij de URL van de staged image en de URL van het sysupdate-kanaal door.
- De downstream-pijplijn voert de normale installatie- en sanity-procedure en de opwaardeerprocedure uit.
- De upstream publish-taak wordt pas uitgevoerd nadat de openQA-pijplijn succesvol is afgerond. Deze bevordert de reeds klaargezette image voor openbaar gebruik.
Hierdoor fungeert een openQA-fout als een blokkade voor de publicatie van de image. Begin met het openen van de downstream-pijplijn vanuit de trigger-openqa-job en open vervolgens de falende openQA-job via het bijbehorende CI-logboek. Op de jobpagina worden de testmodules op volgorde weergegeven; zo kunt u vaststellen of de fout optreedt tijdens de installatie, de sanity-tests van het geïnstalleerde systeem of het opwaardeerproces.
Download een staged image
De koppeling die na het logbericht “In case of failure, you can inspect and download the .iso image and sysupdate tree at…” wordt weergegeven, opent een opslagbrowser voor de build die wordt getest. Download daar de .iso om deze handmatig op te starten of aan een lokale openQA-stack te voeren. De sysupdate-boomstructuur bevat de voorbereide update-artefacten die door de opwaardeertest worden gebruikt.
Onderzoek een mislukte taak
Open de taak in de openQA-webinterface en selecteer eerst de mislukte module. De koppeling naar de webinterface verschijnt na het logbericht “autoinst-log.txt voor de logs van de openQA-worker en de test-engine. Dit is het primaire logbestand voor de taak zelf.
Bij testen die commando's uitvoeren op het te testen systeem, voert KDE Linux deze uit in tijdelijke systemd-services en wordt het service-journal als diagnostische uitvoer in het testresultaat vastgelegd. Raadpleeg autoinst-log.txt voor de uitvoer van de commando's en het journal. U kunt ook het bestand *kde-linux-collected-logs.tar.zst downloaden met de logs die door de hulpmiddel collect-logs zijn verzameld.
Voer testen lokaal uit
U kunt openQA gebruiken om een lokaal gebouwde image te testen voordat u een wijziging indient. Dit is vereist wanneer u werkt vanuit een fork buiten kde-linux/kde-linux: de CI-pijplijn daarvan bouwt weliswaar een test-image, maar start de openQA-pijplijn niet. Het is ook nuttig bij het ontwikkelen van tests voor uw eigen wijzigingen.
De KDE Linux openQA-testopslagruimte bevat een lokale stack met zowel een openQA-webinterface als een worker. Hiervoor zijn Podman en podman-compose vereist, die in KDE Linux zijn opgenomen.
Kloon de testopslagruimte en plaats vervolgens de KDE Linux-.iso-image die u wilt testen in de hoofdmap ervan. Als er geen image aanwezig is, downloadt de testrunner in plaats daarvan de nieuwste publiek beschikbare image.
Start de lokale stack.
./mock.sh up
Zodra het gereed is, opent u http://localhost:1080 om de openQA-webinterface te bekijken. Taken worden niet automatisch ingediend; open daarom een shell in de container en start de standaardprocedure voor installatie en sanity-tests.
podman exec -it openqa-single-instance bash ./qa flow
Voeg --upgrade toe om in plaats daarvan het opwaardeerproces uit te voeren:
./qa flow --upgrade
Voeg --encrypt toe om de installatietestprocedure voor schijfversleuteling uit te voeren:
./qa flow --encrypt
U kunt ook de opties --upgrade en --encrypt combineren:
./qa flow --upgrade --encrypt
De sanity-test-taak vereist dat de install-system-taak eerst wordt uitgevoerd, omdat deze gebruikmaakt van de virtuele schijf die tijdens de installatie is aangemaakt. Om u op een specifieke test te concentreren, kunt u de ingediende taken in lib/worker/job_flow.py aanpassen of een individuele taak uitvoeren met ./qa job, waarbij u rekening houdt met die afhankelijkheid. Voer ./qa job --help uit om de vereiste opties te bekijken.
Om bijvoorbeeld een install-system-taak uit te voeren waarbij u een .iso-bestand hebt gedownload naar de map van de opslagruimte:
./qa job \
--live ./kde-linux_<build-id>.iso \
--hdd kde-linux_<build-id>.qcow2 \
--sysext ./openqa-sysext.img \
--build <build-id> \
--name install-system \
--flavor live
Wanneer u klaar bent, stopt u de stack en verwijdert u de lokale volumes ervan.
./mock.sh down -v
Schrijf een test
De testdefinities en de testcode bevinden zich in os-autoinst-distri-kdelinux. Voeg de test toe aan de juiste flow in main.pm: de live-installatieflow, de sanity-check voor het geïnstalleerde systeem of de opwaardeerflow. Testen bestaan doorgaans uit een kleine openQA-wrapper in tests/ en een Python-test die op het te testen systeem draait, afkomstig uit extensions/openqa/usr/lib/kde-linux-openqa/tests/.
Kies het type test op basis van wat u controleert:
- Gebruik een standaard Python-
unittestvoor opdrachtregelhulpmiddelen, services, de status van het bestandssysteem of ander niet-grafisch gedrag. - Gebruik Selenium via
selenium-webdriver-at-spiwanneer voor het gedrag interactie met een grafische toepassing vereist is.
Normale Python testen
Maak een unittest aan in de eerder genoemde testmap voor systeemextensies. Deze moet beweringen (assertions) doen over het te testen systeem en de resultaten wegschrijven naar een JUnit XML-bestand, dat automatisch wordt verzameld als openQA-asset en GitLab CI-rapport.
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")
Maak een bijbehorende wrapper aan onder tests/ die openQA de test op de host laat uitvoeren.
from testapi import *
from lib.test import cli_test
def run(self):
cli_test.CliTest("example").run_python()
Registreer tot slot de wrapper in de betreffende flow in main.pm. De wrapper verzamelt het JUnit-resultaat en de uitvoer van het commando, zodat fouten zichtbaar zijn in de openQA-job en de CI-artefacten.
Grafische tests met Selenium
Grafische tests zijn ook Python-unittest-klassen, maar ze maken gebruik van de Appium/Selenium-driver om toegankelijke UI-elementen te vinden en ermee te interageren. De Selenium-runner activeert de toegankelijkheidsinfrastructuur en start het stuurprogramma voor u op.
Een grafische test maakt bijvoorbeeld een stuurprogramma aan voor de toepassing, communiceert met toegankelijke elementen en sluit het stuurprogramma vervolgens weer af:
import unittest
from appium import webdriver
from appium.options.common.base import AppiumOptions
from appium.webdriver.common.appiumby import AppiumBy
from lib.test 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")
Voer de bijbehorende wrapper uit met run_selenium() in plaats van run_python(). Geef de geïnstalleerde testgebruiker voor desktopapplicaties door:
from testapi import *
from lib.test import cli_test
from lib.common import user_manager
def run(self):
cli_test.CliTest("example").run_selenium(user=user_manager.installed())
Voeg, net als bij normale Python-testen, de wrapper toe aan main.pm, voer deze lokaal uit tijdens de ontwikkeling en neem hem op in de testflow die de functionaliteit test.
Voor meer informatie over het schrijven van Selenium-tests, zie Appium automation testing en GUI Testing with selenium-webdriver-at-spi.
Kom meer te weten
Voor een uitgebreidere uitleg over het testverloop en de implementatie ervan, zie openQA Testing in KDE Linux. De testinfrastructuur wordt ontwikkeld in de os-autoinst-distri-kdelinux-repository.
Artikel bijgedragen door Thomas Duckworth onder de licentie CC-BY-4.0.