Skip to main content
A plugin’s tests have to run somewhere. This page covers the four test surfaces ADOS plugin authors use, in order of cost and fidelity. All three SDKs ship a test harness: the Python ados.sdk.testing harness, the Rust ados-sdk::testing harness, and the TypeScript @altnautica/plugin-sdk/harness. Pick the one that matches your plugin half and runtime.

1. Agent-side unit tests with a mock backend

The cheapest pass. Most driver plugins ship their own mock backend fixture (the thermal-camera reference plugin ships MockUvcBackend; the gimbal reference plugin ships a mock router) that the driver constructor accepts in place of the real device. For a Python agent half, the SDK testing surface (ados.sdk.testing, also re-exported from ados.sdk) adds PluginTestHarness, FakeVisionEngine, and load_fixture for plugin-level tests. PluginTestHarness wires an in-process plugin context to fake IPC so you can run lifecycle hooks under pytest without the supervisor, sockets, or subprocesses. Grant capabilities explicitly and assert against captured events.
This catches the bulk of bugs and runs in milliseconds. Every first-party reference plugin uses this pattern. For a Rust agent half, ados-sdk::testing mirrors the same ergonomics. FakeVisionEngine emits synthetic frames (from an in-memory list or a directory of raw frame files) through the same frame callback a plugin registers with ctx.vision.subscribe_frames, builds a real frame ring under the hood, and captures the detections the plugin publishes so a test can assert on them. No host, no shared memory, no socket.
The object-detector-rs reference plugin tests this way in its #[cfg(test)] module.

2. The plugin harness, GCS side

@altnautica/plugin-sdk/harness mounts your plugin against an in-memory transport, captures every RPC, and lets you inject telemetry, events, config changes, and theme updates without running Mission Control.
See sdk-typescript for the full harness reference.

3. SITL (software in the loop)

ArduPilot SITL covers everything FC-side: arming, modes, missions, parameters, mount commands, ROI. Run it on the dev machine and have the agent talk to it the same way it would talk to a real flight controller. The reference MAVLink Gimbal v2 plugin tests against ArduPilot SITL exactly this way. SITL launches via the ADOS Mission Control “SITL launcher” tool. Once SITL is running, the agent’s MAVLink router connects to tcp:127.0.0.1:5760, the gimbal driver registers, and command_attitude(pitch=-30, yaw=45) flows through to a simulated mount whose state the test asserts on. SITL does not simulate cameras, LiDARs, payloads, or vendor serial protocols. For those, fall back to the mock backend.

4. Hardware in the loop on a bench rig

The full pass. A real SBC (Pi 4B or Rock 5C Lite) with the agent installed via install.sh, the real device on USB or serial, and your plugin packed and installed via ados plugin install <archive>. Bench-rig testing is what closes the loop on radiometric accuracy, timing jitter, hotplug behaviour, and vendor-binary integration. Run it before cutting a release tag. A good bench-rig session captures:
  • ados plugin logs <id> (or journalctl -u ados-plugin-<id>.service) while exercising the device
  • A telemetry log capture over the test window
  • A photo or short video of the rig and the device under test
These three artifacts go in the release notes for the tag.

What our reference plugins ship

“Gated on hardware” means CI passes against the mock and harness passes; the real bench rig is exercised before the release tag is cut.

See also