openQA para Desenvolvedores e Mantenedores
O KDE Linux utiliza o openQA para testar automaticamente cada imagem do sistema antes de sua publicação. O openQA inicializa cada imagem em uma máquina virtual e verifica se ela pode ser instalada, atualizada e utilizada com sucesso.
O openQA possui uma terminologia específica: um job é uma execução de uma suíte de testes em uma imagem, enquanto um worker é a máquina ou o contêiner que executa o job. A documentação do openQA explica esses e outros conceitos, incluindo módulos de teste, grupos de jobs, ativos e a interface web.
Como os testes funcionam
O worker de testes é executado em paralelo ao pipeline de CI, permitindo utilizar as imagens e os discos virtuais gerados pelo processo de compilação sem a necessidade de transferir esses arquivos grandes para outro local. Os testes são fornecidos à máquina virtual por meio de uma extensão do sistema e comunicam-se com ela via SSH.
Os testes de desktop utilizam a API de acessibilidade por meio do selenium-webdriver-at-spi, permitindo interagir com aplicativos e verificar seu estado sem depender exclusivamente da comparação de capturas de tela. O conjunto de testes também verifica falhas em serviços do sistema, travamentos de processos de desktop, problemas de rede e regressões em comandos do KDE Linux.
Pipeline de CI e fluxo de trabalho do mantenedor
Na branch padrão protegida do repositório upstream KDE Linux, o pipeline funciona da seguinte forma:
- O job de imaging cria, assina e prepara a imagem e seu canal de atualização do sistema no
storage.kde.org. - O job de trigger-openqa inicia o pipeline em os-autoinst-distri-kdelinux, passando a ele a URL da imagem preparada (staged image) e a URL do canal sysupdate.
- O pipeline subsequente executa o fluxo padrão de instalação e verificação de integridade, bem como o fluxo de atualização.
- O job de publish (publicação) seguinte é executado somente após a conclusão bem-sucedida do pipeline do openQA. Ele promove a imagem já preparada para disponibilização pública.
Isso faz com que uma falha no openQA atue como um bloqueio para a publicação da imagem. Comece abrindo o pipeline downstream a partir do job trigger-openqa e, em seguida, abra o job do openQA que falhou, acessando-o pelo log de CI. A página do job exibe os módulos de teste em ordem, permitindo identificar se a falha ocorreu na instalação, nos testes de sanidade do sistema instalado ou no processo de atualização.
Baixar uma imagem preparada
O link fornecido após a mensagem de log “In case of failure, you can inspect and download the .iso image and sysupdate tree at…” abre um navegador de armazenamento para a build em teste. Baixe o arquivo .iso nesse local para inicializá-lo manualmente ou fornecê-lo a uma instância local do openQA. A árvore sysupdate contém os artefatos de atualização preparados para uso no teste de upgrade.
Investigar o job que falhou
Abra o job na interface web do openQA e selecione primeiro o módulo que falhou. O link para a interface web aparecerá após a mensagem de log “autoinst-log.txt referente ao worker do openQA e ao log do motor de testes (test-engine). Este é o log principal do próprio job.
Para testes que executam comandos no sistema em teste, o KDE Linux os executa em serviços systemd temporários e registra o diário do serviço como saída de diagnóstico no resultado do teste. Verifique o arquivo autoinst-log.txt para consultar a saída do comando e o diário. Você também pode baixar o arquivo *kde-linux-collected-logs.tar.zst contendo os logs capturados pela ferramenta collect-logs.
Executar testes localmente
Você pode usar o openQA para testar uma imagem compilada localmente antes de enviar uma alteração. Isso é necessário ao trabalhar a partir de um fork fora de kde-linux/kde-linux — o pipeline de CI desse repositório compila uma imagem de teste, mas não aciona o pipeline do openQA. Também é útil durante o desenvolvimento de testes para suas próprias alterações.
O repositório de testes openQA do KDE Linux inclui uma pilha local contendo tanto a interface web do openQA quanto um worker. Ele requer o Podman e o podman-compose, que estão incluídos no KDE Linux.
Clone o repositório de testes e, em seguida, coloque a imagem .iso do KDE Linux que você deseja testar no diretório raiz dele. Se nenhuma imagem estiver presente, o executor de testes baixará a imagem mais recente disponível publicamente.
Iniciar a pilha local.
./mock.sh up
Assim que estiver pronto, acesse http://localhost:1080 para inspecionar a interface web do openQA. Os jobs não são enviados automaticamente. Portanto, abra um shell no container e execute o fluxo padrão de instalação e teste de sanidade.
podman exec -it openqa-single-instance bash ./qa flow
Para executar o fluxo de atualização, adicione --upgrade:
./qa flow --upgrade
Para executar o fluxo de teste de instalação com criptografia de disco, adicione --encrypt:
./qa flow --encrypt
Você também pode combinar as opções --upgrade e --encrypt:
./qa flow --upgrade --encrypt
O job sanity-test precisa que o job install-system seja executado primeiro, pois utiliza o disco virtual criado pela instalação. Para focar em um teste específico, ajuste os jobs enviados em lib/worker/job_flow.py ou execute um job individual com ./qa job, levando em conta a dependência em questão. Execute ./qa job --help para ver as opções necessárias.
Por exemplo, para executar uma tarefa install-system quando você tiver um arquivo .iso baixado no diretório do repositório:
./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
Quando terminar, pare a pilha e remova seus volumes locais.
./mock.sh down -v
Escrever um teste
As definições e o código dos testes estão localizados em os-autoinst-distri-kdelinux. Adicione o teste ao fluxo apropriado em main.pm: o fluxo de instalação via Live (live-install), o fluxo de verificação de integridade do sistema instalado (installed-system sanity) ou o fluxo de atualização (upgrade). Os testes geralmente consistem em um pequeno wrapper do openQA em tests/ e um teste em Python — localizado em extensions/openqa/usr/lib/kde-linux-openqa/tests/ — que é executado no sistema sob teste.
Escolha o tipo de teste com base no que você está verificando:
- Use o
unittestpadrão do Python para ferramentas de linha de comando, serviços, estado do sistema de arquivos ou outros comportamentos não gráficos. - Use o Selenium por meio do
selenium-webdriver-at-spiquando o comportamento exigir a interação com uma aplicação gráfica.
Testes Python normais
Crie um teste unittest no diretório de testes de extensão do sistema mencionado anteriormente. Ele deve realizar asserções sobre o sistema em teste e gravar seus resultados em um arquivo XML no formato JUnit, o qual será coletado automaticamente como um ativo do openQA e um relatório do 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(TestesExemplo, "exemplo")
Crie um wrapper correspondente em tests/ que faça o openQA executar o teste no host.
from testapi import *
from lib.test import cli_test
def run(self):
cli_test.CliTest("example").run_python()
Por fim, registre o wrapper no fluxo correspondente em main.pm. O wrapper coleta o resultado do JUnit e a saída do comando, de modo que as falhas apareçam no job do openQA e nos artefatos de CI.
Testes gráficos com Selenium
Testes gráficos também são classes unittest do Python, mas utilizam o driver do Appium/Selenium para localizar e interagir com elementos de interface acessíveis. O executor do Selenium habilita a infraestrutura de acessibilidade e inicia o driver para você.
Por exemplo, um teste gráfico cria um driver para sua aplicação, interage com elementos acessíveis e fecha o driver em seguida:
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(TestesExemplo, "exemplo")
Execute o wrapper correspondente com run_selenium() em vez de run_python(). Passe o usuário de teste instalado para aplicativos de desktop:
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())
Assim como nos testes comuns do Python, adicione o wrapper correspondente a main.pm, execute-o localmente durante o desenvolvimento e inclua-o no fluxo de testes que exercita a funcionalidade.
Para mais informações sobre a criação de testes com Selenium, consulte Testes de automação com Appium e Testes de GUI com selenium-webdriver-at-spi.
Saiba mais
Para uma explicação mais detalhada do fluxo de testes e de sua implementação, consulte openQA Testing in KDE Linux. A infraestrutura de testes é desenvolvida no repositório os-autoinst-distri-kdelinux.
Artigo contribuído por Thomas Duckworth sob a licença CC-BY-4.0.