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 <damien@micropython.org>
This commit is contained in:
Damien George
2025-08-19 14:10:13 +10:00
parent 4a60d230c3
commit 3285e52127

View File

@@ -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.