use std::time::Duration;
use futures_lite::StreamExt;
use iroh::{Endpoint, SecretKey, protocol::Router};
use iroh_gossip::api::Event;
use iroh_gossip::net::Gossip;
use tokio::time::timeout;
use iroh_topic_tracker::{TopicDiscoveryConfig, TopicDiscoveryExt};
#[tokio::test(flavor = "multi_thread")]
async fn topic_tracker_gossip_integration_test() -> anyhow::Result<()> {
let secret_key0 = SecretKey::generate();
let secret_key1 = SecretKey::generate();
let endpoint0 = Endpoint::builder(iroh::endpoint::presets::N0)
.secret_key(secret_key0)
.bind()
.await?;
let endpoint1 = Endpoint::builder(iroh::endpoint::presets::N0)
.secret_key(secret_key1)
.bind()
.await?;
let gossip0 = Gossip::builder().spawn(endpoint0.clone());
let gossip1 = Gossip::builder().spawn(endpoint1.clone());
let _router0 = Router::builder(endpoint0.clone())
.accept(iroh_gossip::ALPN, gossip0.clone())
.spawn();
let _router1 = Router::builder(endpoint1.clone())
.accept(iroh_gossip::ALPN, gossip1.clone())
.spawn();
let topic_id = format!("test_topic_{}", rand::random::<u32>()).into_bytes();
let config0 = TopicDiscoveryConfig::builder(endpoint0)
.max_peers_per_round(Some(5))
.build();
let config1 = TopicDiscoveryConfig::builder(endpoint1)
.max_peers_per_round(Some(5))
.build();
let (sender0, mut receiver0, handle0) = gossip0
.subscribe_with_discovery(topic_id.clone(), vec![], config0)
.await?;
let (sender1, mut receiver1, handle1) = gossip1
.subscribe_with_discovery(topic_id, vec![], config1)
.await?;
timeout(Duration::from_secs(15), async {
loop {
match receiver0.next().await {
Some(Ok(Event::NeighborUp(_))) => break,
Some(Err(e)) => panic!("Error receiving event: {}", e),
None => panic!("Stream ended"),
_ => {}
}
}
})
.await
.expect("Node 0 failed to find neighbor");
timeout(Duration::from_secs(15), async {
loop {
match receiver1.next().await {
Some(Ok(Event::NeighborUp(_))) => break,
Some(Err(e)) => panic!("Error receiving event: {}", e),
None => panic!("Stream ended"),
_ => {}
}
}
})
.await
.expect("Node 1 failed to find neighbor");
let test_message = format!("test message from node0: {}", rand::random::<u32>());
sender0.broadcast(test_message.clone().into()).await?;
let received = timeout(Duration::from_secs(30), async {
while let Some(event) = receiver1.next().await {
if let Ok(Event::Received(msg)) = event {
let content = String::from_utf8(msg.content.to_vec())?;
if content == test_message {
return Ok::<bool, anyhow::Error>(true);
}
}
}
Ok(false)
})
.await??;
println!("Node 1 received message: {}", received);
assert!(received, "Node 1 should receive message from Node 0");
handle0.stop();
handle1.stop();
let test_message2 = format!("test message from node1: {}", rand::random::<u32>());
sender1.broadcast(test_message2.clone().into()).await?;
let received2 = timeout(Duration::from_secs(10), async {
while let Some(event) = receiver0.next().await {
if let Ok(Event::Received(msg)) = event {
let content = String::from_utf8(msg.content.to_vec())?;
if content == test_message2 {
return Ok::<bool, anyhow::Error>(true);
}
}
}
Ok(false)
})
.await??;
assert!(received2, "Node 0 should receive message from Node 1");
Ok(())
}