Skip to content

Commit

Permalink
test: add basic tests
Browse files Browse the repository at this point in the history
These are basically the same tests we have in the shell variant of the
test suite (test/rauc-hawkbit-updater.t).

Signed-off-by: Enrico Joerns <ejo@pengutronix.de>
Signed-off-by: Bastian Krause <bst@pengutronix.de>
  • Loading branch information
Bastian-Krause committed Jun 2, 2021
1 parent d63f0e0 commit a5fc698
Show file tree
Hide file tree
Showing 9 changed files with 314 additions and 1 deletion.
13 changes: 12 additions & 1 deletion .github/workflows/tests.yml
Expand Up @@ -31,6 +31,17 @@ jobs:
make
cd -
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: 3.8

- name: Install test dependencies
run: |
sudo apt-get install libgirepository1.0-dev python3-virtualenv
python -m pip install --upgrade pip
pip install -r test-requirements.txt
- name: Login to DockerHub
uses: docker/login-action@v1
if: github.ref == 'refs/heads/master'
Expand All @@ -46,7 +57,7 @@ jobs:
- name: Run test suite
run: |
./test/wait-for-hawkbit-online
cd test && ./rauc-hawkbit-updater.t -v
dbus-run-session -- pytest -v
docs:
runs-on: ubuntu-latest
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Expand Up @@ -8,3 +8,7 @@ build/
# Backup files done by uncrustify
.uncrustify/
*~

