aboutsummaryrefslogtreecommitdiffstats
path: root/src/simtest/reach.rs
blob: b38db8758bf1450bfb6eb84d5f9a9236e565a7ca (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
//! 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;
}