#![recursion_limit = "256"]
#[allow(dead_code)]
mod common;
use common::{node::*, test_peer::TestPeer};
use snarkos_node_network::PeerPoolHandling;
use snarkos_node_tcp::P2P;
use deadline::deadline;
use std::time::Duration;
macro_rules! test_disconnect {
($node_type:ident, $peer_type:ident, $node_disconnects:expr, $($attr:meta)?) => {
#[tokio::test]
$(#[$attr])?
async fn $peer_type() {
use deadline::deadline;
use pea2pea::Pea2Pea;
use snarkos_node_network::PeerPoolHandling;
use snarkos_node_tcp::P2P;
use std::time::Duration;
let node = $crate::$node_type().await;
let peer = $crate::TestPeer::$peer_type().await;
let peer_addr = peer.node().listening_addr().unwrap();
node.router().connect(peer_addr).unwrap().await.unwrap().unwrap();
let node_clone = node.clone();
deadline!(Duration::from_secs(5), move || node_clone.router().number_of_connected_peers() == 1);
let node_clone = node.clone();
deadline!(Duration::from_secs(5), move || node_clone.tcp().num_connected() == 1);
let peer_clone = peer.clone();
deadline!(Duration::from_secs(5), move || peer_clone.node().num_connected() == 1);
if $node_disconnects {
node.router().disconnect(node.tcp().connected_addrs()[0]).await.unwrap();
} else {
peer.node().disconnect(peer.node().connected_addrs()[0]).await;
}
let node_clone = node.clone();
deadline!(Duration::from_secs(5), move || node_clone.router().number_of_connected_peers() == 0);
deadline!(Duration::from_secs(5), move || node.tcp().num_connected() == 0);
deadline!(Duration::from_secs(5), move || peer.node().num_connected() == 0);
}
};
($($node_type:ident |> $peer_type:ident $(= $attr:meta)?),*) => {
mod disconnect_node_side {
$(
test_disconnect!($node_type, $peer_type, true, $($attr)?);
)*
}
};
($($node_type:ident <| $peer_type:ident $(= $attr:meta)?),*) => {
mod disconnect_peer_side {
$(
test_disconnect!($node_type, $peer_type, false, $($attr)?);
)*
}
};
}
mod client {
test_disconnect! {
client |> client,
client |> validator,
client |> prover
}
test_disconnect! {
client <| client,
client <| validator,
client <| prover
}
}
mod prover {
test_disconnect! {
prover |> client,
prover |> validator,
prover |> prover
}
test_disconnect! {
prover <| client,
prover <| validator,
prover <| prover
}
}
mod validator {
test_disconnect! {
validator |> client,
validator |> validator,
validator |> prover
}
test_disconnect! {
validator <| client,
validator <| validator,
validator <| prover
}
}
#[tokio::test(flavor = "multi_thread")]
async fn duplicate_disconnect_attempts() {
let node1 = client().await;
let node2 = client().await;
let addr2 = node2.tcp().listening_addr().unwrap();
assert!(node1.router().connect(addr2).unwrap().await.unwrap().is_ok());
let node1_clone = node1.clone();
let disconn1 = tokio::spawn(async move { node1_clone.router().disconnect(addr2).await.unwrap() });
let node1_clone = node1.clone();
let disconn2 = tokio::spawn(async move { node1_clone.router().disconnect(addr2).await.unwrap() });
let node1_clone = node1.clone();
let disconn3 = tokio::spawn(async move { node1_clone.router().disconnect(addr2).await.unwrap() });
let (result1, result2, result3) = tokio::join!(disconn1, disconn2, disconn3);
let mut successes = 0;
if result1.unwrap() {
successes += 1;
}
if result2.unwrap() {
successes += 1;
}
if result3.unwrap() {
successes += 1;
}
assert_eq!(successes, 1);
let node1_clone = node1.clone();
deadline!(Duration::from_secs(5), move || node1_clone.router().number_of_connected_peers() == 0);
let node2_clone = node2.clone();
deadline!(Duration::from_secs(5), move || node2_clone.router().number_of_connected_peers() == 0);
}