use futures::prelude::*;
use libp2p::PeerId;
use rand::distributions::{Distribution, Uniform, WeightedIndex};
use rand::seq::IteratorRandom;
use std::{collections::HashMap, collections::HashSet, iter, pin::Pin, task::Poll};
use sc_peerset::{IncomingIndex, Message, PeersetConfig, Peerset, ReputationChange};
#[test]
fn run() {
for _ in 0..50 {
test_once();
}
}
fn test_once() {
let mut rng = rand::thread_rng();
let mut known_nodes = HashSet::<PeerId>::new();
let mut reserved_nodes = HashSet::<PeerId>::new();
let (mut peerset, peerset_handle) = Peerset::from_config(PeersetConfig {
bootnodes: (0 .. Uniform::new_inclusive(0, 4).sample(&mut rng)).map(|_| {
let id = PeerId::random();
known_nodes.insert(id.clone());
id
}).collect(),
priority_groups: {
let list = (0 .. Uniform::new_inclusive(0, 2).sample(&mut rng)).map(|_| {
let id = PeerId::random();
known_nodes.insert(id.clone());
reserved_nodes.insert(id.clone());
id
}).collect();
vec![("reserved".to_owned(), list)]
},
reserved_only: Uniform::new_inclusive(0, 10).sample(&mut rng) == 0,
in_peers: Uniform::new_inclusive(0, 25).sample(&mut rng),
out_peers: Uniform::new_inclusive(0, 25).sample(&mut rng),
});
futures::executor::block_on(futures::future::poll_fn(move |cx| {
let mut connected_nodes = HashSet::<PeerId>::new();
let mut incoming_nodes = HashMap::<IncomingIndex, PeerId>::new();
let mut next_incoming_id = IncomingIndex(0);
for _ in 0 .. 2500 {
let action_weights = [150, 90, 90, 30, 30, 1, 1, 4, 4];
match WeightedIndex::new(&action_weights).unwrap().sample(&mut rng) {
0 => match Stream::poll_next(Pin::new(&mut peerset), cx) {
Poll::Ready(Some(Message::Connect(id))) => {
if let Some(id) = incoming_nodes.iter().find(|(_, v)| **v == id).map(|(&id, _)| id) {
incoming_nodes.remove(&id);
}
assert!(connected_nodes.insert(id));
}
Poll::Ready(Some(Message::Drop(id))) => { connected_nodes.remove(&id); }
Poll::Ready(Some(Message::Accept(n))) =>
assert!(connected_nodes.insert(incoming_nodes.remove(&n).unwrap())),
Poll::Ready(Some(Message::Reject(n))) =>
assert!(!connected_nodes.contains(&incoming_nodes.remove(&n).unwrap())),
Poll::Ready(None) => panic!(),
Poll::Pending => {}
}
1 => {
let new_id = PeerId::random();
known_nodes.insert(new_id.clone());
peerset.discovered(iter::once(new_id));
}
2 => if let Some(id) = known_nodes.iter().choose(&mut rng) {
let val = Uniform::new_inclusive(i32::min_value(), i32::max_value()).sample(&mut rng);
peerset_handle.report_peer(id.clone(), ReputationChange::new(val, ""));
}
3 => if let Some(id) = connected_nodes.iter().choose(&mut rng).cloned() {
connected_nodes.remove(&id);
peerset.dropped(id);
}
4 => if let Some(id) = known_nodes.iter()
.filter(|n| incoming_nodes.values().all(|m| m != *n) && !connected_nodes.contains(*n))
.choose(&mut rng) {
peerset.incoming(id.clone(), next_incoming_id.clone());
incoming_nodes.insert(next_incoming_id.clone(), id.clone());
next_incoming_id.0 += 1;
}
5 => peerset_handle.set_reserved_only(true),
6 => peerset_handle.set_reserved_only(false),
7 => if let Some(id) = known_nodes.iter().filter(|n| !reserved_nodes.contains(*n)).choose(&mut rng) {
peerset_handle.add_reserved_peer(id.clone());
reserved_nodes.insert(id.clone());
}
8 => if let Some(id) = reserved_nodes.iter().choose(&mut rng).cloned() {
reserved_nodes.remove(&id);
peerset_handle.remove_reserved_peer(id);
}
_ => unreachable!()
}
}
Poll::Ready(())
}));
}