Testing
nmrs includes unit tests, integration tests, and model tests. Since many operations require a running NetworkManager daemon, tests are divided into offline and online categories.
Running Tests
Unit Tests
Unit tests cover validation, model construction, and builder logic. They run without NetworkManager:
cd nmrs
cargo test --lib --all-features
Specific Test Modules
# Model tests
cargo test --lib api::models::tests
# Builder tests
cargo test --lib api::builders
# Validation tests
cargo test --lib util::validation
Integration Tests
Environmental integration tests are #[ignore] so a normal cargo test never
contacts or mutates the host NetworkManager. Run the NM-only contract through
the isolated Docker harness:
docker compose run --build --rm test-integration
The harness sets NMRS_REQUIRE_NETWORKMANAGER=1 and provisions a private veth
pair with DHCP before setting NMRS_REQUIRE_WIRED=1. It covers saved settings,
exact direct and unified settings events, a NetworkManager-routed secret request
and reply, native WireGuard activation, wired discovery, typed active-connection
data, DHCP activation, disconnect, and cleanup. Once a capability is declared,
an unavailable daemon, a D-Bus error, a missing event, or a timeout is a test
failure. There are no skip-as-pass branches.
To target a deliberately selected local daemon instead, opt in explicitly. The NM-only contracts create, update, and delete a saved profile and register a temporary secret agent, so prefer Docker unless those operations are intentional:
NMRS_REQUIRE_NETWORKMANAGER=1 \
cargo test --test integration_test --all-features \
networkmanager_ -- --ignored --test-threads=1
Test Categories
Model Tests (api/models/tests.rs)
Comprehensive tests for all data types:
- Device type conversions and display formatting
- Device state conversions and transitional state detection
- Wi-Fi security type construction and methods
- EAP options construction (direct and builder)
- VPN credentials construction (direct and builder)
- WireGuard peer configuration
- Bluetooth identity validation
- Timeout config and connection options
- Error type formatting
Builder Tests
Each builder module includes its own tests:
connection_builder.rs— base settings, IPv4/IPv6 configuration, custom sectionswireguard_builder.rs— WireGuard settings, validation, multiple peerswifi_builder.rs— Wi-Fi settings, bands, modes
Validation Tests
util/validation.rs tests input validation:
- SSID validation
- Connection name validation
- Wi-Fi security validation (empty passwords, etc.)
- VPN credential validation
- Bluetooth address validation
Writing Tests
Offline Tests
For logic that doesn't require D-Bus:
#![allow(unused)] fn main() { #[cfg(test)] mod tests { use super::*; #[test] fn test_device_type_from_code() { assert_eq!(DeviceType::from(1), DeviceType::Ethernet); assert_eq!(DeviceType::from(2), DeviceType::Wifi); } } }
Async Tests
For code that uses async:
#![allow(unused)] fn main() { #[cfg(test)] mod tests { use super::*; #[tokio::test] async fn test_something_async() { // Test async logic } } }
Docker Testing
For reproducible testing with a real NetworkManager instance:
docker compose run --build --rm test-integration
This starts a private system D-Bus and NetworkManager instance, provisions a veth-backed DHCP network, waits for both to be ready, and runs the settings, secret-agent, native WireGuard, and wired lifecycle contracts. It fails if any declared facility is unavailable.
Virtual Wi-Fi Integration
On a Linux host, the CI-equivalent test target uses two virtual radios created
with mac80211_hwsim. One radio advertises a WPA2-PSK test network using
hostapd and serves DHCP using dnsmasq. The isolated NetworkManager manages the
other radio.
sudo modprobe mac80211_hwsim radios=2
docker compose run --build --rm test-wifi-integration
sudo modprobe -r mac80211_hwsim
This service uses host networking and is therefore intended for Linux hosts and the GitHub Actions runner, not Docker Desktop.
The harness provides NMRS_REQUIRE_WIFI=1, the exact interface, SSID, and
password, then asserts AP discovery, WPA authentication, DHCP activation,
network and device callback delivery, disconnect, saved-credential reconnect,
forget, and the exact missing-password error after cleanup. Missing declared
capabilities and unexpected errors fail.
It also mounts the host's /run/udev read-only so NetworkManager can manage
the newly created hwsim links.
The self-hosted runner service account needs passwordless sudo permission for
modprobe mac80211_hwsim radios=2 and modprobe -r mac80211_hwsim; CI invokes
both commands with sudo -n.
Approving Wi-Fi CI Runs
Pull requests send the virtual Wi-Fi job to the self-hosted-pr-integration
GitHub Actions environment before it is assigned to the self-hosted runner. To
require manual approval, create that environment in the repository's **Settings
Environments**, add yourself as a required reviewer, and leave Prevent self-review disabled. The job will show Waiting for review in the Actions run; select Review deployments and approve that environment to start only the Wi-Fi integration job.
Pushes to master use the unprotected self-hosted-integration environment
and start automatically.
CI/CD
Tests run automatically via GitHub Actions on every push and pull request. The CI workflow:
- Checks formatting (
cargo fmt --check) - Runs clippy (
cargo clippy) - Runs unit tests (
cargo test --lib) - Runs the ignored integration contracts against isolated NetworkManager and virtual Wi-Fi harnesses
- Builds documentation (
mdbook build)
Next Steps
- Contributing – contribution guidelines
- Architecture – understand the codebase