Skip to content

Commit 0edfed1

Browse files
committed
test(p2p): tests for inital peers connections
1 parent 3899c15 commit 0edfed1

File tree

4 files changed

+211
-15
lines changed

4 files changed

+211
-15
lines changed

node/testing/src/scenarios/driver.rs

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,20 @@ impl<'cluster> Driver<'cluster> {
258258
(node_id, peer_id)
259259
}
260260

261+
pub fn add_rust_node_with<Item, F>(
262+
&mut self,
263+
testing_config: RustNodeTestingConfig,
264+
mut f: F,
265+
) -> (ClusterNodeId, Item)
266+
where
267+
F: FnMut(&State) -> Item,
268+
{
269+
let node_id = self.runner.add_rust_node(testing_config);
270+
let state = self.runner.node(node_id).unwrap().state();
271+
let item = f(state);
272+
(node_id, item)
273+
}
274+
261275
pub fn inner(&self) -> &ClusterRunner {
262276
&self.runner
263277
}
@@ -293,7 +307,6 @@ pub async fn wait_for_nodes_listening_on_localhost<'cluster>(
293307
driver.run_until(duration, pred).await
294308
}
295309

296-
297310
/// Creates `num` Rust nodes in the cluster
298311
pub fn add_rust_nodes<'cluster, N, NodeIds, PeerIds>(
299312
driver: &mut Driver,
@@ -310,3 +323,22 @@ where
310323
.map(|_| driver.add_rust_node(config.clone()))
311324
.unzip()
312325
}
326+
327+
/// Creates `num` Rust nodes in the cluster
328+
pub fn add_rust_nodes_with<'cluster, N, NodeIds, Items, Item, F>(
329+
driver: &mut Driver,
330+
num: N,
331+
config: RustNodeTestingConfig,
332+
mut f: F,
333+
) -> (NodeIds, Items)
334+
where
335+
N: Into<u16>,
336+
NodeIds: Default + Extend<ClusterNodeId>,
337+
Items: Default + Extend<Item>,
338+
F: FnMut(&State) -> Item,
339+
{
340+
(0..num.into())
341+
.into_iter()
342+
.map(|_| driver.add_rust_node_with(config.clone(), &mut f))
343+
.unzip()
344+
}

node/testing/src/scenarios/p2p/basic_outgoing_connections.rs

Lines changed: 160 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ use crate::{
66
cluster::ClusterNodeId,
77
node::RustNodeTestingConfig,
88
scenarios::{
9-
add_rust_nodes, as_connection_finalized_event, connection_finalized_event,
10-
wait_for_nodes_listening_on_localhost, ClusterRunner, Driver, connection_finalized_with_res_event,
9+
add_rust_nodes, add_rust_nodes_with, as_connection_finalized_event,
10+
connection_finalized_event, connection_finalized_with_res_event,
11+
wait_for_nodes_listening_on_localhost, ClusterRunner, Driver,
1112
},
1213
};
1314

