zephyr/scripts/west_commands/tests/test_nrfjprog.py
Marti Bolivar ddce583ca2 scripts: west_commands: decouple runners pkg from west
I've had some requests to be able to use code in the runners package
without having west installed.

It turns out to be pretty easy to make this happen, as west is
currently only used for west.log and some trivial helper methods:

- To replace west log, use the standard logging module
- Add an appropriate handler for each runner's logger in
  run_common.py which delegates to west.log, to keep
  output working as expected.

Signed-off-by: Marti Bolivar <marti.bolivar@nordicsemi.no>
2019-06-26 01:25:54 +02:00

254 lines
9.7 KiB
Python

# Copyright (c) 2018 Foundries.io
#
# SPDX-License-Identifier: Apache-2.0
import argparse
from unittest.mock import patch, call
import pytest
from runners.nrfjprog import NrfJprogBinaryRunner
from conftest import RC_KERNEL_HEX
#
# Test values
#
TEST_DEF_SNR = 'test-default-serial-number' # for mocking user input
TEST_OVR_SNR = 'test-override-serial-number'
#
# Expected results.
#
# This dictionary maps different configurations to the commands we expect to be
# executed for them. Verification is done by mocking the check_call() method,
# which is used to run the commands.
#
# The key naming scheme is <F><SR><SN><E>, where:
#
# - F: family, 1 for 'NRF51' or 2 for 'NRF52'
# - SR: soft reset, Y for yes, N for pin reset
# - SNR: serial number override, Y for yes, N for 'use default'
# - E: full chip erase, Y for yes, N for sector / sector and UICR only
#
EXPECTED_COMMANDS = {
# NRF51:
'1NNN':
(['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF51', '--snr', TEST_DEF_SNR, '--sectorerase'], # noqa: E501
['nrfjprog', '--pinreset', '-f', 'NRF51', '--snr', TEST_DEF_SNR]),
'1NNY':
(['nrfjprog', '--eraseall', '-f', 'NRF51', '--snr', TEST_DEF_SNR],
['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF51', '--snr', TEST_DEF_SNR], # noqa: E501
['nrfjprog', '--pinreset', '-f', 'NRF51', '--snr', TEST_DEF_SNR]),
'1NYN':
(['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF51', '--snr', TEST_OVR_SNR, '--sectorerase'], # noqa: E501
['nrfjprog', '--pinreset', '-f', 'NRF51', '--snr', TEST_OVR_SNR]),
'1NYY':
(['nrfjprog', '--eraseall', '-f', 'NRF51', '--snr', TEST_OVR_SNR],
['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF51', '--snr', TEST_OVR_SNR], # noqa: E501
['nrfjprog', '--pinreset', '-f', 'NRF51', '--snr', TEST_OVR_SNR]),
'1YNN':
(['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF51', '--snr', TEST_DEF_SNR, '--sectorerase'], # noqa: E501
['nrfjprog', '--reset', '-f', 'NRF51', '--snr', TEST_DEF_SNR]),
'1YNY':
(['nrfjprog', '--eraseall', '-f', 'NRF51', '--snr', TEST_DEF_SNR],
['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF51', '--snr', TEST_DEF_SNR], # noqa: E501
['nrfjprog', '--reset', '-f', 'NRF51', '--snr', TEST_DEF_SNR]),
'1YYN':
(['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF51', '--snr', TEST_OVR_SNR, '--sectorerase'], # noqa: E501
['nrfjprog', '--reset', '-f', 'NRF51', '--snr', TEST_OVR_SNR]),
'1YYY':
(['nrfjprog', '--eraseall', '-f', 'NRF51', '--snr', TEST_OVR_SNR],
['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF51', '--snr', TEST_OVR_SNR], # noqa: E501
['nrfjprog', '--reset', '-f', 'NRF51', '--snr', TEST_OVR_SNR]),
# NRF52:
'2NNN':
(['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF52', '--snr', TEST_DEF_SNR, '--sectoranduicrerase'], # noqa: E501
['nrfjprog', '--pinresetenable', '-f', 'NRF52', '--snr', TEST_DEF_SNR],
['nrfjprog', '--pinreset', '-f', 'NRF52', '--snr', TEST_DEF_SNR]),
'2NNY':
(['nrfjprog', '--eraseall', '-f', 'NRF52', '--snr', TEST_DEF_SNR],
['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF52', '--snr', TEST_DEF_SNR], # noqa: E501
['nrfjprog', '--pinresetenable', '-f', 'NRF52', '--snr', TEST_DEF_SNR],
['nrfjprog', '--pinreset', '-f', 'NRF52', '--snr', TEST_DEF_SNR]),
'2NYN':
(['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF52', '--snr', TEST_OVR_SNR, '--sectoranduicrerase'], # noqa: E501
['nrfjprog', '--pinresetenable', '-f', 'NRF52', '--snr', TEST_OVR_SNR],
['nrfjprog', '--pinreset', '-f', 'NRF52', '--snr', TEST_OVR_SNR]),
'2NYY':
(['nrfjprog', '--eraseall', '-f', 'NRF52', '--snr', TEST_OVR_SNR],
['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF52', '--snr', TEST_OVR_SNR], # noqa: E501
['nrfjprog', '--pinresetenable', '-f', 'NRF52', '--snr', TEST_OVR_SNR],
['nrfjprog', '--pinreset', '-f', 'NRF52', '--snr', TEST_OVR_SNR]),
'2YNN':
(['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF52', '--snr', TEST_DEF_SNR, '--sectoranduicrerase'], # noqa: E501
['nrfjprog', '--reset', '-f', 'NRF52', '--snr', TEST_DEF_SNR]),
'2YNY':
(['nrfjprog', '--eraseall', '-f', 'NRF52', '--snr', TEST_DEF_SNR],
['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF52', '--snr', TEST_DEF_SNR], # noqa: E501
['nrfjprog', '--reset', '-f', 'NRF52', '--snr', TEST_DEF_SNR]),
'2YYN':
(['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF52', '--snr', TEST_OVR_SNR, '--sectoranduicrerase'], # noqa: E501
['nrfjprog', '--reset', '-f', 'NRF52', '--snr', TEST_OVR_SNR]),
'2YYY':
(['nrfjprog', '--eraseall', '-f', 'NRF52', '--snr', TEST_OVR_SNR],
['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF52', '--snr', TEST_OVR_SNR], # noqa: E501
['nrfjprog', '--reset', '-f', 'NRF52', '--snr', TEST_OVR_SNR]),
# NRF91:
'9NNN':
(['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF91', '--snr', TEST_DEF_SNR, '--sectorerase'], # noqa: E501
['nrfjprog', '--pinreset', '-f', 'NRF91', '--snr', TEST_DEF_SNR]),
'9NNY':
(['nrfjprog', '--eraseall', '-f', 'NRF91', '--snr', TEST_DEF_SNR],
['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF91', '--snr', TEST_DEF_SNR], # noqa: E501
['nrfjprog', '--pinreset', '-f', 'NRF91', '--snr', TEST_DEF_SNR]),
'9NYN':
(['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF91', '--snr', TEST_OVR_SNR, '--sectorerase'], # noqa: E501
['nrfjprog', '--pinreset', '-f', 'NRF91', '--snr', TEST_OVR_SNR]),
'9NYY':
(['nrfjprog', '--eraseall', '-f', 'NRF91', '--snr', TEST_OVR_SNR],
['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF91', '--snr', TEST_OVR_SNR], # noqa: E501
['nrfjprog', '--pinreset', '-f', 'NRF91', '--snr', TEST_OVR_SNR]),
'9YNN':
(['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF91', '--snr', TEST_DEF_SNR, '--sectorerase'], # noqa: E501
['nrfjprog', '--reset', '-f', 'NRF91', '--snr', TEST_DEF_SNR]),
'9YNY':
(['nrfjprog', '--eraseall', '-f', 'NRF91', '--snr', TEST_DEF_SNR],
['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF91', '--snr', TEST_DEF_SNR], # noqa: E501
['nrfjprog', '--reset', '-f', 'NRF91', '--snr', TEST_DEF_SNR]),
'9YYN':
(['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF91', '--snr', TEST_OVR_SNR, '--sectorerase'], # noqa: E501
['nrfjprog', '--reset', '-f', 'NRF91', '--snr', TEST_OVR_SNR]),
'9YYY':
(['nrfjprog', '--eraseall', '-f', 'NRF91', '--snr', TEST_OVR_SNR],
['nrfjprog', '--program', RC_KERNEL_HEX, '-f', 'NRF91', '--snr', TEST_OVR_SNR], # noqa: E501
['nrfjprog', '--reset', '-f', 'NRF91', '--snr', TEST_OVR_SNR]),
}
def expected_commands(family, softreset, snr, erase):
'''Expected NrfJprogBinaryRunner results given parameters.
Returns a factory function which expects the following arguments:
- family: string, 'NRF51', 'NRF52' or 'NRF91'
- softreset: boolean, controls whether soft reset is performed
- snr: string serial number of board, or None
- erase: boolean, whether to do a full chip erase or not
'''
expected_key = '{}{}{}{}'.format(
'1' if family == 'NRF51' else '2' if family == 'NRF52' else '9',
'Y' if softreset else 'N',
'Y' if snr else 'N',
'Y' if erase else 'N')
return EXPECTED_COMMANDS[expected_key]
#
# Test cases
#
TEST_CASES = [(f, sr, snr, e)
for f in ('NRF51', 'NRF52', 'NRF91')
for sr in (False, True)
for snr in (TEST_OVR_SNR, None)
for e in (False, True)]
def get_board_snr_patch():
return TEST_DEF_SNR
def require_patch(program):
assert program == 'nrfjprog'
def id_fn(test_case):
ret = ''
for x in test_case:
if x in ('NRF51', 'NRF52'):
ret += x[-1:]
else:
ret += 'Y' if x else 'N'
return ret
@pytest.mark.parametrize('test_case', TEST_CASES, ids=id_fn)
@patch('runners.core.ZephyrBinaryRunner.require', side_effect=require_patch)
@patch('runners.nrfjprog.NrfJprogBinaryRunner.get_board_snr_from_user',
side_effect=get_board_snr_patch)
@patch('runners.nrfjprog.NrfJprogBinaryRunner.check_call')
def test_nrfjprog_init(cc, get_snr, req, test_case, runner_config):
family, softreset, snr, erase = test_case
runner = NrfJprogBinaryRunner(runner_config, family, softreset, snr,
erase=erase)
if snr is None:
with pytest.raises(ValueError) as e:
runner.run('flash')
assert 'snr must not be None' in str(e)
else:
runner.run('flash')
assert req.called
assert cc.call_args_list == [call(x) for x in
expected_commands(*test_case)]
get_snr.assert_not_called()
@pytest.mark.parametrize('test_case', TEST_CASES, ids=id_fn)
@patch('runners.core.ZephyrBinaryRunner.require', side_effect=require_patch)
@patch('runners.nrfjprog.NrfJprogBinaryRunner.get_board_snr_from_user',
side_effect=get_board_snr_patch)
@patch('runners.nrfjprog.NrfJprogBinaryRunner.check_call')
def test_nrfjprog_create(cc, get_snr, req, test_case, runner_config):
family, softreset, snr, erase = test_case
args = ['--nrf-family', family]
if softreset:
args.append('--softreset')
if snr is not None:
args.extend(['--snr', snr])
if erase:
args.append('--erase')
parser = argparse.ArgumentParser()
NrfJprogBinaryRunner.add_parser(parser)
arg_namespace = parser.parse_args(args)
runner = NrfJprogBinaryRunner.create(runner_config, arg_namespace)
runner.run('flash')
assert req.called
assert cc.call_args_list == [call(x) for x in
expected_commands(*test_case)]
if snr is None:
get_snr.assert_called_once_with()
else:
get_snr.assert_not_called()