test_pyocd.py 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. # Copyright (c) 2018 Foundries.io
  2. #
  3. # SPDX-License-Identifier: Apache-2.0
  4. import argparse
  5. from unittest.mock import patch
  6. import pytest
  7. from runners.pyocd import PyOcdBinaryRunner
  8. from conftest import RC_BUILD_DIR, RC_GDB, RC_KERNEL_HEX, RC_KERNEL_ELF
  9. #
  10. # Test values to provide as constructor arguments and command line
  11. # parameters, to verify they're respected.
  12. #
  13. TEST_PYOCD = 'test-pyocd'
  14. TEST_ADDR = 0xadd
  15. TEST_BOARD_ID = 'test-board-id'
  16. TEST_FREQUENCY = 'test-frequency'
  17. TEST_DAPARG = 'test-daparg'
  18. TEST_TARGET = 'test-target'
  19. TEST_FLASH_OPTS = ['--test-flash', 'args']
  20. TEST_GDB_PORT = 1
  21. TEST_TELNET_PORT = 2
  22. TEST_TOOL_OPT = 'test-opt'
  23. TEST_ALL_KWARGS = {
  24. 'pyocd': TEST_PYOCD,
  25. 'flash_addr': TEST_ADDR,
  26. 'flash_opts': TEST_FLASH_OPTS,
  27. 'gdb_port': TEST_GDB_PORT,
  28. 'telnet_port': TEST_TELNET_PORT,
  29. 'tui': False,
  30. 'board_id': TEST_BOARD_ID,
  31. 'frequency': TEST_FREQUENCY,
  32. 'daparg': TEST_DAPARG,
  33. 'tool_opt': TEST_TOOL_OPT,
  34. }
  35. TEST_DEF_KWARGS = {}
  36. TEST_ALL_PARAMS = (['--target', TEST_TARGET,
  37. '--daparg', TEST_DAPARG,
  38. '--pyocd', TEST_PYOCD] +
  39. ['--flash-opt={}'.format(o) for o in
  40. TEST_FLASH_OPTS] +
  41. ['--gdb-port', str(TEST_GDB_PORT),
  42. '--telnet-port', str(TEST_TELNET_PORT),
  43. '--board-id', TEST_BOARD_ID,
  44. '--frequency', str(TEST_FREQUENCY),
  45. '--tool-opt', TEST_TOOL_OPT])
  46. TEST_DEF_PARAMS = ['--target', TEST_TARGET]
  47. #
  48. # Expected results.
  49. #
  50. # These record expected argument lists for system calls made by the
  51. # pyocd runner using its check_call() and run_server_and_client()
  52. # methods.
  53. #
  54. # They are shared between tests that create runners directly and
  55. # tests that construct runners from parsed command-line arguments, to
  56. # ensure that results are consistent.
  57. #
  58. FLASH_ALL_EXPECTED_CALL = ([TEST_PYOCD,
  59. 'flash',
  60. '-e', 'sector',
  61. '-a', hex(TEST_ADDR), '-da', TEST_DAPARG,
  62. '-t', TEST_TARGET, '-u', TEST_BOARD_ID,
  63. '-f', TEST_FREQUENCY,
  64. TEST_TOOL_OPT] +
  65. TEST_FLASH_OPTS +
  66. [RC_KERNEL_HEX])
  67. FLASH_DEF_EXPECTED_CALL = ['pyocd', 'flash', '-e', 'sector',
  68. '-t', TEST_TARGET, RC_KERNEL_HEX]
  69. DEBUG_ALL_EXPECTED_SERVER = [TEST_PYOCD,
  70. 'gdbserver',
  71. '-da', TEST_DAPARG,
  72. '-p', str(TEST_GDB_PORT),
  73. '-T', str(TEST_TELNET_PORT),
  74. '-t', TEST_TARGET,
  75. '-u', TEST_BOARD_ID,
  76. '-f', TEST_FREQUENCY,
  77. TEST_TOOL_OPT]
  78. DEBUG_ALL_EXPECTED_CLIENT = [RC_GDB, RC_KERNEL_ELF,
  79. '-ex', 'target remote :{}'.format(TEST_GDB_PORT),
  80. '-ex', 'monitor halt',
  81. '-ex', 'monitor reset',
  82. '-ex', 'load']
  83. DEBUG_DEF_EXPECTED_SERVER = ['pyocd',
  84. 'gdbserver',
  85. '-p', '3333',
  86. '-T', '4444',
  87. '-t', TEST_TARGET]
  88. DEBUG_DEF_EXPECTED_CLIENT = [RC_GDB, RC_KERNEL_ELF,
  89. '-ex', 'target remote :3333',
  90. '-ex', 'monitor halt',
  91. '-ex', 'monitor reset',
  92. '-ex', 'load']
  93. DEBUGSERVER_ALL_EXPECTED_CALL = [TEST_PYOCD,
  94. 'gdbserver',
  95. '-da', TEST_DAPARG,
  96. '-p', str(TEST_GDB_PORT),
  97. '-T', str(TEST_TELNET_PORT),
  98. '-t', TEST_TARGET,
  99. '-u', TEST_BOARD_ID,
  100. '-f', TEST_FREQUENCY,
  101. TEST_TOOL_OPT]
  102. DEBUGSERVER_DEF_EXPECTED_CALL = ['pyocd',
  103. 'gdbserver',
  104. '-p', '3333',
  105. '-T', '4444',
  106. '-t', TEST_TARGET]
  107. #
  108. # Fixtures
  109. #
  110. @pytest.fixture
  111. def pyocd(runner_config, tmpdir):
  112. '''PyOcdBinaryRunner from constructor kwargs or command line parameters'''
  113. # This factory takes either a dict of kwargs to pass to the
  114. # constructor, or a list of command-line arguments to parse and
  115. # use with the create() method.
  116. def _factory(args):
  117. # Ensure kernel binaries exist (as empty files, so commands
  118. # which use them must be patched out).
  119. tmpdir.ensure(RC_KERNEL_HEX)
  120. tmpdir.ensure(RC_KERNEL_ELF)
  121. tmpdir.chdir()
  122. if isinstance(args, dict):
  123. return PyOcdBinaryRunner(runner_config, TEST_TARGET, **args)
  124. elif isinstance(args, list):
  125. parser = argparse.ArgumentParser()
  126. PyOcdBinaryRunner.add_parser(parser)
  127. arg_namespace = parser.parse_args(args)
  128. return PyOcdBinaryRunner.create(runner_config, arg_namespace)
  129. return _factory
  130. #
  131. # Helpers
  132. #
  133. def require_patch(program):
  134. assert program in ['pyocd', TEST_PYOCD, RC_GDB]
  135. #
  136. # Test cases for runners created by constructor.
  137. #
  138. @pytest.mark.parametrize('pyocd_args,expected', [
  139. (TEST_ALL_KWARGS, FLASH_ALL_EXPECTED_CALL),
  140. (TEST_DEF_KWARGS, FLASH_DEF_EXPECTED_CALL)
  141. ])
  142. @patch('runners.pyocd.PyOcdBinaryRunner.check_call')
  143. @patch('runners.core.ZephyrBinaryRunner.require', side_effect=require_patch)
  144. def test_flash(require, cc, pyocd_args, expected, pyocd):
  145. pyocd(pyocd_args).run('flash')
  146. assert require.called
  147. cc.assert_called_once_with(expected)
  148. @pytest.mark.parametrize('pyocd_args,expectedv', [
  149. (TEST_ALL_KWARGS, (DEBUG_ALL_EXPECTED_SERVER, DEBUG_ALL_EXPECTED_CLIENT)),
  150. (TEST_DEF_KWARGS, (DEBUG_DEF_EXPECTED_SERVER, DEBUG_DEF_EXPECTED_CLIENT))
  151. ])
  152. @patch('runners.pyocd.PyOcdBinaryRunner.run_server_and_client')
  153. @patch('runners.core.ZephyrBinaryRunner.require', side_effect=require_patch)
  154. def test_debug(require, rsc, pyocd_args, expectedv, pyocd):
  155. pyocd(pyocd_args).run('debug')
  156. assert require.called
  157. rsc.assert_called_once_with(*expectedv)
  158. @pytest.mark.parametrize('pyocd_args,expected', [
  159. (TEST_ALL_KWARGS, DEBUGSERVER_ALL_EXPECTED_CALL),
  160. (TEST_DEF_KWARGS, DEBUGSERVER_DEF_EXPECTED_CALL)
  161. ])
  162. @patch('runners.pyocd.PyOcdBinaryRunner.check_call')
  163. @patch('runners.core.ZephyrBinaryRunner.require', side_effect=require_patch)
  164. def test_debugserver(require, cc, pyocd_args, expected, pyocd):
  165. pyocd(pyocd_args).run('debugserver')
  166. assert require.called
  167. cc.assert_called_once_with(expected)
  168. #
  169. # Test cases for runners created via command line arguments.
  170. #
  171. # (Unlike the constructor tests, these require additional patching to mock and
  172. # verify runners.core.BuildConfiguration usage.)
  173. #
  174. @pytest.mark.parametrize('pyocd_args,flash_addr,expected', [
  175. (TEST_ALL_PARAMS, TEST_ADDR, FLASH_ALL_EXPECTED_CALL),
  176. (TEST_DEF_PARAMS, 0x0, FLASH_DEF_EXPECTED_CALL)
  177. ])
  178. @patch('runners.pyocd.BuildConfiguration')
  179. @patch('runners.pyocd.PyOcdBinaryRunner.check_call')
  180. @patch('runners.core.ZephyrBinaryRunner.require', side_effect=require_patch)
  181. def test_flash_args(require, cc, bc, pyocd_args, flash_addr, expected, pyocd):
  182. with patch.object(PyOcdBinaryRunner, 'get_flash_address',
  183. return_value=flash_addr):
  184. pyocd(pyocd_args).run('flash')
  185. assert require.called
  186. bc.assert_called_once_with(RC_BUILD_DIR)
  187. cc.assert_called_once_with(expected)
  188. @pytest.mark.parametrize('pyocd_args, expectedv', [
  189. (TEST_ALL_PARAMS, (DEBUG_ALL_EXPECTED_SERVER, DEBUG_ALL_EXPECTED_CLIENT)),
  190. (TEST_DEF_PARAMS, (DEBUG_DEF_EXPECTED_SERVER, DEBUG_DEF_EXPECTED_CLIENT)),
  191. ])
  192. @patch('runners.pyocd.BuildConfiguration')
  193. @patch('runners.pyocd.PyOcdBinaryRunner.run_server_and_client')
  194. @patch('runners.core.ZephyrBinaryRunner.require', side_effect=require_patch)
  195. def test_debug_args(require, rsc, bc, pyocd_args, expectedv, pyocd):
  196. pyocd(pyocd_args).run('debug')
  197. assert require.called
  198. bc.assert_called_once_with(RC_BUILD_DIR)
  199. rsc.assert_called_once_with(*expectedv)
  200. @pytest.mark.parametrize('pyocd_args, expected', [
  201. (TEST_ALL_PARAMS, DEBUGSERVER_ALL_EXPECTED_CALL),
  202. (TEST_DEF_PARAMS, DEBUGSERVER_DEF_EXPECTED_CALL),
  203. ])
  204. @patch('runners.pyocd.BuildConfiguration')
  205. @patch('runners.pyocd.PyOcdBinaryRunner.check_call')
  206. @patch('runners.core.ZephyrBinaryRunner.require', side_effect=require_patch)
  207. def test_debugserver_args(require, cc, bc, pyocd_args, expected, pyocd):
  208. pyocd(pyocd_args).run('debugserver')
  209. assert require.called
  210. bc.assert_called_once_with(RC_BUILD_DIR)
  211. cc.assert_called_once_with(expected)