@@ -142,7 +143,7 @@ impl DontConnectToNodeWithSameId {
142143
let (node, _) = driver.add_rust_node(
143144
RustNodeTestingConfig::berkeley_default()
144145
.libp2p_port(port)
145-
.with_peer_id(bytes)
146+
.with_peer_id(bytes),
146147
);
147148
// wait for it to be ready
148149
assert!(
@@ -156,7 +157,7 @@ impl DontConnectToNodeWithSameId {
156157
let (node_ut, _) = driver.add_rust_node(
157158
RustNodeTestingConfig::berkeley_default()
158159
.libp2p_port(node_ut_port)
159-
.with_peer_id(bytes)
160+
.with_peer_id(bytes),
160161
);
161162

162163
driver
@@ -175,7 +176,10 @@ impl DontConnectToNodeWithSameId {
175176
.await
176177
.unwrap();
177178

178-
assert!(connected.is_none(), "the node sholdn't try to connect to itself");
179+
assert!(
180+
connected.is_none(),
181+
"the node sholdn't try to connect to itself"
182+
);
179183
}
180184
}
181185

@@ -189,7 +193,10 @@ impl DontConnectToSelfInitialPeer {
189193

190194
let port = 11109;
191195
let bytes: [u8; 32] = rand::random();
192-
let peer_id = SecretKey::from_bytes(bytes.clone()).public_key().peer_id().to_libp2p_string();
196+
let peer_id = SecretKey::from_bytes(bytes.clone())
197+
.public_key()
198+
.peer_id()
199+
.to_libp2p_string();
193200
let self_maddr = format!("/ip4/127.0.0.1/tcp/{port}/p2p/{peer_id}")
194201
.parse()
195202
.unwrap();
@@ -214,7 +221,10 @@ impl DontConnectToSelfInitialPeer {
214221
.await
215222
.unwrap();
216223

217-
assert!(connected.is_none(), "the node sholdn't try to connect to itself");
224+
assert!(
225+
connected.is_none(),
226+
"the node sholdn't try to connect to itself"
227+
);
218228
}
219229
}
220230

@@ -229,8 +239,10 @@ impl DontConnectToInitialPeerWithSameId {
229239
let port = 11108;
230240
let node_ut_port = 11109;
231241
let bytes: [u8; 32] = rand::random();
232-
let peer_id = SecretKey::from_bytes(bytes.clone()).public_key().peer_id().to_libp2p_string();
233-
242+
let peer_id = SecretKey::from_bytes(bytes.clone())
243+
.public_key()
244+
.peer_id()
245+
.to_libp2p_string();
234246

235247
let self_maddr = format!("/ip4/127.0.0.1/tcp/{port}/p2p/{peer_id}")
236248
.parse()
@@ -240,7 +252,7 @@ impl DontConnectToInitialPeerWithSameId {
240252
let (node, _) = driver.add_rust_node(
241253
RustNodeTestingConfig::berkeley_default()
242254
.libp2p_port(port)
243-
.with_peer_id(bytes)
255+
.with_peer_id(bytes),
244256
);
245257
// wait for it to be ready
246258
assert!(
@@ -266,6 +278,143 @@ impl DontConnectToInitialPeerWithSameId {
266278
.await
267279
.unwrap();
268280

269-
assert!(connected.is_none(), "the node sholdn't try to connect to itself");
281+
assert!(
282+
connected.is_none(),
283+
"the node sholdn't try to connect to itself"
284+
);
285+
}
286+
}
287+
288+
/// Node should be able to connect to all initial peers.
289+
#[derive(documented::Documented, Default, Clone, Copy)]
290+
pub struct ConnectToInitialPeers;
291+
292+
impl ConnectToInitialPeers {
293+
pub async fn run<'cluster>(self, runner: ClusterRunner<'cluster>) {
294+
const MAX: u8 = 32;
295+
296+
let mut driver = Driver::new(runner);
297+
298+
let (peers, port_peer_ids): (Vec<ClusterNodeId>, Vec<_>) = add_rust_nodes_with(
299+
&mut driver,
300+
MAX,
301+
RustNodeTestingConfig::berkeley_default(),
302+
|state| {
303+
let config = &state.p2p.config;
304+
let port = config.libp2p_port.unwrap();
305+
let peer_id = config.identity_pub_key.peer_id();
306+
(port, peer_id)
307+
},
308+
);
309+
310+
// wait for all peers to listen
311+
let satisfied = wait_for_nodes_listening_on_localhost(
312+
&mut driver,
313+
Duration::from_secs(3 * 60),
314+
peers.clone(),
315+
)
316+
.await
317+
.unwrap();
318+
assert!(satisfied, "all peers should be listening");
319+
320+
let initial_peers = port_peer_ids
321+
.iter()
322+
.map(|(port, peer_id)| {
323+
format!(
324+
"/ip4/127.0.0.1/tcp/{port}/p2p/{peer_id}",
325+
peer_id = peer_id.clone().to_libp2p_string()
326+
)
327+
.parse()
328+
.unwrap()
329+
})
330+
.collect::<Vec<_>>();
331+
let (node_ut, _) = driver
332+
.add_rust_node(RustNodeTestingConfig::berkeley_default().initial_peers(initial_peers));
333+
334+
// matches event "the node established connection with peer"
335+
let mut peer_ids =
336+
BTreeSet::from_iter(port_peer_ids.into_iter().map(|(_, peer_id)| peer_id));
337+
let pred = |node_id, event: &_, _state: &_| {
338+
if node_id != node_ut {
339+
false
340+
} else if let Some((peer_id, res)) = as_connection_finalized_event(event) {
341+
assert!(res.is_ok(), "connection to {peer_id} should succeed");
342+
peer_ids.remove(&peer_id);
343+
peer_ids.is_empty()
344+
} else {
345+
false
346+
}
347+
};
348+
349+
let satisfied = driver
350+
.run_until(Duration::from_secs(3 * 60), pred)
351+
.await
352+
.unwrap();
353+
assert!(satisfied, "did not connect to peers: {:?}", peer_ids);
354+
}
355+
}
356+
357+
/// Node should be able to connect to all initial peers after they become ready.
358+
#[derive(documented::Documented, Default, Clone, Copy)]
359+
pub struct ConnectToInitialPeersBecomeReady;
360+
361+
impl ConnectToInitialPeersBecomeReady {
362+
pub async fn run<'cluster>(self, runner: ClusterRunner<'cluster>) {
363+
const MAX: u16 = 32;
364+
365+
let mut driver = Driver::new(runner);
366+
367+
let port_bytes: Vec<_> = (0..MAX)
368+
.into_iter()
369+
.map(|p| (12000 + p, rand::random::<[u8; 32]>()))
370+
.collect();
371+
372+
let initial_peers = port_bytes
373+
.iter()
374+
.map(|(port, bytes)| {
375+
let secret_key = SecretKey::from_bytes(bytes.clone());
376+
format!(
377+
"/ip4/127.0.0.1/tcp/{port}/p2p/{peer_id}",
378+
peer_id = secret_key.public_key().peer_id().to_libp2p_string()
379+
)
380+
.parse()
381+
.unwrap()
382+
})
383+
.collect::<Vec<_>>();
384+
let (node_ut, _) = driver
385+
.add_rust_node(RustNodeTestingConfig::berkeley_default().initial_peers(initial_peers));
386+
387+
driver.wait_for(Duration::from_secs(10), |_, _, _| false).await.unwrap();
388+
389+
let (_peers, mut peer_ids): (Vec<ClusterNodeId>, BTreeSet<PeerId>) = port_bytes
390+
.into_iter()
391+
.map(|(port, bytes)| {
392+
driver.add_rust_node(
393+
RustNodeTestingConfig::berkeley_default()
394+
.libp2p_port(port)
395+
.with_peer_id(bytes),
396+
)
397+
})
398+
.unzip();
399+
400+
// matches event "the node established connection with peer"
401+
let pred = |node_id, event: &_, _state: &_| {
402+
if node_id != node_ut {
403+
false
404+
} else if let Some((peer_id, res)) = as_connection_finalized_event(event) {
405+
if res.is_ok() {
406+
peer_ids.remove(&peer_id);
407+
}
408+
peer_ids.is_empty()
409+
} else {
410+
false
411+
}
412+
};
413+
414+
let satisfied = driver
415+
.run_until(Duration::from_secs(3 * 60), pred)
416+
.await
417+
.unwrap();
418+
assert!(satisfied, "did not connect to peers: {:?}", peer_ids);
270419
}
271420
}

node/testing/tests/p2p_basic_outgoing.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use openmina_node_testing::scenarios::p2p::basic_outgoing_connections::{
2-
DontConnectToInitialPeerWithSameId, DontConnectToNodeWithSameId, DontConnectToSelfInitialPeer,
3-
MakeMultipleOutgoingConnections, MakeOutgoingConnection,
2+
ConnectToInitialPeers, ConnectToInitialPeersBecomeReady, DontConnectToInitialPeerWithSameId,
3+
DontConnectToNodeWithSameId, DontConnectToSelfInitialPeer, MakeMultipleOutgoingConnections,
4+
MakeOutgoingConnection,
45
};
56

67
mod common;
@@ -15,6 +16,7 @@ scenario_test!(
1516
MakeMultipleOutgoingConnections,
1617
MakeMultipleOutgoingConnections
1718
);
19+
1820
scenario_test!(
1921
dont_connect_to_node_same_id,
2022
DontConnectToNodeWithSameId,
@@ -30,3 +32,14 @@ scenario_test!(
3032
DontConnectToSelfInitialPeer,
3133
DontConnectToSelfInitialPeer
3234
);
35+
36+
scenario_test!(
37+
connect_to_all_initial_peers,
38+
ConnectToInitialPeers,
39+
ConnectToInitialPeers
40+
);
41+
scenario_test!(
42+
connect_to_all_initial_peers_become_ready,
43+
ConnectToInitialPeersBecomeReady,
44+
ConnectToInitialPeersBecomeReady
45+
);

p2p/testing.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ The node can obtain its address from other peers. It shouldn't use it when conne
5959

6060
TODO: what if the number of initial peers exceeds the max number of peers?
6161

62+
- [`p2p_basic_outgoing(connect_to_all_initial_peers)`](../node/testing/src/scenarios/p2p/basic_outgoing_connections.rs#L293)
6263
- [multi_node_initial_joining](../node/testing/src/scenarios/multi_node/basic_connectivity_initial_joining.rs) (partially?)
6364

6465
### Node should be able to connect to initial peers eventually, even if initially they are not available.
@@ -69,7 +70,8 @@ below).
6970

7071
TODO: Use cases where this is important.
7172

72-
**Tests:** TODO
73+
**Tests:**
74+
- [`p2p_basic_outgoing(connect_to_all_initial_peers_become_ready)`](../node/testing/src/scenarios/p2p/basic_outgoing_connections.rs#L362)
7375

7476
### Node should have a reasonable retry rate for reconnection
7577

0 commit comments

Comments
 (0)