1# Copyright (c) 2018 Foundries.io 2# Copyright (c) 2019 Nordic Semiconductor ASA. 3# 4# SPDX-License-Identifier: Apache-2.0 5 6import argparse 7import os 8from unittest.mock import patch, call 9 10import pytest 11 12from runners.dfu import DfuUtilBinaryRunner, DfuSeConfig 13from conftest import RC_KERNEL_BIN 14 15DFU_UTIL = 'dfu-util' 16TEST_EXE = 'test-dfu-util' 17TEST_PID = '0000:9999' 18TEST_PID_RES = '-d,{}'.format(TEST_PID) 19TEST_ALT_INT = '1' 20TEST_ALT_STR = 'alt-name' 21TEST_BIN_NAME = 'test-img.bin' 22TEST_DFUSE_ADDR = 2 23TEST_DFUSE_OPTS = 'test-dfuse-opt' 24TEST_DCFG_OPT = DfuSeConfig(address=TEST_DFUSE_ADDR, options='test-dfuse-opt') 25TEST_DCFG_OPT_RES = '{}:{}'.format(hex(TEST_DFUSE_ADDR), TEST_DFUSE_OPTS) 26TEST_DCFG_NOPT = DfuSeConfig(address=TEST_DFUSE_ADDR, options='') 27TEST_DCFG_NOPT_RES = '{}:'.format(hex(TEST_DFUSE_ADDR)) 28# A map from a test case to the expected dfu-util call. 29# Test cases are (alt, exe, img, dfuse) tuples. 30EXPECTED_COMMAND = { 31 (DFU_UTIL, TEST_ALT_INT, None, RC_KERNEL_BIN): 32 [DFU_UTIL, TEST_PID_RES, '-a', TEST_ALT_INT, '-D', RC_KERNEL_BIN], 33 34 (DFU_UTIL, TEST_ALT_STR, None, RC_KERNEL_BIN): 35 [DFU_UTIL, TEST_PID_RES, '-a', TEST_ALT_STR, '-D', RC_KERNEL_BIN], 36 37 (TEST_EXE, TEST_ALT_INT, None, RC_KERNEL_BIN): 38 [TEST_EXE, TEST_PID_RES, '-a', TEST_ALT_INT, '-D', RC_KERNEL_BIN], 39 40 (DFU_UTIL, TEST_ALT_INT, None, TEST_BIN_NAME): 41 [DFU_UTIL, TEST_PID_RES, '-a', TEST_ALT_INT, '-D', TEST_BIN_NAME], 42 43 (DFU_UTIL, TEST_ALT_INT, TEST_DCFG_OPT, RC_KERNEL_BIN): 44 [DFU_UTIL, TEST_PID_RES, '-s', TEST_DCFG_OPT_RES, '-a', TEST_ALT_INT, 45 '-D', RC_KERNEL_BIN], 46 47 (DFU_UTIL, TEST_ALT_INT, TEST_DCFG_NOPT, RC_KERNEL_BIN): 48 [DFU_UTIL, TEST_PID_RES, '-s', TEST_DCFG_NOPT_RES, '-a', TEST_ALT_INT, 49 '-D', RC_KERNEL_BIN], 50} 51 52def find_device_patch(): 53 return True 54 55def require_patch(program): 56 assert program in [DFU_UTIL, TEST_EXE] 57 58os_path_isfile = os.path.isfile 59 60def os_path_isfile_patch(filename): 61 if filename == RC_KERNEL_BIN: 62 return True 63 return os_path_isfile(filename) 64 65def id_fn(tc): 66 return 'exe={},alt={},dfuse_config={},img={}'.format(*tc) 67 68@pytest.mark.parametrize('tc', [ 69 # (exe, alt, dfuse_config, img) 70 (DFU_UTIL, TEST_ALT_INT, None, RC_KERNEL_BIN), 71 (DFU_UTIL, TEST_ALT_STR, None, RC_KERNEL_BIN), 72 (TEST_EXE, TEST_ALT_INT, None, RC_KERNEL_BIN), 73 (DFU_UTIL, TEST_ALT_INT, None, TEST_BIN_NAME), 74 (DFU_UTIL, TEST_ALT_INT, TEST_DCFG_OPT, RC_KERNEL_BIN), 75 (DFU_UTIL, TEST_ALT_INT, TEST_DCFG_NOPT, RC_KERNEL_BIN), 76], ids=id_fn) 77@patch('runners.dfu.DfuUtilBinaryRunner.find_device', 78 side_effect=find_device_patch) 79@patch('runners.core.ZephyrBinaryRunner.require', side_effect=require_patch) 80@patch('runners.core.ZephyrBinaryRunner.check_call') 81def test_dfu_util_init(cc, req, find_device, tc, runner_config): 82 '''Test commands using a runner created by constructor.''' 83 exe, alt, dfuse_config, img = tc 84 runner = DfuUtilBinaryRunner(runner_config, TEST_PID, alt, img, exe=exe, 85 dfuse_config=dfuse_config) 86 with patch('os.path.isfile', side_effect=os_path_isfile_patch): 87 runner.run('flash') 88 assert find_device.called 89 assert req.called_with(exe) 90 assert cc.call_args_list == [call(EXPECTED_COMMAND[tc])] 91 92def get_flash_address_patch(args, bcfg): 93 return TEST_DFUSE_ADDR 94 95@pytest.mark.parametrize('tc', [ 96 # arg spec: (exe, alt, dfuse, modifiers, img) 97 (None, TEST_ALT_INT, False, None, None), 98 (None, TEST_ALT_STR, False, None, None), 99 (TEST_EXE, TEST_ALT_INT, False, None, None), 100 (None, TEST_ALT_INT, False, None, TEST_BIN_NAME), 101 (None, TEST_ALT_INT, True, TEST_DFUSE_OPTS, None), 102 (None, TEST_ALT_INT, True, None, None), 103 104], ids=id_fn) 105@patch('runners.dfu.DfuUtilBinaryRunner.find_device', 106 side_effect=find_device_patch) 107@patch('runners.core.ZephyrBinaryRunner.get_flash_address', 108 side_effect=get_flash_address_patch) 109@patch('runners.core.ZephyrBinaryRunner.require', side_effect=require_patch) 110@patch('runners.core.ZephyrBinaryRunner.check_call') 111def test_dfu_util_create(cc, req, gfa, find_device, tc, runner_config, tmpdir): 112 '''Test commands using a runner created from command line parameters.''' 113 exe, alt, dfuse, modifiers, img = tc 114 args = ['--pid', TEST_PID, '--alt', alt] 115 if img: 116 args.extend(['--img', img]) 117 if dfuse: 118 args.append('--dfuse') 119 if modifiers: 120 args.extend(['--dfuse-modifiers', modifiers]) 121 else: 122 args.extend(['--dfuse-modifiers', '']) 123 if exe: 124 args.extend(['--dfu-util', exe]) 125 126 (tmpdir / 'zephyr').mkdir() 127 with open(os.fspath(tmpdir / 'zephyr' / '.config'), 'w') as f: 128 f.write('\n') 129 runner_config = runner_config._replace(build_dir=os.fspath(tmpdir)) 130 131 parser = argparse.ArgumentParser() 132 DfuUtilBinaryRunner.add_parser(parser) 133 arg_namespace = parser.parse_args(args) 134 runner = DfuUtilBinaryRunner.create(runner_config, arg_namespace) 135 with patch('os.path.isfile', side_effect=os_path_isfile_patch): 136 runner.run('flash') 137 138 if dfuse: 139 cfg = DfuSeConfig(address=TEST_DFUSE_ADDR, options=modifiers or '') 140 else: 141 cfg = None 142 map_tc = (exe or DFU_UTIL, alt, cfg, img or RC_KERNEL_BIN) 143 assert find_device.called 144 assert req.called_with(exe) 145 assert cc.call_args_list == [call(EXPECTED_COMMAND[map_tc])] 146