openQA para desarrolladores y mantenedores
KDE Linux usa openQA to automatically para probar automáticamente cada imagen del sistema antes de publicarla. openQA arranca cada imagen en una máquina virtual y comprueba que se puede instalar, actualizar y usar de forma correcta.
openQA usa cierta terminología: un trabajo es una ejecución de un paquete de pruebas sobre una imagen, mientras que un trabajador es la máquina o el contenedor que ejecuta el trabajo. La documentación de openQA explica estos y otros conceptos, incluidos los módulos de pruebas, los grupos de trabajo, activos y la interfaz web.
Cómo funcionan las pruebas
El proceso de la prueba se ejecuta junto con la canalización de integración continua (CI), lo que le permite usar las imágenes y los discos virtuales generados durante la compilación sin tener que subir esos archivos grandes a otro lugar. Las pruebas se envían a la máquina virtual mediante una extensión del sistema y se comunican con ella a través de SSH.
Las pruebas de escritorio usan la API de accesibilidad a través de selenium-webdriver-at-spi, lo que les permite interactuar con las aplicaciones y comprobar su estado sin depender únicamente de la comparación de capturas de pantalla. El conjunto de pruebas también verifica si hay servicios del sistema con fallos, procesos de escritorio bloqueados, problemas de red y regresiones en las órdenes de KDE Linux.
Flujo de trabajo del mantenedor y de la canalización de CI
En la rama predeterminada protegida del repositorio principal de KDE Linux, la canalización funciona de la siguiente manera:
- El trabajo imaging compila, firma y prepara la imagen y su canal sysupdate en
storage.kde.org. - El trabajo trigger-openqa inicia la canalización en os-autoinst-distri-kdelinux, pasándole la URL de la imagen preparada y la URL del canal sysupdate.
- The downstream pipeline runs the
installandupgradeflows declared intests/tests.toml, each with plain and encrypted installations. - El trabajo publish principal se ejecuta solo después de que la canalización de openQA haya finalizado correctamente. Su función es promocionar la imagen ya preparada para su consumo público.
Esto convierte un fallo de openQA en un obstáculo para la publicación de la imagen. Para empezar, abre la canalización descendente del trabajo trigger-openqa y, a continuación, abre el trabajo de openQA que ha fallado desde su registro de CI. La página del trabajo muestra los módulos de prueba en orden y permite identificar si el fallo se produce durante la instalación, las pruebas de integridad del sistema instalado o la ruta de actualización.
Descargar una imagen preparada
El enlace que se proporciona tras el mensaje de registro «En caso de fallo, inspecciona y descarga la imagen y el árbol sysupdate en…», abre un explorador de almacenamiento para la compilación bajo prueba. Descarga la .iso ahí para arrancarla manualmente o proporciónasela a una pila openQA local. El árbol sysupdate contiene los artefactos de actualización preparados que usa la prueba de actualización.
Investigar un trabajo que ha fallado
Abre el trabajo en la interfaz web de openQA y selecciona primero el módulo que ha fallado. El enlace a la interfaz web aparecerá tras el mensaje del registro «El trabajo de prueba autoinst-log.txt del trabajador openQA y el registro «test-engine». Este es el registro principal para el propio trabajo.
Para las pruebas que ejecutan órdenes en el sistema bajo prueba, KDE Linux las ejecuta en servicios systemd transitorios y graba el diario del servicio como salida de diagnóstico en el resultado de la prueba. Inspecciona el autoinst-log.txt de la salida de la orden y el diario. También puedes descargar el archivo *kde-linux-collected-logs.tar.zst para los registros capturados por la herramienta collect-logs.
Ejecutar pruebas localmente
Puedes usar openQA para probar una imagen compilada localmente antes de enviar un cambio. Esto es necesario cuando se trabaja con una bifurcación fuera de kde-linux/kde-linux: su canalización de CI crea una imagen de prueba, pero no lanza la canalización openQA. También es útil cuando se desarrollan pruebas para los cambios propios.
El repositorio de pruebas openQA de KDE Linux incluye una pila local que contiene tanto una interfaz web de openQA como un trabajador. Requiere Python 3.14, Podman y podman-compose, que se incluyen en KDE Linux.
Clona el repositorio de pruebas y luego sitúa la imagen .iso de KDE Linux que quieras probar en su directorio raíz. Si no hay ninguna imagen presente, el lanzador de la prueba descarga la última imagen disponible públicamente.
Inicia la pila local desde la raíz del repositorio.
./qa-mock up
Cuando esté preparada, abre http://localhost:1080 para inspeccionar la interfaz web de openQA. Los trabajos no se envían de forma automática, por lo que debes abrir un intérprete en el contenedor y enviar el flujo install. Ejecuta las órdenes flow, job y build-sysext dentro de este contenedor.
./qa-mock enter ./qa flow install
Para ejecutar el flujo 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
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 <build-id> 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:
installboots the live image and creates the installed disk.upgradeboots the installed disk and setsDO_UPGRADEfor tests that perform the upgrade.testboots 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.
Escribir una prueba
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.
Escoge el tipo de prueba según lo que quieras comprobar:
- Usa una
unittestnormal de Python para herramientas de la línea de órdenes, servicios, estado de sistemas de archivos u otro comportamiento no gráfico. - Usa Selenium mediante
selenium-webdriver-at-spicuando el comportamiento requiera interactuar con una aplicación gráfica.
Pruebas normales de Python
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.
Pruebas gráficas con Selenium
Las pruebas gráficas también son clases unittest de Python, pero usan el controlador de Appium/Selenium para encontrar elementos accesibles de la interfaz de usuario e interactuar con ellos. El lanzador de Selenium activa la infraestructura de accesibilidad e inicia el controlador automáticamente.
Por ejemplo, una prueba gráfica crea un controlador para su aplicación, interactúa con los elementos accesibles y cierra el controlador después:
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.
Para más información sobre la escritura de pruebas con Selenium, consulta Pruebas de automatización de Appium y Pruebas de la interfaz gráfica con selenium-webdriver-at-spi.
Saber más
Para una explicación más detallada sobre la prueba y su implementación, consulta Pruebas openQA en KDE Linux. El desarrollo de la infraestructura de pruebas se lleva a cabo en el repositorio os-autoinst-distri-kdelinux.
Artículo escrito por Thomas Duckworth bajo las condiciones de la licencia CC-BY-4.0.