qinterface 0.7.2

dquic's network interface and IO abstractions
Documentation
mod common;

use std::{sync::Arc, time::Duration};

use common::*;
use qinterface::{
    component::alive::RebindOnNetworkChangedComponent, device::Devices, manager::InterfaceManager,
};
use tokio::time;

#[test]
fn rebind_on_network_changed_triggers_on_recoverable_failure() {
    run(async {
        let Some(bind_uri) = any_iface_bind_uri() else {
            // No real network interface in this environment; skip.
            return;
        };

        let manager = InterfaceManager::global().clone();
        let factory = Arc::new(FakeFactory::new());

        let bind_iface = manager.bind(bind_uri.clone(), factory).await;
        let before = bind_iface.borrow();

        let probe = Arc::new(Probe::default());
        bind_iface.insert_component_with(|iface| {
            RebindOnNetworkChangedComponent::new(iface, Devices::global())
        });
        bind_iface.insert_component_with(|_iface| ProbeComponent::new(probe.clone()));

        // The component calls try_rebind() once at init.
        // If alive-check considers the interface unhealthy (recoverable error), it will rebind.
        let _ = time::timeout(Duration::from_secs(2), async {
            loop {
                let now = bind_iface.borrow();
                if !now.same_io(&before) {
                    break;
                }
                time::sleep(Duration::from_millis(10)).await;
            }
        })
        .await;

        // If it did rebind, the probe should have seen reinit.
        // If it didn't (alive-check passed), that's also acceptable on some systems.
        let _reinit_calls = probe.reinit_calls.load(std::sync::atomic::Ordering::SeqCst);
    })
}