//! Whom neighbours reach (`swarm::reach`): told in STATUSes, as measured. use std::time::Duration; use super::Sim; use crate::state::AppState; use crate::swarm::bootstrap::Start; use crate::swarm::{reach, topology}; const SOON: Duration = Duration::from_secs(30); /// Whether `node` reaches `member`, as `node` measured and told it. fn reaches(node: &AppState, member: &AppState) -> bool { reach::published(node).contains(&topology::pair_key(member.local_id())) } /// Whether `node` heard from `neighbour` that it reaches `member`. async fn heard(node: &AppState, neighbour: &AppState, member: &AppState) -> bool { let Some(peer_state) = node.get_peer_state(neighbour.local_id()).await else { return false; }; let said = peer_state.lock().await.reaches.clone(); reach::of(node, said.as_ref()) .is_some_and(|keys| keys.contains(&topology::pair_key(member.local_id()))) } /// x, b and c on one net, all members of one full mesh, but nothing passes between x /// and c: b reaches both and says so; c learns from b that b reaches x, which c itself /// doesn't. #[tokio::test(flavor = "multi_thread", worker_threads = 4)] async fn neighbours_tell_whom_they_reach() { let sim = Sim::with_identity(66); let cut = crate::transport::sim::LinkParams { loss: 1.0, ..Default::default() }; sim.net.set_link("x", "c", cut.clone()); sim.net.set_link("c", "x", cut); let b = sim.start_on("b", &["sim"], &[], Start::Genesis); let c = sim.start_on("c", &["sim"], &["b"], Start::Join); let x = sim.start_on("x", &["sim"], &["b"], Start::Join); sim.wait_ready(&[&b, &c, &x], SOON).await; let (b, c, x) = (&b, &c, &x); sim.wait_until( "c heard from b that b reaches x, and c doesn't reach x", SOON, move || async move { reaches(b, x) && reaches(b, c) && !reaches(c, x) && heard(c, b, x).await }, ) .await; }