Skip to content

mpremote/tests: Rewrite test runner to run correctly under Windows. #17089

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: master
Choose a base branch
from

Conversation

AJMansfield
Copy link
Contributor

@AJMansfield AJMansfield commented Apr 7, 2025

Summary

This PR rewrites the test runner script used for testing mpremote to run correctly under Windows, and adds some functionality present in the main test runner that it was previously missing.

This PR adds inheritance behavior for the TESTS_DIR and MPREMOTE variables in the run-mpremote-tests.sh test script. It adds a new RESULT_DIR variable that can be specified to direct the runner for a path to place output .exp and .out files. It expands the use of the input arguments to allow specifying multiple test scripts.

Among other things, this rewrite also enables multiple concurrent instances of the test runner to be run against multiple simultaneously-connected target boards, via:

SERIAL_PORT="/dev/serial/by-id/usb-MY_BOARD"
MPREMOTE="./mpremote.py connect ${SERIAL_PORT}" RESULT_DIR="tests/results/MY_BOARD" tests/run-mpremote-tests.sh

Previously, the test runner had no way to override its automatic serial port selection, and concurrent instances had no way to specify different output paths to avoid clobbering each other's .out files.

Testing

I've tested these changes manually and as part of the local automations I've been using to test #16994. I can confirm they address the configurability and concurrency issues described above.

For the moment I'm relying on @Josverl to report on whether this rewrite runs appropriately under Windows implementations of bash.

Trade-Offs and Alternatives

Some attention should probably be paid to adapting this to also run against locally-runnable ports, so that the mpremote tests can be added to automated CI/CD.

Copy link

codecov bot commented Apr 7, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 98.38%. Comparing base (e993f53) to head (c7182e4).
Report is 59 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master   #17089      +/-   ##
==========================================
- Coverage   98.41%   98.38%   -0.03%     
==========================================
  Files         171      171              
  Lines       22210    22239      +29     
==========================================
+ Hits        21857    21880      +23     
- Misses        353      359       +6     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link

github-actions bot commented Apr 7, 2025

Code size report:

   bare-arm:    +0 +0.000% 
minimal x86:    +0 +0.000% 
   unix x64:    +0 +0.000% standard
      stm32:    +0 +0.000% PYBV10
     mimxrt:    +0 +0.000% TEENSY40
        rp2:    +0 +0.000% RPI_PICO_W
       samd:    +0 +0.000% ADAFRUIT_ITSYBITSY_M4_EXPRESS
  qemu rv32:    +0 +0.000% VIRT_RV32

@Josverl
Copy link
Contributor

Josverl commented Apr 7, 2025

Windows - Git Bash

Some test cases pass :

./test_eval_exec_run.sh: OK
./test_recursive_cp.sh: OK
./test_resume.sh: OK

all others fail

