# Copyright (c) 2018 Foundries.io # Copyright (c) 2020 Nordic Semiconductor ASA # # SPDX-License-Identifier: Apache-2.0 import argparse import functools import io import os from pathlib import Path import shlex import shutil import typing from unittest.mock import patch, call import pytest from runners.nrfjprog import NrfJprogBinaryRunner from runners.nrfutil import NrfUtilBinaryRunner 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' TEST_TOOL_OPT = '--ip 192.168.1.10' TEST_TOOL_OPT_L = shlex.split(TEST_TOOL_OPT) # nRF53 flashing is special in that we have different results # depending on the input hex file. For that reason, we test it with # real hex files. TEST_DIR = Path(__file__).parent / 'nrf' NRF5340_APP_ONLY_HEX = os.fspath(TEST_DIR / 'nrf5340_app_only.hex') NRF5340_NET_ONLY_HEX = os.fspath(TEST_DIR / 'nrf5340_net_only.hex') NRF5340_APP_AND_NET_HEX = os.fspath(TEST_DIR / 'nrf5340_app_and_net.hex') CLASS_MAP = {'nrfjprog': NrfJprogBinaryRunner, 'nrfutil': NrfUtilBinaryRunner} # # A dictionary mapping test cases to expected results. # # The keys are TC objects. # # The values are usually tool commands we expect to be executed for # each test case. Verification is done by mocking the check_call() # ZephyrBinaryRunner method which is used to run the commands. # # Values can also be callables which take a tmpdir and return the # expected commands. This is needed for nRF53 testing. # class TC(typing.NamedTuple): # 'TestCase' # NRF51, NRF52, etc. family: str # 'APP', 'NET', 'APP+NET', or None. coprocessor: typing.Optional[str] # Run a recover command first if True recover: bool # Use --reset instead of --pinreset if True softreset: bool # --snr TEST_OVR_SNR if True, --snr TEST_DEF_SNR if False snr: bool # --chiperase if True, # --sectorerase if False (or --sectoranduicrerase on nRF52) erase: bool # --tool-opt TEST_TOOL_OPT if True tool_opt: bool EXPECTED_MAP = {'nrfjprog': 0, 'nrfutil': 1} EXPECTED_RESULTS = { # ------------------------------------------------------------------------- # NRF51 # # family CP recov soft snr erase tool_opt TC('NRF51_FAMILY', None, False, False, False, False, False): ((['nrfjprog', '--program', RC_KERNEL_HEX, '--sectorerase', '--verify', '-f', 'NRF51', '--snr', TEST_DEF_SNR], ['nrfjprog', '--pinreset', '-f', 'NRF51', '--snr', TEST_DEF_SNR]), (TEST_DEF_SNR, None)), TC('NRF51_FAMILY', None, False, False, False, True, False): ((['nrfjprog', '--program', RC_KERNEL_HEX, '--chiperase', '--verify', '-f', 'NRF51', '--snr', TEST_DEF_SNR], ['nrfjprog', '--pinreset', '-f', 'NRF51', '--snr', TEST_DEF_SNR]), (TEST_DEF_SNR, None)), TC('NRF51_FAMILY', None, False, False, True, False, False): ((['nrfjprog', '--program', RC_KERNEL_HEX, '--sectorerase', '--verify', '-f', 'NRF51', '--snr', TEST_OVR_SNR], ['nrfjprog', '--pinreset', '-f', 'NRF51', '--snr', TEST_OVR_SNR]), (TEST_OVR_SNR, None)), TC('NRF51_FAMILY', None, False, True, False, False, False): ((['nrfjprog', '--program', RC_KERNEL_HEX, '--sectorerase', '--verify', '-f', 'NRF51', '--snr', TEST_DEF_SNR], ['nrfjprog', '--reset', '-f', 'NRF51', '--snr', TEST_DEF_SNR]), (TEST_DEF_SNR, None)), TC('NRF51_FAMILY', None, True, False, False, False, False): ((['nrfjprog', '--recover', '-f', 'NRF51', '--snr', TEST_DEF_SNR], ['nrfjprog', '--program', RC_KERNEL_HEX, '--sectorerase', '--verify', '-f', 'NRF51', '--snr', TEST_DEF_SNR], ['nrfjprog', '--pinreset', '-f', 'NRF51', '--snr', TEST_DEF_SNR]), (TEST_DEF_SNR, None)), TC('NRF51_FAMILY', None, True, True, True, True, False): ((['nrfjprog', '--recover', '-f', 'NRF51', '--snr', TEST_OVR_SNR], ['nrfjprog', '--program', RC_KERNEL_HEX, '--chiperase', '--verify', '-f', 'NRF51', '--snr', TEST_OVR_SNR], ['nrfjprog', '--reset', '-f', 'NRF51', '--snr', TEST_OVR_SNR]), (TEST_OVR_SNR, None)), TC('NRF51_FAMILY', None, True, True, True, True, True): ((['nrfjprog', '--recover', '-f', 'NRF51', '--snr', TEST_OVR_SNR] + TEST_TOOL_OPT_L, ['nrfjprog', '--program', RC_KERNEL_HEX, '--chiperase', '--verify', '-f', 'NRF51', '--snr', TEST_OVR_SNR] + TEST_TOOL_OPT_L, ['nrfjprog', '--reset', '-f', 'NRF51', '--snr', TEST_OVR_SNR] + TEST_TOOL_OPT_L), (TEST_OVR_SNR, None)), # ------------------------------------------------------------------------- # NRF52 # # family CP recov soft snr erase tool_opt TC('NRF52_FAMILY', None, False, False, False, False, False): ((['nrfjprog', '--program', RC_KERNEL_HEX, '--sectoranduicrerase', '--verify', '-f', 'NRF52', '--snr', TEST_DEF_SNR], ['nrfjprog', '--pinresetenable', '-f', 'NRF52', '--snr', TEST_DEF_SNR], ['nrfjprog', '--pinreset', '-f', 'NRF52', '--snr', TEST_DEF_SNR]), (TEST_DEF_SNR, None)), TC('NRF52_FAMILY', None, False, False, False, True, False): ((['nrfjprog', '--program', RC_KERNEL_HEX, '--chiperase', '--verify', '-f', 'NRF52', '--snr', TEST_DEF_SNR], ['nrfjprog', '--pinresetenable', '-f', 'NRF52', '--snr', TEST_DEF_SNR], ['nrfjprog', '--pinreset', '-f', 'NRF52', '--snr', TEST_DEF_SNR]), (TEST_DEF_SNR, None)), TC('NRF52_FAMILY', None, False, False, True, False, False): ((['nrfjprog', '--program', RC_KERNEL_HEX, '--sectoranduicrerase', '--verify', '-f', 'NRF52', '--snr', TEST_OVR_SNR], ['nrfjprog', '--pinresetenable', '-f', 'NRF52', '--snr', TEST_OVR_SNR], ['nrfjprog', '--pinreset', '-f', 'NRF52', '--snr', TEST_OVR_SNR]), (TEST_OVR_SNR, None)), TC('NRF52_FAMILY', None, False, True, False, False, False): ((['nrfjprog', '--program', RC_KERNEL_HEX, '--sectoranduicrerase', '--verify', '-f', 'NRF52', '--snr', TEST_DEF_SNR], ['nrfjprog', '--reset', '-f', 'NRF52', '--snr', TEST_DEF_SNR]), (TEST_DEF_SNR, None)), TC('NRF52_FAMILY', None, True, False, False, False, False): ((['nrfjprog', '--recover', '-f', 'NRF52', '--snr', TEST_DEF_SNR], ['nrfjprog', '--program', RC_KERNEL_HEX, '--sectoranduicrerase', '--verify', '-f', 'NRF52', '--snr', TEST_DEF_SNR], ['nrfjprog', '--pinresetenable', '-f', 'NRF52', '--snr', TEST_DEF_SNR], ['nrfjprog', '--pinreset', '-f', 'NRF52', '--snr', TEST_DEF_SNR]), (TEST_DEF_SNR, None)), TC('NRF52_FAMILY', None, True, True, True, True, False): ((['nrfjprog', '--recover', '-f', 'NRF52', '--snr', TEST_OVR_SNR], ['nrfjprog', '--program', RC_KERNEL_HEX, '--chiperase', '--verify', '-f', 'NRF52', '--snr', TEST_OVR_SNR], ['nrfjprog', '--reset', '-f', 'NRF52', '--snr', TEST_OVR_SNR]), (TEST_OVR_SNR, None)), TC('NRF52_FAMILY', None, True, True, True, True, True): ((['nrfjprog', '--recover', '-f', 'NRF52', '--snr', TEST_OVR_SNR] + TEST_TOOL_OPT_L, ['nrfjprog', '--program', RC_KERNEL_HEX, '--chiperase', '--verify', '-f', 'NRF52', '--snr', TEST_OVR_SNR] + TEST_TOOL_OPT_L, ['nrfjprog', '--reset', '-f', 'NRF52', '--snr', TEST_OVR_SNR] + TEST_TOOL_OPT_L), (TEST_OVR_SNR, None)), # ------------------------------------------------------------------------- # NRF53 APP only # # family CP recov soft snr erase tool_opt TC('NRF53_FAMILY', 'APP', False, False, False, False, False): ((['nrfjprog', '--program', NRF5340_APP_ONLY_HEX, '--sectorerase', '--verify', '-f', 'NRF53', '--coprocessor', 'CP_APPLICATION', '--snr', TEST_DEF_SNR], ['nrfjprog', '--pinreset', '-f', 'NRF53', '--snr', TEST_DEF_SNR]), (TEST_DEF_SNR, None)), TC('NRF53_FAMILY', 'APP', False, False, False, True, False): ((['nrfjprog', '--program', NRF5340_APP_ONLY_HEX, '--chiperase', '--verify', '-f', 'NRF53', '--coprocessor', 'CP_APPLICATION', '--snr', TEST_DEF_SNR], ['nrfjprog', '--pinreset', '-f', 'NRF53', '--snr', TEST_DEF_SNR]), (TEST_DEF_SNR, None)), TC('NRF53_FAMILY', 'APP', False, False, True, False, False): ((['nrfjprog', '--program', NRF5340_APP_ONLY_HEX, '--sectorerase', '--verify', '-f', 'NRF53', '--coprocessor', 'CP_APPLICATION', '--snr', TEST_OVR_SNR], ['nrfjprog', '--pinreset', '-f', 'NRF53', '--snr', TEST_OVR_SNR]), (TEST_OVR_SNR, None)), TC('NRF53_FAMILY', 'APP', False, True, False, False, False): ((['nrfjprog', '--program', NRF5340_APP_ONLY_HEX, '--sectorerase', '--verify', '-f', 'NRF53', '--coprocessor', 'CP_APPLICATION', '--snr', TEST_DEF_SNR], ['nrfjprog', '--reset', '-f', 'NRF53', '--snr', TEST_DEF_SNR]), (TEST_DEF_SNR, None)), TC('NRF53_FAMILY', 'APP', True, False, False, False, False): ((['nrfjprog', '--recover', '-f', 'NRF53', '--coprocessor', 'CP_NETWORK', '--snr', TEST_DEF_SNR], ['nrfjprog', '--recover', '-f', 'NRF53', '--snr', TEST_DEF_SNR], ['nrfjprog', '--program', NRF5340_APP_ONLY_HEX, '--sectorerase', '--verify', '-f', 'NRF53', '--coprocessor', 'CP_APPLICATION', '--snr', TEST_DEF_SNR], ['nrfjprog', '--pinreset', '-f', 'NRF53', '--snr', TEST_DEF_SNR]), (TEST_DEF_SNR, None)), TC('NRF53_FAMILY', 'APP', True, True, True, True, False): ((['nrfjprog', '--recover', '-f', 'NRF53', '--coprocessor', 'CP_NETWORK', '--snr', TEST_OVR_SNR], ['nrfjprog', '--recover', '-f', 'NRF53', '--snr', TEST_OVR_SNR], ['nrfjprog', '--program', NRF5340_APP_ONLY_HEX, '--chiperase', '--verify', '-f', 'NRF53', '--coprocessor', 'CP_APPLICATION', '--snr', TEST_OVR_SNR], ['nrfjprog', '--reset', '-f', 'NRF53', '--snr', TEST_OVR_SNR]), (TEST_OVR_SNR, None)), # ------------------------------------------------------------------------- # NRF53 NET only # # family CP recov soft snr erase tool_opt TC('NRF53_FAMILY', 'NET', False, False, False, False, False): ((['nrfjprog', '--program', NRF5340_NET_ONLY_HEX, '--sectorerase', '--verify', '-f', 'NRF53', '--coprocessor', 'CP_NETWORK', '--snr', TEST_DEF_SNR], ['nrfjprog', '--pinreset', '-f', 'NRF53', '--snr', TEST_DEF_SNR]), (TEST_DEF_SNR, None)), TC('NRF53_FAMILY', 'NET', False, False, False, True, False): ((['nrfjprog', '--program', NRF5340_NET_ONLY_HEX, '--chiperase', '--verify', '-f', 'NRF53', '--coprocessor', 'CP_NETWORK', '--snr', TEST_DEF_SNR], ['nrfjprog', '--pinreset', '-f', 'NRF53', '--snr', TEST_DEF_SNR]), (TEST_DEF_SNR, None)), TC('NRF53_FAMILY', 'NET', False, False, True, False, False): ((['nrfjprog', '--program', NRF5340_NET_ONLY_HEX, '--sectorerase', '--verify', '-f', 'NRF53', '--coprocessor', 'CP_NETWORK', '--snr', TEST_OVR_SNR], ['nrfjprog', '--pinreset', '-f', 'NRF53', '--snr', TEST_OVR_SNR]), (TEST_OVR_SNR, None)), TC('NRF53_FAMILY', 'NET', False, True, False, False, False): ((['nrfjprog', '--program', NRF5340_NET_ONLY_HEX, '--sectorerase', '--verify', '-f', 'NRF53', '--coprocessor', 'CP_NETWORK', '--snr', TEST_DEF_SNR], ['nrfjprog', '--reset', '-f', 'NRF53', '--snr', TEST_DEF_SNR]), (TEST_DEF_SNR, None)), TC('NRF53_FAMILY', 'NET', True, False, False, False, False): ((['nrfjprog', '--recover', '-f', 'NRF53', '--coprocessor', 'CP_NETWORK', '--snr', TEST_DEF_SNR], ['nrfjprog', '--recover', '-f', 'NRF53', '--snr', TEST_DEF_SNR], ['nrfjprog', '--program', NRF5340_NET_ONLY_HEX, '--sectorerase', '--verify', '-f', 'NRF53', '--coprocessor', 'CP_NETWORK', '--snr', TEST_DEF_SNR], ['nrfjprog', '--pinreset', '-f', 'NRF53', '--snr', TEST_DEF_SNR]), (TEST_DEF_SNR, None)), TC('NRF53_FAMILY', 'NET', True, True, True, True, False): ((['nrfjprog', '--recover', '-f', 'NRF53', '--coprocessor', 'CP_NETWORK', '--snr', TEST_OVR_SNR], ['nrfjprog', '--recover', '-f', 'NRF53', '--snr', TEST_OVR_SNR], ['nrfjprog', '--program', NRF5340_NET_ONLY_HEX, '--chiperase', '--verify', '-f', 'NRF53', '--coprocessor', 'CP_NETWORK', '--snr', TEST_OVR_SNR], ['nrfjprog', '--reset', '-f', 'NRF53', '--snr', TEST_OVR_SNR]), (TEST_OVR_SNR, None)), # ------------------------------------------------------------------------- # NRF53 APP+NET # # family CP recov soft snr erase tool_opt TC('NRF53_FAMILY', 'APP+NET', False, False, False, False, False): ((lambda tmpdir, infile: \ (['nrfjprog', '--program', os.fspath(tmpdir / 'GENERATED_CP_NETWORK_' + Path(infile).name), '--sectorerase', '--verify', '-f', 'NRF53', '--coprocessor', 'CP_NETWORK', '--snr', TEST_DEF_SNR], ['nrfjprog', '--program', os.fspath(tmpdir / 'GENERATED_CP_APPLICATION_' + Path(infile).name), '--sectorerase', '--verify', '-f', 'NRF53', '--coprocessor', 'CP_APPLICATION', '--snr', TEST_DEF_SNR], ['nrfjprog', '--pinreset', '-f', 'NRF53', '--snr', TEST_DEF_SNR])), (TEST_DEF_SNR, None)), TC('NRF53_FAMILY', 'APP+NET', False, False, False, True, False): ((lambda tmpdir, infile: \ (['nrfjprog', '--program', os.fspath(tmpdir / 'GENERATED_CP_NETWORK_' + Path(infile).name), '--chiperase', '--verify', '-f', 'NRF53', '--coprocessor', 'CP_NETWORK', '--snr', TEST_DEF_SNR], ['nrfjprog', '--program', os.fspath(tmpdir / 'GENERATED_CP_APPLICATION_' + Path(infile).name), '--chiperase', '--verify', '-f', 'NRF53', '--coprocessor', 'CP_APPLICATION', '--snr', TEST_DEF_SNR], ['nrfjprog', '--pinreset', '-f', 'NRF53', '--snr', TEST_DEF_SNR])), (TEST_DEF_SNR, None)), TC('NRF53_FAMILY', 'APP+NET', False, False, True, False, False): ((lambda tmpdir, infile: \ (['nrfjprog', '--program', os.fspath(tmpdir / 'GENERATED_CP_NETWORK_' + Path(infile).name), '--sectorerase', '--verify', '-f', 'NRF53', '--coprocessor', 'CP_NETWORK', '--snr', TEST_OVR_SNR], ['nrfjprog', '--program', os.fspath(tmpdir / 'GENERATED_CP_APPLICATION_' + Path(infile).name), '--sectorerase', '--verify', '-f', 'NRF53', '--coprocessor', 'CP_APPLICATION', '--snr', TEST_OVR_SNR], ['nrfjprog', '--pinreset', '-f', 'NRF53', '--snr', TEST_OVR_SNR])), (TEST_OVR_SNR, None)), TC('NRF53_FAMILY', 'APP+NET', False, True, False, False, False): ((lambda tmpdir, infile: \ (['nrfjprog', '--program', os.fspath(tmpdir / 'GENERATED_CP_NETWORK_' + Path(infile).name), '--sectorerase', '--verify', '-f', 'NRF53', '--coprocessor', 'CP_NETWORK', '--snr', TEST_DEF_SNR], ['nrfjprog', '--program', os.fspath(tmpdir / 'GENERATED_CP_APPLICATION_' + Path(infile).name), '--sectorerase', '--verify', '-f', 'NRF53', '--coprocessor', 'CP_APPLICATION', '--snr', TEST_DEF_SNR], ['nrfjprog', '--reset', '-f', 'NRF53', '--snr', TEST_DEF_SNR])), (TEST_DEF_SNR, None)), TC('NRF53_FAMILY', 'APP+NET', True, False, False, False, False): ((lambda tmpdir, infile: \ (['nrfjprog', '--recover', '-f', 'NRF53', '--coprocessor', 'CP_NETWORK', '--snr', TEST_DEF_SNR], ['nrfjprog', '--recover', '-f', 'NRF53', '--snr', TEST_DEF_SNR], ['nrfjprog', '--program', os.fspath(tmpdir / 'GENERATED_CP_NETWORK_' + Path(infile).name), '--sectorerase', '--verify', '-f', 'NRF53', '--coprocessor', 'CP_NETWORK', '--snr', TEST_DEF_SNR], ['nrfjprog', '--program', os.fspath(tmpdir / 'GENERATED_CP_APPLICATION_' + Path(infile).name), '--sectorerase', '--verify', '-f', 'NRF53', '--coprocessor', 'CP_APPLICATION', '--snr', TEST_DEF_SNR], ['nrfjprog', '--pinreset', '-f', 'NRF53', '--snr', TEST_DEF_SNR])), (TEST_DEF_SNR, None)), TC('NRF53_FAMILY', 'APP+NET', True, True, True, True, False): ((lambda tmpdir, infile: \ (['nrfjprog', '--recover', '-f', 'NRF53', '--coprocessor', 'CP_NETWORK', '--snr', TEST_OVR_SNR], ['nrfjprog', '--recover', '-f', 'NRF53', '--snr', TEST_OVR_SNR], ['nrfjprog', '--program', os.fspath(tmpdir / 'GENERATED_CP_NETWORK_' + Path(infile).name), '--chiperase', '--verify', '-f', 'NRF53', '--coprocessor', 'CP_NETWORK', '--snr', TEST_OVR_SNR], ['nrfjprog', '--program', os.fspath(tmpdir / 'GENERATED_CP_APPLICATION_' + Path(infile).name), '--chiperase', '--verify', '-f', 'NRF53', '--coprocessor', 'CP_APPLICATION', '--snr', TEST_OVR_SNR], ['nrfjprog', '--reset', '-f', 'NRF53', '--snr', TEST_OVR_SNR])), (TEST_OVR_SNR, None)), TC('NRF53_FAMILY', 'APP+NET', True, True, True, True, True): ((lambda tmpdir, infile: \ (['nrfjprog', '--recover', '-f', 'NRF53', '--coprocessor', 'CP_NETWORK', '--snr', TEST_OVR_SNR] + TEST_TOOL_OPT_L, ['nrfjprog', '--recover', '-f', 'NRF53', '--snr', TEST_OVR_SNR] + TEST_TOOL_OPT_L, ['nrfjprog', '--program', os.fspath(tmpdir / 'GENERATED_CP_NETWORK_' + Path(infile).name), '--chiperase', '--verify', '-f', 'NRF53', '--coprocessor', 'CP_NETWORK', '--snr', TEST_OVR_SNR] + TEST_TOOL_OPT_L, ['nrfjprog', '--program', os.fspath(tmpdir / 'GENERATED_CP_APPLICATION_' + Path(infile).name), '--chiperase', '--verify', '-f', 'NRF53', '--coprocessor', 'CP_APPLICATION', '--snr', TEST_OVR_SNR] + TEST_TOOL_OPT_L, ['nrfjprog', '--reset', '-f', 'NRF53', '--snr', TEST_OVR_SNR] + TEST_TOOL_OPT_L)), (TEST_OVR_SNR, None)), # ------------------------------------------------------------------------- # NRF91 # # family CP recov soft snr erase tool_opt TC('NRF91_FAMILY', None, False, False, False, False, False): ((['nrfjprog', '--program', RC_KERNEL_HEX, '--sectorerase', '--verify', '-f', 'NRF91', '--snr', TEST_DEF_SNR], ['nrfjprog', '--pinreset', '-f', 'NRF91', '--snr', TEST_DEF_SNR]), (TEST_DEF_SNR, None)), TC('NRF91_FAMILY', None, False, False, False, True, False): ((['nrfjprog', '--program', RC_KERNEL_HEX, '--chiperase', '--verify', '-f', 'NRF91', '--snr', TEST_DEF_SNR], ['nrfjprog', '--pinreset', '-f', 'NRF91', '--snr', TEST_DEF_SNR]), (TEST_DEF_SNR, None)), TC('NRF91_FAMILY', None, False, False, True, False, False): ((['nrfjprog', '--program', RC_KERNEL_HEX, '--sectorerase', '--verify', '-f', 'NRF91', '--snr', TEST_OVR_SNR], ['nrfjprog', '--pinreset', '-f', 'NRF91', '--snr', TEST_OVR_SNR]), (TEST_OVR_SNR, None)), TC('NRF91_FAMILY', None, False, True, False, False, False): ((['nrfjprog', '--program', RC_KERNEL_HEX, '--sectorerase', '--verify', '-f', 'NRF91', '--snr', TEST_DEF_SNR], ['nrfjprog', '--reset', '-f', 'NRF91', '--snr', TEST_DEF_SNR]), (TEST_DEF_SNR, None)), TC('NRF91_FAMILY', None, True, False, False, False, False): ((['nrfjprog', '--recover', '-f', 'NRF91', '--snr', TEST_DEF_SNR], ['nrfjprog', '--program', RC_KERNEL_HEX, '--sectorerase', '--verify', '-f', 'NRF91', '--snr', TEST_DEF_SNR], ['nrfjprog', '--pinreset', '-f', 'NRF91', '--snr', TEST_DEF_SNR]), (TEST_DEF_SNR, None)), TC('NRF91_FAMILY', None, True, True, True, True, False): ((['nrfjprog', '--recover', '-f', 'NRF91', '--snr', TEST_OVR_SNR], ['nrfjprog', '--program', RC_KERNEL_HEX, '--chiperase', '--verify', '-f', 'NRF91', '--snr', TEST_OVR_SNR], ['nrfjprog', '--reset', '-f', 'NRF91', '--snr', TEST_OVR_SNR]), (TEST_OVR_SNR, None)), TC('NRF91_FAMILY', None, True, True, True, True, True): ((['nrfjprog', '--recover', '-f', 'NRF91', '--snr', TEST_OVR_SNR] + TEST_TOOL_OPT_L, ['nrfjprog', '--program', RC_KERNEL_HEX, '--chiperase', '--verify', '-f', 'NRF91', '--snr', TEST_OVR_SNR] + TEST_TOOL_OPT_L, ['nrfjprog', '--reset', '-f', 'NRF91', '--snr', TEST_OVR_SNR] + TEST_TOOL_OPT_L), (TEST_OVR_SNR, None)), } # # Monkey-patches # def get_board_snr_patch(glob): return TEST_DEF_SNR def require_patch(cur_tool, program): assert cur_tool == program os_path_isfile = os.path.isfile def os_path_isfile_patch(filename): if filename == RC_KERNEL_HEX: return True return os_path_isfile(filename) # # Test functions. # # These are white box tests that rely on the above monkey-patches. # def id_fn(test_case): if test_case.coprocessor is None: cp = '' else: cp = f'-{test_case.coprocessor}' s = 'soft_reset' if test_case.softreset else 'pin_reset' sn = 'default_snr' if test_case.snr else 'override_snr' e = 'chip_erase' if test_case.erase else 'sector[anduicr]_erase' r = 'recover' if test_case.recover else 'no_recover' t = 'tool_opt' if test_case.tool_opt else 'no_tool_opt' return f'{test_case.family[:5]}{cp}-{s}-{sn}-{e}-{r}-{t}' def fix_up_runner_config(test_case, runner_config, tmpdir): # Helper that adjusts the common runner_config fixture for our # nRF-specific tests. to_replace = {} # Provide a skeletal zephyr/.config file to use as the runner's # BuildConfiguration. zephyr = tmpdir / 'zephyr' zephyr.mkdir() dotconfig = os.fspath(zephyr / '.config') with open(dotconfig, 'w') as f: f.write(f''' CONFIG_SOC_SERIES_{test_case.family[:5]}X=y ''') to_replace['build_dir'] = tmpdir if test_case.family != 'NRF53_FAMILY': return runner_config._replace(**to_replace) if test_case.coprocessor == 'APP': to_replace['hex_file'] = NRF5340_APP_ONLY_HEX elif test_case.coprocessor == 'NET': to_replace['hex_file'] = NRF5340_NET_ONLY_HEX elif test_case.coprocessor == 'APP+NET': # Since the runner is going to generate files next to its input # file, we need to stash a copy in a tmpdir it can use. outfile = tmpdir / Path(NRF5340_APP_AND_NET_HEX).name shutil.copyfile(NRF5340_APP_AND_NET_HEX, outfile) to_replace['hex_file'] = os.fspath(outfile) else: assert False, f'bad test case {test_case}' return runner_config._replace(**to_replace) def check_expected(tool, test_case, check_fn, get_snr, tmpdir, runner_config): expected = EXPECTED_RESULTS[test_case][EXPECTED_MAP[tool]] if tool == 'nrfutil': assert len(check_fn.call_args_list) == 1 assert len(check_fn.call_args_list[0].args) == 1 # Extract filename nrfutil_args = check_fn.call_args_list[0].args[0] tmpfile = nrfutil_args[nrfutil_args.index('--batch-path') + 1] cmds = (['nrfutil', '--json', 'device', 'x-execute-batch', '--batch-path', tmpfile, '--serial-number', expected[0]],) call_args = [call(nrfutil_args)] else: cmds = expected call_args = check_fn.call_args_list if callable(cmds): assert (call_args == [call(x) for x in cmds(tmpdir, runner_config.hex_file)]) else: assert call_args == [call(x) for x in cmds] if not test_case.snr: get_snr.assert_called_once_with('*') else: get_snr.assert_not_called() @pytest.mark.parametrize('tool', ["nrfjprog","nrfutil"]) @pytest.mark.parametrize('test_case', EXPECTED_RESULTS.keys(), ids=id_fn) @patch('runners.core.ZephyrBinaryRunner.require') @patch('runners.nrfjprog.NrfBinaryRunner.get_board_snr', side_effect=get_board_snr_patch) @patch('runners.nrfutil.subprocess.Popen') @patch('runners.nrfjprog.NrfBinaryRunner.check_call') def test_init(check_call, popen, get_snr, require, tool, test_case, runner_config, tmpdir): popen.return_value.__enter__.return_value.stdout = io.BytesIO(b'') require.side_effect = functools.partial(require_patch, tool) runner_config = fix_up_runner_config(test_case, runner_config, tmpdir) snr = TEST_OVR_SNR if test_case.snr else None tool_opt = TEST_TOOL_OPT_L if test_case.tool_opt else [] cls = CLASS_MAP[tool] runner = cls(runner_config, test_case.family, test_case.softreset, snr, erase=test_case.erase, tool_opt=tool_opt, recover=test_case.recover) with patch('os.path.isfile', side_effect=os_path_isfile_patch): runner.run('flash') assert require.called CHECK_FN_MAP = {'nrfjprog': check_call, 'nrfutil': popen} check_expected(tool, test_case, CHECK_FN_MAP[tool], get_snr, tmpdir, runner_config) @pytest.mark.parametrize('tool', ["nrfjprog","nrfutil"]) @pytest.mark.parametrize('test_case', EXPECTED_RESULTS.keys(), ids=id_fn) @patch('runners.core.ZephyrBinaryRunner.require') @patch('runners.nrfjprog.NrfBinaryRunner.get_board_snr', side_effect=get_board_snr_patch) @patch('runners.nrfutil.subprocess.Popen') @patch('runners.nrfjprog.NrfBinaryRunner.check_call') def test_create(check_call, popen, get_snr, require, tool, test_case, runner_config, tmpdir): popen.return_value.__enter__.return_value.stdout = io.BytesIO(b'') require.side_effect = functools.partial(require_patch, tool) runner_config = fix_up_runner_config(test_case, runner_config, tmpdir) args = [] if test_case.softreset: args.append('--softreset') if test_case.snr: args.extend(['--dev-id', TEST_OVR_SNR]) if test_case.erase: args.append('--erase') if test_case.recover: args.append('--recover') if test_case.tool_opt: args.extend(['--tool-opt', TEST_TOOL_OPT]) parser = argparse.ArgumentParser(allow_abbrev=False) cls = CLASS_MAP[tool] cls.add_parser(parser) arg_namespace = parser.parse_args(args) runner = cls.create(runner_config, arg_namespace) with patch('os.path.isfile', side_effect=os_path_isfile_patch): runner.run('flash') assert require.called CHECK_FN_MAP = {'nrfjprog': check_call, 'nrfutil': popen} check_expected(tool, test_case, CHECK_FN_MAP[tool], get_snr, tmpdir, runner_config)