volli-agent 0.1.10

Agent node for volli
Documentation
#![allow(unused_crate_dependencies)]
use async_trait::async_trait;
use eyre::Report;
use std::sync::{
    Arc,
    atomic::{AtomicUsize, Ordering},
};
use volli_agent::AgentConfig;
use volli_core::Message;
use volli_transport::Transport;

#[derive(Default)]
struct MockTransport;

#[async_trait]
impl Transport for MockTransport {
    async fn send(&mut self, _msg: &Message) -> Result<(), Report> {
        Ok(())
    }
    async fn recv(&mut self) -> Result<Option<Message>, Report> {
        Ok(None)
    }
}

#[tokio::test]
async fn quic_failure_falls_back_to_tcp() {
    let quic_called = Arc::new(AtomicUsize::new(0));
    let tcp_called = Arc::new(AtomicUsize::new(0));
    let q = quic_called.clone();
    let quic = move |_cfg: &AgentConfig| {
        let q = q.clone();
        async move {
            q.fetch_add(1, Ordering::SeqCst);
            Err(eyre::eyre!("quic fail"))
        }
    };
    let t = tcp_called.clone();
    let tcp = move |_cfg: &AgentConfig| {
        let t = t.clone();
        async move {
            t.fetch_add(1, Ordering::SeqCst);
            Ok((
                Box::new(MockTransport::default()) as Box<dyn Transport>,
                "peer".into(),
            ))
        }
    };

    async fn attempt<FQ, FutQ, FT, FutT>(cfg: &AgentConfig, quic: FQ, tcp: FT) -> Result<(), Report>
    where
        FQ: Fn(&AgentConfig) -> FutQ,
        FutQ: std::future::Future<Output = Result<(Box<dyn Transport>, String), Report>>,
        FT: Fn(&AgentConfig) -> FutT,
        FutT: std::future::Future<Output = Result<(Box<dyn Transport>, String), Report>>,
    {
        match quic(cfg).await {
            Ok(_) => Ok(()),
            Err(_) => tcp(cfg).await.map(|_| ()),
        }
    }

    let cfg = AgentConfig::default();
    attempt(&cfg, quic, tcp).await.unwrap();
    assert_eq!(quic_called.load(Ordering::SeqCst), 1);
    assert_eq!(tcp_called.load(Ordering::SeqCst), 1);
}