Test the NM layer against an in-process D-Bus fake
All checks were successful
check / check (push) Successful in 1m39s

`tests/common/fake_nm.rs` stands up a fake `org.freedesktop.NetworkManager`
on a private bus so `cli.rs` and `flow_watch.rs` exercise the real
`nm` code paths without a live NetworkManager and without shelling out.
Replaces the previous command-capture scaffolding in those two files;
scenario coverage (captive portal, exit-node failover, 802.1x,
per-network DNS, schedule triggers, Tailscale recovery, SSID
verification) is preserved — 139 tests.
This commit is contained in:
Breadway 2026-08-31 15:10:42 +08:00
parent b4c1d0b233
commit cc709a4af9
4 changed files with 1345 additions and 612 deletions

1007
tests/common/fake_nm.rs Normal file

File diff suppressed because it is too large Load diff

View file

@ -9,7 +9,7 @@
//! rules ("if the program+args match this predicate, return this canned
//! `Output`"), which also records every invocation so a test can assert
//! exactly what was — or, just as importantly, was *not* — passed (e.g.
//! that a password argument never reaches a fake `nmcli`).
//! that a password argument never reaches a fake subprocess).
//! - [`EnvSandbox`]: real logic (`flow::run`, `watch::classify`) still does
//! its own best-effort file logging via `notify::log`, which resolves a
//! path from `$HOME`/`$XDG_STATE_HOME`. `EnvSandbox` points those at a
@ -18,9 +18,15 @@
//! inherently cross-test-within-this-binary racy, so it's guarded by a
//! process-wide mutex — tests using it serialize against each other but
//! not against unrelated tests (each `tests/*.rs` file is its own binary).
//! - [`fake_nm`]: a real fake NetworkManager D-Bus service on a private
//! `dbus-daemon`. The production `nm` module talks to it over real D-Bus
//! marshalling (`Connection::system()` honors `DBUS_SYSTEM_BUS_ADDRESS`),
//! replacing the old fake-`nmcli`-argv rules.
#![allow(dead_code)] // not every test file uses every helper here
pub mod fake_nm;
use std::cell::RefCell;
use std::collections::HashSet;
use std::path::{Path, PathBuf};
@ -94,7 +100,7 @@ impl FakeRunner {
}
/// Shorthand for matching on `prog` plus a whitespace-joined view of
/// `args` containing `substr` (handy for `nmcli`/`tailscale` calls, whose
/// `args` containing `substr` (handy for `tailscale`/`curl` calls, whose
/// interesting bit is usually a subcommand somewhere in the middle).
pub fn on_contains(self, prog: &'static str, substr: &'static str, output: Output) -> Self {
self.on(