tests/run-tests.py: Allow running tests via mpy-cross on remote targets.

This adds support for the `--via-mpy` and `--emit native` options when
running tests on remote targets (via pyboard.py).  It's now possible to do:

    $ ./run-tests.py --target pyboard --via-mpy
    $ ./run-tests.py --target pyboard --via-mpy --emit native

Signed-off-by: Damien George <damien@micropython.org>
This commit is contained in:
Damien George 2022-05-19 14:54:06 +10:00
parent ef16796f49
commit 1786dacc83
1 changed files with 94 additions and 10 deletions

View File

@ -48,6 +48,37 @@ DIFF = os.getenv("MICROPY_DIFF", "diff -u")
# Set PYTHONIOENCODING so that CPython will use utf-8 on systems which set another encoding in the locale # Set PYTHONIOENCODING so that CPython will use utf-8 on systems which set another encoding in the locale
os.environ["PYTHONIOENCODING"] = "utf-8" os.environ["PYTHONIOENCODING"] = "utf-8"
# Code to allow a target MicroPython to import an .mpy from RAM
injected_import_hook_code = """\
import usys, uos, uio
class __File(uio.IOBase):
def __init__(self):
self.off = 0
def ioctl(self, request, arg):
return 0
def readinto(self, buf):
buf[:] = memoryview(__buf)[self.off:self.off + len(buf)]
self.off += len(buf)
return len(buf)
class __FS:
def mount(self, readonly, mkfs):
pass
def umount(self):
pass
def chdir(self, path):
pass
def stat(self, path):
if path == '__injected_test.mpy':
return tuple(0 for _ in range(10))
else:
raise OSError(-2) # ENOENT
def open(self, path, mode):
return __File()
uos.mount(__FS(), '/__vfstest')
uos.chdir('/__vfstest')
__import__('__injected_test')
"""
def rm_f(fname): def rm_f(fname):
if os.path.exists(fname): if os.path.exists(fname):
@ -74,6 +105,59 @@ def convert_regex_escapes(line):
return bytes("".join(cs), "utf8") return bytes("".join(cs), "utf8")
def prepare_script_for_target(args, *, script_filename=None, script_text=None, force_plain=False):
if force_plain or (not args.via_mpy and args.emit == "bytecode"):
if script_filename is not None:
with open(script_filename, "rb") as f:
script_text = f.read()
elif args.via_mpy:
tempname = tempfile.mktemp(dir="")
mpy_filename = tempname + ".mpy"
if script_filename is None:
script_filename = tempname + ".py"
cleanup_script_filename = True
with open(script_filename, "wb") as f:
f.write(script_text)
else:
cleanup_script_filename = False
subprocess.check_output(
[MPYCROSS]
+ args.mpy_cross_flags.split()
+ ["-o", mpy_filename, "-X", "emit=" + args.emit, script_filename]
)
with open(mpy_filename, "rb") as f:
script_text = b"__buf=" + bytes(repr(f.read()), "ascii") + b"\n"
rm_f(mpy_filename)
if cleanup_script_filename:
rm_f(script_filename)
script_text += bytes(injected_import_hook_code, "ascii")
else:
print("error: using emit={} must go via .mpy".format(args.emit))
sys.exit(1)
return script_text
def run_script_on_remote_target(pyb, args, test_file, is_special):
script = prepare_script_for_target(args, script_filename=test_file, force_plain=is_special)
try:
had_crash = False
pyb.enter_raw_repl()
output_mupy = pyb.exec_(script)
except pyboard.PyboardError as e:
had_crash = True
if not is_special and e.args[0] == "exception":
output_mupy = e.args[1] + e.args[2] + b"CRASH"
else:
output_mupy = bytes(e.args[0], "ascii") + b"\nCRASH"
return had_crash, output_mupy
def run_micropython(pyb, args, test_file, is_special=False): def run_micropython(pyb, args, test_file, is_special=False):
special_tests = ( special_tests = (
"micropython/meminfo.py", "micropython/meminfo.py",
@ -196,16 +280,8 @@ def run_micropython(pyb, args, test_file, is_special=False):
rm_f(mpy_filename) rm_f(mpy_filename)
else: else:
# run on pyboard # run via pyboard interface
pyb.enter_raw_repl() had_crash, output_mupy = run_script_on_remote_target(pyb, args, test_file, is_special)
try:
output_mupy = pyb.execfile(test_file)
except pyboard.PyboardError as e:
had_crash = True
if not is_special and e.args[0] == "exception":
output_mupy = e.args[1] + e.args[2] + b"CRASH"
else:
output_mupy = bytes(e.args[0], "ascii") + b"\nCRASH"
# canonical form for all ports/platforms is to use \n for end-of-line # canonical form for all ports/platforms is to use \n for end-of-line
output_mupy = output_mupy.replace(b"\r\n", b"\n") output_mupy = output_mupy.replace(b"\r\n", b"\n")
@ -818,6 +894,14 @@ the last matching regex is used:
sys.path.append(base_path("../tools")) sys.path.append(base_path("../tools"))
import pyboard import pyboard
if not args.mpy_cross_flags:
if args.target == "esp8266":
args.mpy_cross_flags = "-march=xtensa"
elif args.target == "esp32":
args.mpy_cross_flags = "-march=xtensawin"
else:
args.mpy_cross_flags = "-march=armv7m"
pyb = pyboard.Pyboard(args.device, args.baudrate, args.user, args.password) pyb = pyboard.Pyboard(args.device, args.baudrate, args.user, args.password)
pyb.enter_raw_repl() pyb.enter_raw_repl()
else: else: