# Copyright (c) 2018 Foundries.io # Copyright (c) 2019 Nordic Semiconductor ASA. # # SPDX-License-Identifier: Apache-2.0 import argparse import os from unittest.mock import patch, call import pytest from runners.dfu import DfuUtilBinaryRunner, DfuSeConfig from conftest import RC_KERNEL_BIN DFU_UTIL = 'dfu-util' TEST_EXE = 'test-dfu-util' TEST_PID = '0000:9999' TEST_PID_RES = '-d,{}'.format(TEST_PID) TEST_ALT_INT = '1' TEST_ALT_STR = 'alt-name' TEST_BIN_NAME = 'test-img.bin' TEST_DFUSE_ADDR = 2 TEST_DFUSE_OPTS = 'test-dfuse-opt' TEST_DCFG_OPT = DfuSeConfig(address=TEST_DFUSE_ADDR, options='test-dfuse-opt') TEST_DCFG_OPT_RES = '{}:{}'.format(hex(TEST_DFUSE_ADDR), TEST_DFUSE_OPTS) TEST_DCFG_NOPT = DfuSeConfig(address=TEST_DFUSE_ADDR, options='') TEST_DCFG_NOPT_RES = '{}:'.format(hex(TEST_DFUSE_ADDR)) # A map from a test case to the expected dfu-util call. # Test cases are (alt, exe, img, dfuse) tuples. EXPECTED_COMMAND = { (DFU_UTIL, TEST_ALT_INT, None, RC_KERNEL_BIN): [DFU_UTIL, TEST_PID_RES, '-a', TEST_ALT_INT, '-D', RC_KERNEL_BIN], (DFU_UTIL, TEST_ALT_STR, None, RC_KERNEL_BIN): [DFU_UTIL, TEST_PID_RES, '-a', TEST_ALT_STR, '-D', RC_KERNEL_BIN], (TEST_EXE, TEST_ALT_INT, None, RC_KERNEL_BIN): [TEST_EXE, TEST_PID_RES, '-a', TEST_ALT_INT, '-D', RC_KERNEL_BIN], (DFU_UTIL, TEST_ALT_INT, None, TEST_BIN_NAME): [DFU_UTIL, TEST_PID_RES, '-a', TEST_ALT_INT, '-D', TEST_BIN_NAME], (DFU_UTIL, TEST_ALT_INT, TEST_DCFG_OPT, RC_KERNEL_BIN): [DFU_UTIL, TEST_PID_RES, '-s', TEST_DCFG_OPT_RES, '-a', TEST_ALT_INT, '-D', RC_KERNEL_BIN], (DFU_UTIL, TEST_ALT_INT, TEST_DCFG_NOPT, RC_KERNEL_BIN): [DFU_UTIL, TEST_PID_RES, '-s', TEST_DCFG_NOPT_RES, '-a', TEST_ALT_INT, '-D', RC_KERNEL_BIN], } def find_device_patch(): return True def require_patch(program): assert program in [DFU_UTIL, TEST_EXE] os_path_isfile = os.path.isfile def os_path_isfile_patch(filename): if filename == RC_KERNEL_BIN: return True return os_path_isfile(filename) def id_fn(tc): return 'exe={},alt={},dfuse_config={},img={}'.format(*tc) @pytest.mark.parametrize('tc', [ # (exe, alt, dfuse_config, img) (DFU_UTIL, TEST_ALT_INT, None, RC_KERNEL_BIN), (DFU_UTIL, TEST_ALT_STR, None, RC_KERNEL_BIN), (TEST_EXE, TEST_ALT_INT, None, RC_KERNEL_BIN), (DFU_UTIL, TEST_ALT_INT, None, TEST_BIN_NAME), (DFU_UTIL, TEST_ALT_INT, TEST_DCFG_OPT, RC_KERNEL_BIN), (DFU_UTIL, TEST_ALT_INT, TEST_DCFG_NOPT, RC_KERNEL_BIN), ], ids=id_fn) @patch('runners.dfu.DfuUtilBinaryRunner.find_device', side_effect=find_device_patch) @patch('runners.core.ZephyrBinaryRunner.require', side_effect=require_patch) @patch('runners.core.ZephyrBinaryRunner.check_call') def test_dfu_util_init(cc, req, find_device, tc, runner_config): '''Test commands using a runner created by constructor.''' exe, alt, dfuse_config, img = tc runner = DfuUtilBinaryRunner(runner_config, TEST_PID, alt, img, exe=exe, dfuse_config=dfuse_config) with patch('os.path.isfile', side_effect=os_path_isfile_patch): runner.run('flash') assert find_device.called assert req.call_args_list == [call(exe)] assert cc.call_args_list == [call(EXPECTED_COMMAND[tc])] def get_flash_address_patch(args, bcfg): return TEST_DFUSE_ADDR @pytest.mark.parametrize('tc', [ # arg spec: (exe, alt, dfuse, modifiers, img) (None, TEST_ALT_INT, False, None, None), (None, TEST_ALT_STR, False, None, None), (TEST_EXE, TEST_ALT_INT, False, None, None), (None, TEST_ALT_INT, False, None, TEST_BIN_NAME), (None, TEST_ALT_INT, True, TEST_DFUSE_OPTS, None), (None, TEST_ALT_INT, True, None, None), ], ids=id_fn) @patch('runners.dfu.DfuUtilBinaryRunner.find_device', side_effect=find_device_patch) @patch('runners.core.ZephyrBinaryRunner.get_flash_address', side_effect=get_flash_address_patch) @patch('runners.core.ZephyrBinaryRunner.require', side_effect=require_patch) @patch('runners.core.ZephyrBinaryRunner.check_call') def test_dfu_util_create(cc, req, gfa, find_device, tc, runner_config, tmpdir): '''Test commands using a runner created from command line parameters.''' exe, alt, dfuse, modifiers, img = tc args = ['--pid', TEST_PID, '--alt', alt] if img: args.extend(['--img', img]) if dfuse: args.append('--dfuse') if modifiers: args.extend(['--dfuse-modifiers', modifiers]) else: args.extend(['--dfuse-modifiers', '']) if exe: args.extend(['--dfu-util', exe]) (tmpdir / 'zephyr').mkdir() with open(os.fspath(tmpdir / 'zephyr' / '.config'), 'w') as f: f.write('\n') runner_config = runner_config._replace(build_dir=os.fspath(tmpdir)) parser = argparse.ArgumentParser(allow_abbrev=False) DfuUtilBinaryRunner.add_parser(parser) arg_namespace = parser.parse_args(args) runner = DfuUtilBinaryRunner.create(runner_config, arg_namespace) with patch('os.path.isfile', side_effect=os_path_isfile_patch): runner.run('flash') if dfuse: cfg = DfuSeConfig(address=TEST_DFUSE_ADDR, options=modifiers or '') else: cfg = None map_tc = (exe or DFU_UTIL, alt, cfg, img or RC_KERNEL_BIN) assert find_device.called assert req.call_args_list == [call(exe or DFU_UTIL)] assert cc.call_args_list == [call(EXPECTED_COMMAND[map_tc])]