From 65bb4f2b7d868316d2bc552c4e878b16f1a145a1 Mon Sep 17 00:00:00 2001 From: folex <0xdxdy@gmail.com> Date: Mon, 16 Mar 2020 16:54:53 +0300 Subject: [PATCH] Comment out tests for better IDE experience, add some comments --- protocols/kad/src/kbucket.rs | 372 +++++++++++----------- protocols/kad/src/kbucket/bucket.rs | 462 ++++++++++++++-------------- 2 files changed, 419 insertions(+), 415 deletions(-) diff --git a/protocols/kad/src/kbucket.rs b/protocols/kad/src/kbucket.rs index 0f985759..fb7bdbb1 100644 --- a/protocols/kad/src/kbucket.rs +++ b/protocols/kad/src/kbucket.rs @@ -475,189 +475,189 @@ where } #[cfg(test)] -mod tests { - use super::*; - use libp2p_core::PeerId; - use quickcheck::*; - use rand::Rng; - - type TestTable = KBucketsTable; - - impl Arbitrary for TestTable { - fn arbitrary(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::>(); - 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::>(); - // 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) -> 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; +// +// impl Arbitrary for TestTable { +// fn arbitrary(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::>(); +// 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::>(); +// // 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) -> 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(_,_) -> _) +// } +// } diff --git a/protocols/kad/src/kbucket/bucket.rs b/protocols/kad/src/kbucket/bucket.rs index 40601ba3..fe64e6ab 100644 --- a/protocols/kad/src/kbucket/bucket.rs +++ b/protocols/kad/src/kbucket/bucket.rs @@ -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, ()> { - fn arbitrary(g: &mut G) -> KBucket, ()> { - let timeout = Duration::from_secs(g.gen_range(1, g.size() as u64)); - let mut bucket = KBucket::, ()>::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: &mut G) -> NodeStatus { - if g.gen() { - NodeStatus::Connected - } else { - NodeStatus::Disconnected - } - } - } - - impl Arbitrary for Position { - fn arbitrary(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, ()>, 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) -> bool { - let mut bucket = KBucket::, ()>::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::>(); - - // 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::, ()>::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::, ()>::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, ()>, 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::>(); - - // 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::>(); - 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, ()> { +// fn arbitrary(g: &mut G) -> KBucket, ()> { +// let timeout = Duration::from_secs(g.gen_range(1, g.size() as u64)); +// let mut bucket = KBucket::, ()>::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: &mut G) -> NodeStatus { +// if g.gen() { +// NodeStatus::Connected +// } else { +// NodeStatus::Disconnected +// } +// } +// } +// +// impl Arbitrary for Position { +// fn arbitrary(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, ()>, 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) -> bool { +// let mut bucket = KBucket::, ()>::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::>(); +// +// // 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::, ()>::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::, ()>::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, ()>, 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::>(); +// +// // 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::>(); +// expected == actual +// } +// +// quickcheck(prop as fn(_,_,_) -> _); +// } +// }