fix(e2e): peer sendText moved to Interface; add RF failure diagnostics

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.
This commit is contained in:
2026-09-07 21:46:25 -07:00
parent eff352b2ea
commit 6125130e6a
2 changed files with 33 additions and 2 deletions
+21 -1
View File
@@ -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) return any(getattr(e, "text", None) == sent for e in node0.received_events)
# Radio delivery is not guaranteed per attempt; retry a few times. # 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): for _ in range(3):
if _got(): if _got():
break break
peer.localNode.sendText( peer.sendText(
text=sent, destinationId="^all", channelIndex=E2E_CHANNEL_INDEX text=sent, destinationId="^all", channelIndex=E2E_CHANNEL_INDEX
) )
time.sleep(1) 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) 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") _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: finally:
pub.unsubscribe(_on_receive, "meshtastic.receive.text") pub.unsubscribe(_on_receive, "meshtastic.receive.text")
peer.close() peer.close()
+12 -1
View File
@@ -93,7 +93,7 @@ start_forwards() {
} }
SIM_LOG="$REPO_ROOT/meshtasticator-sim.log" 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 if [ "$MODE" = native ]; then
[ -n "$PROGRAM" ] && [ -d "$PROGRAM" ] || { echo "--mode native needs --program <dir>" >&2; exit 2; } [ -n "$PROGRAM" ] && [ -d "$PROGRAM" ] || { echo "--mode native needs --program <dir>" >&2; exit 2; }
SIM_ARGS+=(-p "$PROGRAM") SIM_ARGS+=(-p "$PROGRAM")
@@ -222,3 +222,14 @@ echo "== running radio-level e2e tests =="
E2E_CHANNEL_INDEX="$CHANNEL_INDEX" \ E2E_CHANNEL_INDEX="$CHANNEL_INDEX" \
"$VENV/bin/python" -m pytest plugin/tests/e2e -q "$@" "$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