Tests fail when

  • uses {$TMP} or assumes a host path convention

  • comparison of a sha256sum is slightly different with an additional asterix.
    The default mode is to print a line with checksum, a space, a character indicating input mode ('*' for binary, ' ' for text or where binary is insignificant), and name for each FILE`

    can be mitigated with 'sha256sum -t'

  • the ramdisk creation in test_mip_local_install.sh fails while the one in test_filesystem.sh works.
    it is trying to create file in a location where it should not attempt write at all.

       > cp ${TMP}/package :
       ./test_mip_local_install.sh: FAIL
       2,3c2,11
       < mkdir :C:/Program Files/Git/__ramdisk/lib
       < mpremote: mkdir: C:/Program Files/Git/__ramdisk/lib: No such file or directory.
    

    I would suggest ramdisk.py that should not be created on the fly, but be part of the testsuite and referenced from both scripts.

Details

testrub with 'echo -n "" | sha256sum -t' fix ``` EUROPE+josverl@josverl-sb5 MINGW64 /d/mypython/micropython/tools/mpremote/tests (mpremote-testfix) $ ./run-mpremote-tests.sh ./test_eval_exec_run.sh: OK ./test_filesystem.sh: FAIL 13,15c13,15 < cp C:/Users/josverl/AppData/Local/Temp/tmp.U2wf3UI3x1/a.py : < cp C:/Users/josverl/AppData/Local/Temp/tmp.U2wf3UI3x1/a.py :b.py < cp C:/Users/josverl/AppData/Local/Temp/tmp.U2wf3UI3x1/a.py :c.py --- > cp ${TMP}/a.py : &gt; cp ${TMP}/a.py :b.py > cp ${TMP}/a.py :c.py 34,35c34,35 &lt; cp C:/Users/josverl/AppData/Local/Temp/tmp.U2wf3UI3x1/a.py :aaa &lt; cp C:/Users/josverl/AppData/Local/Temp/tmp.U2wf3UI3x1/a.py :bbb/b.py --- &gt; cp ${TMP}/a.py :aaa > cp ${TMP}/a.py :bbb/b.py 41c41 &lt; cp C:/Users/josverl/AppData/Local/Temp/tmp.U2wf3UI3x1/a.py :aaa --- &gt; cp ${TMP}/a.py :aaa 45c45 < cp C:/Users/josverl/AppData/Local/Temp/tmp.U2wf3UI3x1/a.py :aaa/ --- > cp ${TMP}/a.py :aaa/ 47c47 &lt; cp C:/Users/josverl/AppData/Local/Temp/tmp.U2wf3UI3x1/a.py :aaa/a.py/ --- &gt; cp ${TMP}/a.py :aaa/a.py/ 66d65 < sed: cannot rename ./sedYbcCFs: Invalid cross-device link 69,70c68,69 < 50f0a701dd6cd6125387b96515300c9d5294c006518f8e62fa9eea3b66587f21 < Hello --- > 612c7ddb88390ac86b4174b26a6e5b52fc2f2838b234efd8f6f7c41631a49d04 > Goodbye 73c72 < cp C:/Users/josverl/AppData/Local/Temp/tmp.U2wf3UI3x1/package : --- > cp ${TMP}/package : 86c85 &lt; cp C:/Users/josverl/AppData/Local/Temp/tmp.U2wf3UI3x1/package :package2 --- &gt; cp ${TMP}/package :package2 100c99 < cp C:/Users/josverl/AppData/Local/Temp/tmp.U2wf3UI3x1/package :test --- > cp ${TMP}/package :test 111c110 &lt; cp C:/Users/josverl/AppData/Local/Temp/tmp.U2wf3UI3x1/package :test/package2 --- &gt; cp ${TMP}/package :test/package2 123c122 < cp :test/package C:/Users/josverl/AppData/Local/Temp/tmp.U2wf3UI3x1/copy --- > cp :test/package ${TMP}/copy 136c135 &lt; cp :test/package C:/Users/josverl/AppData/Local/Temp/tmp.U2wf3UI3x1/copy/package2 --- &gt; cp :test/package ${TMP}/copy/package2 150c149 < cp C:/Users/josverl/AppData/Local/Temp/tmp.U2wf3UI3x1/package : --- > cp ${TMP}/package : 163c162 &lt; cp C:/Users/josverl/AppData/Local/Temp/tmp.U2wf3UI3x1/package : --- &gt; cp ${TMP}/package : 179c178 < cp C:/Users/josverl/AppData/Local/Temp/tmp.U2wf3UI3x1/package : --- > cp ${TMP}/package : ./test_mip_local_install.sh: FAIL 2,3c2,11 &lt; mkdir :C:/Program Files/Git/__ramdisk/lib &lt; mpremote: mkdir: C:/Program Files/Git/__ramdisk/lib: No such file or directory. --- &gt; mkdir :/__ramdisk/lib &gt; &gt; ---- Install package &gt; Install ${TMP}/example/package.json > Installing: /__ramdisk/lib/mip_example/__init__.py > Installing: /__ramdisk/lib/mip_example/hello.py > Done > > ---- Test package > Hello, world! ./test_mount.sh: FAIL 4c4 < Local directory C:/Users/josverl/AppData/Local/Temp/tmp.xJ0SnGMaZU is mounted at /remote --- > Local directory ${TMP} is mounted at /remote 6c6 &lt; Local directory C:/Users/josverl/AppData/Local/Temp/tmp.xJ0SnGMaZU is mounted at /remote --- &gt; Local directory ${TMP} is mounted at /remote 10c10 < Local directory C:/Users/josverl/AppData/Local/Temp/tmp.xJ0SnGMaZU is mounted at /remote --- > Local directory ${TMP} is mounted at /remote ./test_recursive_cp.sh: OK ./test_resume.sh: OK ```

@dpgeorge dpgeorge added the tools Relates to tools/ directory in source, or other tooling label Apr 8, 2025
@AJMansfield
Copy link
Contributor Author

AJMansfield commented Apr 8, 2025

@Josverl could you test the latest push? I've now majorly rewritten most of the test runner script with far more paranoid/maximalist quoting, and updated it to use a separate results directory to match the behavior of the main test suite (with a .gitignore line matching the way the main test suite gets its results ignored).

This also reduces some of the jank by inverting the way the tests are compared -- that is, instead of trying to use sed to replace instances of the temporary directory path with the string ${TMP} in the .out file, it instead uses envsubst to generate a copy of the .exp file with TMP expanded.

Also updated, it uses a diff compare mode that ignores carriage returns, and outputs the failure diffs at the end in unified-diff format the same way the main test suite does.

I've also fixed the tests that were individually broken due to insufficient quoting, and added --text to the sha256sum invocations in test_filesystem.sh to make them more windows compatible.

@AJMansfield AJMansfield changed the title mpremote: Fix test suite for multiple-board situations. mpremote/tests: Rewrite test runner to run correctly under Windows. Apr 8, 2025
@Josverl
Copy link
Contributor

Josverl commented Apr 8, 2025

initial results : recursive now also FAILS

./test_eval_exec_run.sh: OK
./test_filesystem.sh: FAIL
./test_mip_local_install.sh: CRASH
./test_mount.sh: FAIL
./test_recursive_cp.sh: FAIL
./test_resume.sh: OK

common issues :
There is a common patter to setup a ramdisk. This should be a common fixture.
Instead it is setup in multiple slightly different ways , and only one (the filesystem test ) works on Windows.

I think the bash syntax: ${target@Q} does not work or work the same. Simpler to just use the correct delimiters instead.

I think the diffing on errors would be better to understand when $DIFF "${result}.exp" "${result}.out"
That shows the extra's as + and the missing lines as - , which makes more sense to my simple Dutch brain.

main problems in filesystem test

  • Windows path <> Posix Path
  • the "editor" test via sed fails / stops the entire script

Details : https://gist.github.com/Josverl/32de060bfa072f19ea55ad326aca6403

🪲While debugging I found this bug 🦗
Git bash + mpremote result in a transport error on mpremote resume mkdir /ramdisk/lib ( no leading :)
#17093

The same command works just fine in Windows powershell or even an old style command prompt.
soo, just testing on Git bash - does not appear to cover enough ( id say that about 2% of windows users use git bash for mpremote)
Even with a perfect bash script , that would cover only about 20% of the end user computing scenarios.

Personally I think that test are best written using a test framework, such as pytest.
And that can handle .exp files, and has much more flexibility and parametrization and fuzzing capabilities, code coverage etc etc that will take so much more time to try to accomplish using bash, or any other shell language for that matter.

https://github.com/Josverl/micropython/blob/mpr/pytest/tools/mpremote/tests/test_filesystem.py

@AJMansfield
Copy link
Contributor Author

AJMansfield commented Apr 8, 2025

I really need to spend some more time getting my Windows build environment working so we're not just playing telephone on this.

There is a common patter to setup a ramdisk. This should be a common fixture. Instead it is setup in multiple slightly different ways , and only one (the filesystem test ) works on Windows.

I'll try to see about refactoring this.

I think the bash syntax: ${target@Q} does not work or work the same. Simpler to just use the correct delimiters instead.

You're right that that that doesn't address all possible escaping problems, but there is one remaining issue I also just spotted even with that, in that it's actually the missing r prefix to get python to not interpret backslashes as escapes.

I think the diffing on errors would be better to understand when $DIFF "${result}.exp" "${result}.out" That shows the extra's as + and the missing lines as - , which makes more sense to my simple Dutch brain.

Good catch, the other test runners also diff their .exp and .out in the order you suggest, so that'll make it more consistent.

🪲While debugging I found this bug 🦗 Git bash + mpremote result in a transport error on mpremote resume mkdir /ramdisk/lib ( no leading :) #17093

Could you run that command with set -x enabled? That'll print a trace as commands run that includes the final interpolated value of everything.

just testing on Git bash - does not appear to cover enough ( id say that about 2% of windows users use git bash for mpremote) Even with a perfect bash script , that would cover only about 20% of the end user computing scenarios.

Agreed, this should also at least support .ps1 test cases, and probably .cmd test cases too.
This might also make it easier to test windows-y behaviors, too, since there's a port of powershell for linux it could use.

Personally I think that test are best written using a test framework, such as pytest. And that can handle .exp files, and has much more flexibility and parametrization and fuzzing capabilities, code coverage etc etc that will take so much more time to try to accomplish using bash, or any other shell language for that matter.

Almost definitely. There's a saying that, if you're using arrays in bash, it's time to rewrite it in a different language... and the rewrite technically does, even if just barely.

As a shell tool, it makes sense to have the test case files for mpremote in shell languages, but I do think it'll be useful to rewrite the test runner in python so it can reuse and integrate with parts of the other test runners.

I want to get to a working 'good' config first before refactoring further, though -- it's not just the runner that's broken, many of the actual tests are too.

@Josverl
Copy link
Contributor

Josverl commented Jul 26, 2025

Is this ready for another test run?

@AJMansfield
Copy link
Contributor Author

Is this ready for another test run?

Not really, no; just rebased this in order to more easily experiment with #12802 --- since its patch theoretically enables raw repl mode on the unix port, and might make it possible to run the mpremote tests as part of CI.

@AJMansfield AJMansfield force-pushed the mpremote-testfix branch 2 times, most recently from 7cf5415 to 545b256 Compare July 26, 2025 23:48
Signed-off-by: Anson Mansfield <amansfield@mantaro.com>
Signed-off-by: Anson Mansfield <amansfield@mantaro.com>
Signed-off-by: Anson Mansfield <amansfield@mantaro.com>
Signed-off-by: Anson Mansfield <amansfield@mantaro.com>
@AJMansfield AJMansfield force-pushed the mpremote-testfix branch 2 times, most recently from 45fa6d5 to 05abd10 Compare July 26, 2025 23:58
Replacing the original bash script with a test script derived from
the main suite's run-tests.py.

Signed-off-by: Anson Mansfield <amansfield@mantaro.com>
Signed-off-by: Anson Mansfield <amansfield@mantaro.com>
@AJMansfield
Copy link
Contributor Author

AJMansfield commented Jul 27, 2025

@Josverl Just rewrote the test driver to use more-or-less the same test code as the main suite's run-tests.py.

I've tested it against my own boards and can confirm it works correctly on unix; and since it's now just doing exactly what the main test suite does it should be compatible with windows too. Theoretically, hopefully you can confirm this.

It now also looks for and tries to run test_*.bat and test_*.ps1 scripts in addition to test_*.sh scripts, though I've not been able to test that just yet.

Still need to test the merge with #12802 or #16141 to confirm that the micropython socket server it sets up actually works though, and add the relevant CI jobs for it.

On a separate note, does the Windows port of micropython support raw repl mode? If it's possible to add an mpremote CI job for windows that'd be pretty useful to have too, given that it's been one of the tool's main pain points.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
tools Relates to tools/ directory in source, or other tooling
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy