1# Copyright 2023 NXP 2# SPDX-License-Identifier: Apache-2.0 3 4import argparse 5import os 6from pathlib import Path 7from unittest.mock import patch 8 9import pytest 10from conftest import RC_KERNEL_ELF 11from runners.nxp_s32dbg import NXPS32DebugProbeConfig, NXPS32DebugProbeRunner 12 13TEST_DEVICE = 's32dbg' 14TEST_SPEED = 16000 15TEST_SERVER_PORT = 45000 16TEST_REMOTE_TIMEOUT = 30 17TEST_CORE_NAME = 'R52_0_0' 18TEST_SOC_NAME = 'S32Z270' 19TEST_SOC_FAMILY_NAME = 's32e2z2' 20TEST_START_ALL_CORES = True 21TEST_S32DS_PATH_OVERRIDE = None 22TEST_TOOL_OPT = ['--test-opt-1', '--test-opt-2'] 23TEST_RESET_TYPE = 'default' 24TEST_RESET_DELAY = 0 25 26TEST_S32DS_CMD = 's32ds' 27TEST_SERVER_CMD = Path('S32DS') / 'tools' / 'S32Debugger' / 'Debugger' / 'Server' / 'gta' / 'gta' 28TEST_ARM_GDB_CMD = Path('S32DS') / 'tools' / 'gdb-arm' / 'arm32-eabi' / 'bin' / 'arm-none-eabi-gdb-py' 29 30TEST_S32DS_PYTHON_LIB = Path('S32DS') / 'build_tools' / 'msys32' / 'mingw32' / 'lib' / 'python2.7' 31TEST_S32DS_RUNTIME_ENV = { 32 'PYTHONPATH': f'{TEST_S32DS_PYTHON_LIB}{os.pathsep}{TEST_S32DS_PYTHON_LIB / "site-packages"}' 33} 34 35TEST_ALL_KWARGS = { 36 'NXPS32DebugProbeConfig': { 37 'conn_str': TEST_DEVICE, 38 'server_port': TEST_SERVER_PORT, 39 'speed': TEST_SPEED, 40 'remote_timeout': TEST_REMOTE_TIMEOUT, 41 }, 42 'NXPS32DebugProbeRunner': { 43 'core_name': TEST_CORE_NAME, 44 'soc_name': TEST_SOC_NAME, 45 'soc_family_name': TEST_SOC_FAMILY_NAME, 46 'start_all_cores': TEST_START_ALL_CORES, 47 's32ds_path': TEST_S32DS_PATH_OVERRIDE, 48 'tool_opt': TEST_TOOL_OPT 49 } 50} 51 52TEST_ALL_PARAMS = [ 53 # generic 54 '--dev-id', TEST_DEVICE, 55 *[f'--tool-opt={o}' for o in TEST_TOOL_OPT], 56 # from runner 57 '--s32ds-path', TEST_S32DS_PATH_OVERRIDE, 58 '--core-name', TEST_CORE_NAME, 59 '--soc-name', TEST_SOC_NAME, 60 '--soc-family-name', TEST_SOC_FAMILY_NAME, 61 '--server-port', TEST_SERVER_PORT, 62 '--speed', TEST_SPEED, 63 '--remote-timeout', TEST_REMOTE_TIMEOUT, 64 '--start-all-cores', 65] 66 67TEST_ALL_S32DBG_PY_VARS = [ 68 f'py _PROBE_IP = {repr(TEST_DEVICE)}', 69 f'py _JTAG_SPEED = {repr(TEST_SPEED)}', 70 f'py _GDB_SERVER_PORT = {repr(TEST_SERVER_PORT)}', 71 f"py _RESET_TYPE = {repr(TEST_RESET_TYPE)}", 72 f'py _RESET_DELAY = {repr(TEST_RESET_DELAY)}', 73 f'py _REMOTE_TIMEOUT = {repr(TEST_REMOTE_TIMEOUT)}', 74 f'py _CORE_NAME = {repr(f"{TEST_SOC_NAME}_{TEST_CORE_NAME}")}', 75 f'py _SOC_NAME = {repr(TEST_SOC_NAME)}', 76 'py _IS_LOGGING_ENABLED = False', 77 'py _FLASH_NAME = None', 78 'py _SECURE_TYPE = None', 79 'py _SECURE_KEY = None', 80] 81 82DEBUGSERVER_ALL_EXPECTED_CALL = [ 83 str(TEST_SERVER_CMD), 84 '-p', str(TEST_SERVER_PORT), 85 *TEST_TOOL_OPT, 86] 87 88DEBUG_ALL_EXPECTED_CALL = { 89 'client': [ 90 str(TEST_ARM_GDB_CMD), 91 '-x', 'TEST_GDB_SCRIPT', 92 *TEST_TOOL_OPT, 93 ], 94 'server': [ 95 str(TEST_SERVER_CMD), 96 '-p', str(TEST_SERVER_PORT), 97 ], 98 'gdb_script': [ 99 *TEST_ALL_S32DBG_PY_VARS, 100 f'source generic_bareboard{"_all_cores" if TEST_START_ALL_CORES else ""}.py', 101 'py board_init()', 102 'py core_init()', 103 f'file {RC_KERNEL_ELF}', 104 'load', 105 ] 106} 107 108ATTACH_ALL_EXPECTED_CALL = { 109 **DEBUG_ALL_EXPECTED_CALL, 110 'gdb_script': [ 111 *TEST_ALL_S32DBG_PY_VARS, 112 f'source attach.py', 113 'py core_init()', 114 f'file {RC_KERNEL_ELF}', 115 ] 116} 117 118 119@pytest.fixture 120def s32dbg(runner_config, tmp_path): 121 '''NXPS32DebugProbeRunner from constructor kwargs or command line parameters''' 122 def _factory(args): 123 # create empty files to ensure kernel binaries exist 124 (tmp_path / RC_KERNEL_ELF).touch() 125 os.chdir(tmp_path) 126 127 runner_config_patched = fix_up_runner_config(runner_config, tmp_path) 128 129 if isinstance(args, dict): 130 probe_cfg = NXPS32DebugProbeConfig(**args['NXPS32DebugProbeConfig']) 131 return NXPS32DebugProbeRunner(runner_config_patched, probe_cfg, 132 **args['NXPS32DebugProbeRunner']) 133 elif isinstance(args, list): 134 parser = argparse.ArgumentParser(allow_abbrev=False) 135 NXPS32DebugProbeRunner.add_parser(parser) 136 arg_namespace = parser.parse_args(str(x) for x in args) 137 return NXPS32DebugProbeRunner.create(runner_config_patched, arg_namespace) 138 return _factory 139 140 141def fix_up_runner_config(runner_config, tmp_path): 142 to_replace = {} 143 144 zephyr = tmp_path / 'zephyr' 145 zephyr.mkdir() 146 dotconfig = zephyr / '.config' 147 dotconfig.write_text('CONFIG_ARCH="arm"') 148 to_replace['build_dir'] = tmp_path 149 150 return runner_config._replace(**to_replace) 151 152 153def require_patch(program, path=None): 154 assert Path(program).stem == TEST_S32DS_CMD 155 return program 156 157 158def s32dbg_get_script(name): 159 return Path(f'{name}.py') 160 161 162@pytest.mark.parametrize('s32dbg_args,expected,osname', [ 163 (TEST_ALL_KWARGS, DEBUGSERVER_ALL_EXPECTED_CALL, 'Windows'), 164 (TEST_ALL_PARAMS, DEBUGSERVER_ALL_EXPECTED_CALL, 'Windows'), 165 (TEST_ALL_KWARGS, DEBUGSERVER_ALL_EXPECTED_CALL, 'Linux'), 166 (TEST_ALL_PARAMS, DEBUGSERVER_ALL_EXPECTED_CALL, 'Linux'), 167]) 168@patch('platform.system') 169@patch('runners.core.ZephyrBinaryRunner.check_call') 170@patch('runners.core.ZephyrBinaryRunner.require', side_effect=require_patch) 171def test_debugserver(require, check_call, system, 172 s32dbg_args, expected, osname, s32dbg): 173 system.return_value = osname 174 175 runner = s32dbg(s32dbg_args) 176 runner.run('debugserver') 177 178 assert require.called 179 check_call.assert_called_once_with(expected) 180 181 182@pytest.mark.parametrize('s32dbg_args,expected,osname', [ 183 (TEST_ALL_KWARGS, DEBUG_ALL_EXPECTED_CALL, 'Windows'), 184 (TEST_ALL_PARAMS, DEBUG_ALL_EXPECTED_CALL, 'Windows'), 185 (TEST_ALL_KWARGS, DEBUG_ALL_EXPECTED_CALL, 'Linux'), 186 (TEST_ALL_PARAMS, DEBUG_ALL_EXPECTED_CALL, 'Linux'), 187]) 188@patch.dict(os.environ, TEST_S32DS_RUNTIME_ENV, clear=True) 189@patch('platform.system') 190@patch('tempfile.TemporaryDirectory') 191@patch('runners.nxp_s32dbg.NXPS32DebugProbeRunner.get_script', side_effect=s32dbg_get_script) 192@patch('runners.core.ZephyrBinaryRunner.popen_ignore_int') 193@patch('runners.core.ZephyrBinaryRunner.check_call') 194@patch('runners.core.ZephyrBinaryRunner.require', side_effect=require_patch) 195def test_debug(require, check_call, popen_ignore_int, get_script, temporary_dir, system, 196 s32dbg_args, expected, osname, s32dbg, tmp_path): 197 198 # mock tempfile.TemporaryDirectory to return `tmp_path` and create gdb init script there 199 temporary_dir.return_value.__enter__.return_value = tmp_path 200 gdb_script = tmp_path / 'runner.nxp_s32dbg' 201 expected_client = [e.replace('TEST_GDB_SCRIPT', gdb_script.as_posix()) 202 for e in expected['client']] 203 204 system.return_value = osname 205 expected_env = TEST_S32DS_RUNTIME_ENV if osname == 'Windows' else None 206 207 runner = s32dbg(s32dbg_args) 208 runner.run('debug') 209 210 assert require.called 211 assert gdb_script.read_text().splitlines() == expected['gdb_script'] 212 popen_ignore_int.assert_called_once_with(expected['server'], env=expected_env) 213 check_call.assert_called_once_with(expected_client, env=expected_env) 214 215 216@pytest.mark.parametrize('s32dbg_args,expected,osname', [ 217 (TEST_ALL_KWARGS, ATTACH_ALL_EXPECTED_CALL, 'Windows'), 218 (TEST_ALL_PARAMS, ATTACH_ALL_EXPECTED_CALL, 'Windows'), 219 (TEST_ALL_KWARGS, ATTACH_ALL_EXPECTED_CALL, 'Linux'), 220 (TEST_ALL_PARAMS, ATTACH_ALL_EXPECTED_CALL, 'Linux'), 221]) 222@patch.dict(os.environ, TEST_S32DS_RUNTIME_ENV, clear=True) 223@patch('platform.system') 224@patch('tempfile.TemporaryDirectory') 225@patch('runners.nxp_s32dbg.NXPS32DebugProbeRunner.get_script', side_effect=s32dbg_get_script) 226@patch('runners.core.ZephyrBinaryRunner.popen_ignore_int') 227@patch('runners.core.ZephyrBinaryRunner.check_call') 228@patch('runners.core.ZephyrBinaryRunner.require', side_effect=require_patch) 229def test_attach(require, check_call, popen_ignore_int, get_script, temporary_dir, system, 230 s32dbg_args, expected, osname, s32dbg, tmp_path): 231 232 # mock tempfile.TemporaryDirectory to return `tmp_path` and create gdb init script there 233 temporary_dir.return_value.__enter__.return_value = tmp_path 234 gdb_script = tmp_path / 'runner.nxp_s32dbg' 235 expected_client = [e.replace('TEST_GDB_SCRIPT', gdb_script.as_posix()) 236 for e in expected['client']] 237 238 system.return_value = osname 239 expected_env = TEST_S32DS_RUNTIME_ENV if osname == 'Windows' else None 240 241 runner = s32dbg(s32dbg_args) 242 runner.run('attach') 243 244 assert require.called 245 assert gdb_script.read_text().splitlines() == expected['gdb_script'] 246 popen_ignore_int.assert_called_once_with(expected['server'], env=expected_env) 247 check_call.assert_called_once_with(expected_client, env=expected_env) 248