summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJim Mussared <jim.mussared@gmail.com>2023-06-14 15:38:01 +1000
committerDamien George <damien@micropython.org>2024-10-09 16:39:00 +1100
commit6461ffd9d174fdf799c8de27f92e4505ec731c7e (patch)
tree556094b579587ef8638ca1ce0fabf797ee3fc05b
parentdd6f78f0142a0567ed21a7b29aa6d810c85e1bdb (diff)
tools/mpremote: Add initial regression tests for mpremote.
These tests are specifically for the command-line interface and cover: - resume/soft-reset/connect/disconnect - mount - fs cp,touch,mkdir,cat,sha256sum,rm,rmdir - eval/exec/run This work was funded through GitHub Sponsors. Signed-off-by: Jim Mussared <jim.mussared@gmail.com> Signed-off-by: Damien George <damien@micropython.org>
-rw-r--r--tools/mpremote/tests/README.md14
-rwxr-xr-xtools/mpremote/tests/run-mpremote-tests.sh30
-rwxr-xr-xtools/mpremote/tests/test_eval_exec_run.sh26
-rw-r--r--tools/mpremote/tests/test_eval_exec_run.sh.exp6
-rwxr-xr-xtools/mpremote/tests/test_filesystem.sh162
-rw-r--r--tools/mpremote/tests/test_filesystem.sh.exp183
-rwxr-xr-xtools/mpremote/tests/test_mount.sh28
-rw-r--r--tools/mpremote/tests/test_mount.sh.exp7
-rwxr-xr-xtools/mpremote/tests/test_recursive_cp.sh60
-rw-r--r--tools/mpremote/tests/test_recursive_cp.sh.exp98
-rwxr-xr-xtools/mpremote/tests/test_resume.sh23
-rw-r--r--tools/mpremote/tests/test_resume.sh.exp17
12 files changed, 654 insertions, 0 deletions
diff --git a/tools/mpremote/tests/README.md b/tools/mpremote/tests/README.md
new file mode 100644
index 000000000..5b924d2fb
--- /dev/null
+++ b/tools/mpremote/tests/README.md
@@ -0,0 +1,14 @@
+# Tests for mpremote
+
+This directory contains a set of tests for `mpremote`.
+
+Requirements:
+- A device running MicroPython connected to a serial port on the host.
+- Python 3.x, `bash` and various Unix tools such as `find`, `mktemp`, `sed`, `sort`, `tr`.
+
+To run the tests do:
+
+ $ ./run-mpremote-tests.sh
+
+Each test should print "OK" if it passed. Otherwise it will print "CRASH", or "FAIL"
+and a diff of the expected and actual test output.
diff --git a/tools/mpremote/tests/run-mpremote-tests.sh b/tools/mpremote/tests/run-mpremote-tests.sh
new file mode 100755
index 000000000..11d82c9bb
--- /dev/null
+++ b/tools/mpremote/tests/run-mpremote-tests.sh
@@ -0,0 +1,30 @@
+#!/bin/bash
+set -e
+
+TEST_DIR=$(dirname $0)
+MPREMOTE=${TEST_DIR}/../mpremote.py
+
+if [ -z "$1" ]; then
+ # Find tests matching test_*.sh
+ TESTS=${TEST_DIR}/test_*.sh
+else
+ # Specific test path from the command line.
+ TESTS="$1"
+fi
+
+for t in $TESTS; do
+ TMP=$(mktemp -d)
+ echo -n "${t}: "
+ # Strip CR and replace the random temp dir with a token.
+ if env MPREMOTE=${MPREMOTE} TMP="${TMP}" "${t}" | tr -d '\r' | sed "s,${TMP},"'${TMP},g' > "${t}.out"; then
+ if diff "${t}.out" "${t}.exp" > /dev/null; then
+ echo "OK"
+ else
+ echo "FAIL"
+ diff "${t}.out" "${t}.exp" || true
+ fi
+ else
+ echo "CRASH"
+ fi
+ rm -r "${TMP}"
+done
diff --git a/tools/mpremote/tests/test_eval_exec_run.sh b/tools/mpremote/tests/test_eval_exec_run.sh
new file mode 100755
index 000000000..dd30b2594
--- /dev/null
+++ b/tools/mpremote/tests/test_eval_exec_run.sh
@@ -0,0 +1,26 @@
+#!/bin/bash
+set -e
+
+$MPREMOTE exec "print('mpremote')"
+
+$MPREMOTE exec "print('before sleep'); import time; time.sleep(0.1); print('after sleep')"
+$MPREMOTE exec --no-follow "print('before sleep'); import time; time.sleep(0.1); print('after sleep')"
+sleep 0.3
+
+$MPREMOTE eval "1+2"
+$MPREMOTE eval "[{'a': 'b'}, (1,2,3,), True]"
+
+cat << EOF > /tmp/run.py
+print("run")
+EOF
+
+$MPREMOTE run /tmp/run.py
+
+cat << EOF > /tmp/run.py
+import time
+for i in range(3):
+ time.sleep(0.1)
+ print("run")
+EOF
+$MPREMOTE run --no-follow /tmp/run.py
+sleep 0.5
diff --git a/tools/mpremote/tests/test_eval_exec_run.sh.exp b/tools/mpremote/tests/test_eval_exec_run.sh.exp
new file mode 100644
index 000000000..3ea7a9d7c
--- /dev/null
+++ b/tools/mpremote/tests/test_eval_exec_run.sh.exp
@@ -0,0 +1,6 @@
+mpremote
+before sleep
+after sleep
+3
+[{'a': 'b'}, (1, 2, 3), True]
+run
diff --git a/tools/mpremote/tests/test_filesystem.sh b/tools/mpremote/tests/test_filesystem.sh
new file mode 100755
index 000000000..b6d5a7feb
--- /dev/null
+++ b/tools/mpremote/tests/test_filesystem.sh
@@ -0,0 +1,162 @@
+#!/bin/bash
+set -e
+
+# Creates a RAM disk big enough to hold two copies of the test directory
+# structure.
+cat << EOF > "${TMP}/ramdisk.py"
+class RAMBlockDev:
+ def __init__(self, block_size, num_blocks):
+ self.block_size = block_size
+ self.data = bytearray(block_size * num_blocks)
+
+ def readblocks(self, block_num, buf):
+ for i in range(len(buf)):
+ buf[i] = self.data[block_num * self.block_size + i]
+
+ def writeblocks(self, block_num, buf):
+ for i in range(len(buf)):
+ self.data[block_num * self.block_size + i] = buf[i]
+
+ def ioctl(self, op, arg):
+ if op == 4: # get number of blocks
+ return len(self.data) // self.block_size
+ if op == 5: # get block size
+ return self.block_size
+
+import os
+
+bdev = RAMBlockDev(512, 50)
+os.VfsFat.mkfs(bdev)
+os.mount(bdev, '/ramdisk')
+os.chdir('/ramdisk')
+EOF
+
+
+echo -----
+$MPREMOTE run "${TMP}/ramdisk.py"
+$MPREMOTE resume ls
+
+echo -----
+$MPREMOTE resume touch a.py
+$MPREMOTE resume touch :b.py
+$MPREMOTE resume ls :
+$MPREMOTE resume cat a.py
+$MPREMOTE resume cat :b.py
+$MPREMOTE resume sha256sum a.py
+echo -n "" | sha256sum
+
+echo -----
+cat << EOF > "${TMP}/a.py"
+print("Hello")
+print("World")
+EOF
+$MPREMOTE resume cp "${TMP}/a.py" :
+$MPREMOTE resume cp "${TMP}/a.py" :b.py
+$MPREMOTE resume cp "${TMP}/a.py" :c.py
+$MPREMOTE resume cp :a.py :d.py
+$MPREMOTE resume ls
+$MPREMOTE resume exec "import a; import b; import c"
+$MPREMOTE resume sha256sum a.py
+cat "${TMP}/a.py" | sha256sum
+
+echo -----
+$MPREMOTE resume mkdir aaa
+$MPREMOTE resume mkdir :bbb
+$MPREMOTE resume cp "${TMP}/a.py" :aaa
+$MPREMOTE resume cp "${TMP}/a.py" :bbb/b.py
+$MPREMOTE resume cat :aaa/a.py bbb/b.py
+
+echo -----
+$MPREMOTE resume rm :b.py c.py
+$MPREMOTE resume ls
+$MPREMOTE resume rm :aaa/a.py bbb/b.py
+$MPREMOTE resume rmdir aaa :bbb
+$MPREMOTE resume ls
+
+echo -----
+env EDITOR="sed -i s/Hello/Goodbye/" $MPREMOTE resume edit d.py
+$MPREMOTE resume sha256sum :d.py
+$MPREMOTE resume exec "import d"
+
+
+# Create a local directory structure and copy it to `:` on the device.
+echo -----
+mkdir -p "${TMP}/package"
+mkdir -p "${TMP}/package/subpackage"
+cat << EOF > "${TMP}/package/__init__.py"
+from .x import x
+from .subpackage import y
+EOF
+cat << EOF > "${TMP}/package/x.py"
+def x():
+ print("x")
+EOF
+cat << EOF > "${TMP}/package/subpackage/__init__.py"
+from .y import y
+EOF
+cat << EOF > "${TMP}/package/subpackage/y.py"
+def y():
+ print("y")
+EOF
+$MPREMOTE run "${TMP}/ramdisk.py"
+$MPREMOTE resume cp -r "${TMP}/package" :
+$MPREMOTE resume ls : :package :package/subpackage
+$MPREMOTE resume exec "import package; package.x(); package.y()"
+
+
+# Same thing except with a destination directory name.
+echo -----
+$MPREMOTE run "${TMP}/ramdisk.py"
+$MPREMOTE resume cp -r "${TMP}/package" :package2
+$MPREMOTE resume ls : :package2 :package2/subpackage
+$MPREMOTE resume exec "import package2; package2.x(); package2.y()"
+
+
+# Copy to an existing directory, it will be copied inside.
+echo -----
+$MPREMOTE run "${TMP}/ramdisk.py"
+$MPREMOTE resume mkdir :test
+$MPREMOTE resume cp -r "${TMP}/package" :test
+$MPREMOTE resume ls :test :test/package :test/package/subpackage
+
+# Copy to non-existing sub-directory.
+echo -----
+$MPREMOTE resume cp -r "${TMP}/package" :test/package2
+$MPREMOTE resume ls :test :test/package2 :test/package2/subpackage
+
+# Copy from the device back to local.
+echo -----
+mkdir "${TMP}/copy"
+$MPREMOTE resume cp -r :test/package "${TMP}/copy"
+ls "${TMP}/copy" "${TMP}/copy/package" "${TMP}/copy/package/subpackage"
+
+# Copy from the device back to local with destination directory name.
+echo -----
+$MPREMOTE resume cp -r :test/package "${TMP}/copy/package2"
+ls "${TMP}/copy" "${TMP}/copy/package2" "${TMP}/copy/package2/subpackage"
+
+
+# Copy from device to another location on the device with destination directory name.
+echo -----
+$MPREMOTE run "${TMP}/ramdisk.py"
+$MPREMOTE resume cp -r "${TMP}/package" :
+$MPREMOTE resume cp -r :package :package3
+$MPREMOTE resume ls : :package3 :package3/subpackage
+
+# Copy from device to another location on the device into an existing directory.
+echo -----
+$MPREMOTE run "${TMP}/ramdisk.py"
+$MPREMOTE resume cp -r "${TMP}/package" :
+$MPREMOTE resume mkdir :package4
+$MPREMOTE resume cp -r :package :package4
+$MPREMOTE resume ls : :package4 :package4/package :package4/package/subpackage
+
+# Repeat an existing copy with one file modified.
+echo -----
+cat << EOF > "${TMP}/package/subpackage/y.py"
+def y():
+ print("y2")
+EOF
+$MPREMOTE resume cp -r "${TMP}/package" :
+$MPREMOTE resume ls : :package :package/subpackage
+$MPREMOTE resume exec "import package; package.x(); package.y()"
diff --git a/tools/mpremote/tests/test_filesystem.sh.exp b/tools/mpremote/tests/test_filesystem.sh.exp
new file mode 100644
index 000000000..7220dc41e
--- /dev/null
+++ b/tools/mpremote/tests/test_filesystem.sh.exp
@@ -0,0 +1,183 @@
+-----
+ls :
+-----
+touch :a.py
+touch :b.py
+ls :
+ 0 a.py
+ 0 b.py
+sha256sum :a.py
+e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
+e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 -
+-----
+cp ${TMP}/a.py :
+cp ${TMP}/a.py :b.py
+cp ${TMP}/a.py :c.py
+cp :a.py :d.py
+ls :
+ 30 a.py
+ 30 b.py
+ 30 c.py
+ 30 d.py
+Hello
+World
+Hello
+World
+Hello
+World
+sha256sum :a.py
+50f0a701dd6cd6125387b96515300c9d5294c006518f8e62fa9eea3b66587f21
+50f0a701dd6cd6125387b96515300c9d5294c006518f8e62fa9eea3b66587f21 -
+-----
+mkdir :aaa
+mkdir :bbb
+cp ${TMP}/a.py :aaa
+cp ${TMP}/a.py :bbb/b.py
+print("Hello")
+print("World")
+print("Hello")
+print("World")
+-----
+rm :b.py
+rm :c.py
+ls :
+ 30 a.py
+ 30 d.py
+ 0 aaa/
+ 0 bbb/
+rm :aaa/a.py
+rm :bbb/b.py
+rmdir :aaa
+rmdir :bbb
+ls :
+ 30 a.py
+ 30 d.py
+-----
+edit :d.py
+sha256sum :d.py
+612c7ddb88390ac86b4174b26a6e5b52fc2f2838b234efd8f6f7c41631a49d04
+Goodbye
+World
+-----
+cp ${TMP}/package :
+ls :
+ 0 package/
+ls :package
+ 0 subpackage/
+ 43 __init__.py
+ 22 x.py
+ls :package/subpackage
+ 17 __init__.py
+ 22 y.py
+x
+y
+-----
+cp ${TMP}/package :package2
+ls :
+ 0 package2/
+ls :package2
+ 0 subpackage/
+ 43 __init__.py
+ 22 x.py
+ls :package2/subpackage
+ 17 __init__.py
+ 22 y.py
+x
+y
+-----
+mkdir :test
+cp ${TMP}/package :test
+ls :test
+ 0 package/
+ls :test/package
+ 0 subpackage/
+ 43 __init__.py
+ 22 x.py
+ls :test/package/subpackage
+ 17 __init__.py
+ 22 y.py
+-----
+cp ${TMP}/package :test/package2
+ls :test
+ 0 package/
+ 0 package2/
+ls :test/package2
+ 0 subpackage/
+ 43 __init__.py
+ 22 x.py
+ls :test/package2/subpackage
+ 17 __init__.py
+ 22 y.py
+-----
+cp :test/package ${TMP}/copy
+${TMP}/copy:
+package
+
+${TMP}/copy/package:
+__init__.py
+subpackage
+x.py
+
+${TMP}/copy/package/subpackage:
+__init__.py
+y.py
+-----
+cp :test/package ${TMP}/copy/package2
+${TMP}/copy:
+package
+package2
+
+${TMP}/copy/package2:
+__init__.py
+subpackage
+x.py
+
+${TMP}/copy/package2/subpackage:
+__init__.py
+y.py
+-----
+cp ${TMP}/package :
+cp :package :package3
+ls :
+ 0 package/
+ 0 package3/
+ls :package3
+ 0 subpackage/
+ 43 __init__.py
+ 22 x.py
+ls :package3/subpackage
+ 17 __init__.py
+ 22 y.py
+-----
+cp ${TMP}/package :
+mkdir :package4
+cp :package :package4
+ls :
+ 0 package/
+ 0 package4/
+ls :package4
+ 0 package/
+ls :package4/package
+ 0 subpackage/
+ 43 __init__.py
+ 22 x.py
+ls :package4/package/subpackage
+ 17 __init__.py
+ 22 y.py
+-----
+cp ${TMP}/package :
+Up to date: ./package/__init__.py
+Up to date: ./package/subpackage/__init__.py
+Up to date: ./package/x.py
+ls :
+ 0 package/
+ 0 package4/
+ls :package
+ 0 subpackage/
+ 43 __init__.py
+ 22 x.py
+ls :package/subpackage
+ 17 __init__.py
+ 23 y.py
+x
+y2
diff --git a/tools/mpremote/tests/test_mount.sh b/tools/mpremote/tests/test_mount.sh
new file mode 100755
index 000000000..9eab0b0d6
--- /dev/null
+++ b/tools/mpremote/tests/test_mount.sh
@@ -0,0 +1,28 @@
+#!/bin/bash
+set -e
+
+# Create a local directory structure and mount the parent directory on the device.
+echo -----
+mkdir -p "${TMP}/mount_package"
+mkdir -p "${TMP}/mount_package/subpackage"
+cat << EOF > "${TMP}/mount_package/__init__.py"
+from .x import x
+from .subpackage import y
+EOF
+cat << EOF > "${TMP}/mount_package/x.py"
+def x():
+ print("x")
+EOF
+cat << EOF > "${TMP}/mount_package/subpackage/__init__.py"
+from .y import y
+EOF
+cat << EOF > "${TMP}/mount_package/subpackage/y.py"
+def y():
+ print("y")
+EOF
+$MPREMOTE mount ${TMP} exec "import mount_package; mount_package.x(); mount_package.y()"
+
+# Write to a file on the device and see that it's written locally.
+echo -----
+$MPREMOTE mount ${TMP} exec "open('test.txt', 'w').write('hello world\n')"
+cat "${TMP}/test.txt"
diff --git a/tools/mpremote/tests/test_mount.sh.exp b/tools/mpremote/tests/test_mount.sh.exp
new file mode 100644
index 000000000..560f5e4f1
--- /dev/null
+++ b/tools/mpremote/tests/test_mount.sh.exp
@@ -0,0 +1,7 @@
+-----
+x
+y
+Local directory ${TMP} is mounted at /remote
+-----
+Local directory ${TMP} is mounted at /remote
+hello world
diff --git a/tools/mpremote/tests/test_recursive_cp.sh b/tools/mpremote/tests/test_recursive_cp.sh
new file mode 100755
index 000000000..397b5fd57
--- /dev/null
+++ b/tools/mpremote/tests/test_recursive_cp.sh
@@ -0,0 +1,60 @@
+#!/bin/bash
+set -e
+
+echo -----
+mkdir -p $TMP/a $TMP/a/b
+touch $TMP/a/x.py $TMP/a/b/y.py
+ls $TMP/a | sort
+ls $TMP/a/b | sort
+
+# TODO
+echo -----
+touch $TMP/y.py
+ls $TMP | sort
+
+# Recursive copy to a directory that doesn't exist. The source directory will
+# be copied to the destination (i.e. bX will the same as a).
+echo -----
+cp -r $TMP/a $TMP/b1
+cp -r $TMP/a/ $TMP/b2
+cp -r $TMP/a $TMP/b3/
+cp -r $TMP/a/ $TMP/b4/
+
+# Recursive copy to a directory that does exist. The source directory will be
+# copied into the destination (i.e. bX will contain a copy of a).
+echo -----
+mkdir $TMP/c{1,2,3,4}
+cp -r $TMP/a $TMP/c1
+cp -r $TMP/a/ $TMP/c2
+cp -r $TMP/a $TMP/c3/
+cp -r $TMP/a/ $TMP/c4/
+
+echo -----
+find $TMP | sort
+
+echo -----
+rm -rf $TMP/b{1,2,3,4} $TMP/c{1,2,3,4}
+
+
+
+# Now replicate the same thing using `mpremote cp`.
+
+# Recursive copy to a directory that doesn't exist. The source directory will
+# be copied to the destination (i.e. bX will the same as a).
+echo -----
+$MPREMOTE cp --no-verbose -r $TMP/a $TMP/b1
+$MPREMOTE cp --no-verbose -r $TMP/a/ $TMP/b2
+$MPREMOTE cp --no-verbose -r $TMP/a $TMP/b3/
+$MPREMOTE cp --no-verbose -r $TMP/a/ $TMP/b4/
+
+# Recursive copy to a directory that does exist. The source directory will be
+# copied into the destination (i.e. bX will contain a copy of a).
+echo -----
+mkdir $TMP/c{1,2,3,4}
+$MPREMOTE cp --no-verbose -r $TMP/a $TMP/c1
+$MPREMOTE cp --no-verbose -r $TMP/a/ $TMP/c2
+$MPREMOTE cp --no-verbose -r $TMP/a $TMP/c3/
+$MPREMOTE cp --no-verbose -r $TMP/a/ $TMP/c4/
+
+echo -----
+find $TMP | sort
diff --git a/tools/mpremote/tests/test_recursive_cp.sh.exp b/tools/mpremote/tests/test_recursive_cp.sh.exp
new file mode 100644
index 000000000..3b787dfe7
--- /dev/null
+++ b/tools/mpremote/tests/test_recursive_cp.sh.exp
@@ -0,0 +1,98 @@
+-----
+b
+x.py
+y.py
+-----
+a
+y.py
+-----
+-----
+-----
+${TMP}
+${TMP}/a
+${TMP}/a/b
+${TMP}/a/b/y.py
+${TMP}/a/x.py
+${TMP}/b1
+${TMP}/b1/b
+${TMP}/b1/b/y.py
+${TMP}/b1/x.py
+${TMP}/b2
+${TMP}/b2/b
+${TMP}/b2/b/y.py
+${TMP}/b2/x.py
+${TMP}/b3
+${TMP}/b3/b
+${TMP}/b3/b/y.py
+${TMP}/b3/x.py
+${TMP}/b4
+${TMP}/b4/b
+${TMP}/b4/b/y.py
+${TMP}/b4/x.py
+${TMP}/c1
+${TMP}/c1/a
+${TMP}/c1/a/b
+${TMP}/c1/a/b/y.py
+${TMP}/c1/a/x.py
+${TMP}/c2
+${TMP}/c2/a
+${TMP}/c2/a/b
+${TMP}/c2/a/b/y.py
+${TMP}/c2/a/x.py
+${TMP}/c3
+${TMP}/c3/a
+${TMP}/c3/a/b
+${TMP}/c3/a/b/y.py
+${TMP}/c3/a/x.py
+${TMP}/c4
+${TMP}/c4/a
+${TMP}/c4/a/b
+${TMP}/c4/a/b/y.py
+${TMP}/c4/a/x.py
+${TMP}/y.py
+-----
+-----
+-----
+-----
+${TMP}
+${TMP}/a
+${TMP}/a/b
+${TMP}/a/b/y.py
+${TMP}/a/x.py
+${TMP}/b1
+${TMP}/b1/b
+${TMP}/b1/b/y.py
+${TMP}/b1/x.py
+${TMP}/b2
+${TMP}/b2/b
+${TMP}/b2/b/y.py
+${TMP}/b2/x.py
+${TMP}/b3
+${TMP}/b3/b
+${TMP}/b3/b/y.py
+${TMP}/b3/x.py
+${TMP}/b4
+${TMP}/b4/b
+${TMP}/b4/b/y.py
+${TMP}/b4/x.py
+${TMP}/c1
+${TMP}/c1/a
+${TMP}/c1/a/b
+${TMP}/c1/a/b/y.py
+${TMP}/c1/a/x.py
+${TMP}/c2
+${TMP}/c2/a
+${TMP}/c2/a/b
+${TMP}/c2/a/b/y.py
+${TMP}/c2/a/x.py
+${TMP}/c3
+${TMP}/c3/a
+${TMP}/c3/a/b
+${TMP}/c3/a/b/y.py
+${TMP}/c3/a/x.py
+${TMP}/c4
+${TMP}/c4/a
+${TMP}/c4/a/b
+${TMP}/c4/a/b/y.py
+${TMP}/c4/a/x.py
+${TMP}/y.py
diff --git a/tools/mpremote/tests/test_resume.sh b/tools/mpremote/tests/test_resume.sh
new file mode 100755
index 000000000..dfc351c83
--- /dev/null
+++ b/tools/mpremote/tests/test_resume.sh
@@ -0,0 +1,23 @@
+#!/bin/bash
+set -e
+
+# The eval command will continue the state of the exec.
+echo -----
+$MPREMOTE exec "a = 'hello'" eval "a"
+
+# Automatic soft reset. `a` will trigger NameError.
+echo -----
+$MPREMOTE eval "a" || true
+
+# Resume will skip soft reset.
+echo -----
+$MPREMOTE exec "a = 'resume'"
+$MPREMOTE resume eval "a"
+
+# The eval command will continue the state of the exec.
+echo -----
+$MPREMOTE exec "a = 'soft-reset'" eval "a" soft-reset eval "1+1" eval "a" || true
+
+# A disconnect will trigger auto-reconnect.
+echo -----
+$MPREMOTE eval "1+2" disconnect eval "2+3"
diff --git a/tools/mpremote/tests/test_resume.sh.exp b/tools/mpremote/tests/test_resume.sh.exp
new file mode 100644
index 000000000..20c75928a
--- /dev/null
+++ b/tools/mpremote/tests/test_resume.sh.exp
@@ -0,0 +1,17 @@
+-----
+hello
+-----
+Traceback (most recent call last):
+ File "<stdin>", line 1, in <module>
+NameError: name 'a' isn't defined
+-----
+resume
+-----
+soft-reset
+2
+Traceback (most recent call last):
+ File "<stdin>", line 1, in <module>
+NameError: name 'a' isn't defined
+-----
+3
+5