1# Copyright (c) 2018 Foundries.io 2# Copyright (c) 2020 Nordic Semiconductor ASA 3# 4# SPDX-License-Identifier: Apache-2.0 5 6import argparse 7import functools 8import io 9import os 10from pathlib import Path 11import shlex 12import shutil 13import typing 14from unittest.mock import patch, call 15 16import pytest 17 18from runners.nrfjprog import NrfJprogBinaryRunner 19from runners.nrfutil import NrfUtilBinaryRunner 20from conftest import RC_KERNEL_HEX 21 22 23# 24# Test values 25# 26 27TEST_DEF_SNR = 'test-default-serial-number' # for mocking user input 28TEST_OVR_SNR = 'test-override-serial-number' 29 30TEST_TOOL_OPT = '--ip 192.168.1.10' 31TEST_TOOL_OPT_L = shlex.split(TEST_TOOL_OPT) 32 33# nRF53 flashing is special in that we have different results 34# depending on the input hex file. For that reason, we test it with 35# real hex files. 36TEST_DIR = Path(__file__).parent / 'nrf' 37NRF5340_APP_ONLY_HEX = os.fspath(TEST_DIR / 'nrf5340_app_only.hex') 38NRF5340_NET_ONLY_HEX = os.fspath(TEST_DIR / 'nrf5340_net_only.hex') 39NRF5340_APP_AND_NET_HEX = os.fspath(TEST_DIR / 'nrf5340_app_and_net.hex') 40 41CLASS_MAP = {'nrfjprog': NrfJprogBinaryRunner, 'nrfutil': NrfUtilBinaryRunner} 42 43# 44# A dictionary mapping test cases to expected results. 45# 46# The keys are TC objects. 47# 48# The values are usually tool commands we expect to be executed for 49# each test case. Verification is done by mocking the check_call() 50# ZephyrBinaryRunner method which is used to run the commands. 51# 52# Values can also be callables which take a tmpdir and return the 53# expected commands. This is needed for nRF53 testing. 54# 55 56class TC(typing.NamedTuple): # 'TestCase' 57 # NRF51, NRF52, etc. 58 family: str 59 60 # 'APP', 'NET', 'APP+NET', or None. 61 coprocessor: typing.Optional[str] 62 63 # Run a recover command first if True 64 recover: bool 65 66 # Use --reset instead of --pinreset if True 67 softreset: bool 68 69 # --snr TEST_OVR_SNR if True, --snr TEST_DEF_SNR if False 70 snr: bool 71 72 # --chiperase if True, 73 # --sectorerase if False (or --sectoranduicrerase on nRF52) 74 erase: bool 75 76 # --tool-opt TEST_TOOL_OPT if True 77 tool_opt: bool 78 79EXPECTED_MAP = {'nrfjprog': 0, 'nrfutil': 1} 80EXPECTED_RESULTS = { 81 82 # ------------------------------------------------------------------------- 83 # NRF51 84 # 85 # family CP recov soft snr erase tool_opt 86 TC('NRF51_FAMILY', None, False, False, False, False, False): 87 ((['nrfjprog', '--program', RC_KERNEL_HEX, '--sectorerase', '--verify', '-f', 'NRF51', 88 '--snr', TEST_DEF_SNR], 89 ['nrfjprog', '--pinreset', '-f', 'NRF51', '--snr', TEST_DEF_SNR]), 90 (TEST_DEF_SNR, None)), 91 92 TC('NRF51_FAMILY', None, False, False, False, True, False): 93 ((['nrfjprog', '--program', RC_KERNEL_HEX, '--chiperase', '--verify', '-f', 'NRF51', 94 '--snr', TEST_DEF_SNR], 95 ['nrfjprog', '--pinreset', '-f', 'NRF51', '--snr', TEST_DEF_SNR]), 96 (TEST_DEF_SNR, None)), 97 98 TC('NRF51_FAMILY', None, False, False, True, False, False): 99 ((['nrfjprog', '--program', RC_KERNEL_HEX, '--sectorerase', '--verify', '-f', 'NRF51', 100 '--snr', TEST_OVR_SNR], 101 ['nrfjprog', '--pinreset', '-f', 'NRF51', '--snr', TEST_OVR_SNR]), 102 (TEST_OVR_SNR, None)), 103 104 TC('NRF51_FAMILY', None, False, True, False, False, False): 105 ((['nrfjprog', '--program', RC_KERNEL_HEX, '--sectorerase', '--verify', '-f', 'NRF51', 106 '--snr', TEST_DEF_SNR], 107 ['nrfjprog', '--reset', '-f', 'NRF51', '--snr', TEST_DEF_SNR]), 108 (TEST_DEF_SNR, None)), 109 110 TC('NRF51_FAMILY', None, True, False, False, False, False): 111 ((['nrfjprog', '--recover', '-f', 'NRF51', '--snr', TEST_DEF_SNR], 112 ['nrfjprog', '--program', RC_KERNEL_HEX, '--sectorerase', '--verify', '-f', 'NRF51', 113 '--snr', TEST_DEF_SNR], 114 ['nrfjprog', '--pinreset', '-f', 'NRF51', '--snr', TEST_DEF_SNR]), 115 (TEST_DEF_SNR, None)), 116 117 TC('NRF51_FAMILY', None, True, True, True, True, False): 118 ((['nrfjprog', '--recover', '-f', 'NRF51', '--snr', TEST_OVR_SNR], 119 ['nrfjprog', '--program', RC_KERNEL_HEX, '--chiperase', '--verify', '-f', 'NRF51', 120 '--snr', TEST_OVR_SNR], 121 ['nrfjprog', '--reset', '-f', 'NRF51', '--snr', TEST_OVR_SNR]), 122 (TEST_OVR_SNR, None)), 123 124 TC('NRF51_FAMILY', None, True, True, True, True, True): 125 ((['nrfjprog', '--recover', '-f', 'NRF51', '--snr', TEST_OVR_SNR] + TEST_TOOL_OPT_L, 126 ['nrfjprog', '--program', RC_KERNEL_HEX, '--chiperase', '--verify', '-f', 'NRF51', 127 '--snr', TEST_OVR_SNR] + TEST_TOOL_OPT_L, 128 ['nrfjprog', '--reset', '-f', 'NRF51', '--snr', TEST_OVR_SNR] + TEST_TOOL_OPT_L), 129 (TEST_OVR_SNR, None)), 130 131 # ------------------------------------------------------------------------- 132 # NRF52 133 # 134 # family CP recov soft snr erase tool_opt 135 TC('NRF52_FAMILY', None, False, False, False, False, False): 136 ((['nrfjprog', '--program', RC_KERNEL_HEX, '--sectoranduicrerase', 137 '--verify', '-f', 'NRF52', '--snr', TEST_DEF_SNR], 138 ['nrfjprog', '--pinresetenable', '-f', 'NRF52', '--snr', TEST_DEF_SNR], 139 ['nrfjprog', '--pinreset', '-f', 'NRF52', '--snr', TEST_DEF_SNR]), 140 (TEST_DEF_SNR, None)), 141 142 TC('NRF52_FAMILY', None, False, False, False, True, False): 143 ((['nrfjprog', '--program', RC_KERNEL_HEX, '--chiperase', '--verify', '-f', 'NRF52', 144 '--snr', TEST_DEF_SNR], 145 ['nrfjprog', '--pinresetenable', '-f', 'NRF52', '--snr', TEST_DEF_SNR], 146 ['nrfjprog', '--pinreset', '-f', 'NRF52', '--snr', TEST_DEF_SNR]), 147 (TEST_DEF_SNR, None)), 148 149 TC('NRF52_FAMILY', None, False, False, True, False, False): 150 ((['nrfjprog', '--program', RC_KERNEL_HEX, '--sectoranduicrerase', 151 '--verify', '-f', 'NRF52', '--snr', TEST_OVR_SNR], 152 ['nrfjprog', '--pinresetenable', '-f', 'NRF52', '--snr', TEST_OVR_SNR], 153 ['nrfjprog', '--pinreset', '-f', 'NRF52', '--snr', TEST_OVR_SNR]), 154 (TEST_OVR_SNR, None)), 155 156 TC('NRF52_FAMILY', None, False, True, False, False, False): 157 ((['nrfjprog', '--program', RC_KERNEL_HEX, '--sectoranduicrerase', 158 '--verify', '-f', 'NRF52', '--snr', TEST_DEF_SNR], 159 ['nrfjprog', '--reset', '-f', 'NRF52', '--snr', TEST_DEF_SNR]), 160 (TEST_DEF_SNR, None)), 161 162 TC('NRF52_FAMILY', None, True, False, False, False, False): 163 ((['nrfjprog', '--recover', '-f', 'NRF52', '--snr', TEST_DEF_SNR], 164 ['nrfjprog', '--program', RC_KERNEL_HEX, '--sectoranduicrerase', 165 '--verify', '-f', 'NRF52', '--snr', TEST_DEF_SNR], 166 ['nrfjprog', '--pinresetenable', '-f', 'NRF52', '--snr', TEST_DEF_SNR], 167 ['nrfjprog', '--pinreset', '-f', 'NRF52', '--snr', TEST_DEF_SNR]), 168 (TEST_DEF_SNR, None)), 169 170 TC('NRF52_FAMILY', None, True, True, True, True, False): 171 ((['nrfjprog', '--recover', '-f', 'NRF52', '--snr', TEST_OVR_SNR], 172 ['nrfjprog', '--program', RC_KERNEL_HEX, '--chiperase', '--verify', '-f', 'NRF52', 173 '--snr', TEST_OVR_SNR], 174 ['nrfjprog', '--reset', '-f', 'NRF52', '--snr', TEST_OVR_SNR]), 175 (TEST_OVR_SNR, None)), 176 177 TC('NRF52_FAMILY', None, True, True, True, True, True): 178 ((['nrfjprog', '--recover', '-f', 'NRF52', '--snr', TEST_OVR_SNR] + TEST_TOOL_OPT_L, 179 ['nrfjprog', '--program', RC_KERNEL_HEX, '--chiperase', '--verify', '-f', 'NRF52', 180 '--snr', TEST_OVR_SNR] + TEST_TOOL_OPT_L, 181 ['nrfjprog', '--reset', '-f', 'NRF52', '--snr', TEST_OVR_SNR] + TEST_TOOL_OPT_L), 182 (TEST_OVR_SNR, None)), 183 184 # ------------------------------------------------------------------------- 185 # NRF53 APP only 186 # 187 # family CP recov soft snr erase tool_opt 188 TC('NRF53_FAMILY', 'APP', False, False, False, False, False): 189 ((['nrfjprog', '--program', NRF5340_APP_ONLY_HEX, '--sectorerase', 190 '--verify', '-f', 'NRF53', '--coprocessor', 'CP_APPLICATION', '--snr', TEST_DEF_SNR], 191 ['nrfjprog', '--pinreset', '-f', 'NRF53', '--snr', TEST_DEF_SNR]), 192 (TEST_DEF_SNR, None)), 193 194 TC('NRF53_FAMILY', 'APP', False, False, False, True, False): 195 ((['nrfjprog', '--program', NRF5340_APP_ONLY_HEX, '--chiperase', 196 '--verify', '-f', 'NRF53', '--coprocessor', 'CP_APPLICATION', '--snr', TEST_DEF_SNR], 197 ['nrfjprog', '--pinreset', '-f', 'NRF53', '--snr', TEST_DEF_SNR]), 198 (TEST_DEF_SNR, None)), 199 200 TC('NRF53_FAMILY', 'APP', False, False, True, False, False): 201 ((['nrfjprog', '--program', NRF5340_APP_ONLY_HEX, '--sectorerase', 202 '--verify', '-f', 'NRF53', '--coprocessor', 'CP_APPLICATION', '--snr', TEST_OVR_SNR], 203 ['nrfjprog', '--pinreset', '-f', 'NRF53', '--snr', TEST_OVR_SNR]), 204 (TEST_OVR_SNR, None)), 205 206 TC('NRF53_FAMILY', 'APP', False, True, False, False, False): 207 ((['nrfjprog', '--program', NRF5340_APP_ONLY_HEX, '--sectorerase', 208 '--verify', '-f', 'NRF53', '--coprocessor', 'CP_APPLICATION', '--snr', TEST_DEF_SNR], 209 ['nrfjprog', '--reset', '-f', 'NRF53', '--snr', TEST_DEF_SNR]), 210 (TEST_DEF_SNR, None)), 211 212 TC('NRF53_FAMILY', 'APP', True, False, False, False, False): 213 ((['nrfjprog', '--recover', '-f', 'NRF53', '--coprocessor', 'CP_NETWORK', 214 '--snr', TEST_DEF_SNR], 215 ['nrfjprog', '--recover', '-f', 'NRF53', '--snr', TEST_DEF_SNR], 216 ['nrfjprog', '--program', NRF5340_APP_ONLY_HEX, '--sectorerase', 217 '--verify', '-f', 'NRF53', '--coprocessor', 'CP_APPLICATION', '--snr', TEST_DEF_SNR], 218 ['nrfjprog', '--pinreset', '-f', 'NRF53', '--snr', TEST_DEF_SNR]), 219 (TEST_DEF_SNR, None)), 220 221 TC('NRF53_FAMILY', 'APP', True, True, True, True, False): 222 ((['nrfjprog', '--recover', '-f', 'NRF53', '--coprocessor', 'CP_NETWORK', 223 '--snr', TEST_OVR_SNR], 224 ['nrfjprog', '--recover', '-f', 'NRF53', '--snr', TEST_OVR_SNR], 225 ['nrfjprog', '--program', NRF5340_APP_ONLY_HEX, '--chiperase', 226 '--verify', '-f', 'NRF53', '--coprocessor', 'CP_APPLICATION', '--snr', TEST_OVR_SNR], 227 ['nrfjprog', '--reset', '-f', 'NRF53', '--snr', TEST_OVR_SNR]), 228 (TEST_OVR_SNR, None)), 229 230 # ------------------------------------------------------------------------- 231 # NRF53 NET only 232 # 233 # family CP recov soft snr erase tool_opt 234 TC('NRF53_FAMILY', 'NET', False, False, False, False, False): 235 ((['nrfjprog', '--program', NRF5340_NET_ONLY_HEX, '--sectorerase', 236 '--verify', '-f', 'NRF53', '--coprocessor', 'CP_NETWORK', '--snr', TEST_DEF_SNR], 237 ['nrfjprog', '--pinreset', '-f', 'NRF53', '--snr', TEST_DEF_SNR]), 238 (TEST_DEF_SNR, None)), 239 240 TC('NRF53_FAMILY', 'NET', False, False, False, True, False): 241 ((['nrfjprog', '--program', NRF5340_NET_ONLY_HEX, '--chiperase', 242 '--verify', '-f', 'NRF53', '--coprocessor', 'CP_NETWORK', '--snr', TEST_DEF_SNR], 243 ['nrfjprog', '--pinreset', '-f', 'NRF53', '--snr', TEST_DEF_SNR]), 244 (TEST_DEF_SNR, None)), 245 246 TC('NRF53_FAMILY', 'NET', False, False, True, False, False): 247 ((['nrfjprog', '--program', NRF5340_NET_ONLY_HEX, '--sectorerase', 248 '--verify', '-f', 'NRF53', '--coprocessor', 'CP_NETWORK', '--snr', TEST_OVR_SNR], 249 ['nrfjprog', '--pinreset', '-f', 'NRF53', '--snr', TEST_OVR_SNR]), 250 (TEST_OVR_SNR, None)), 251 252 TC('NRF53_FAMILY', 'NET', False, True, False, False, False): 253 ((['nrfjprog', '--program', NRF5340_NET_ONLY_HEX, '--sectorerase', 254 '--verify', '-f', 'NRF53', '--coprocessor', 'CP_NETWORK', '--snr', TEST_DEF_SNR], 255 ['nrfjprog', '--reset', '-f', 'NRF53', '--snr', TEST_DEF_SNR]), 256 (TEST_DEF_SNR, None)), 257 258 TC('NRF53_FAMILY', 'NET', True, False, False, False, False): 259 ((['nrfjprog', '--recover', '-f', 'NRF53', '--coprocessor', 'CP_NETWORK', 260 '--snr', TEST_DEF_SNR], 261 ['nrfjprog', '--recover', '-f', 'NRF53', '--snr', TEST_DEF_SNR], 262 ['nrfjprog', '--program', NRF5340_NET_ONLY_HEX, '--sectorerase', 263 '--verify', '-f', 'NRF53', '--coprocessor', 'CP_NETWORK', '--snr', TEST_DEF_SNR], 264 ['nrfjprog', '--pinreset', '-f', 'NRF53', '--snr', TEST_DEF_SNR]), 265 (TEST_DEF_SNR, None)), 266 267 TC('NRF53_FAMILY', 'NET', True, True, True, True, False): 268 ((['nrfjprog', '--recover', '-f', 'NRF53', '--coprocessor', 'CP_NETWORK', 269 '--snr', TEST_OVR_SNR], 270 ['nrfjprog', '--recover', '-f', 'NRF53', '--snr', TEST_OVR_SNR], 271 ['nrfjprog', '--program', NRF5340_NET_ONLY_HEX, '--chiperase', 272 '--verify', '-f', 'NRF53', '--coprocessor', 'CP_NETWORK', '--snr', TEST_OVR_SNR], 273 ['nrfjprog', '--reset', '-f', 'NRF53', '--snr', TEST_OVR_SNR]), 274 (TEST_OVR_SNR, None)), 275 276 # ------------------------------------------------------------------------- 277 # NRF53 APP+NET 278 # 279 # family CP recov soft snr erase tool_opt 280 TC('NRF53_FAMILY', 'APP+NET', False, False, False, False, False): 281 ((lambda tmpdir, infile: \ 282 (['nrfjprog', 283 '--program', 284 os.fspath(tmpdir / 'GENERATED_CP_NETWORK_' + Path(infile).name), 285 '--sectorerase', '--verify', '-f', 'NRF53', 286 '--coprocessor', 'CP_NETWORK', '--snr', TEST_DEF_SNR], 287 ['nrfjprog', 288 '--program', 289 os.fspath(tmpdir / 'GENERATED_CP_APPLICATION_' + Path(infile).name), 290 '--sectorerase', '--verify', '-f', 'NRF53', 291 '--coprocessor', 'CP_APPLICATION', '--snr', TEST_DEF_SNR], 292 ['nrfjprog', '--pinreset', '-f', 'NRF53', '--snr', TEST_DEF_SNR])), 293 (TEST_DEF_SNR, None)), 294 295 TC('NRF53_FAMILY', 'APP+NET', False, False, False, True, False): 296 ((lambda tmpdir, infile: \ 297 (['nrfjprog', 298 '--program', 299 os.fspath(tmpdir / 'GENERATED_CP_NETWORK_' + Path(infile).name), 300 '--chiperase', '--verify', '-f', 'NRF53', 301 '--coprocessor', 'CP_NETWORK', '--snr', TEST_DEF_SNR], 302 ['nrfjprog', 303 '--program', 304 os.fspath(tmpdir / 'GENERATED_CP_APPLICATION_' + Path(infile).name), 305 '--chiperase', '--verify', '-f', 'NRF53', 306 '--coprocessor', 'CP_APPLICATION', '--snr', TEST_DEF_SNR], 307 ['nrfjprog', '--pinreset', '-f', 'NRF53', '--snr', TEST_DEF_SNR])), 308 (TEST_DEF_SNR, None)), 309 310 TC('NRF53_FAMILY', 'APP+NET', False, False, True, False, False): 311 ((lambda tmpdir, infile: \ 312 (['nrfjprog', 313 '--program', 314 os.fspath(tmpdir / 'GENERATED_CP_NETWORK_' + Path(infile).name), 315 '--sectorerase', '--verify', '-f', 'NRF53', 316 '--coprocessor', 'CP_NETWORK', '--snr', TEST_OVR_SNR], 317 ['nrfjprog', 318 '--program', 319 os.fspath(tmpdir / 'GENERATED_CP_APPLICATION_' + Path(infile).name), 320 '--sectorerase', '--verify', '-f', 'NRF53', 321 '--coprocessor', 'CP_APPLICATION', '--snr', TEST_OVR_SNR], 322 ['nrfjprog', '--pinreset', '-f', 'NRF53', '--snr', TEST_OVR_SNR])), 323 (TEST_OVR_SNR, None)), 324 325 TC('NRF53_FAMILY', 'APP+NET', False, True, False, False, False): 326 ((lambda tmpdir, infile: \ 327 (['nrfjprog', 328 '--program', 329 os.fspath(tmpdir / 'GENERATED_CP_NETWORK_' + Path(infile).name), 330 '--sectorerase', '--verify', '-f', 'NRF53', 331 '--coprocessor', 'CP_NETWORK', '--snr', TEST_DEF_SNR], 332 ['nrfjprog', 333 '--program', 334 os.fspath(tmpdir / 'GENERATED_CP_APPLICATION_' + Path(infile).name), 335 '--sectorerase', '--verify', '-f', 'NRF53', 336 '--coprocessor', 'CP_APPLICATION', '--snr', TEST_DEF_SNR], 337 ['nrfjprog', '--reset', '-f', 'NRF53', '--snr', TEST_DEF_SNR])), 338 (TEST_DEF_SNR, None)), 339 340 TC('NRF53_FAMILY', 'APP+NET', True, False, False, False, False): 341 ((lambda tmpdir, infile: \ 342 (['nrfjprog', '--recover', '-f', 'NRF53', '--coprocessor', 'CP_NETWORK', 343 '--snr', TEST_DEF_SNR], 344 ['nrfjprog', '--recover', '-f', 'NRF53', '--snr', TEST_DEF_SNR], 345 ['nrfjprog', 346 '--program', 347 os.fspath(tmpdir / 'GENERATED_CP_NETWORK_' + Path(infile).name), 348 '--sectorerase', '--verify', '-f', 'NRF53', 349 '--coprocessor', 'CP_NETWORK', '--snr', TEST_DEF_SNR], 350 ['nrfjprog', 351 '--program', 352 os.fspath(tmpdir / 'GENERATED_CP_APPLICATION_' + Path(infile).name), 353 '--sectorerase', '--verify', '-f', 'NRF53', 354 '--coprocessor', 'CP_APPLICATION', '--snr', TEST_DEF_SNR], 355 ['nrfjprog', '--pinreset', '-f', 'NRF53', '--snr', TEST_DEF_SNR])), 356 (TEST_DEF_SNR, None)), 357 358 TC('NRF53_FAMILY', 'APP+NET', True, True, True, True, False): 359 ((lambda tmpdir, infile: \ 360 (['nrfjprog', '--recover', '-f', 'NRF53', '--coprocessor', 'CP_NETWORK', 361 '--snr', TEST_OVR_SNR], 362 ['nrfjprog', '--recover', '-f', 'NRF53', '--snr', TEST_OVR_SNR], 363 ['nrfjprog', 364 '--program', 365 os.fspath(tmpdir / 'GENERATED_CP_NETWORK_' + Path(infile).name), 366 '--chiperase', '--verify', '-f', 'NRF53', 367 '--coprocessor', 'CP_NETWORK', '--snr', TEST_OVR_SNR], 368 ['nrfjprog', 369 '--program', 370 os.fspath(tmpdir / 'GENERATED_CP_APPLICATION_' + Path(infile).name), 371 '--chiperase', '--verify', '-f', 'NRF53', 372 '--coprocessor', 'CP_APPLICATION', '--snr', TEST_OVR_SNR], 373 ['nrfjprog', '--reset', '-f', 'NRF53', '--snr', TEST_OVR_SNR])), 374 (TEST_OVR_SNR, None)), 375 376 TC('NRF53_FAMILY', 'APP+NET', True, True, True, True, True): 377 ((lambda tmpdir, infile: \ 378 (['nrfjprog', '--recover', '-f', 'NRF53', '--coprocessor', 'CP_NETWORK', 379 '--snr', TEST_OVR_SNR] + TEST_TOOL_OPT_L, 380 ['nrfjprog', '--recover', '-f', 'NRF53', '--snr', TEST_OVR_SNR] + TEST_TOOL_OPT_L, 381 ['nrfjprog', 382 '--program', 383 os.fspath(tmpdir / 'GENERATED_CP_NETWORK_' + Path(infile).name), 384 '--chiperase', '--verify', '-f', 'NRF53', 385 '--coprocessor', 'CP_NETWORK', '--snr', TEST_OVR_SNR] + TEST_TOOL_OPT_L, 386 ['nrfjprog', 387 '--program', 388 os.fspath(tmpdir / 'GENERATED_CP_APPLICATION_' + Path(infile).name), 389 '--chiperase', '--verify', '-f', 'NRF53', 390 '--coprocessor', 'CP_APPLICATION', '--snr', TEST_OVR_SNR] + TEST_TOOL_OPT_L, 391 ['nrfjprog', '--reset', '-f', 'NRF53', '--snr', TEST_OVR_SNR] + TEST_TOOL_OPT_L)), 392 (TEST_OVR_SNR, None)), 393 394 395 # ------------------------------------------------------------------------- 396 # NRF91 397 # 398 # family CP recov soft snr erase tool_opt 399 TC('NRF91_FAMILY', None, False, False, False, False, False): 400 ((['nrfjprog', '--program', RC_KERNEL_HEX, '--sectorerase', '--verify', '-f', 'NRF91', 401 '--snr', TEST_DEF_SNR], 402 ['nrfjprog', '--pinreset', '-f', 'NRF91', '--snr', TEST_DEF_SNR]), 403 (TEST_DEF_SNR, None)), 404 405 TC('NRF91_FAMILY', None, False, False, False, True, False): 406 ((['nrfjprog', '--program', RC_KERNEL_HEX, '--chiperase', '--verify', '-f', 'NRF91', 407 '--snr', TEST_DEF_SNR], 408 ['nrfjprog', '--pinreset', '-f', 'NRF91', '--snr', TEST_DEF_SNR]), 409 (TEST_DEF_SNR, None)), 410 411 TC('NRF91_FAMILY', None, False, False, True, False, False): 412 ((['nrfjprog', '--program', RC_KERNEL_HEX, '--sectorerase', '--verify', '-f', 'NRF91', 413 '--snr', TEST_OVR_SNR], 414 ['nrfjprog', '--pinreset', '-f', 'NRF91', '--snr', TEST_OVR_SNR]), 415 (TEST_OVR_SNR, None)), 416 417 TC('NRF91_FAMILY', None, False, True, False, False, False): 418 ((['nrfjprog', '--program', RC_KERNEL_HEX, '--sectorerase', '--verify', '-f', 'NRF91', 419 '--snr', TEST_DEF_SNR], 420 ['nrfjprog', '--reset', '-f', 'NRF91', '--snr', TEST_DEF_SNR]), 421 (TEST_DEF_SNR, None)), 422 423 TC('NRF91_FAMILY', None, True, False, False, False, False): 424 ((['nrfjprog', '--recover', '-f', 'NRF91', '--snr', TEST_DEF_SNR], 425 ['nrfjprog', '--program', RC_KERNEL_HEX, '--sectorerase', '--verify', '-f', 'NRF91', 426 '--snr', TEST_DEF_SNR], 427 ['nrfjprog', '--pinreset', '-f', 'NRF91', '--snr', TEST_DEF_SNR]), 428 (TEST_DEF_SNR, None)), 429 430 TC('NRF91_FAMILY', None, True, True, True, True, False): 431 ((['nrfjprog', '--recover', '-f', 'NRF91', '--snr', TEST_OVR_SNR], 432 ['nrfjprog', '--program', RC_KERNEL_HEX, '--chiperase', '--verify', '-f', 'NRF91', 433 '--snr', TEST_OVR_SNR], 434 ['nrfjprog', '--reset', '-f', 'NRF91', '--snr', TEST_OVR_SNR]), 435 (TEST_OVR_SNR, None)), 436 437 TC('NRF91_FAMILY', None, True, True, True, True, True): 438 ((['nrfjprog', '--recover', '-f', 'NRF91', '--snr', TEST_OVR_SNR] + TEST_TOOL_OPT_L, 439 ['nrfjprog', '--program', RC_KERNEL_HEX, '--chiperase', '--verify', '-f', 'NRF91', 440 '--snr', TEST_OVR_SNR] + TEST_TOOL_OPT_L, 441 ['nrfjprog', '--reset', '-f', 'NRF91', '--snr', TEST_OVR_SNR] + TEST_TOOL_OPT_L), 442 (TEST_OVR_SNR, None)), 443} 444 445# 446# Monkey-patches 447# 448 449def get_board_snr_patch(glob): 450 return TEST_DEF_SNR 451 452def require_patch(cur_tool, program): 453 assert cur_tool == program 454 455os_path_isfile = os.path.isfile 456 457def os_path_isfile_patch(filename): 458 if filename == RC_KERNEL_HEX: 459 return True 460 return os_path_isfile(filename) 461 462# 463# Test functions. 464# 465# These are white box tests that rely on the above monkey-patches. 466# 467 468def id_fn(test_case): 469 if test_case.coprocessor is None: 470 cp = '' 471 else: 472 cp = f'-{test_case.coprocessor}' 473 s = 'soft_reset' if test_case.softreset else 'pin_reset' 474 sn = 'default_snr' if test_case.snr else 'override_snr' 475 e = 'chip_erase' if test_case.erase else 'sector[anduicr]_erase' 476 r = 'recover' if test_case.recover else 'no_recover' 477 t = 'tool_opt' if test_case.tool_opt else 'no_tool_opt' 478 479 return f'{test_case.family[:5]}{cp}-{s}-{sn}-{e}-{r}-{t}' 480 481def fix_up_runner_config(test_case, runner_config, tmpdir): 482 # Helper that adjusts the common runner_config fixture for our 483 # nRF-specific tests. 484 485 to_replace = {} 486 487 # Provide a skeletal zephyr/.config file to use as the runner's 488 # BuildConfiguration. 489 zephyr = tmpdir / 'zephyr' 490 zephyr.mkdir() 491 dotconfig = os.fspath(zephyr / '.config') 492 with open(dotconfig, 'w') as f: 493 f.write(f''' 494CONFIG_SOC_SERIES_{test_case.family[:5]}X=y 495''') 496 to_replace['build_dir'] = tmpdir 497 498 if test_case.family != 'NRF53_FAMILY': 499 return runner_config._replace(**to_replace) 500 501 if test_case.coprocessor == 'APP': 502 to_replace['hex_file'] = NRF5340_APP_ONLY_HEX 503 elif test_case.coprocessor == 'NET': 504 to_replace['hex_file'] = NRF5340_NET_ONLY_HEX 505 elif test_case.coprocessor == 'APP+NET': 506 # Since the runner is going to generate files next to its input 507 # file, we need to stash a copy in a tmpdir it can use. 508 outfile = tmpdir / Path(NRF5340_APP_AND_NET_HEX).name 509 shutil.copyfile(NRF5340_APP_AND_NET_HEX, outfile) 510 to_replace['hex_file'] = os.fspath(outfile) 511 else: 512 assert False, f'bad test case {test_case}' 513 514 return runner_config._replace(**to_replace) 515 516def check_expected(tool, test_case, check_fn, get_snr, tmpdir, runner_config): 517 518 expected = EXPECTED_RESULTS[test_case][EXPECTED_MAP[tool]] 519 if tool == 'nrfutil': 520 assert len(check_fn.call_args_list) == 1 521 assert len(check_fn.call_args_list[0].args) == 1 522 # Extract filename 523 nrfutil_args = check_fn.call_args_list[0].args[0] 524 tmpfile = nrfutil_args[nrfutil_args.index('--batch-path') + 1] 525 cmds = (['nrfutil', '--json', 'device', 'x-execute-batch', '--batch-path', 526 tmpfile, '--serial-number', expected[0]],) 527 call_args = [call(nrfutil_args)] 528 else: 529 cmds = expected 530 call_args = check_fn.call_args_list 531 532 if callable(cmds): 533 assert (call_args == 534 [call(x) for x in cmds(tmpdir, runner_config.hex_file)]) 535 else: 536 assert call_args == [call(x) for x in cmds] 537 538 if not test_case.snr: 539 get_snr.assert_called_once_with('*') 540 else: 541 get_snr.assert_not_called() 542 543@pytest.mark.parametrize('tool', ["nrfjprog","nrfutil"]) 544@pytest.mark.parametrize('test_case', EXPECTED_RESULTS.keys(), ids=id_fn) 545@patch('runners.core.ZephyrBinaryRunner.require') 546@patch('runners.nrfjprog.NrfBinaryRunner.get_board_snr', 547 side_effect=get_board_snr_patch) 548@patch('runners.nrfutil.subprocess.Popen') 549@patch('runners.nrfjprog.NrfBinaryRunner.check_call') 550def test_init(check_call, popen, get_snr, require, tool, test_case, 551 runner_config, tmpdir): 552 popen.return_value.__enter__.return_value.stdout = io.BytesIO(b'') 553 554 require.side_effect = functools.partial(require_patch, tool) 555 runner_config = fix_up_runner_config(test_case, runner_config, tmpdir) 556 snr = TEST_OVR_SNR if test_case.snr else None 557 tool_opt = TEST_TOOL_OPT_L if test_case.tool_opt else [] 558 cls = CLASS_MAP[tool] 559 runner = cls(runner_config, 560 test_case.family, 561 test_case.softreset, 562 snr, 563 erase=test_case.erase, 564 tool_opt=tool_opt, 565 recover=test_case.recover) 566 567 with patch('os.path.isfile', side_effect=os_path_isfile_patch): 568 runner.run('flash') 569 assert require.called 570 571 CHECK_FN_MAP = {'nrfjprog': check_call, 'nrfutil': popen} 572 check_expected(tool, test_case, CHECK_FN_MAP[tool], get_snr, tmpdir, 573 runner_config) 574 575@pytest.mark.parametrize('tool', ["nrfjprog","nrfutil"]) 576@pytest.mark.parametrize('test_case', EXPECTED_RESULTS.keys(), ids=id_fn) 577@patch('runners.core.ZephyrBinaryRunner.require') 578@patch('runners.nrfjprog.NrfBinaryRunner.get_board_snr', 579 side_effect=get_board_snr_patch) 580@patch('runners.nrfutil.subprocess.Popen') 581@patch('runners.nrfjprog.NrfBinaryRunner.check_call') 582def test_create(check_call, popen, get_snr, require, tool, test_case, 583 runner_config, tmpdir): 584 popen.return_value.__enter__.return_value.stdout = io.BytesIO(b'') 585 586 require.side_effect = functools.partial(require_patch, tool) 587 runner_config = fix_up_runner_config(test_case, runner_config, tmpdir) 588 589 args = [] 590 if test_case.softreset: 591 args.append('--softreset') 592 if test_case.snr: 593 args.extend(['--dev-id', TEST_OVR_SNR]) 594 if test_case.erase: 595 args.append('--erase') 596 if test_case.recover: 597 args.append('--recover') 598 if test_case.tool_opt: 599 args.extend(['--tool-opt', TEST_TOOL_OPT]) 600 601 parser = argparse.ArgumentParser(allow_abbrev=False) 602 cls = CLASS_MAP[tool] 603 cls.add_parser(parser) 604 arg_namespace = parser.parse_args(args) 605 runner = cls.create(runner_config, arg_namespace) 606 with patch('os.path.isfile', side_effect=os_path_isfile_patch): 607 runner.run('flash') 608 609 assert require.called 610 611 CHECK_FN_MAP = {'nrfjprog': check_call, 'nrfutil': popen} 612 check_expected(tool, test_case, CHECK_FN_MAP[tool], get_snr, tmpdir, 613 runner_config) 614