From 6125130e6ac2b80cd7c770561cbb3e5ef941b9cc Mon Sep 17 00:00:00 2001 From: Eric Liu Date: Mon, 7 Sep 2026 21:46:25 -0700 Subject: [PATCH] fix(e2e): peer sendText moved to Interface; add RF failure diagnostics MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Run 10538 booted the full simulator and ran pytest — both failures were test-side: the installed meshtastic client moved sendText from Node to the Interface, and the outbound chunked message never arrived at the peer (cause still unknown). Fix the sendText call and add in-run diagnostics so the next failure is self-explaining: - e2e: outbound-timeout failure now reports what arrived at the peer and the simulator log tail; sim now boots with -v (meshtastic debug logging). - run_e2e.sh: on pytest failure in docker mode, dump per-node meshtasticd logs (meshtasticator-nodes.log) before cleanup removes the container. --- plugin/tests/e2e/test_meshtasticator_e2e.py | 22 ++++++++++++++++++++- scripts/meshtasticator_e2e/run_e2e.sh | 13 +++++++++++- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/plugin/tests/e2e/test_meshtasticator_e2e.py b/plugin/tests/e2e/test_meshtasticator_e2e.py index 5476e48..5d19278 100644 --- a/plugin/tests/e2e/test_meshtasticator_e2e.py +++ b/plugin/tests/e2e/test_meshtasticator_e2e.py @@ -226,10 +226,11 @@ def test_adapter_receives_broadcast_from_peer(node0): return any(getattr(e, "text", None) == sent for e in node0.received_events) # Radio delivery is not guaranteed per attempt; retry a few times. + # (meshtastic client >=2.8: sendText lives on the Interface, not Node.) for _ in range(3): if _got(): break - peer.localNode.sendText( + peer.sendText( text=sent, destinationId="^all", channelIndex=E2E_CHANNEL_INDEX ) time.sleep(1) @@ -271,6 +272,25 @@ def test_adapter_chunked_send_reaches_peer(node0, loop): return any(str(r).rstrip().endswith("word59") for r in received) _wait_for(_all_chunks_arrived, timeout_s=45, what="chunked outbound send at peer") + + except Exception as exc: + # Fast-fail diagnostics: what arrived at the peer, and what the + # simulator itself logged (RF forwarding/routing noise). + tail = "" + try: + sim_log = os.path.join(os.getcwd(), "..", "..", "meshtasticator-sim.log") + if not os.path.exists(sim_log): + sim_log = os.path.join(os.getcwd(), "meshtasticator-sim.log") + if os.path.exists(sim_log): + tail = "\n".join( + open(sim_log, errors="replace").read().splitlines()[-40:] + ) + except OSError: + pass + raise AssertionError( + f"{exc}\nreceived at peer so far: {received[-10:]!r}\n" + f"--- meshtasticator-sim.log tail ---\n{tail}" + ) from exc finally: pub.unsubscribe(_on_receive, "meshtastic.receive.text") peer.close() diff --git a/scripts/meshtasticator_e2e/run_e2e.sh b/scripts/meshtasticator_e2e/run_e2e.sh index 3a527dc..e3f5da4 100755 --- a/scripts/meshtasticator_e2e/run_e2e.sh +++ b/scripts/meshtasticator_e2e/run_e2e.sh @@ -93,7 +93,7 @@ start_forwards() { } SIM_LOG="$REPO_ROOT/meshtasticator-sim.log" -SIM_ARGS=("$NODES") +SIM_ARGS=("$NODES" -v) # -v: meshtastic/debug logging for RF diagnostics if [ "$MODE" = native ]; then [ -n "$PROGRAM" ] && [ -d "$PROGRAM" ] || { echo "--mode native needs --program " >&2; exit 2; } SIM_ARGS+=(-p "$PROGRAM") @@ -222,3 +222,14 @@ echo "== running radio-level e2e tests ==" E2E_CHANNEL_INDEX="$CHANNEL_INDEX" \ "$VENV/bin/python" -m pytest plugin/tests/e2e -q "$@" ) +RC=$? + +if [ $RC -ne 0 ] && [ "$MODE" = docker ]; then + # Capture per-node meshtasticd logs before cleanup removes the container. + echo "== dumping node logs (pytest rc=$RC) ==" + docker exec Meshtastic sh -c 'for f in /home/out_*.log; do echo "----- $f -----"; tail -n 60 "$f" 2>/dev/null; done' \ + >"$REPO_ROOT/meshtasticator-nodes.log" 2>&1 || true + echo " node logs: $REPO_ROOT/meshtasticator-nodes.log" +fi + +exit $RC