Testes em sistemas embarcados utilizando labgrid integrado ao pytest

 




{getToc} $title={Índice}

O labgrid é uma ferramenta de abstração de hardware, com foco em teste, desenvolvimento e automação em geral. Pode ser utilizada como uma CLI para comandar um sistema, como uma ferramenta para scripts (bibliotecas em python) ou como ferramenta de testes (integrado ao pytest). Ele é bastante eficaz quando se trata de testes em sistemas Linux embarcado. Neste artigo, o labgrid será instalado num host, e acessará um target via serial.
Vale lembrar que o labgrid não é um framework de teste por si só, mas é feito pra ser combinado com o pytest e seus plugins.
Os testes aqui realizados foram baseados na documentação oficial do labgrid [1], mais especificamente na documentação de uso [2].

Instalação do labgrid

O labgrid é facilmente instalado por meio do pip, conforme a seguir. Para o que será realizado no presente artigo, basta instalá-lo em um host Linux, não sendo necessário a instalação na máquina target.
```sh
pip install labgrid
```

labgrid como biblioteca

Um sistema é representado como um Target. Um target costuma possuir Resources (recursos) e Drivers. Em casos que a placa precisa de uma transição (ex.: off no Bootloader), pode ser necessário uma Strategy (estratégia). Aqui serão explorados apenas Resources e Drivers.

Exemplos de Drivers [3]: SSHDriver, CommandProtocol, GpioDigitalOutputDriver, etc.
Exemplos de Resources [4]: NetworkService, RawSerialPort, SysfsGPIO, etc.

Teste com acesso remoto via porta serial

A biblioteca do labgrid oferece duas maneiras de configurar targets com resources e drivers: criar o Target diretamente ou usar o Environment (ambiente) para carregar um arquivo de configuração (.yaml).
```yaml
targets:
    main:
        resources:
            RawSerialPort: 
                port: "/dev/ttyUSB0"
        drivers:
            SerialDriver: {} 
            ShellDriver:
                login_timeout: 75
                prompt: '# '
                login_prompt: 'login: '
                username: 'root' 
                password: 'sua senha'
    target2: 
        resources: 
            resource1:
                arg1: 'ex'
        drivers:
            drv1: {}
            drv2: 
                arg1: 'ex1'
                arg2: 123
```

No exemplo do acima é usado um arquivo local.yaml para configurar o ambiente, e ele é chamado usando o argumento --lg-env local.yaml no comando do pytest (usando por padrão o target main). 
O campo "targets: main: resources: RawSerialPort" possui as informações da serial, e deve ser preenchido com o caminho para a porta serial adequada do host. Outro parâmetro que pode ser preenchido é o valor de baud rate, com o parâmetro "speed", cujo valor padrão é 115200 bps, sendo opcional para esta aplicação.

O campo "targets: main: drivers" possui configurações dos drivers necessários para o teste que será realizado, neste caso, o "SerialDriver" e o "ShellDriver". As configurações do "ShellDriver" são o tempo máximo para realizar o login em segundos (login_timeout), o texto do prompt de comando (neste caso, o texto é "# "), o texto do prompt de login (login_prompt), o usuário e a senha de login ("root" e "sua senha", respectivamente).
A inicialização do ambiente e do target é feita em uma fixture do pytest. Se desejar, é possível remover o argumento --lg-env local.yaml do comando do pytest, criando um objeto pro ambiente e pro target direto de dentro da fixture command. Considere esta fixture dentro do módulo conftest.py, que será executada antes da módulo de teste. As duas opções podem ser vistas a seguir:
Com ambiente por comando do pytest:
```python
import pytest
@pytest.fixture(scope='session')
def command(target):
    # target padrão = main
    shell = target.get_driver('CommandProtocol')
    target.activate(shell)
    return shell
```
Com ambiente por código:
```python
import pytest
from labgrid import Environment
@pytest.fixture(scope='session')
def command():
    env = Environment('local.yaml')
    target = env.get_target('main')
    shell = target.get_driver('CommandProtocol')
    target.activate(shell)
    return shell
```
Por fim, basta usar os recursos configurados em um módulo python (neste caso, test_shell.py):
```python
def test_shell(command):
    stdout, stderr, returncode = command.run('cat /proc/version')
    assert returncode == 0
    assert stdout
    assert not stderr
    assert 'Linux' in stdout[0]

    stdout, stderr, returncode = command.run('false')
    assert returncode != 0
    assert not stdout
    assert not stderr
```
Para executar o teste, a partir da máquina de host, deve-se usar um dos dois comandos:
```shell
# com ambiente por comando do pytest
pytest --lg-env local.yaml test_shell.py

# com ambiente por codigo
pytest test_shell.py
```
Inicializando o target com o console externado em uma porta serial conectada ao host, a seguinte mensagem deverá ser mostrada logo após a inicialização e realização do teste:
```shell
========================================== test session starts ==========================================
platform linux -- Python 3.8.10, pytest-7.2.2, pluggy-1.2.0
rootdir: /home/matheusaguiar/Projetos/labgridtest/test/shell
plugins: labgrid-23.0.3
collected 1 item                                                                                       
 
test_shell.py .                                                                                   [100%]
 
=========================================== 1 passed in 2.31s ===========================================
```

Com poucas modificações é possível configurar a conexão para ser feita via ssh, utilizando o mesmo módulo de teste test_shell.py.
Na configuração do ambiente, no arquivo local.yaml:
```yaml
targets:
  main:
    resources:
      NetworkService:
        address: '192.168.0.1'
        name: 'board_network'
        username: 'root'
        password: 'sua senha'
    drivers:
      SSHDriver: {}
```
O campo "targets: main: resources: NetworkService: address:" deve conter o endereço IP do target.

No arquivo conftest.py, que possui a fixture command:
```python
import pytest
@pytest.fixture(scope='session')
def command(target):
    ssh = target.get_driver('SSHDriver')
    return ssh
```
Assim como no caso do teste via serial, os comandos realizados dependem de como foi configurado o target, sendo um ponto que merece atenção.

Referências:

Postar um comentário

Deixe seu comentário ou sua sugestão!

Postagem Anterior Próxima Postagem

Formulário de contato