Testing Guide
This is the validation matrix for the active Ioruba stack. Run commands from the repository root unless noted otherwise.
Linux is the only platform with full audio-target coverage. Native CI still compiles and tests the Windows WASAPI and macOS CoreAudio backends, which support default-output (
master) volume only.
Validation levels
Fast local gate
npm run verify
npm run firmware:compile
verify runs:
- shared and desktop TypeScript typechecks;
- shared and desktop Vitest suites;
- Rust tests;
- desktop production build.
firmware:compile compiles the default Arduino Nano target.
CI-equivalent root command
npm run ci
This is verify plus the default firmware compile. GitHub CI performs additional formatting, linting, coverage, firmware-matrix, native-platform, installer, packaging, and repository checks described below.
Extended local release gate
npm run release:check
This adds:
npm auditagainst the complete npm workspace;cargo auditagainst the Rust lockfile;- default and wide host-side firmware parser tests;
- the AVR firmware compile matrix;
- shell script lint;
- installer and package-manifest tests;
- Gitleaks and TruffleHog scans;
- GitHub Pages source generation.
Required tools for the extended gate include cargo-audit, arduino-cli, shellcheck, gitleaks, and trufflehog.
Targeted commands
| Area | Command |
|---|---|
| Shared typecheck | npm run shared:typecheck |
| Shared tests | npm run shared:test |
| Desktop typecheck | npm run desktop:typecheck |
| Desktop tests | npm run desktop:test |
| Rust tests | npm run rust:test |
| Rust formatting | cargo fmt --check --manifest-path apps/desktop/src-tauri/Cargo.toml |
| Rust lint | cargo clippy --manifest-path apps/desktop/src-tauri/Cargo.toml --all-targets -- -D warnings |
| Frontend production build | npm run desktop:build |
| Local Tauri binary | npm run desktop:tauri:build |
| Nano firmware | npm run firmware:compile |
| AVR firmware matrix | npm run firmware:compile:matrix |
| Firmware parser (default) | npm run firmware:test |
| Firmware parser (8 knobs, 12-bit) | npm run firmware:test:wide |
| Installer fixtures | npm run test:installer |
| Packaging/updater manifests | npm run test:packaging |
| Docs site source | npm run docs:prepare-site |
Run one Vitest file:
npm --workspace @ioruba/desktop run test -- src/lib/serial.test.ts
npm --workspace @ioruba/shared run test -- tests/protocol.test.ts
Run one Rust test:
cargo test --manifest-path apps/desktop/src-tauri/Cargo.toml <test_name>
What GitHub CI validates
The reusable .github/workflows/ci.yml workflow contains these jobs:
- Desktop And Shared: Node 22 install, npm audit, TypeScript checks, tests with coverage, Rust format/clippy/tests, RustSec audit, vendored glib patch guard, frontend build, and docs generation.
- Firmware Host Tests: pure C++ config-parser tests for default and wide/12-bit configurations.
- Firmware AVR matrix: Nano, Uno, Mega, Leonardo, and Micro.
- Firmware architecture matrix: ESP32, RP2040/Pico, and ESP8266.
- Installer Scripts Lint: ShellCheck, installer fixtures, package/updater manifest tests, and PSScriptAnalyzer.
- Native Audio Smoke: Rust clippy/tests on
windows-latestandmacos-15so cfg-gated audio modules compile on their native platforms. - Repo Smoke: required files and removal of retired root/legacy build surfaces.
Separate workflows run CodeQL and secret scanning.
Desktop runtime smoke test
Start the native development app:
npm run desktop:watch
Verify:
- persisted profiles and app settings load;
- serial auto-detection or preferred-port selection works;
- connection state changes realistically;
- demo mode produces telemetry without applying system audio;
- real frames update controls, telemetry, and session statistics;
- Hardware reports board, MCU, ADC bits, protocol, and calibration;
- profile visual editing and advanced JSON validation work;
- import/export, duplication, presets, and reset behave correctly;
- Watch records, filters, clears, persists, and exports events;
- closing the window hides it, the tray/
Ctrl+Alt+Irestores it, and Quit ends the process; - launch-on-login and update preferences persist;
- unsupported target kinds produce explicit outcomes instead of silent success.
Serial and firmware validation
The current reference firmware defaults to 115200 baud and protocol 2:
HELLO board=Ioruba Nano; fw=0.6.1; protocol=2; knobs=3; mcu=ATmega328P; adcBits=10; threshold=4; deadzone=7; smooth=75; mins=0,0,0; maxs=1023,1023,1023
512|768|1023
The runtime also accepts:
P1:512
P2:768
P3:1023
With real hardware, confirm:
HELLO?returns a valid handshake;- every configured knob appears in each full frame;
- values span the calibrated range;
- idle heartbeats do not trigger disconnect loops;
- disconnect/reconnect restores reading without a zombie port;
EVENTS ONenables button/encoder events when compiled in;- calibration changes survive a reset;
- a protocol mismatch is shown as a warning.
Compile all AVR targets:
npm run firmware:compile:matrix
The CI architecture matrix is the source of truth for ESP32/RP2040/ESP8266 toolchain compilation; local commands are in Hardware setup.
Audio backend validation
Linux (pactl)
pactl info
pactl list short sink-inputs
pactl list short sinks
pactl list short sources
pactl get-default-sink
pactl get-default-source
Test:
masterchanges the default sink;applicationmatches active streams case-insensitively by partial app/display name;sinkandsourcematch custom names and descriptions;default_outputanddefault_microphoneresolve correctly;- targeted mute works for master, sink, source, and application;
next/prevreport availability based onplayerctl;- unavailable, idle, partial, and error outcomes are visible in the UI and Watch log;
- bursty knob movement applies promptly and coalesces writes.
Windows (WASAPI)
Test on Windows:
masterchanges the default render endpoint volume;- default-output mute works;
- application/source/sink targets return unsupported outcomes;
- inventory reports backend
windowsand the default endpoint; - repeated writes work through the dedicated COM thread;
- serial, profiles, telemetry, persistence, tray, packaging, and updater behavior remain functional.
macOS (CoreAudio)
Test on macOS:
masterchanges default-output volume;- application/source/sink targets return unsupported outcomes;
- inventory reports backend
macos; - serial, profiles, telemetry, persistence, tray, packaging, and updater behavior remain functional;
- unsigned/non-notarized release behavior is described honestly in the release docs.
Persistence and recovery validation
Typical configuration directories:
- Linux:
~/.config/io.ioruba.desktop/; - macOS:
~/Library/Application Support/io.ioruba.desktop/; - Windows:
%APPDATA%\io.ioruba.desktop\.
Confirm:
- state writes are atomic and valid JSON;
- incompatible/corrupt state creates a backup when replaced;
- legacy profiles using the old 9600 default migrate to 115200;
ioruba-watch.logremains bounded to roughly 1 MiB;- malformed watch lines are ignored and reported;
- deleting
ioruba-state.jsonrecreates safe defaults; - reinstalling/updating does not delete the config directory.
Release artifact validation
Before publishing a tag:
npm run release:checkpasses locally where the required security tools are available.- The reusable CI workflow passes on Linux, Windows, and macOS jobs.
- A real controller passes the Linux serial/audio smoke test.
- Linux builds
.deb,.rpm, and AppImage; Windows builds MSI and NSIS; macOS builds both architecture-specific app archives. scripts/validate-appimage.sh --require-launch <AppImage>passes on the Ubuntu 22.04 release runner.- Firmware artifacts compile and upload.
- Every updater platform artifact has a detached
.sig, and one completelatest.jsonis published after the bundle matrix. SHA256SUMS.txtand GitHub provenance attestations are published.- Homebrew, Scoop, winget, and AUR metadata is generated from release checksums rather than handwritten digests.
- The source AUR
PKGBUILDretainsoptions=('!lto' '!debug'). - Release notes match the corresponding
CHANGELOG.mdsection. - macOS signing/notarization claims match the secrets and artifacts actually produced.
Verify a downloaded artifact:
sha256sum --check SHA256SUMS.txt --ignore-missing
gh attestation verify <asset> --repo bernardopg/ioruba
Troubleshooting tests
Serial permission denied
sudo usermod -a -G dialout "$USER"
sudo usermod -a -G uucp "$USER"
Log out and back in.
No frames
- Confirm 115200 baud.
- Confirm the current firmware is flashed.
- Close other serial monitors.
- Check the data cable and analog wiring.
- Inspect
arduino-cli board listandfuser -v /dev/ttyUSB0.
Linux application volume does not move
- Keep the target app playing audio.
- Refresh the inventory.
- Compare profile names with
pactl list short sink-inputs. - Inspect the target outcome and Watch log.
Tauri build fails on Linux
Install the Tauri 2 prerequisites for your distribution, including WebKitGTK 4.1, GTK 3, librsvg, and app-indicator development libraries.
For deeper triage, use the Support playbook.