From 3285e52127017e58125c7aacc361daae48dc6744 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 19 Aug 2025 14:10:13 +1000 Subject: [PATCH] tests/run-tests.py: Add support for board-specific target_wiring config. There are currently a few "hardware" tests that need external board connections to be made for them to work, such as bridging a pair of pins. For example, all tests in `tests/extmod_hardware` need some kind of connection. Along with the physical connections -- which are different for each board -- there needs to be corresponding Python settings, eg which UART instance to use and which pins for TX/RX. These settings are currently hard-coded in each test file. That has a few problems: - settings are repeated, eg all the UART tests have pretty much the same settings code duplicated across them - changing the settings means changing many files - adding a new board means adding a lot of code - the tests get bigger and bigger with each new board that they support, meaning they may not fit on targets with a small amount of RAM (that's already the case with `tests/extmod_hardware/machine_pwm.py`) - if you have a custom board you have to manually edit the test to add your own settings This commit aims to solve all the above problems by splitting the board- specific settings out into separate files, one for each board (or port). They are placed in the `tests/target_wiring/` directory. The `run-tests.py` test runner then loads the appropriate configuration for the target that is being tested, sends it to the board so it's available as `import target_wiring` (without needing a filesystem), and then executes the test. Note tht only tests that need `target_wiring` have it loaded. This commit adds support for this `target_wiring` scheme. Signed-off-by: Damien George --- tests/run-tests.py | 60 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/tests/run-tests.py b/tests/run-tests.py index c434cd6fc1..feeaa98227 100755 --- a/tests/run-tests.py +++ b/tests/run-tests.py @@ -216,6 +216,9 @@ platform_tests_to_skip = { ), } +# Tests that require `import target_wiring` to work. +tests_requiring_target_wiring = () + def rm_f(fname): if os.path.exists(fname): @@ -310,6 +313,7 @@ def detect_test_platform(pyb, args): args.float_prec = float_prec args.unicode = unicode + # Print the detected information about the target. print("platform={}".format(platform), end="") if arch: print(" arch={}".format(arch), end="") @@ -321,7 +325,43 @@ def detect_test_platform(pyb, args): print(" float={}-bit".format(float_prec), end="") if unicode: print(" unicode", end="") - print() + + +def detect_target_wiring_script(pyb, args): + tw_data = b"" + tw_source = None + if args.target_wiring: + # A target_wiring path is explicitly provided, so use that. + tw_source = args.target_wiring + with open(tw_source, "rb") as f: + tw_data = f.read() + elif hasattr(pyb, "exec_raw") and pyb.exec_raw("import target_wiring") == (b"", b""): + # The board already has a target_wiring module available, so use that. + tw_source = "on-device" + else: + port = platform_to_port(args.platform) + build = args.build + tw_board_exact = None + tw_board_partial = None + tw_port = None + for file in os.listdir("target_wiring"): + file_base = file.removesuffix(".py") + if file_base == build: + # A file matching the target's board/build name. + tw_board_exact = file + elif file_base.endswith("x") and build.startswith(file_base.removesuffix("x")): + # A file with a partial match to the target's board/build name. + tw_board_partial = file + elif file_base == port: + # A file matching the target's port. + tw_port = file + tw_source = tw_board_exact or tw_board_partial or tw_port + if tw_source: + with open("target_wiring/" + tw_source, "rb") as f: + tw_data = f.read() + if tw_source: + print(" target_wiring={}".format(tw_source), end="") + pyb.target_wiring_script = tw_data def prepare_script_for_target(args, *, script_text=None, force_plain=False): @@ -382,6 +422,12 @@ def run_script_on_remote_target(pyb, args, test_file, is_special): try: had_crash = False pyb.enter_raw_repl() + if test_file.endswith(tests_requiring_target_wiring) and pyb.target_wiring_script: + pyb.exec_( + "import sys;sys.modules['target_wiring']=__build_class__(lambda:exec(" + + repr(pyb.target_wiring_script) + + "),'target_wiring')" + ) output_mupy = pyb.exec_(script, timeout=TEST_TIMEOUT) except pyboard.PyboardError as e: had_crash = True @@ -1285,6 +1331,11 @@ the last matching regex is used: default=None, help="prologue python file to execute before module import", ) + cmd_parser.add_argument( + "--target-wiring", + default=None, + help="force the given script to be used as target_wiring.py", + ) args = cmd_parser.parse_args() prologue = "" @@ -1381,6 +1432,13 @@ the last matching regex is used: # tests explicitly given tests = args.files + # If any tests need it, prepare the target_wiring script for the target. + if pyb and any(test.endswith(tests_requiring_target_wiring) for test in tests): + detect_target_wiring_script(pyb, args) + + # End the target information line. + print() + if not args.keep_path: # Clear search path to make sure tests use only builtin modules, those in # extmod, and a path to unittest in case it's needed.