mirror of
https://github.com/fluencelabs/rust-libp2p
synced 2025-05-18 21:51:19 +00:00
Comment out tests for better IDE experience, add some comments
This commit is contained in:
parent
96cd509c60
commit
65bb4f2b7d
@ -475,189 +475,189 @@ where
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use libp2p_core::PeerId;
|
||||
use quickcheck::*;
|
||||
use rand::Rng;
|
||||
|
||||
type TestTable = KBucketsTable<KeyBytes, ()>;
|
||||
|
||||
impl Arbitrary for TestTable {
|
||||
fn arbitrary<G: Gen>(g: &mut G) -> TestTable {
|
||||
let local_key = Key::from(PeerId::random());
|
||||
let timeout = Duration::from_secs(g.gen_range(1, 360));
|
||||
let mut table = TestTable::new(local_key.clone().into(), timeout);
|
||||
let mut num_total = g.gen_range(0, 100);
|
||||
for (i, b) in &mut table.buckets.iter_mut().enumerate().rev() {
|
||||
let ix = BucketIndex(i);
|
||||
let num = g.gen_range(0, usize::min(K_VALUE.get(), num_total) + 1);
|
||||
num_total -= num;
|
||||
for _ in 0 .. num {
|
||||
let distance = ix.rand_distance(g);
|
||||
let key = local_key.for_distance(distance);
|
||||
let node = Node { key: key.clone(), value: () };
|
||||
let status = NodeStatus::arbitrary(g);
|
||||
match b.insert(node, status) {
|
||||
InsertResult::Inserted => {}
|
||||
_ => panic!()
|
||||
}
|
||||
}
|
||||
}
|
||||
table
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rand_distance() {
|
||||
fn prop(ix: u8) -> bool {
|
||||
let d = BucketIndex(ix as usize).rand_distance(&mut rand::thread_rng());
|
||||
let n = U256::from(<[u8; 32]>::from(d.0));
|
||||
let b = U256::from(2);
|
||||
let e = U256::from(ix);
|
||||
let lower = b.pow(e);
|
||||
let upper = b.pow(e + U256::from(1)) - U256::from(1);
|
||||
lower <= n && n <= upper
|
||||
}
|
||||
quickcheck(prop as fn(_) -> _);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn entry_inserted() {
|
||||
let local_key = Key::from(PeerId::random());
|
||||
let other_id = Key::from(PeerId::random());
|
||||
|
||||
let mut table = KBucketsTable::<_, ()>::new(local_key, Duration::from_secs(5));
|
||||
if let Entry::Absent(entry) = table.entry(&other_id) {
|
||||
match entry.insert((), NodeStatus::Connected) {
|
||||
InsertResult::Inserted => (),
|
||||
_ => panic!()
|
||||
}
|
||||
} else {
|
||||
panic!()
|
||||
}
|
||||
|
||||
let res = table.closest_keys(&other_id).collect::<Vec<_>>();
|
||||
assert_eq!(res.len(), 1);
|
||||
assert_eq!(res[0], other_id);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn entry_self() {
|
||||
let local_key = Key::from(PeerId::random());
|
||||
let mut table = KBucketsTable::<_, ()>::new(local_key.clone(), Duration::from_secs(5));
|
||||
match table.entry(&local_key) {
|
||||
Entry::SelfEntry => (),
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn closest() {
|
||||
let local_key = Key::from(PeerId::random());
|
||||
let mut table = KBucketsTable::<_, ()>::new(local_key, Duration::from_secs(5));
|
||||
let mut count = 0;
|
||||
loop {
|
||||
if count == 100 { break; }
|
||||
let key = Key::from(PeerId::random());
|
||||
if let Entry::Absent(e) = table.entry(&key) {
|
||||
match e.insert((), NodeStatus::Connected) {
|
||||
InsertResult::Inserted => count += 1,
|
||||
_ => continue,
|
||||
}
|
||||
} else {
|
||||
panic!("entry exists")
|
||||
}
|
||||
}
|
||||
|
||||
let mut expected_keys: Vec<_> = table.buckets
|
||||
.iter()
|
||||
.flat_map(|t| t.iter().map(|(n,_)| n.key.clone()))
|
||||
.collect();
|
||||
|
||||
for _ in 0 .. 10 {
|
||||
let target_key = Key::from(PeerId::random());
|
||||
let keys = table.closest_keys(&target_key).collect::<Vec<_>>();
|
||||
// The list of keys is expected to match the result of a full-table scan.
|
||||
expected_keys.sort_by_key(|k| k.distance(&target_key));
|
||||
assert_eq!(keys, expected_keys);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn applied_pending() {
|
||||
let local_key = Key::from(PeerId::random());
|
||||
let mut table = KBucketsTable::<_, ()>::new(local_key.clone(), Duration::from_millis(1));
|
||||
let expected_applied;
|
||||
let full_bucket_index;
|
||||
loop {
|
||||
let key = Key::from(PeerId::random());
|
||||
if let Entry::Absent(e) = table.entry(&key) {
|
||||
match e.insert((), NodeStatus::Disconnected) {
|
||||
InsertResult::Full => {
|
||||
if let Entry::Absent(e) = table.entry(&key) {
|
||||
match e.insert((), NodeStatus::Connected) {
|
||||
InsertResult::Pending { disconnected } => {
|
||||
expected_applied = AppliedPending {
|
||||
inserted: Node { key: key.clone(), value: () },
|
||||
evicted: Some(Node { key: disconnected, value: () })
|
||||
};
|
||||
full_bucket_index = BucketIndex::new(&key.distance(&local_key));
|
||||
break
|
||||
},
|
||||
_ => panic!()
|
||||
}
|
||||
} else {
|
||||
panic!()
|
||||
}
|
||||
},
|
||||
_ => continue,
|
||||
}
|
||||
} else {
|
||||
panic!("entry exists")
|
||||
}
|
||||
}
|
||||
|
||||
// Expire the timeout for the pending entry on the full bucket.`
|
||||
let full_bucket = &mut table.buckets[full_bucket_index.unwrap().get()];
|
||||
let elapsed = Instant::now() - Duration::from_secs(1);
|
||||
full_bucket.pending_mut().unwrap().set_ready_at(elapsed);
|
||||
|
||||
match table.entry(&expected_applied.inserted.key) {
|
||||
Entry::Present(_, NodeStatus::Connected) => {}
|
||||
x => panic!("Unexpected entry: {:?}", x)
|
||||
}
|
||||
|
||||
match table.entry(&expected_applied.evicted.as_ref().unwrap().key) {
|
||||
Entry::Absent(_) => {}
|
||||
x => panic!("Unexpected entry: {:?}", x)
|
||||
}
|
||||
|
||||
assert_eq!(Some(expected_applied), table.take_applied_pending());
|
||||
assert_eq!(None, table.take_applied_pending());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn count_nodes_between() {
|
||||
fn prop(mut table: TestTable, target: Key<PeerId>) -> bool {
|
||||
let num_to_target = table.count_nodes_between(&target);
|
||||
let distance = table.local_key.distance(&target);
|
||||
let base2 = U256::from(2);
|
||||
let mut iter = ClosestBucketsIter::new(distance);
|
||||
iter.all(|i| {
|
||||
// Flip the distance bit related to the bucket.
|
||||
let d = Distance(distance.0 ^ (base2.pow(U256::from(i.get()))));
|
||||
let k = table.local_key.for_distance(d);
|
||||
if distance.0.bit(i.get()) {
|
||||
// Bit flip `1` -> `0`, the key must be closer than `target`.
|
||||
d < distance && table.count_nodes_between(&k) <= num_to_target
|
||||
} else {
|
||||
// Bit flip `0` -> `1`, the key must be farther than `target`.
|
||||
d > distance && table.count_nodes_between(&k) >= num_to_target
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
QuickCheck::new().tests(10).quickcheck(prop as fn(_,_) -> _)
|
||||
}
|
||||
}
|
||||
// mod tests {
|
||||
// use super::*;
|
||||
// use libp2p_core::PeerId;
|
||||
// use quickcheck::*;
|
||||
// use rand::Rng;
|
||||
//
|
||||
// type TestTable = KBucketsTable<KeyBytes, ()>;
|
||||
//
|
||||
// impl Arbitrary for TestTable {
|
||||
// fn arbitrary<G: Gen>(g: &mut G) -> TestTable {
|
||||
// let local_key = Key::from(PeerId::random());
|
||||
// let timeout = Duration::from_secs(g.gen_range(1, 360));
|
||||
// let mut table = TestTable::new(local_key.clone().into(), timeout);
|
||||
// let mut num_total = g.gen_range(0, 100);
|
||||
// for (i, b) in &mut table.buckets.iter_mut().enumerate().rev() {
|
||||
// let ix = BucketIndex(i);
|
||||
// let num = g.gen_range(0, usize::min(K_VALUE.get(), num_total) + 1);
|
||||
// num_total -= num;
|
||||
// for _ in 0 .. num {
|
||||
// let distance = ix.rand_distance(g);
|
||||
// let key = local_key.for_distance(distance);
|
||||
// let node = Node { key: key.clone(), value: () };
|
||||
// let status = NodeStatus::arbitrary(g);
|
||||
// match b.insert(node, status) {
|
||||
// InsertResult::Inserted => {}
|
||||
// _ => panic!()
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// table
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// #[test]
|
||||
// fn rand_distance() {
|
||||
// fn prop(ix: u8) -> bool {
|
||||
// let d = BucketIndex(ix as usize).rand_distance(&mut rand::thread_rng());
|
||||
// let n = U256::from(<[u8; 32]>::from(d.0));
|
||||
// let b = U256::from(2);
|
||||
// let e = U256::from(ix);
|
||||
// let lower = b.pow(e);
|
||||
// let upper = b.pow(e + U256::from(1)) - U256::from(1);
|
||||
// lower <= n && n <= upper
|
||||
// }
|
||||
// quickcheck(prop as fn(_) -> _);
|
||||
// }
|
||||
//
|
||||
// #[test]
|
||||
// fn entry_inserted() {
|
||||
// let local_key = Key::from(PeerId::random());
|
||||
// let other_id = Key::from(PeerId::random());
|
||||
//
|
||||
// let mut table = KBucketsTable::<_, ()>::new(local_key, Duration::from_secs(5));
|
||||
// if let Entry::Absent(entry) = table.entry(&other_id) {
|
||||
// match entry.insert((), NodeStatus::Connected) {
|
||||
// InsertResult::Inserted => (),
|
||||
// _ => panic!()
|
||||
// }
|
||||
// } else {
|
||||
// panic!()
|
||||
// }
|
||||
//
|
||||
// let res = table.closest_keys(&other_id).collect::<Vec<_>>();
|
||||
// assert_eq!(res.len(), 1);
|
||||
// assert_eq!(res[0], other_id);
|
||||
// }
|
||||
//
|
||||
// #[test]
|
||||
// fn entry_self() {
|
||||
// let local_key = Key::from(PeerId::random());
|
||||
// let mut table = KBucketsTable::<_, ()>::new(local_key.clone(), Duration::from_secs(5));
|
||||
// match table.entry(&local_key) {
|
||||
// Entry::SelfEntry => (),
|
||||
// _ => panic!(),
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// #[test]
|
||||
// fn closest() {
|
||||
// let local_key = Key::from(PeerId::random());
|
||||
// let mut table = KBucketsTable::<_, ()>::new(local_key, Duration::from_secs(5));
|
||||
// let mut count = 0;
|
||||
// loop {
|
||||
// if count == 100 { break; }
|
||||
// let key = Key::from(PeerId::random());
|
||||
// if let Entry::Absent(e) = table.entry(&key) {
|
||||
// match e.insert((), NodeStatus::Connected) {
|
||||
// InsertResult::Inserted => count += 1,
|
||||
// _ => continue,
|
||||
// }
|
||||
// } else {
|
||||
// panic!("entry exists")
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// let mut expected_keys: Vec<_> = table.buckets
|
||||
// .iter()
|
||||
// .flat_map(|t| t.iter().map(|(n,_)| n.key.clone()))
|
||||
// .collect();
|
||||
//
|
||||
// for _ in 0 .. 10 {
|
||||
// let target_key = Key::from(PeerId::random());
|
||||
// let keys = table.closest_keys(&target_key).collect::<Vec<_>>();
|
||||
// // The list of keys is expected to match the result of a full-table scan.
|
||||
// expected_keys.sort_by_key(|k| k.distance(&target_key));
|
||||
// assert_eq!(keys, expected_keys);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// #[test]
|
||||
// fn applied_pending() {
|
||||
// let local_key = Key::from(PeerId::random());
|
||||
// let mut table = KBucketsTable::<_, ()>::new(local_key.clone(), Duration::from_millis(1));
|
||||
// let expected_applied;
|
||||
// let full_bucket_index;
|
||||
// loop {
|
||||
// let key = Key::from(PeerId::random());
|
||||
// if let Entry::Absent(e) = table.entry(&key) {
|
||||
// match e.insert((), NodeStatus::Disconnected) {
|
||||
// InsertResult::Full => {
|
||||
// if let Entry::Absent(e) = table.entry(&key) {
|
||||
// match e.insert((), NodeStatus::Connected) {
|
||||
// InsertResult::Pending { disconnected } => {
|
||||
// expected_applied = AppliedPending {
|
||||
// inserted: Node { key: key.clone(), value: () },
|
||||
// evicted: Some(Node { key: disconnected, value: () })
|
||||
// };
|
||||
// full_bucket_index = BucketIndex::new(&key.distance(&local_key));
|
||||
// break
|
||||
// },
|
||||
// _ => panic!()
|
||||
// }
|
||||
// } else {
|
||||
// panic!()
|
||||
// }
|
||||
// },
|
||||
// _ => continue,
|
||||
// }
|
||||
// } else {
|
||||
// panic!("entry exists")
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // Expire the timeout for the pending entry on the full bucket.`
|
||||
// let full_bucket = &mut table.buckets[full_bucket_index.unwrap().get()];
|
||||
// let elapsed = Instant::now() - Duration::from_secs(1);
|
||||
// full_bucket.pending_mut().unwrap().set_ready_at(elapsed);
|
||||
//
|
||||
// match table.entry(&expected_applied.inserted.key) {
|
||||
// Entry::Present(_, NodeStatus::Connected) => {}
|
||||
// x => panic!("Unexpected entry: {:?}", x)
|
||||
// }
|
||||
//
|
||||
// match table.entry(&expected_applied.evicted.as_ref().unwrap().key) {
|
||||
// Entry::Absent(_) => {}
|
||||
// x => panic!("Unexpected entry: {:?}", x)
|
||||
// }
|
||||
//
|
||||
// assert_eq!(Some(expected_applied), table.take_applied_pending());
|
||||
// assert_eq!(None, table.take_applied_pending());
|
||||
// }
|
||||
//
|
||||
// #[test]
|
||||
// fn count_nodes_between() {
|
||||
// fn prop(mut table: TestTable, target: Key<PeerId>) -> bool {
|
||||
// let num_to_target = table.count_nodes_between(&target);
|
||||
// let distance = table.local_key.distance(&target);
|
||||
// let base2 = U256::from(2);
|
||||
// let mut iter = ClosestBucketsIter::new(distance);
|
||||
// iter.all(|i| {
|
||||
// // Flip the distance bit related to the bucket.
|
||||
// let d = Distance(distance.0 ^ (base2.pow(U256::from(i.get()))));
|
||||
// let k = table.local_key.for_distance(d);
|
||||
// if distance.0.bit(i.get()) {
|
||||
// // Bit flip `1` -> `0`, the key must be closer than `target`.
|
||||
// d < distance && table.count_nodes_between(&k) <= num_to_target
|
||||
// } else {
|
||||
// // Bit flip `0` -> `1`, the key must be farther than `target`.
|
||||
// d > distance && table.count_nodes_between(&k) >= num_to_target
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
//
|
||||
// QuickCheck::new().tests(10).quickcheck(prop as fn(_,_) -> _)
|
||||
// }
|
||||
// }
|
||||
|
@ -324,6 +324,7 @@ where
|
||||
match status {
|
||||
NodeStatus::Connected => {
|
||||
if self.nodes.is_full() {
|
||||
// All nodes are connected OR there is already a pending node
|
||||
if self.first_connected_pos == Some(0) || self.pending.is_some() {
|
||||
return InsertResult::Full
|
||||
} else {
|
||||
@ -338,6 +339,7 @@ where
|
||||
}
|
||||
}
|
||||
let pos = self.nodes.len();
|
||||
// If there were no previously connected nodes – set mark to the last one
|
||||
self.first_connected_pos = self.first_connected_pos.or(Some(pos));
|
||||
self.nodes.push(node);
|
||||
InsertResult::Inserted
|
||||
@ -346,10 +348,12 @@ where
|
||||
if self.nodes.is_full() {
|
||||
return InsertResult::Full
|
||||
}
|
||||
// There are some connected nodes
|
||||
if let Some(ref mut p) = self.first_connected_pos {
|
||||
self.nodes.insert(*p, node);
|
||||
// Lower the mark of connected nodes
|
||||
*p += 1;
|
||||
} else {
|
||||
} else { // There are no connected nodes
|
||||
self.nodes.push(node);
|
||||
}
|
||||
InsertResult::Inserted
|
||||
@ -401,231 +405,231 @@ where
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use libp2p_core::PeerId;
|
||||
use rand::Rng;
|
||||
use std::collections::VecDeque;
|
||||
use super::*;
|
||||
use quickcheck::*;
|
||||
|
||||
impl Arbitrary for KBucket<Key<PeerId>, ()> {
|
||||
fn arbitrary<G: Gen>(g: &mut G) -> KBucket<Key<PeerId>, ()> {
|
||||
let timeout = Duration::from_secs(g.gen_range(1, g.size() as u64));
|
||||
let mut bucket = KBucket::<Key<PeerId>, ()>::new(timeout);
|
||||
let num_nodes = g.gen_range(1, K_VALUE.get() + 1);
|
||||
for _ in 0 .. num_nodes {
|
||||
let key = Key::new(PeerId::random());
|
||||
let node = Node { key: key.clone(), value: () };
|
||||
let status = NodeStatus::arbitrary(g);
|
||||
match bucket.insert(node, status) {
|
||||
InsertResult::Inserted => {}
|
||||
_ => panic!()
|
||||
}
|
||||
}
|
||||
bucket
|
||||
}
|
||||
}
|
||||
|
||||
impl Arbitrary for NodeStatus {
|
||||
fn arbitrary<G: Gen>(g: &mut G) -> NodeStatus {
|
||||
if g.gen() {
|
||||
NodeStatus::Connected
|
||||
} else {
|
||||
NodeStatus::Disconnected
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Arbitrary for Position {
|
||||
fn arbitrary<G: Gen>(g: &mut G) -> Position {
|
||||
Position(g.gen_range(0, K_VALUE.get()))
|
||||
}
|
||||
}
|
||||
|
||||
// Fill a bucket with random nodes with the given status.
|
||||
fn fill_bucket(bucket: &mut KBucket<Key<PeerId>, ()>, status: NodeStatus) {
|
||||
let num_entries_start = bucket.num_entries();
|
||||
for i in 0 .. K_VALUE.get() - num_entries_start {
|
||||
let key = Key::new(PeerId::random());
|
||||
let node = Node { key, value: () };
|
||||
assert_eq!(InsertResult::Inserted, bucket.insert(node, status));
|
||||
assert_eq!(bucket.num_entries(), num_entries_start + i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ordering() {
|
||||
fn prop(status: Vec<NodeStatus>) -> bool {
|
||||
let mut bucket = KBucket::<Key<PeerId>, ()>::new(Duration::from_secs(1));
|
||||
|
||||
// The expected lists of connected and disconnected nodes.
|
||||
let mut connected = VecDeque::new();
|
||||
let mut disconnected = VecDeque::new();
|
||||
|
||||
// Fill the bucket, thereby populating the expected lists in insertion order.
|
||||
for status in status {
|
||||
let key = Key::new(PeerId::random());
|
||||
let node = Node { key: key.clone(), value: () };
|
||||
let full = bucket.num_entries() == K_VALUE.get();
|
||||
match bucket.insert(node, status) {
|
||||
InsertResult::Inserted => {
|
||||
let vec = match status {
|
||||
NodeStatus::Connected => &mut connected,
|
||||
NodeStatus::Disconnected => &mut disconnected
|
||||
};
|
||||
if full {
|
||||
vec.pop_front();
|
||||
}
|
||||
vec.push_back((status, key.clone()));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
// Get all nodes from the bucket, together with their status.
|
||||
let mut nodes = bucket.iter()
|
||||
.map(|(n, s)| (s, n.key.clone()))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// Split the list of nodes at the first connected node.
|
||||
let first_connected_pos = nodes.iter().position(|(s,_)| *s == NodeStatus::Connected);
|
||||
assert_eq!(bucket.first_connected_pos, first_connected_pos);
|
||||
let tail = first_connected_pos.map_or(Vec::new(), |p| nodes.split_off(p));
|
||||
|
||||
// All nodes before the first connected node must be disconnected and
|
||||
// in insertion order. Similarly, all remaining nodes must be connected
|
||||
// and in insertion order.
|
||||
nodes == Vec::from(disconnected)
|
||||
&&
|
||||
tail == Vec::from(connected)
|
||||
}
|
||||
|
||||
quickcheck(prop as fn(_) -> _);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn full_bucket() {
|
||||
let mut bucket = KBucket::<Key<PeerId>, ()>::new(Duration::from_secs(1));
|
||||
|
||||
// Fill the bucket with disconnected nodes.
|
||||
fill_bucket(&mut bucket, NodeStatus::Disconnected);
|
||||
|
||||
// Trying to insert another disconnected node fails.
|
||||
let key = Key::new(PeerId::random());
|
||||
let node = Node { key, value: () };
|
||||
match bucket.insert(node, NodeStatus::Disconnected) {
|
||||
InsertResult::Full => {},
|
||||
x => panic!("{:?}", x)
|
||||
}
|
||||
|
||||
// One-by-one fill the bucket with connected nodes, replacing the disconnected ones.
|
||||
for i in 0 .. K_VALUE.get() {
|
||||
let (first, first_status) = bucket.iter().next().unwrap();
|
||||
let first_disconnected = first.clone();
|
||||
assert_eq!(first_status, NodeStatus::Disconnected);
|
||||
|
||||
// Add a connected node, which is expected to be pending, scheduled to
|
||||
// replace the first (i.e. least-recently connected) node.
|
||||
let key = Key::new(PeerId::random());
|
||||
let node = Node { key: key.clone(), value: () };
|
||||
match bucket.insert(node.clone(), NodeStatus::Connected) {
|
||||
InsertResult::Pending { disconnected } =>
|
||||
assert_eq!(disconnected, first_disconnected.key),
|
||||
x => panic!("{:?}", x)
|
||||
}
|
||||
|
||||
// Trying to insert another connected node fails.
|
||||
match bucket.insert(node.clone(), NodeStatus::Connected) {
|
||||
InsertResult::Full => {},
|
||||
x => panic!("{:?}", x)
|
||||
}
|
||||
|
||||
assert!(bucket.pending().is_some());
|
||||
|
||||
// Apply the pending node.
|
||||
let pending = bucket.pending_mut().expect("No pending node.");
|
||||
pending.set_ready_at(Instant::now() - Duration::from_secs(1));
|
||||
let result = bucket.apply_pending();
|
||||
assert_eq!(result, Some(AppliedPending {
|
||||
inserted: node.clone(),
|
||||
evicted: Some(first_disconnected)
|
||||
}));
|
||||
assert_eq!(Some((&node, NodeStatus::Connected)), bucket.iter().last());
|
||||
assert!(bucket.pending().is_none());
|
||||
assert_eq!(Some(K_VALUE.get() - (i + 1)), bucket.first_connected_pos);
|
||||
}
|
||||
|
||||
assert!(bucket.pending().is_none());
|
||||
assert_eq!(K_VALUE.get(), bucket.num_entries());
|
||||
|
||||
// Trying to insert another connected node fails.
|
||||
let key = Key::new(PeerId::random());
|
||||
let node = Node { key, value: () };
|
||||
match bucket.insert(node, NodeStatus::Connected) {
|
||||
InsertResult::Full => {},
|
||||
x => panic!("{:?}", x)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn full_bucket_discard_pending() {
|
||||
let mut bucket = KBucket::<Key<PeerId>, ()>::new(Duration::from_secs(1));
|
||||
fill_bucket(&mut bucket, NodeStatus::Disconnected);
|
||||
let (first, _) = bucket.iter().next().unwrap();
|
||||
let first_disconnected = first.clone();
|
||||
|
||||
// Add a connected pending node.
|
||||
let key = Key::new(PeerId::random());
|
||||
let node = Node { key: key.clone(), value: () };
|
||||
if let InsertResult::Pending { disconnected } = bucket.insert(node, NodeStatus::Connected) {
|
||||
assert_eq!(&disconnected, &first_disconnected.key);
|
||||
} else {
|
||||
panic!()
|
||||
}
|
||||
assert!(bucket.pending().is_some());
|
||||
|
||||
// Update the status of the first disconnected node to be connected.
|
||||
bucket.update(&first_disconnected.key, NodeStatus::Connected);
|
||||
|
||||
// The pending node has been discarded.
|
||||
assert!(bucket.pending().is_none());
|
||||
assert!(bucket.iter().all(|(n,_)| &n.key != &key));
|
||||
|
||||
// The initially disconnected node is now the most-recently connected.
|
||||
assert_eq!(Some((&first_disconnected, NodeStatus::Connected)), bucket.iter().last());
|
||||
assert_eq!(bucket.position(&first_disconnected.key).map(|p| p.0), bucket.first_connected_pos);
|
||||
assert_eq!(1, bucket.num_connected());
|
||||
assert_eq!(K_VALUE.get() - 1, bucket.num_disconnected());
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn bucket_update() {
|
||||
fn prop(mut bucket: KBucket<Key<PeerId>, ()>, pos: Position, status: NodeStatus) -> bool {
|
||||
let num_nodes = bucket.num_entries();
|
||||
|
||||
// Capture position and key of the random node to update.
|
||||
let pos = pos.0 % num_nodes;
|
||||
let key = bucket.nodes[pos].key.clone();
|
||||
|
||||
// Record the (ordered) list of status of all nodes in the bucket.
|
||||
let mut expected = bucket.iter().map(|(n,s)| (n.key.clone(), s)).collect::<Vec<_>>();
|
||||
|
||||
// Update the node in the bucket.
|
||||
bucket.update(&key, status);
|
||||
|
||||
// Check that the bucket now contains the node with the new status,
|
||||
// preserving the status and relative order of all other nodes.
|
||||
let expected_pos = match status {
|
||||
NodeStatus::Connected => num_nodes - 1,
|
||||
NodeStatus::Disconnected => bucket.first_connected_pos.unwrap_or(num_nodes) - 1
|
||||
};
|
||||
expected.remove(pos);
|
||||
expected.insert(expected_pos, (key.clone(), status));
|
||||
let actual = bucket.iter().map(|(n,s)| (n.key.clone(), s)).collect::<Vec<_>>();
|
||||
expected == actual
|
||||
}
|
||||
|
||||
quickcheck(prop as fn(_,_,_) -> _);
|
||||
}
|
||||
}
|
||||
// mod tests {
|
||||
// use libp2p_core::PeerId;
|
||||
// use rand::Rng;
|
||||
// use std::collections::VecDeque;
|
||||
// use super::*;
|
||||
// use quickcheck::*;
|
||||
//
|
||||
// impl Arbitrary for KBucket<Key<PeerId>, ()> {
|
||||
// fn arbitrary<G: Gen>(g: &mut G) -> KBucket<Key<PeerId>, ()> {
|
||||
// let timeout = Duration::from_secs(g.gen_range(1, g.size() as u64));
|
||||
// let mut bucket = KBucket::<Key<PeerId>, ()>::new(timeout);
|
||||
// let num_nodes = g.gen_range(1, K_VALUE.get() + 1);
|
||||
// for _ in 0 .. num_nodes {
|
||||
// let key = Key::new(PeerId::random());
|
||||
// let node = Node { key: key.clone(), value: () };
|
||||
// let status = NodeStatus::arbitrary(g);
|
||||
// match bucket.insert(node, status) {
|
||||
// InsertResult::Inserted => {}
|
||||
// _ => panic!()
|
||||
// }
|
||||
// }
|
||||
// bucket
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// impl Arbitrary for NodeStatus {
|
||||
// fn arbitrary<G: Gen>(g: &mut G) -> NodeStatus {
|
||||
// if g.gen() {
|
||||
// NodeStatus::Connected
|
||||
// } else {
|
||||
// NodeStatus::Disconnected
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// impl Arbitrary for Position {
|
||||
// fn arbitrary<G: Gen>(g: &mut G) -> Position {
|
||||
// Position(g.gen_range(0, K_VALUE.get()))
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // Fill a bucket with random nodes with the given status.
|
||||
// fn fill_bucket(bucket: &mut KBucket<Key<PeerId>, ()>, status: NodeStatus) {
|
||||
// let num_entries_start = bucket.num_entries();
|
||||
// for i in 0 .. K_VALUE.get() - num_entries_start {
|
||||
// let key = Key::new(PeerId::random());
|
||||
// let node = Node { key, value: () };
|
||||
// assert_eq!(InsertResult::Inserted, bucket.insert(node, status));
|
||||
// assert_eq!(bucket.num_entries(), num_entries_start + i + 1);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// #[test]
|
||||
// fn ordering() {
|
||||
// fn prop(status: Vec<NodeStatus>) -> bool {
|
||||
// let mut bucket = KBucket::<Key<PeerId>, ()>::new(Duration::from_secs(1));
|
||||
//
|
||||
// // The expected lists of connected and disconnected nodes.
|
||||
// let mut connected = VecDeque::new();
|
||||
// let mut disconnected = VecDeque::new();
|
||||
//
|
||||
// // Fill the bucket, thereby populating the expected lists in insertion order.
|
||||
// for status in status {
|
||||
// let key = Key::new(PeerId::random());
|
||||
// let node = Node { key: key.clone(), value: () };
|
||||
// let full = bucket.num_entries() == K_VALUE.get();
|
||||
// match bucket.insert(node, status) {
|
||||
// InsertResult::Inserted => {
|
||||
// let vec = match status {
|
||||
// NodeStatus::Connected => &mut connected,
|
||||
// NodeStatus::Disconnected => &mut disconnected
|
||||
// };
|
||||
// if full {
|
||||
// vec.pop_front();
|
||||
// }
|
||||
// vec.push_back((status, key.clone()));
|
||||
// }
|
||||
// _ => {}
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // Get all nodes from the bucket, together with their status.
|
||||
// let mut nodes = bucket.iter()
|
||||
// .map(|(n, s)| (s, n.key.clone()))
|
||||
// .collect::<Vec<_>>();
|
||||
//
|
||||
// // Split the list of nodes at the first connected node.
|
||||
// let first_connected_pos = nodes.iter().position(|(s,_)| *s == NodeStatus::Connected);
|
||||
// assert_eq!(bucket.first_connected_pos, first_connected_pos);
|
||||
// let tail = first_connected_pos.map_or(Vec::new(), |p| nodes.split_off(p));
|
||||
//
|
||||
// // All nodes before the first connected node must be disconnected and
|
||||
// // in insertion order. Similarly, all remaining nodes must be connected
|
||||
// // and in insertion order.
|
||||
// nodes == Vec::from(disconnected)
|
||||
// &&
|
||||
// tail == Vec::from(connected)
|
||||
// }
|
||||
//
|
||||
// quickcheck(prop as fn(_) -> _);
|
||||
// }
|
||||
//
|
||||
// #[test]
|
||||
// fn full_bucket() {
|
||||
// let mut bucket = KBucket::<Key<PeerId>, ()>::new(Duration::from_secs(1));
|
||||
//
|
||||
// // Fill the bucket with disconnected nodes.
|
||||
// fill_bucket(&mut bucket, NodeStatus::Disconnected);
|
||||
//
|
||||
// // Trying to insert another disconnected node fails.
|
||||
// let key = Key::new(PeerId::random());
|
||||
// let node = Node { key, value: () };
|
||||
// match bucket.insert(node, NodeStatus::Disconnected) {
|
||||
// InsertResult::Full => {},
|
||||
// x => panic!("{:?}", x)
|
||||
// }
|
||||
//
|
||||
// // One-by-one fill the bucket with connected nodes, replacing the disconnected ones.
|
||||
// for i in 0 .. K_VALUE.get() {
|
||||
// let (first, first_status) = bucket.iter().next().unwrap();
|
||||
// let first_disconnected = first.clone();
|
||||
// assert_eq!(first_status, NodeStatus::Disconnected);
|
||||
//
|
||||
// // Add a connected node, which is expected to be pending, scheduled to
|
||||
// // replace the first (i.e. least-recently connected) node.
|
||||
// let key = Key::new(PeerId::random());
|
||||
// let node = Node { key: key.clone(), value: () };
|
||||
// match bucket.insert(node.clone(), NodeStatus::Connected) {
|
||||
// InsertResult::Pending { disconnected } =>
|
||||
// assert_eq!(disconnected, first_disconnected.key),
|
||||
// x => panic!("{:?}", x)
|
||||
// }
|
||||
//
|
||||
// // Trying to insert another connected node fails.
|
||||
// match bucket.insert(node.clone(), NodeStatus::Connected) {
|
||||
// InsertResult::Full => {},
|
||||
// x => panic!("{:?}", x)
|
||||
// }
|
||||
//
|
||||
// assert!(bucket.pending().is_some());
|
||||
//
|
||||
// // Apply the pending node.
|
||||
// let pending = bucket.pending_mut().expect("No pending node.");
|
||||
// pending.set_ready_at(Instant::now() - Duration::from_secs(1));
|
||||
// let result = bucket.apply_pending();
|
||||
// assert_eq!(result, Some(AppliedPending {
|
||||
// inserted: node.clone(),
|
||||
// evicted: Some(first_disconnected)
|
||||
// }));
|
||||
// assert_eq!(Some((&node, NodeStatus::Connected)), bucket.iter().last());
|
||||
// assert!(bucket.pending().is_none());
|
||||
// assert_eq!(Some(K_VALUE.get() - (i + 1)), bucket.first_connected_pos);
|
||||
// }
|
||||
//
|
||||
// assert!(bucket.pending().is_none());
|
||||
// assert_eq!(K_VALUE.get(), bucket.num_entries());
|
||||
//
|
||||
// // Trying to insert another connected node fails.
|
||||
// let key = Key::new(PeerId::random());
|
||||
// let node = Node { key, value: () };
|
||||
// match bucket.insert(node, NodeStatus::Connected) {
|
||||
// InsertResult::Full => {},
|
||||
// x => panic!("{:?}", x)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// #[test]
|
||||
// fn full_bucket_discard_pending() {
|
||||
// let mut bucket = KBucket::<Key<PeerId>, ()>::new(Duration::from_secs(1));
|
||||
// fill_bucket(&mut bucket, NodeStatus::Disconnected);
|
||||
// let (first, _) = bucket.iter().next().unwrap();
|
||||
// let first_disconnected = first.clone();
|
||||
//
|
||||
// // Add a connected pending node.
|
||||
// let key = Key::new(PeerId::random());
|
||||
// let node = Node { key: key.clone(), value: () };
|
||||
// if let InsertResult::Pending { disconnected } = bucket.insert(node, NodeStatus::Connected) {
|
||||
// assert_eq!(&disconnected, &first_disconnected.key);
|
||||
// } else {
|
||||
// panic!()
|
||||
// }
|
||||
// assert!(bucket.pending().is_some());
|
||||
//
|
||||
// // Update the status of the first disconnected node to be connected.
|
||||
// bucket.update(&first_disconnected.key, NodeStatus::Connected);
|
||||
//
|
||||
// // The pending node has been discarded.
|
||||
// assert!(bucket.pending().is_none());
|
||||
// assert!(bucket.iter().all(|(n,_)| &n.key != &key));
|
||||
//
|
||||
// // The initially disconnected node is now the most-recently connected.
|
||||
// assert_eq!(Some((&first_disconnected, NodeStatus::Connected)), bucket.iter().last());
|
||||
// assert_eq!(bucket.position(&first_disconnected.key).map(|p| p.0), bucket.first_connected_pos);
|
||||
// assert_eq!(1, bucket.num_connected());
|
||||
// assert_eq!(K_VALUE.get() - 1, bucket.num_disconnected());
|
||||
// }
|
||||
//
|
||||
//
|
||||
// #[test]
|
||||
// fn bucket_update() {
|
||||
// fn prop(mut bucket: KBucket<Key<PeerId>, ()>, pos: Position, status: NodeStatus) -> bool {
|
||||
// let num_nodes = bucket.num_entries();
|
||||
//
|
||||
// // Capture position and key of the random node to update.
|
||||
// let pos = pos.0 % num_nodes;
|
||||
// let key = bucket.nodes[pos].key.clone();
|
||||
//
|
||||
// // Record the (ordered) list of status of all nodes in the bucket.
|
||||
// let mut expected = bucket.iter().map(|(n,s)| (n.key.clone(), s)).collect::<Vec<_>>();
|
||||
//
|
||||
// // Update the node in the bucket.
|
||||
// bucket.update(&key, status);
|
||||
//
|
||||
// // Check that the bucket now contains the node with the new status,
|
||||
// // preserving the status and relative order of all other nodes.
|
||||
// let expected_pos = match status {
|
||||
// NodeStatus::Connected => num_nodes - 1,
|
||||
// NodeStatus::Disconnected => bucket.first_connected_pos.unwrap_or(num_nodes) - 1
|
||||
// };
|
||||
// expected.remove(pos);
|
||||
// expected.insert(expected_pos, (key.clone(), status));
|
||||
// let actual = bucket.iter().map(|(n,s)| (n.key.clone(), s)).collect::<Vec<_>>();
|
||||
// expected == actual
|
||||
// }
|
||||
//
|
||||
// quickcheck(prop as fn(_,_,_) -> _);
|
||||
// }
|
||||
// }
|
||||
|
Loading…
x
Reference in New Issue
Block a user