Files
meshtastic/scripts/meshtasticator_e2e/README.md
T
eric a4abb5d15d feat(e2e): Meshtasticator radio-level validation harness for the adapter
Adds a skip-gated end-to-end suite (plugin/tests/e2e) that drives the
adapter against live Meshtasticator simulated nodes - real MeshtasticD
instances speaking the actual TCP/protobuf API - covering the layer no
contract test can reach: TCP handshake, inbound text over the simulated
mesh, and chunked outbound sends arriving at a peer node.

scripts/meshtasticator_e2e/run_e2e.sh boots N nodes (Docker or Linux
native MeshtasticD), discovers their TCP API ports, and runs the suite.
Radio-level reconnect and CI wiring are documented as open items pending
a Linux/Docker validation run.
2026-09-07 21:06:01 -07:00

100 lines
4.3 KiB
Markdown

# Meshtasticator e2e — radio-level validation for hermes-meshtastic
This directory is the **radio-level counterpart** to the contract suite
(`plugin/tests/contract`). The contract suite guarantees the adapter matches
the Hermes gateway API; it cannot prove the adapter actually talks to a
Meshtastic node. These e2e tests boot the
[Meshtasticator](https://meshtastic.org/docs/software/meshtasticator/)
interactive simulator — which runs the **real MeshtasticD device software**
per node with a simulated LoRa PHY — and drive the adapter against a live
simulated node.
| Layer | Validated by |
|---|---|
| Adapter ↔ Hermes gateway API | `plugin/tests/contract` (no deployment) |
| Adapter ↔ real MeshtasticD TCP/protobuf session | **this suite** |
| Inbound text across the (simulated) LoRa mesh | **this suite** |
| Outbound chunked sends arriving at another node | **this suite** |
| True RF (silicon LoRa, real propagation, duty cycle) | physical radio only |
## Layout
```
scripts/meshtasticator_e2e/
run_e2e.sh orchestrator: boots N nodes, runs pytest, tears down
README.md this file
plugin/tests/e2e/
test_meshtasticator_e2e.py the e2e assertions (skip-gated)
```
## Prerequisites
* **uv** + Python 3.13.
* A contract venv with the real gateway **and** the plugin (with deps) installed:
```bash
scripts/contract-test.sh # creates plugin/.venv-contract (hermes-agent pinned)
uv pip install --python plugin/.venv-contract/bin/python -e plugin
```
(`-e plugin` installs the meshtastic client library the tests also use.)
* A clone of Meshtasticator: `git clone https://github.com/meshtastic/meshtasticator`
* Runtime for the simulator — pick one:
* **Docker** (simplest, works on macOS/Windows): the simulator builds
MeshtasticD from a container image on first run (slow once).
* **Linux native**: build MeshtasticD's `native` PlatformIO target and pass
the build dir with `--program`.
## Run
```bash
# Docker mode (default)
MESHTASTICATOR_DIR=/path/to/meshtasticator \
scripts/meshtasticator_e2e/run_e2e.sh
# Linux native mode
MESHTASTICATOR_DIR=/path/to/meshtasticator \
scripts/meshtasticator_e2e/run_e2e.sh \
--mode native --program /path/to/firmware/.pio/build/native
# Tune the scenario
... --nodes 3 --channel-index 0 --host 127.0.0.1
```
The orchestrator boots the simulator, waits until `N` node TCP API ports accept
connections (Meshtasticator assigns node *n* → port `4404 + n`), then runs
`pytest plugin/tests/e2e` with `MESHTASTICATOR_E2E=1`. Simulator output lands in
`meshtasticator-sim.log` at the repo root.
Without `MESHTASTICATOR_E2E=1` the e2e module skips, so ordinary unit/CI runs
stay fast and gateway-free.
## What the tests do
1. **Inbound**: peer node 1 broadcasts text; the adapter (connected to node 0)
must receive it as a real gateway `MessageEvent` (`host/port/channel_index`
come from `E2E_PORTS`/`E2E_HOST`/`E2E_CHANNEL_INDEX`).
2. **Outbound**: the adapter sends a >180-char message; it must be chunked and
the final chunk (`(i/n) … word59`) must arrive at peer node 1.
A `_ProbeAdapter` subclass records inbound events instead of dispatching to a
Hermes agent handler (no agent runs in these tests; dispatch is already covered
by the contract suite).
## Status / open items (v1 scaffold)
This is an initial, structurally validated scaffold. A full green run still
needs to happen on a Linux/Docker host with a MeshtasticD build, and these
items are expected to need iteration there:
* **Node adjacency**: the simulator's default random placement may put nodes out
of range. For deterministic tests, seed close-together coordinates (the sim
supports `--from-file` with an `out/nodeConfig.yaml`).
* **Channel semantics**: tests default to channel index 0 (stock primary
channel). Mirroring production (channel 1 / private channel) requires
configuring matching channels on the simulated nodes.
* **Reconnect flow**: killing/restarting a single simulated node needs per-node
lifecycle control (native mode subprocesses; docker mode currently runs all
nodes in one container), so the adapter's watchdog reconnect is **not** yet
exercised here. See the watchdog unit coverage in the adapter for now.
* **CI wiring**: an e2e job needs a docker-enabled runner and tolerates a long
first-run firmware build — deliberately left out of this PR.