2022-01-14 10:27:28 +01:00
|
|
|
// Copyright 2021 Protocol Labs.
|
|
|
|
//
|
|
|
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
// copy of this software and associated documentation files (the "Software"),
|
|
|
|
// to deal in the Software without restriction, including without limitation
|
|
|
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
|
|
// and/or sell copies of the Software, and to permit persons to whom the
|
|
|
|
// Software is furnished to do so, subject to the following conditions:
|
|
|
|
//
|
|
|
|
// The above copyright notice and this permission notice shall be included in
|
|
|
|
// all copies or substantial portions of the Software.
|
|
|
|
//
|
|
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
|
|
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
|
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
|
|
// DEALINGS IN THE SOFTWARE.
|
|
|
|
|
|
|
|
use futures::{channel::oneshot, Future, FutureExt, StreamExt};
|
|
|
|
use futures_timer::Delay;
|
2022-09-19 17:32:02 +10:00
|
|
|
use libp2p::core::{ConnectedPoint, Endpoint};
|
|
|
|
use libp2p::swarm::DialError;
|
2022-01-14 10:27:28 +01:00
|
|
|
use libp2p::{
|
|
|
|
development_transport,
|
|
|
|
identity::Keypair,
|
|
|
|
multiaddr::Protocol,
|
|
|
|
swarm::{AddressScore, Swarm, SwarmEvent},
|
|
|
|
Multiaddr, PeerId,
|
|
|
|
};
|
|
|
|
use libp2p_autonat::{
|
|
|
|
Behaviour, Config, Event, InboundProbeError, InboundProbeEvent, ResponseError,
|
|
|
|
};
|
|
|
|
use std::{num::NonZeroU32, time::Duration};
|
|
|
|
|
|
|
|
async fn init_swarm(config: Config) -> Swarm<Behaviour> {
|
|
|
|
let keypair = Keypair::generate_ed25519();
|
|
|
|
let local_id = PeerId::from_public_key(&keypair.public());
|
|
|
|
let transport = development_transport(keypair).await.unwrap();
|
|
|
|
let behaviour = Behaviour::new(local_id, config);
|
2022-11-15 15:26:03 +01:00
|
|
|
Swarm::with_async_std_executor(transport, behaviour, local_id)
|
2022-01-14 10:27:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
async fn init_server(config: Option<Config>) -> (Swarm<Behaviour>, PeerId, Multiaddr) {
|
2022-05-22 22:04:05 +02:00
|
|
|
let mut config = config.unwrap_or_else(|| Config {
|
|
|
|
only_global_ips: false,
|
|
|
|
..Default::default()
|
|
|
|
});
|
2022-01-14 10:27:28 +01:00
|
|
|
// Don't do any outbound probes.
|
|
|
|
config.boot_delay = Duration::from_secs(60);
|
|
|
|
|
|
|
|
let mut server = init_swarm(config).await;
|
|
|
|
let peer_id = *server.local_peer_id();
|
|
|
|
server
|
|
|
|
.listen_on("/ip4/0.0.0.0/tcp/0".parse().unwrap())
|
|
|
|
.unwrap();
|
|
|
|
let addr = loop {
|
2022-10-04 18:24:38 +11:00
|
|
|
if let SwarmEvent::NewListenAddr { address, .. } = server.select_next_some().await {
|
|
|
|
break address;
|
2022-01-14 10:27:28 +01:00
|
|
|
};
|
|
|
|
};
|
|
|
|
(server, peer_id, addr)
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn spawn_client(
|
|
|
|
listen: bool,
|
|
|
|
add_dummy_external_addr: bool,
|
|
|
|
server_id: PeerId,
|
|
|
|
server_addr: Multiaddr,
|
|
|
|
kill: oneshot::Receiver<()>,
|
|
|
|
) -> (PeerId, Option<Multiaddr>) {
|
|
|
|
let (tx, rx) = oneshot::channel();
|
|
|
|
async_std::task::spawn(async move {
|
|
|
|
let mut client = init_swarm(Config {
|
2022-02-15 14:12:41 +01:00
|
|
|
boot_delay: Duration::from_secs(1),
|
|
|
|
retry_interval: Duration::from_secs(1),
|
2022-01-14 10:27:28 +01:00
|
|
|
throttle_server_period: Duration::ZERO,
|
2022-05-22 22:04:05 +02:00
|
|
|
only_global_ips: false,
|
2022-01-14 10:27:28 +01:00
|
|
|
..Default::default()
|
|
|
|
})
|
|
|
|
.await;
|
|
|
|
client
|
|
|
|
.behaviour_mut()
|
|
|
|
.add_server(server_id, Some(server_addr));
|
|
|
|
let peer_id = *client.local_peer_id();
|
|
|
|
let mut addr = None;
|
|
|
|
if listen {
|
|
|
|
client
|
|
|
|
.listen_on("/ip4/0.0.0.0/tcp/0".parse().unwrap())
|
|
|
|
.unwrap();
|
|
|
|
loop {
|
2022-10-04 18:24:38 +11:00
|
|
|
if let SwarmEvent::NewListenAddr { address, .. } = client.select_next_some().await {
|
|
|
|
addr = Some(address);
|
|
|
|
break;
|
2022-01-14 10:27:28 +01:00
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if add_dummy_external_addr {
|
2022-02-15 14:12:41 +01:00
|
|
|
let dummy_addr: Multiaddr = "/ip4/127.0.0.1/tcp/12345".parse().unwrap();
|
2022-01-14 10:27:28 +01:00
|
|
|
client.add_external_address(dummy_addr, AddressScore::Infinite);
|
|
|
|
}
|
|
|
|
tx.send((peer_id, addr)).unwrap();
|
|
|
|
let mut kill = kill.fuse();
|
|
|
|
loop {
|
|
|
|
futures::select! {
|
|
|
|
_ = client.select_next_some() => {},
|
|
|
|
_ = kill => return,
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
rx.await.unwrap()
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn next_event(swarm: &mut Swarm<Behaviour>) -> Event {
|
|
|
|
loop {
|
2022-10-04 18:24:38 +11:00
|
|
|
if let SwarmEvent::Behaviour(event) = swarm.select_next_some().await {
|
|
|
|
break event;
|
2022-01-14 10:27:28 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn run_test_with_timeout(test: impl Future) {
|
|
|
|
futures::select! {
|
|
|
|
_ = test.fuse() => {},
|
|
|
|
_ = Delay::new(Duration::from_secs(60)).fuse() => panic!("test timed out")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[async_std::test]
|
|
|
|
async fn test_dial_back() {
|
|
|
|
let test = async {
|
|
|
|
let (mut server, server_id, server_addr) = init_server(None).await;
|
|
|
|
let (_handle, rx) = oneshot::channel();
|
|
|
|
let (client_id, client_addr) = spawn_client(true, false, server_id, server_addr, rx).await;
|
|
|
|
let client_port = client_addr
|
|
|
|
.unwrap()
|
|
|
|
.into_iter()
|
|
|
|
.find_map(|p| match p {
|
|
|
|
Protocol::Tcp(port) => Some(port),
|
|
|
|
_ => None,
|
|
|
|
})
|
|
|
|
.unwrap();
|
|
|
|
let observed_client_ip = loop {
|
|
|
|
match server.select_next_some().await {
|
|
|
|
SwarmEvent::ConnectionEstablished {
|
|
|
|
peer_id,
|
|
|
|
endpoint:
|
|
|
|
ConnectedPoint::Listener {
|
|
|
|
mut send_back_addr, ..
|
|
|
|
},
|
|
|
|
..
|
|
|
|
} => {
|
|
|
|
assert_eq!(peer_id, client_id);
|
|
|
|
let observed_client_ip = loop {
|
2022-10-04 18:24:38 +11:00
|
|
|
if let Protocol::Ip4(ip4_addr) = send_back_addr.pop().unwrap() {
|
|
|
|
break ip4_addr;
|
2022-01-14 10:27:28 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
break observed_client_ip;
|
|
|
|
}
|
2022-01-29 12:33:15 +01:00
|
|
|
SwarmEvent::IncomingConnection { .. }
|
|
|
|
| SwarmEvent::NewListenAddr { .. }
|
|
|
|
| SwarmEvent::ExpiredListenAddr { .. } => {}
|
|
|
|
other => panic!("Unexpected swarm event: {:?}.", other),
|
2022-01-14 10:27:28 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
let expect_addr = Multiaddr::empty()
|
|
|
|
.with(Protocol::Ip4(observed_client_ip))
|
|
|
|
.with(Protocol::Tcp(client_port))
|
|
|
|
.with(Protocol::P2p(client_id.into()));
|
|
|
|
let request_probe_id = match next_event(&mut server).await {
|
|
|
|
Event::InboundProbe(InboundProbeEvent::Request {
|
|
|
|
peer,
|
|
|
|
addresses,
|
|
|
|
probe_id,
|
|
|
|
}) => {
|
|
|
|
assert_eq!(peer, client_id);
|
|
|
|
assert_eq!(addresses.len(), 1);
|
|
|
|
assert_eq!(addresses[0], expect_addr);
|
|
|
|
probe_id
|
|
|
|
}
|
2022-01-29 12:33:15 +01:00
|
|
|
other => panic!("Unexpected behaviour event: {:?}.", other),
|
2022-01-14 10:27:28 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
loop {
|
|
|
|
match server.select_next_some().await {
|
|
|
|
SwarmEvent::ConnectionEstablished {
|
|
|
|
peer_id,
|
2022-01-17 16:35:14 +01:00
|
|
|
endpoint:
|
|
|
|
ConnectedPoint::Dialer {
|
|
|
|
address,
|
|
|
|
role_override: Endpoint::Dialer,
|
|
|
|
},
|
2022-01-14 10:27:28 +01:00
|
|
|
num_established,
|
|
|
|
concurrent_dial_errors,
|
|
|
|
} => {
|
|
|
|
assert_eq!(peer_id, client_id);
|
|
|
|
assert_eq!(num_established, NonZeroU32::new(2).unwrap());
|
|
|
|
assert!(concurrent_dial_errors.unwrap().is_empty());
|
|
|
|
assert_eq!(address, expect_addr);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
SwarmEvent::Dialing(peer) => assert_eq!(peer, client_id),
|
2022-01-29 12:33:15 +01:00
|
|
|
SwarmEvent::NewListenAddr { .. } | SwarmEvent::ExpiredListenAddr { .. } => {}
|
|
|
|
other => panic!("Unexpected swarm event: {:?}.", other),
|
2022-01-14 10:27:28 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
match next_event(&mut server).await {
|
|
|
|
Event::InboundProbe(InboundProbeEvent::Response {
|
|
|
|
probe_id,
|
|
|
|
peer,
|
|
|
|
address,
|
|
|
|
}) => {
|
|
|
|
assert_eq!(probe_id, request_probe_id);
|
|
|
|
assert_eq!(peer, client_id);
|
|
|
|
assert_eq!(address, expect_addr);
|
|
|
|
}
|
2022-01-29 12:33:15 +01:00
|
|
|
other => panic!("Unexpected behaviour event: {:?}.", other),
|
2022-01-14 10:27:28 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
run_test_with_timeout(test).await;
|
|
|
|
}
|
|
|
|
|
|
|
|
#[async_std::test]
|
|
|
|
async fn test_dial_error() {
|
|
|
|
let test = async {
|
|
|
|
let (mut server, server_id, server_addr) = init_server(None).await;
|
|
|
|
let (_handle, rx) = oneshot::channel();
|
|
|
|
let (client_id, _) = spawn_client(false, true, server_id, server_addr, rx).await;
|
|
|
|
let request_probe_id = match next_event(&mut server).await {
|
|
|
|
Event::InboundProbe(InboundProbeEvent::Request { peer, probe_id, .. }) => {
|
|
|
|
assert_eq!(peer, client_id);
|
|
|
|
probe_id
|
|
|
|
}
|
2022-01-29 12:33:15 +01:00
|
|
|
other => panic!("Unexpected behaviour event: {:?}.", other),
|
2022-01-14 10:27:28 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
loop {
|
|
|
|
match server.select_next_some().await {
|
|
|
|
SwarmEvent::OutgoingConnectionError { peer_id, error } => {
|
|
|
|
assert_eq!(peer_id.unwrap(), client_id);
|
|
|
|
assert!(matches!(error, DialError::Transport(_)));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
SwarmEvent::Dialing(peer) => assert_eq!(peer, client_id),
|
2022-01-29 12:33:15 +01:00
|
|
|
SwarmEvent::NewListenAddr { .. } | SwarmEvent::ExpiredListenAddr { .. } => {}
|
|
|
|
other => panic!("Unexpected swarm event: {:?}.", other),
|
2022-01-14 10:27:28 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
match next_event(&mut server).await {
|
|
|
|
Event::InboundProbe(InboundProbeEvent::Error {
|
|
|
|
probe_id,
|
|
|
|
peer,
|
|
|
|
error,
|
|
|
|
}) => {
|
|
|
|
assert_eq!(probe_id, request_probe_id);
|
|
|
|
assert_eq!(peer, client_id);
|
|
|
|
assert_eq!(error, InboundProbeError::Response(ResponseError::DialError));
|
|
|
|
}
|
2022-01-29 12:33:15 +01:00
|
|
|
other => panic!("Unexpected behaviour event: {:?}.", other),
|
2022-01-14 10:27:28 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
run_test_with_timeout(test).await;
|
|
|
|
}
|
|
|
|
|
|
|
|
#[async_std::test]
|
|
|
|
async fn test_throttle_global_max() {
|
|
|
|
let test = async {
|
|
|
|
let (mut server, server_id, server_addr) = init_server(Some(Config {
|
|
|
|
throttle_clients_global_max: 1,
|
|
|
|
throttle_clients_period: Duration::from_secs(60),
|
2022-05-22 22:04:05 +02:00
|
|
|
only_global_ips: false,
|
2022-01-14 10:27:28 +01:00
|
|
|
..Default::default()
|
|
|
|
}))
|
|
|
|
.await;
|
|
|
|
let mut _handles = Vec::new();
|
|
|
|
for _ in 0..2 {
|
|
|
|
let (_handle, rx) = oneshot::channel();
|
|
|
|
spawn_client(true, false, server_id, server_addr.clone(), rx).await;
|
|
|
|
_handles.push(_handle);
|
|
|
|
}
|
|
|
|
|
|
|
|
let (first_probe_id, first_peer_id) = match next_event(&mut server).await {
|
|
|
|
Event::InboundProbe(InboundProbeEvent::Request { peer, probe_id, .. }) => {
|
|
|
|
(probe_id, peer)
|
|
|
|
}
|
2022-01-29 12:33:15 +01:00
|
|
|
other => panic!("Unexpected behaviour event: {:?}.", other),
|
2022-01-14 10:27:28 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
loop {
|
|
|
|
match next_event(&mut server).await {
|
|
|
|
Event::InboundProbe(InboundProbeEvent::Error {
|
|
|
|
peer,
|
|
|
|
probe_id,
|
|
|
|
error: InboundProbeError::Response(ResponseError::DialRefused),
|
|
|
|
}) => {
|
|
|
|
assert_ne!(first_peer_id, peer);
|
|
|
|
assert_ne!(first_probe_id, probe_id);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
Event::InboundProbe(InboundProbeEvent::Response { peer, probe_id, .. }) => {
|
|
|
|
assert_eq!(first_peer_id, peer);
|
|
|
|
assert_eq!(first_probe_id, probe_id);
|
|
|
|
}
|
2022-01-29 12:33:15 +01:00
|
|
|
other => panic!("Unexpected behaviour event: {:?}.", other),
|
2022-01-14 10:27:28 +01:00
|
|
|
};
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
run_test_with_timeout(test).await;
|
|
|
|
}
|
|
|
|
|
|
|
|
#[async_std::test]
|
|
|
|
async fn test_throttle_peer_max() {
|
|
|
|
let test = async {
|
|
|
|
let (mut server, server_id, server_addr) = init_server(Some(Config {
|
|
|
|
throttle_clients_peer_max: 1,
|
|
|
|
throttle_clients_period: Duration::from_secs(60),
|
2022-05-22 22:04:05 +02:00
|
|
|
only_global_ips: false,
|
2022-01-14 10:27:28 +01:00
|
|
|
..Default::default()
|
|
|
|
}))
|
|
|
|
.await;
|
|
|
|
|
|
|
|
let (_handle, rx) = oneshot::channel();
|
|
|
|
let (client_id, _) = spawn_client(true, false, server_id, server_addr.clone(), rx).await;
|
|
|
|
|
|
|
|
let first_probe_id = match next_event(&mut server).await {
|
|
|
|
Event::InboundProbe(InboundProbeEvent::Request { peer, probe_id, .. }) => {
|
|
|
|
assert_eq!(client_id, peer);
|
|
|
|
probe_id
|
|
|
|
}
|
2022-01-29 12:33:15 +01:00
|
|
|
other => panic!("Unexpected behaviour event: {:?}.", other),
|
2022-01-14 10:27:28 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
match next_event(&mut server).await {
|
|
|
|
Event::InboundProbe(InboundProbeEvent::Response { peer, probe_id, .. }) => {
|
|
|
|
assert_eq!(peer, client_id);
|
|
|
|
assert_eq!(probe_id, first_probe_id);
|
|
|
|
}
|
2022-01-29 12:33:15 +01:00
|
|
|
other => panic!("Unexpected behaviour event: {:?}.", other),
|
2022-01-14 10:27:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
match next_event(&mut server).await {
|
|
|
|
Event::InboundProbe(InboundProbeEvent::Error {
|
|
|
|
peer,
|
|
|
|
probe_id,
|
|
|
|
error,
|
|
|
|
}) => {
|
|
|
|
assert_eq!(client_id, peer);
|
|
|
|
assert_ne!(first_probe_id, probe_id);
|
|
|
|
assert_eq!(
|
|
|
|
error,
|
|
|
|
InboundProbeError::Response(ResponseError::DialRefused)
|
|
|
|
)
|
|
|
|
}
|
2022-01-29 12:33:15 +01:00
|
|
|
other => panic!("Unexpected behaviour event: {:?}.", other),
|
2022-01-14 10:27:28 +01:00
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
run_test_with_timeout(test).await;
|
|
|
|
}
|
|
|
|
|
|
|
|
#[async_std::test]
|
|
|
|
async fn test_dial_multiple_addr() {
|
|
|
|
let test = async {
|
|
|
|
let (mut server, server_id, server_addr) = init_server(Some(Config {
|
|
|
|
throttle_clients_peer_max: 1,
|
|
|
|
throttle_clients_period: Duration::from_secs(60),
|
2022-05-22 22:04:05 +02:00
|
|
|
only_global_ips: false,
|
2022-01-14 10:27:28 +01:00
|
|
|
..Default::default()
|
|
|
|
}))
|
|
|
|
.await;
|
|
|
|
|
|
|
|
let (_handle, rx) = oneshot::channel();
|
|
|
|
let (client_id, _) = spawn_client(true, true, server_id, server_addr.clone(), rx).await;
|
|
|
|
|
|
|
|
let dial_addresses = match next_event(&mut server).await {
|
|
|
|
Event::InboundProbe(InboundProbeEvent::Request {
|
|
|
|
peer, addresses, ..
|
|
|
|
}) => {
|
|
|
|
assert_eq!(addresses.len(), 2);
|
|
|
|
assert_eq!(client_id, peer);
|
|
|
|
addresses
|
|
|
|
}
|
2022-01-29 12:33:15 +01:00
|
|
|
other => panic!("Unexpected behaviour event: {:?}.", other),
|
2022-01-14 10:27:28 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
loop {
|
|
|
|
match server.select_next_some().await {
|
|
|
|
SwarmEvent::ConnectionEstablished {
|
|
|
|
peer_id,
|
2022-01-17 16:35:14 +01:00
|
|
|
endpoint:
|
|
|
|
ConnectedPoint::Dialer {
|
|
|
|
address,
|
|
|
|
role_override: Endpoint::Dialer,
|
|
|
|
},
|
2022-01-14 10:27:28 +01:00
|
|
|
concurrent_dial_errors,
|
|
|
|
..
|
|
|
|
} => {
|
|
|
|
assert_eq!(peer_id, client_id);
|
|
|
|
let dial_errors = concurrent_dial_errors.unwrap();
|
|
|
|
assert_eq!(dial_errors.len(), 1);
|
|
|
|
assert_eq!(dial_errors[0].0, dial_addresses[0]);
|
|
|
|
assert_eq!(address, dial_addresses[1]);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
SwarmEvent::Dialing(peer) => assert_eq!(peer, client_id),
|
2022-01-29 12:33:15 +01:00
|
|
|
SwarmEvent::NewListenAddr { .. } | SwarmEvent::ExpiredListenAddr { .. } => {}
|
|
|
|
other => panic!("Unexpected swarm event: {:?}.", other),
|
2022-01-14 10:27:28 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
run_test_with_timeout(test).await;
|
|
|
|
}
|
2022-05-22 22:04:05 +02:00
|
|
|
|
|
|
|
#[async_std::test]
|
|
|
|
async fn test_global_ips_config() {
|
|
|
|
let test = async {
|
|
|
|
let (mut server, server_id, server_addr) = init_server(Some(Config {
|
|
|
|
// Enforce that only clients outside of the local network are qualified for dial-backs.
|
|
|
|
only_global_ips: true,
|
|
|
|
..Default::default()
|
|
|
|
}))
|
|
|
|
.await;
|
|
|
|
|
|
|
|
let (_handle, rx) = oneshot::channel();
|
|
|
|
spawn_client(true, false, server_id, server_addr.clone(), rx).await;
|
|
|
|
|
|
|
|
// Expect the probe to be refused as both peers run on the same machine and thus in the same local network.
|
|
|
|
match next_event(&mut server).await {
|
|
|
|
Event::InboundProbe(InboundProbeEvent::Error { error, .. }) => assert!(matches!(
|
|
|
|
error,
|
|
|
|
InboundProbeError::Response(ResponseError::DialRefused)
|
|
|
|
)),
|
|
|
|
other => panic!("Unexpected behaviour event: {:?}.", other),
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
run_test_with_timeout(test).await;
|
|
|
|
}
|