Skip to main content
The crate is designed so your HIL suite is just ordinary Rust integration tests: files under tests/, run by cargo test, living in the same repository as your firmware.

Structure

Point tests at a box with the LAGER_BOX_HOST environment variable and construct the client with LagerBox::from_env():
Group tests by net or by DUT feature — one file per concern (boot.rs, power.rs, sensors.rs) keeps cargo test <name> filtering useful.

Parallel tests and instrument safety

cargo test runs tests on multiple threads by default. That is safe at the instrument level: the box serializes access per physical instrument — every net command runs under a per-device lock in the box’s single-owner hardware service — so parallel tests can never interleave I/O on one instrument (e.g. a LabJack shared across GPIO/ADC/SPI nets, or a Keithley shared by supply and battery roles). Tests sharing a net still observe each other’s state changes (one test’s disable() is visible to another test reading the same supply). Either partition nets across tests, or serialize:

Timeouts

Timeout budgets mirror the Lager CLI: quick commands use 10 s, and operations that block on the box for a caller-controlled duration (watt/energy integration windows, wait_for_level) widen or drop the client timeout automatically, so a healthy long measurement is never aborted mid-flight.

Hermetic tests vs. hardware tests

Tests that always need real hardware should be marked #[ignore] so a plain cargo test (on a laptop with no box, or in a PR check) stays green:
Then opt in explicitly where a box is available:
This is the convention the crate itself uses: its own suite is hermetic (cargo test runs against a mock box), and its hardware smoke tests run with cargo test --test hardware -- --ignored.

CI

A minimal GitHub Actions job, assuming the runner can reach the box (e.g. a self-hosted runner on the lab network or a Tailscale-connected runner):
For gateway-fronted boxes, see Authentication for how the token is attached and refreshed.