Skip to content

Commit 17f95a2

Browse files
committed
feat(ci): Hardware-in-the-loop sweep + close test-infra gaps
Adds a `--hil` mode that uploads + runs every test group in `tests/integration/firmware` against the device named by `$PIO_LABGRID_DEVICE`, for both the `serial` (streaming Protocol path) and `i2c` envs. `--full` invokes it automatically after `run_ci`; the step self-skips when the env var is unset so headless CI stays green. Naming dodges the singular/plural confusion with the existing `--integrations` (host-only JSON-backend doctest binary). `--hil` is unambiguous and matches the established hardware-in-the-loop term. `run_full()` consolidates the two phases into a named helper so the dispatch `case` doesn't need a multi-line bash invocation. Also closes a test-infra gap surfaced while reviewing this: the PIO integration compile-only loop covered `serial` + `i2c` but not `both` (the env that links both pin sets into one image — exists specifically to catch their interaction at link time). Adding `both` to the loop keeps the env from being dead infrastructure. `nointerface` stays out of the loop deliberately: it's a negative compile test (verifies the `#error` guard fires when no pin set is defined). Wiring that into ci.sh needs an inverted exit-code check that doesn't fit naturally into the existing positive-build loop; left for a follow-up.
1 parent 72a5d12 commit 17f95a2

1 file changed

Lines changed: 79 additions & 4 deletions

File tree

ci.sh

Lines changed: 79 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,15 @@ ROOT="$(cd "$(dirname "$0")" && pwd)"
99
# ── Multi-compiler support ──────────────────────────────────────────────────
1010
# Usage:
1111
# ./ci.sh Quick check: codegen + unit tests (default)
12-
# ./ci.sh --full Full CI: headers, examples, version gating, docs
12+
# ./ci.sh --full Full CI: headers, examples, version gating, docs,
13+
# *plus* the hardware-in-the-loop sweep when
14+
# $PIO_LABGRID_DEVICE points at an available board
1315
# ./ci.sh --all-compilers Full CI with all available compilers
1416
# ./ci.sh --coverage Build with coverage instrumentation and generate report
15-
# ./ci.sh --integrations Build and run JSON backend integration tests
17+
# ./ci.sh --integrations Build and run JSON backend integration tests (host)
18+
# ./ci.sh --hil Hardware-in-the-loop sweep — upload + run all
19+
# test groups on $PIO_LABGRID_DEVICE for the
20+
# `serial` and `i2c` envs in tests/integration/firmware
1621
# CXX=g++-13 ./ci.sh Run with a specific compiler
1722
#
1823
# --all-compilers discovers compilers matching the CI matrix (g++-13, clang++-18) plus
@@ -980,7 +985,11 @@ run_quick() {
980985
# `pio run`: `pio run` only compiles src/, so the integration test
981986
# files under test/ are skipped silently. The build-only form of
982987
# `pio test` exercises the test/ tree without needing hardware.
983-
for env in serial i2c; do
988+
# `both` exists so the build catches conflicts between the serial
989+
# and I2C pin sets when both transports are linked into one image;
990+
# `nointerface` is intentionally broken (negative compile test)
991+
# and is not run here.
992+
for env in serial i2c both; do
984993
echo " Building $env..."
985994
NOTECARD_SERIAL_RX=38 NOTECARD_SERIAL_TX=39 \
986995
NOTECARD_I2C_SDA=14 NOTECARD_I2C_SCL=21 \
@@ -1050,6 +1059,61 @@ run_integrations() {
10501059
echo "All integration tests passed."
10511060
}
10521061

1062+
# ── Hardware integration sweep ────────────────────────────────────────────
1063+
# Upload + run every test group in tests/integration/firmware on the device
1064+
# named by $PIO_LABGRID_DEVICE, for both the `serial` and `i2c` envs.
1065+
# Exercises the typed API on real ESP32-S3 silicon — catches anything host
1066+
# tests miss (allocator interaction with real malloc/free, timing-sensitive
1067+
# transport behaviour, codegen output on a non-host CPU).
1068+
#
1069+
# Requires:
1070+
# - $PIO_LABGRID_DEVICE set to a registered usb-device name
1071+
# (e.g. "MPCB 1.9 Development") — pio-labgrid auto-acquires/releases
1072+
# the device lock for each `pio test` invocation.
1073+
# - The board powered, connected, and not locked by another session.
1074+
#
1075+
# Skips with a clear message (does not error) when $PIO_LABGRID_DEVICE is
1076+
# unset, so GitHub CI and headless `--full` runs degrade gracefully.
1077+
run_integration_hardware() {
1078+
ci_stage "Hardware integration sweep"
1079+
1080+
if [ -z "${PIO_LABGRID_DEVICE:-}" ]; then
1081+
echo " PIO_LABGRID_DEVICE not set — skipping hardware sweep."
1082+
echo " To run on hardware:"
1083+
echo " PIO_LABGRID_DEVICE='MPCB 1.9 Development' $0 --hil"
1084+
return 0
1085+
fi
1086+
1087+
if ! command -v pio >/dev/null 2>&1; then
1088+
echo " pio not on PATH — skipping hardware sweep."
1089+
return 0
1090+
fi
1091+
1092+
local PIO_DIR="$ROOT/tests/integration/firmware"
1093+
1094+
# `serial` first (streaming Protocol path), then `i2c`. Each env runs
1095+
# all four test groups discovered under test/ (test_fixtures plus
1096+
# test_units_a/b/c). pio-labgrid locks/unlocks the device per
1097+
# invocation; the loop is sequential because there is one device.
1098+
local failed=0
1099+
for env in serial i2c; do
1100+
echo " Running $env env on '$PIO_LABGRID_DEVICE'..."
1101+
if ! pio test -d "$PIO_DIR" -e "$env" -v; then
1102+
failed=1
1103+
echo " FAIL: $env env reported failures."
1104+
fi
1105+
done
1106+
1107+
if [ "$failed" -ne 0 ]; then
1108+
echo
1109+
echo "Hardware integration sweep FAILED."
1110+
return 1
1111+
fi
1112+
1113+
echo
1114+
echo "Hardware integration sweep passed (serial + i2c)."
1115+
}
1116+
10531117
# Log every run
10541118
CI_LOG="$ROOT/ci.log"
10551119

@@ -1060,9 +1124,17 @@ run_and_log() {
10601124
return $rc
10611125
}
10621126

1127+
run_full() {
1128+
# Host CI + hardware sweep. The hardware step is self-skipping when
1129+
# $PIO_LABGRID_DEVICE isn't set, so this stays safe in headless
1130+
# environments.
1131+
run_ci "${CXX:-c++}" "${CXXFLAGS:--std=c++2b}"
1132+
run_integration_hardware
1133+
}
1134+
10631135
case "${1:-}" in
10641136
--full)
1065-
run_and_log run_ci "${CXX:-c++}" "${CXXFLAGS:--std=c++2b}"
1137+
run_and_log run_full
10661138
;;
10671139
--coverage)
10681140
run_and_log run_coverage
@@ -1073,6 +1145,9 @@ case "${1:-}" in
10731145
--integrations)
10741146
run_and_log run_integrations
10751147
;;
1148+
--hil)
1149+
run_and_log run_integration_hardware
1150+
;;
10761151
--all-compilers)
10771152
echo "Discovering compilers..."
10781153
FAILED=0

0 commit comments

Comments
 (0)