Skip to content

Commit beaca13

Browse files
add testing file, outsourced from usage, add manual testing docker file
1 parent 65b578f commit beaca13

File tree

2 files changed

+192
-0
lines changed

2 files changed

+192
-0
lines changed

Dockerfile.tests_manually

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Build image
2+
# $ docker build -t micropython-test-manually -f Dockerfile.tests_manually .
3+
# if a unittest fails, it will exit with non-zero code
4+
#
5+
# Run image, only possible if all tests passed
6+
# $ docker run -it --rm --name micropython-test-manually micropython-test-manually
7+
8+
FROM micropython/unix:v1.18
9+
10+
COPY ./ /home
11+
# keep examples and tests registers JSON file easily in sync
12+
COPY registers/example.json /home/tests/test-registers.json
13+
COPY umodbus /root/.micropython/lib/umodbus
14+
COPY mpy_unittest.py /root/.micropython/lib/mpy_unittest.py
15+
16+
RUN micropython-dev -m upip install micropython-ulogging
17+
18+
ENTRYPOINT ["/bin/bash"]

docs/TESTING.md

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
# Testing
2+
3+
Testing is done inside MicroPython Docker container
4+
5+
---------------
6+
7+
## Basics
8+
9+
This library is as of now tested with the `v1.18` version of MicroPython
10+
11+
### Pull container
12+
13+
Checkout the available
14+
[MicroPython containers](https://hub.docker.com/r/micropython/unix/tags) and
15+
pull the `v1.18` locally.
16+
17+
```bash
18+
docker pull micropython/unix:v1.18
19+
```
20+
21+
### Spin up container
22+
23+
#### Simple container
24+
25+
Use this command for your first tests or to run some MicroPython commands in
26+
a simple REPL
27+
28+
```bash
29+
docker run -it --name micropython-1.18 --network=host --entrypoint bash micropython/unix:v1.18
30+
```
31+
32+
#### Enter MicroPython REPL
33+
34+
Inside the container enter the REPL by running `micropython-dev`. The console
35+
should now look similar to this
36+
37+
```
38+
root@debian:/home#
39+
MicroPython v1.18 on 2022-01-17; linux version
40+
Use Ctrl-D to exit, Ctrl-E for paste mode
41+
>>>
42+
```
43+
44+
## Testing
45+
46+
All tests are automatically executed on a push to GitHub and have to be passed
47+
in order to be allowed to merge to the main development branch, see also [CONTRIBUTING](CONTRIBUTING.md).
48+
49+
### Run unittests manually
50+
51+
First build and run the docker image with the following command
52+
53+
```bash
54+
docker build -t micropython-test-manually -f Dockerfile.tests_manually .
55+
docker run -it --name micropython-test-manually micropython-test-manually
56+
```
57+
58+
Run all unittests defined in the `tests` directory and exit with status result
59+
60+
```bash
61+
micropython-dev -c "import mpy_unittest as unittest; unittest.main('tests')"
62+
```
63+
64+
In order to execute only a specific set of tests use the following command
65+
inside the built and running MicroPython container
66+
67+
```bash
68+
# run all tests of "TestAbsoluteTruth" defined in tests/test_absolute_truth.py
69+
# and exit with status result
70+
micropython-dev -c "import mpy_unittest as unittest; unittest.main(name='tests.test_absolute_truth', fromlist=['TestAbsoluteTruth'])"
71+
```
72+
73+
### Custom container for unittests
74+
75+
```bash
76+
docker build --tag micropython-test --file Dockerfile.tests .
77+
```
78+
79+
As soon as the built image is executed all unittests are executed. The
80+
container will exit with a non-zero status in case of a unittest failure.
81+
82+
The return value can be collected by `echo $?` (on Linux based systems) or
83+
`echo %errorlevel%` (on Windows), which will be either `0` in case all tests
84+
passed, or `1` if one or multiple tests failed.
85+
86+
### Docker compose
87+
88+
For more complex unittests and integration tests, several Dockerfiles are
89+
combined into a docker-compose file.
90+
91+
The option `--build` can be skipped on the second run, to avoid rebuilds of
92+
the containers. All "dynamic" data is shared via `volumes`.
93+
94+
#### TCP integration tests
95+
96+
##### Overview
97+
98+
The TCP integration tests defined by `test_tcp_example.py` uses the
99+
`Dockerfile.client_tcp` and `Dockerfile.test_examples`.
100+
101+
A network bridge is created with fixed IPv4 addresses in order to bind the
102+
client to a known IP and let the host reach it on that predefined IP.
103+
104+
The port defined in `tcp_client_example.py`, executed by
105+
`Dockerfile.client_tcp` has to be open, exposed to the `micropython-host`
106+
service running `Dockerfile.test_examples` and optionally exposed in the
107+
`docker-compose-tcp-test.yaml` file.
108+
109+
Finally the tests defined in `TestTcpExample` are executed. The tests read and
110+
write all available register types on the client and check the response with
111+
the expected data.
112+
113+
##### Usage
114+
115+
```bash
116+
docker compose -f docker-compose-tcp-test.yaml up --build --exit-code-from micropython-host --remove-orphans
117+
```
118+
119+
#### RTU integration tests
120+
121+
##### UART interface
122+
123+
As the [MicroPython containers](https://hub.docker.com/r/micropython/unix/tags)
124+
do not have a UART interface, which is additionally anyway not connectable via
125+
two containers, a [`UART fake`](fakes.machine.UART) has been implemented.
126+
127+
The fake [`UART`](fakes.machine.UART) class provides all required functions
128+
like [`any()`](fakes.machine.UART.any), [`read()`](fakes.machine.UART.read) and
129+
[`write()`](fakes.machine.UART.write) to simulate a UART interface.
130+
131+
During the initialisation of the fake UART a simple and very basic socket
132+
request is made to `172.25.0.2`, a predefined IP address, see
133+
`docker-compose-rtu-test.yaml`. In case no response is received, a socket based
134+
server is started. It is thereby important to start the RTU client before the
135+
RTU host. The RTU host will perform the same check during the UART init, but
136+
will reach the (already running) socket server and connect to it.
137+
138+
The data provided to the [`write()`](fakes.machine.UART.write) call of the RTU
139+
host, will be sent to the background socket server of the RTU client and be
140+
read inside the [`get_request()`](umodbus.serial.Serial.get_request) function
141+
which is constantly called by the [`process()`](umodbus.modbus.Modbus.process)
142+
function.
143+
144+
After it has been processed from Modbus perspective, the RTU client response
145+
will then be put by the [`write()`](fakes.machine.UART.write) function into a
146+
queue on RTU client side, picked up by the RTU client background socket server
147+
thread and sent back to the RTU host where it is made available via the
148+
[`read()`](fakes.machine.UART.read) function.
149+
150+
##### Overview
151+
152+
The RTU integration tests defined by `test_rtu_example.py` uses the
153+
`Dockerfile.client_rtu` and `Dockerfile.test_examples`.
154+
155+
A network bridge is created with fixed IPv4 addresses in order to bind the
156+
client to a known IP and let the host reach it on that predefined IP.
157+
158+
The port defined in `rtu_client_example.py`, executed by
159+
`Dockerfile.client_rtu` has to be open, exposed to the `micropython-host`
160+
service running `Dockerfile.test_examples` and optionally exposed in the
161+
`docker-compose-rtu-test.yaml` file.
162+
163+
Finally the tests defined in `TestRtuExample` are executed. The tests read and
164+
write all available register types on the client and check the response with
165+
the expected data.
166+
167+
##### Usage
168+
169+
```bash
170+
docker compose -f docker-compose-rtu-test.yaml up --build --exit-code-from micropython-host-rtu --remove-orphans
171+
```
172+
173+
<!-- Links -->
174+
[ref-fakes]: https://github.com/brainelectronics/micropython-modbus/blob/develop/fakes/machine.py

0 commit comments

Comments
 (0)