|
| 1 | +#!/usr/bin/env bash |
| 2 | +# Headless smoke test for the O3DE sim. |
| 3 | +# |
| 4 | +# Boots the GameLauncher with the null renderer (--rhi=null) — no GPU, no X |
| 5 | +# display needed — and passes if the simulation is actually *ticking*, proven by |
| 6 | +# catching a message on /clock within a timeout. That single check exercises the |
| 7 | +# whole cold path: binary runs, assets + level load, PhysX ticks, and the ROS 2 |
| 8 | +# bridge publishes. |
| 9 | +# |
| 10 | +# NOT checked: camera / rendered sensors. Those need the Atom (Vulkan) renderer, |
| 11 | +# which headless needs a DRI3-capable display for — Xvfb doesn't provide DRI3, so |
| 12 | +# the GPU+Vulkan path wedges on swapchain creation. rhi=null has no renderer at |
| 13 | +# all, so camera topics are advertised but never publish. Verifying rendered |
| 14 | +# output headless is a separate, unsolved problem; keep it out of the fast gate. |
| 15 | +# |
| 16 | +# Run: pixi run sim-smoke |
| 17 | +# In Docker: docker run --rm --entrypoint pixi <o3de-image> run sim-smoke |
| 18 | +# Tune: SIM_SMOKE_TIMEOUT=120 pixi run sim-smoke |
| 19 | +# SIM_SMOKE_TOPIC=/joint_states SIM_SMOKE_TYPE=sensor_msgs/msg/JointState pixi run sim-smoke |
| 20 | +set -uo pipefail |
| 21 | + |
| 22 | +# Hermetic: only ever see our own sim on loopback, so a neighbouring sim on a |
| 23 | +# shared CI runner can't cause a false pass. |
| 24 | +export ROS_LOCALHOST_ONLY=1 |
| 25 | + |
| 26 | +LAUNCHER="${DEMO_ROOT:-$PWD}/sim/build/linux/bin/profile/MobileManipulatorDemo.GameLauncher" |
| 27 | +TIMEOUT="${SIM_SMOKE_TIMEOUT:-90}" # boot + first message; rhi=null is faster than Vulkan |
| 28 | +TOPIC="${SIM_SMOKE_TOPIC:-/clock}" |
| 29 | +# Type must be explicit: with no publisher up yet, `ros2 topic echo` can't infer |
| 30 | +# the type from the graph and bails instantly instead of waiting. |
| 31 | +TYPE="${SIM_SMOKE_TYPE:-rosgraph_msgs/msg/Clock}" |
| 32 | +LOG="$(mktemp)" |
| 33 | + |
| 34 | +[ -x "$LAUNCHER" ] || { echo "[FAIL] launcher not built: $LAUNCHER"; exit 1; } |
| 35 | + |
| 36 | +# GameLauncher ignores SIGINT (won't stop on Ctrl+C), so hard-kill on exit. |
| 37 | +# Kill the captured PID, plus a pkill by full command line as a fallback (the |
| 38 | +# comm name isn't reliably set during early boot). pkill -f is safe: this shell's |
| 39 | +# own argv is just "bash scripts/sim_smoke.sh", so it can't match itself. |
| 40 | +LAUNCHER_PID="" |
| 41 | +cleanup() { |
| 42 | + [ -n "$LAUNCHER_PID" ] && kill -9 "$LAUNCHER_PID" 2>/dev/null |
| 43 | + pkill -9 -f 'MobileManipulatorDemo.GameLauncher' 2>/dev/null |
| 44 | +} |
| 45 | +trap cleanup EXIT |
| 46 | + |
| 47 | +echo "[smoke] launching sim headless (--rhi=null)" |
| 48 | +env -u DISPLAY "$LAUNCHER" -bg_ConnectToAssetProcessor=0 --rhi=null >"$LOG" 2>&1 & |
| 49 | +LAUNCHER_PID=$! |
| 50 | + |
| 51 | +# /clock is published BEST_EFFORT; a default (reliable) subscriber gets nothing. |
| 52 | +echo "[smoke] waiting up to ${TIMEOUT}s for a message on ${TOPIC} (${TYPE})" |
| 53 | +if timeout "$TIMEOUT" ros2 topic echo --once --qos-reliability best_effort "$TOPIC" "$TYPE" >/dev/null 2>&1; then |
| 54 | + echo "[PASS] ${TOPIC} is publishing — sim ticks headless" |
| 55 | + exit 0 |
| 56 | +fi |
| 57 | + |
| 58 | +echo "[FAIL] no message on ${TOPIC} within ${TIMEOUT}s" |
| 59 | +echo "----- last 30 log lines -----" |
| 60 | +tail -30 "$LOG" |
| 61 | +exit 1 |
0 commit comments