diff --git a/nmrs/CHANGELOG.md b/nmrs/CHANGELOG.md index 1822cfb3..7bb85f0f 100644 --- a/nmrs/CHANGELOG.md +++ b/nmrs/CHANGELOG.md @@ -10,6 +10,14 @@ All notable changes to the `nmrs` crate will be documented in this file. `NetworkManager::set_device_autoconnect()` / `set_device_managed()` provide high-level control of both writable properties. ([#541](https://github.com/freedesktop-rs/nmrs/issues/541)) +### Fixed + +- `wired_connection_lifecycle` restored device autoconnect immediately after + remanaging the veth, which let NetworkManager reactivate the saved profile and + race the disconnect assertions that follow. Autoconnect is now restored once + the profile is deleted, and the test waits for the remanaged device to settle. + ([#547](https://github.com/freedesktop-rs/nmrs/pull/547)) + ## [3.5.2] - 2026-09-05 ### Fixed - `#[deprecated(since = ...)]` on `connect_vpn_by_uuid()` and `disconnect_vpn_by_uuid()` said `3.6.0`; corrected to `3.5.1`, the release that actually deprecated them.([#544](https://github.com/freedesktop-rs/nmrs/pull/544)) diff --git a/nmrs/tests/integration_test.rs b/nmrs/tests/integration_test.rs index b3b8d28c..8fcdfeab 100644 --- a/nmrs/tests/integration_test.rs +++ b/nmrs/tests/integration_test.rs @@ -1136,13 +1136,28 @@ async fn wired_connection_lifecycle() { ) .await .expect("failed to restore managed state"); - bounded( - "restore autoconnect on the managed veth client", - DBUS_TIMEOUT, - nm.set_device_autoconnect(&interface, true), - ) + // Remanaging clears the autoconnect block that an explicit disconnect + // leaves behind, so NetworkManager reactivates the saved profile as soon + // as the device is ready. Keep device autoconnect off until the profile + // is deleted and wait for the device to settle; otherwise that + // reactivation races the disconnect assertions below. + timeout(EVENT_TIMEOUT, async { + loop { + let devices = bounded("refresh remanaged device", DBUS_TIMEOUT, nm.list_devices()) + .await + .expect("failed to refresh devices after restoring managed state"); + let device = devices + .iter() + .find(|device| device.interface == interface) + .expect("veth disappeared after restoring managed state"); + if device.managed == Some(true) && device.state == DeviceState::Disconnected { + break; + } + sleep(Duration::from_millis(25)).await; + } + }) .await - .expect("failed to restore device autoconnect"); + .expect("the remanaged veth never settled to Disconnected"); bounded( "disconnect the managed veth client", @@ -1236,6 +1251,26 @@ async fn wired_connection_lifecycle() { .expect("failed to resolve wired profile after deletion") .is_none() ); + + bounded( + "restore autoconnect on the managed veth client", + DBUS_TIMEOUT, + nm.set_device_autoconnect(&interface, true), + ) + .await + .expect("failed to restore device autoconnect"); + let devices = bounded( + "read restored autoconnect", + DBUS_TIMEOUT, + nm.list_wired_devices(), + ) + .await + .expect("failed to refresh wired devices"); + let device = devices + .iter() + .find(|device| device.interface == interface) + .expect("veth disappeared after restoring autoconnect"); + assert_eq!(device.autoconnect, Some(true)); }) .catch_unwind() .await;