# tests
venv/
test/__pycache__/
27 changes: 27 additions & 0 deletions README.md
Expand Up @@ -81,8 +81,35 @@ Compile
cd build
cmake ..
make
cd ..
```

Test Suite
----------

Prepare test suite:

```shell
virtualenv -p python3 venv
source venv/bin/activate
python -m pip install --upgrade pip
pip install -r test-requirements.txt
```

Run hawkBit docker container:

```shell
docker pull hawkbit/hawkbit-update-server
docker run -d --name hawkbit -p 8080:8080 hawkbit/hawkbit-update-server
```

Run test suite:

```shell
./test/wait-for-hawkbit-online && dbus-run-session -- pytest -v
```

Pass `-o log_cli=true` to pytest in order to enable live logging for all test cases.

Usage / options
---------------
Expand Down
4 changes: 4 additions & 0 deletions pytest.ini
@@ -0,0 +1,4 @@
[pytest]
log_file_level = INFO
log_format = %(levelname)s %(name)s %(message)s
addopts = --show-capture=log -rs
1 change: 1 addition & 0 deletions test-requirements.txt
@@ -1,3 +1,4 @@
pytest
attrs
requests
pydbus
Expand Down
105 changes: 105 additions & 0 deletions test/conftest.py
@@ -0,0 +1,105 @@
# SPDX-License-Identifier: LGPL-2.1-only
# SPDX-FileCopyrightText: 2021 Enrico Jörns <e.joerns@pengutronix.de>, Pengutronix
# SPDX-FileCopyrightText: 2021 Bastian Krause <bst@pengutronix.de>, Pengutronix

import os
from configparser import ConfigParser

import pytest

from hawkbit_mgmt import HawkbitMgmtTestClient, HawkbitError

def pytest_addoption(parser):
"""Register custom argparse-style options."""
parser.addoption(
'--hawkbit-instance',
help='HOST:PORT of hawkBit instance to use (default: %(default)s)',
default='localhost:8080')

@pytest.fixture(scope='session')
def hawkbit(pytestconfig):
"""Instance of HawkbitMgmtTestClient connecting to a hawkBit instance."""
from uuid import uuid4

host, port = pytestconfig.option.hawkbit_instance.split(':')
client = HawkbitMgmtTestClient(host, int(port))

client.set_config('pollingTime', '00:00:30')
client.set_config('pollingOverdueTime', '00:03:00')
client.set_config('authentication.targettoken.enabled', True)
client.set_config('authentication.gatewaytoken.enabled', True)
client.set_config('authentication.gatewaytoken.key', uuid4().hex)

return client

@pytest.fixture
def hawkbit_target_added(hawkbit):
"""Creates a hawkBit target."""
target = hawkbit.add_target()
yield target

hawkbit.delete_target(target)

@pytest.fixture
def config(tmp_path, hawkbit, hawkbit_target_added):
"""
Creates a temporary rauc-hawkbit-updater configuration matching the hawkBit (target)
configuration of the hawkbit and hawkbit_target_added fixtures.
"""
target = hawkbit.get_target()
target_token = target.get('securityToken')
target_name = target.get('name')
bundle_location = tmp_path / 'bundle.raucb'

hawkbit_config = ConfigParser()
hawkbit_config['client'] = {
'hawkbit_server': f'{hawkbit.host}:{hawkbit.port}',
'ssl': 'false',
'ssl_verify': 'false',
'tenant_id': 'DEFAULT',
'target_name': target_name,
'auth_token': target_token,
'bundle_download_location': str(bundle_location),
'retry_wait': '60',
'connect_timeout': '20',
'timeout': '60',
'log_level': 'debug',
}
hawkbit_config['device'] = {
'product': 'Terminator',
'model': 'T-1000',
'serialnumber': '8922673153',
'hw_revision': '2',
'mac_address': 'ff:ff:ff:ff:ff:ff',
}

tmp_config = tmp_path / 'rauc-hawkbit-updater.conf'
with tmp_config.open('w') as f:
hawkbit_config.write(f)
return tmp_config

@pytest.fixture
def adjust_config(config):
"""
Adjusts the rauc-hawkbit-updater configuration created by the config fixture by
adding/overwriting or removing options.
"""
config_files = []
def _adjust_config(options={'client': {}}, remove={}):
adjusted_config = ConfigParser()
adjusted_config.read(config)

# update
for section, option in options.items():
for key, value in option.items():
adjusted_config.set(section, key, value)

# remove
for section, option in remove.items():
adjusted_config.remove_option(section, option)

with config.open('w') as f:
adjusted_config.write(f)
return config

return _adjust_config
1 change: 1 addition & 0 deletions test/hawkbit_mgmt.py
38 changes: 38 additions & 0 deletions test/helper.py
@@ -0,0 +1,38 @@
# SPDX-License-Identifier: LGPL-2.1-only
# SPDX-FileCopyrightText: 2021 Enrico Jörns <e.joerns@pengutronix.de>, Pengutronix
# SPDX-FileCopyrightText: 2021 Bastian Krause <bst@pengutronix.de>, Pengutronix

import os
import subprocess
import shlex
import logging


def run(command, *, timeout=30):
"""
Runs given command as subprocess with DBUS_STARTER_BUS_TYPE=session and PATH+=./build. Blocks
until command terminates. Logs command (with updated env) and its stdout/stderr/exit code.
Returns tuple (stdout, stderr, exit code).
"""
env = os.environ.copy()
env.update({'DBUS_STARTER_BUS_TYPE': 'session'})
env['PATH'] += f':{os.path.dirname(os.path.abspath(__file__))}/../build'

logger = logging.getLogger(command.split()[0])

log_env = [ f'{key}={value}' for key, value in set(env.items()) - set(os.environ.items()) ]
logger.info('running: %s %s', ' '.join(log_env), command)

proc = subprocess.run(shlex.split(command), capture_output=True, text=True, check=False,
env=env, timeout=timeout)

for line in proc.stdout.splitlines():
if line:
logger.info('stdout: %s', line)
for line in proc.stderr.splitlines():
if line:
logger.warning('stderr: %s', line)

logger.info('exitcode: %d', proc.returncode)

return proc.stdout, proc.stderr, proc.returncode
122 changes: 122 additions & 0 deletions test/test_basics.py
@@ -0,0 +1,122 @@
# SPDX-License-Identifier: LGPL-2.1-only
# SPDX-FileCopyrightText: 2021 Enrico Jörns <e.joerns@pengutronix.de>, Pengutronix
# SPDX-FileCopyrightText: 2021 Bastian Krause <bst@pengutronix.de>, Pengutronix

from configparser import ConfigParser

from helper import run

def test_version():
"""Test version argument."""
out, err, exitcode = run('rauc-hawkbit-updater -v')

assert exitcode == 0
assert out.startswith('Version ')
assert err == ''

def test_invalid_arg():
"""Test invalid argument."""
out, err, exitcode = run('rauc-hawkbit-updater --invalidarg')

assert exitcode == 1
assert out == ''
assert err.strip() == 'option parsing failed: Unknown option --invalidarg'

def test_config_unspecified():
"""Test call without config argument."""
out, err, exitcode = run('rauc-hawkbit-updater')

assert exitcode == 2
assert out == ''
assert err.strip() == 'No configuration file given'

def test_config_file_non_existent():
"""Test call with inexistent config file."""
out, err, exitcode = run('rauc-hawkbit-updater -c does-not-exist.conf')

assert exitcode == 3
assert out == ''
assert err.strip() == 'No such configuration file: does-not-exist.conf'

def test_config_no_auth_token(adjust_config):
"""Test config without auth_token option in client section."""
config = adjust_config(remove={'client': 'auth_token'})

out, err, exitcode = run(f'rauc-hawkbit-updater -c "{config}" -r')

assert exitcode == 4
assert out == ''
assert err.strip() == \
'Loading config file failed: Neither auth_token nor gateway_token is set in the config.'

def test_config_multiple_auth_methods(adjust_config):
"""Test config with auth_token and gateway_token options in client section."""
config = adjust_config({'client': {'gateway_token': 'wrong-gateway-token'}})

out, err, exitcode = run(f'rauc-hawkbit-updater -c "{config}" -r')

assert exitcode == 4
assert out == ''
assert err.strip() == \
'Loading config file failed: Both auth_token and gateway_token are set in the config.'

def test_register_and_check_invalid_gateway_token(adjust_config):
"""Test config with invalid gateway_token."""
config = adjust_config(
{'client': {'gateway_token': 'wrong-gateway-token'}},
remove={'client': 'auth_token'}
)

out, err, exitcode = run(f'rauc-hawkbit-updater -c "{config}" -r')

assert exitcode == 1
assert 'MESSAGE: Checking for new software...' in out
assert err.strip() == 'WARNING: Failed to authenticate. Check if gateway_token is correct?'

def test_register_and_check_valid_gateway_token(hawkbit, adjust_config):
"""Test config with valid gateway_token."""
gateway_token = hawkbit.get_config('authentication.gatewaytoken.key')
config = adjust_config(
{'client': {'gateway_token': gateway_token}},
remove={'client': 'auth_token'}
)

out, err, exitcode = run(f'rauc-hawkbit-updater -c "{config}" -r')

assert exitcode == 0
assert 'MESSAGE: Checking for new software...' in out
assert err == ''

def test_register_and_check_invalid_auth_token(adjust_config):
"""Test config with invalid auth_token."""
config = adjust_config({'client': {'auth_token': 'wrong-auth-token'}})

out, err, exitcode = run(f'rauc-hawkbit-updater -c "{config}" -r')

assert exitcode == 1
assert 'MESSAGE: Checking for new software...' in out
assert err.strip() == 'WARNING: Failed to authenticate. Check if auth_token is correct?'

def test_register_and_check_valid_auth_token(config):
"""Test config with valid auth_token."""
out, err, exitcode = run(f'rauc-hawkbit-updater -c "{config}" -r')

assert exitcode == 0
assert 'MESSAGE: Checking for new software...' in out
assert err == ''

def test_identify(hawkbit, config):
"""
Test that supplying target meta information works and information are received correctly by
hawkBit.
"""
out, err, exitcode = run(f'rauc-hawkbit-updater -c "{config}" -r')

assert exitcode == 0
assert 'Providing meta information to hawkbit server' in out
assert err == ''

ref_config = ConfigParser()
ref_config.read(config)

assert dict(ref_config.items('device')) == hawkbit.get_attributes()

0 comments on commit a5fc698

Please sign in to comment.