feat(e2e): Meshtasticator radio-level validation harness for the adapter #2
@@ -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()
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user