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>
This commit is contained in:
Jim Mussared 2023-06-14 15:38:01 +10:00 committed by Damien George
parent dd6f78f014
commit 6461ffd9d1
12 changed files with 654 additions and 0 deletions

View File

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

View File

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

View File

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

View File

@ -0,0 +1,6 @@
mpremote
before sleep
after sleep
3
[{'a': 'b'}, (1, 2, 3), True]
run

View File

@ -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()"

View File

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

View File

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

View File

@ -0,0 +1,7 @@
-----
x
y
Local directory ${TMP} is mounted at /remote
-----
Local directory ${TMP} is mounted at /remote
hello world

View File

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

View File

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

View File

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

View File

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