Add testing for blocked bucket cleanup
This commit is contained in:
parent
3c88f4471b
commit
a62b537aa6
|
@ -279,118 +279,23 @@ impl BridgeTable {
|
||||||
self.buckets.len()
|
self.buckets.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get today's (real or simulated) date
|
// /// Get today's (real or simulated) date
|
||||||
fn today(&self) -> u32 {
|
// fn today(&self) -> u32 {
|
||||||
// We will not encounter negative Julian dates (~6700 years ago)
|
// // We will not encounter negative Julian dates (~6700 years ago)
|
||||||
// or ones larger than 32 bits
|
// // or ones larger than 32 bits
|
||||||
(time::OffsetDateTime::now_utc().date())
|
// (time::OffsetDateTime::now_utc().date())
|
||||||
.to_julian_day()
|
// .to_julian_day()
|
||||||
.try_into()
|
// .try_into()
|
||||||
.unwrap()
|
// .unwrap()
|
||||||
}
|
// }
|
||||||
|
|
||||||
// This function looks for and removes buckets so their indexes can be reused
|
|
||||||
// This should include buckets that have been blocked for a sufficiently long period
|
|
||||||
// that we no longer want to allow migration to, or else, open-entry buckets that
|
|
||||||
// have been unblocked long enough to become trusted and who's users' credentials
|
|
||||||
// would have expired (after 511 days)
|
|
||||||
|
|
||||||
fn clean_up_expired_buckets(&mut self) {
|
|
||||||
// Consider including migration tables and check age of from buckets
|
|
||||||
// If an open-invitation bucket is more than 511 days old, it should be recycled
|
|
||||||
// If a blocked bridge is more than 511 (the maximum validity of a credential in days) days old, it should also be recycled
|
|
||||||
|
|
||||||
// First check if there are any blocked indexes that are old enough to be replaced
|
|
||||||
if !self.blocked_keys.is_empty()
|
|
||||||
&& self.blocked_keys.iter().any(|&x| x.1 > self.today() + 511)
|
|
||||||
//Perhaps 511 should be changed to an earlier time
|
|
||||||
{
|
|
||||||
let blocked_keys_clone = self.blocked_keys.clone();
|
|
||||||
// If so, separate them from the fresh blockages
|
|
||||||
let (expired, fresh): (Vec<(u32, u32)>, Vec<(u32, u32)>) = blocked_keys_clone
|
|
||||||
.into_iter()
|
|
||||||
.partition(|&x| x.1 > self.today() + 511);
|
|
||||||
for item in expired {
|
|
||||||
let new_item = item.0;
|
|
||||||
// check each single bridge line and ensure none are still marked as reachable.
|
|
||||||
// if any are still reachable, remove from reachable bridges.
|
|
||||||
// When syncing resources, we will likely have to reallocate this bridge but if it hasn't already been
|
|
||||||
// blocked, this might be fine?
|
|
||||||
let bridgelines = self.buckets.get(&new_item).unwrap();
|
|
||||||
for bridgeline in bridgelines {
|
|
||||||
// If the bridge hasn't been set to default, assume it's still reachable
|
|
||||||
if bridgeline.port > 0 {
|
|
||||||
// Move to unallocated bridges
|
|
||||||
self.unallocated_bridges.push(*bridgeline);
|
|
||||||
// Check if it's still in the reachable bridges. It should be if we've gotten this far.
|
|
||||||
if let Some(_reachable_indexes_for_bridgeline) = self.reachable.get(bridgeline) {
|
|
||||||
// and remove it until it's reallocated
|
|
||||||
self.reachable.remove(bridgeline);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Then remove the bucket and keys at the specified index
|
|
||||||
self.buckets.remove(&new_item);
|
|
||||||
self.keys.remove(&new_item);
|
|
||||||
//and add them to the recyclable keys
|
|
||||||
self.recycleable_keys.push(new_item);
|
|
||||||
}
|
|
||||||
// Finally, update the blocked_keys vector to only include the fresh keys
|
|
||||||
self.blocked_keys = fresh
|
|
||||||
}
|
|
||||||
// Next do the same for open_invitations buckets
|
|
||||||
// First check if there are any open invitation indexes that are old enough to be replaced
|
|
||||||
if !self.open_inv_keys.is_empty()
|
|
||||||
&& self.open_inv_keys.iter().any(|&x| x.1 > self.today() + 511)
|
|
||||||
//Perhaps 511 should be changed to an earlier time
|
|
||||||
{
|
|
||||||
let open_inv_keys_clone = self.open_inv_keys.clone();
|
|
||||||
// If so, separate them from the fresh open invitation indexes
|
|
||||||
let (expired, fresh): (Vec<(u32, u32)>, Vec<(u32, u32)>) = open_inv_keys_clone
|
|
||||||
.into_iter()
|
|
||||||
.partition(|&x| x.1 > self.today() + 511);
|
|
||||||
for item in expired {
|
|
||||||
let new_item = item.0;
|
|
||||||
self.buckets.remove(&new_item);
|
|
||||||
self.keys.remove(&new_item);
|
|
||||||
//and add them to the recyclable keys
|
|
||||||
self.recycleable_keys.push(new_item);
|
|
||||||
}
|
|
||||||
// update the open_inv_keys vector to only include the fresh keys
|
|
||||||
self.open_inv_keys = fresh
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Since buckets are moved around in the bridge_table, finding a lookup key that
|
|
||||||
// does not overwrite existing bridges could become an issue. We keep a list
|
|
||||||
// of recycleable lookup keys from buckets that have been removed and prioritize
|
|
||||||
// this list before increasing the counter
|
|
||||||
fn find_next_available_key(&mut self) -> u32 {
|
|
||||||
self.clean_up_expired_buckets(); //This function probably should be moved to lib.rs to handle trustup and migration tables too
|
|
||||||
if self.recycleable_keys.is_empty() {
|
|
||||||
let mut test_index = 1;
|
|
||||||
let mut test_counter = self.counter.wrapping_add(test_index);
|
|
||||||
let mut i = 0;
|
|
||||||
while self.buckets.contains_key(&test_counter) && i < 5000 {
|
|
||||||
test_index += i;
|
|
||||||
test_counter = self.counter.wrapping_add(test_index);
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
self.counter = self.counter.wrapping_add(test_index);
|
|
||||||
self.counter
|
|
||||||
} else {
|
|
||||||
self.recycleable_keys.pop().unwrap()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Append a new bucket to the bridge table, returning its index
|
/// Append a new bucket to the bridge table, returning its index
|
||||||
pub fn new_bucket(&mut self, bucket: &[BridgeLine; MAX_BRIDGES_PER_BUCKET]) -> u32 {
|
pub fn new_bucket(&mut self, bucket: &[BridgeLine; MAX_BRIDGES_PER_BUCKET], index: u32) -> u32 {
|
||||||
// Pick a random key to encrypt this bucket
|
// Pick a random key to encrypt this bucket
|
||||||
let mut rng = rand::thread_rng();
|
let mut rng = rand::thread_rng();
|
||||||
let mut key: [u8; 16] = [0; 16];
|
let mut key: [u8; 16] = [0; 16];
|
||||||
rng.fill_bytes(&mut key);
|
rng.fill_bytes(&mut key);
|
||||||
// Increase the counter to identify the bucket, wrap value if beyond u32::MAX
|
// Increase the counter to identify the bucket, wrap value if beyond u32::MAX
|
||||||
let index = self.find_next_available_key();
|
|
||||||
//self.counter = self.counter.wrapping_add(1);
|
//self.counter = self.counter.wrapping_add(1);
|
||||||
self.keys.insert(index, key);
|
self.keys.insert(index, key);
|
||||||
self.buckets.insert(index, *bucket);
|
self.buckets.insert(index, *bucket);
|
||||||
|
@ -495,7 +400,8 @@ mod tests {
|
||||||
for _ in 0..20 {
|
for _ in 0..20 {
|
||||||
let bucket: [BridgeLine; 3] =
|
let bucket: [BridgeLine; 3] =
|
||||||
[BridgeLine::random(), Default::default(), Default::default()];
|
[BridgeLine::random(), Default::default(), Default::default()];
|
||||||
btable.new_bucket(&bucket);
|
btable.counter += 1;
|
||||||
|
btable.new_bucket(&bucket, btable.counter);
|
||||||
}
|
}
|
||||||
// And 20 more with three random bridges each
|
// And 20 more with three random bridges each
|
||||||
for _ in 0..20 {
|
for _ in 0..20 {
|
||||||
|
@ -504,7 +410,8 @@ mod tests {
|
||||||
BridgeLine::random(),
|
BridgeLine::random(),
|
||||||
BridgeLine::random(),
|
BridgeLine::random(),
|
||||||
];
|
];
|
||||||
btable.new_bucket(&bucket);
|
btable.counter += 1;
|
||||||
|
btable.new_bucket(&bucket, btable.counter);
|
||||||
}
|
}
|
||||||
let today: u32 = time::OffsetDateTime::now_utc()
|
let today: u32 = time::OffsetDateTime::now_utc()
|
||||||
.date()
|
.date()
|
||||||
|
@ -514,15 +421,15 @@ mod tests {
|
||||||
// Create the encrypted bridge table
|
// Create the encrypted bridge table
|
||||||
btable.encrypt_table(today, &reachability_priv);
|
btable.encrypt_table(today, &reachability_priv);
|
||||||
// Try to decrypt a 1-bridge bucket
|
// Try to decrypt a 1-bridge bucket
|
||||||
let key7 = btable.keys[&7u32];
|
let key7 = btable.keys.get(&7u32).unwrap();
|
||||||
let bucket7 = btable.decrypt_bucket_id(7, &key7)?;
|
let bucket7 = btable.decrypt_bucket_id(7, &key7)?;
|
||||||
println!("bucket 7 = {:?}", bucket7);
|
println!("bucket 7 = {:?}", bucket7);
|
||||||
// Try to decrypt a 3-bridge bucket
|
// Try to decrypt a 3-bridge bucket
|
||||||
let key24 = btable.keys[&24u32];
|
let key24 = btable.keys.get(&24u32).unwrap();
|
||||||
let bucket24 = btable.decrypt_bucket_id(24, &key24)?;
|
let bucket24 = btable.decrypt_bucket_id(24, &key24)?;
|
||||||
println!("bucket 24 = {:?}", bucket24);
|
println!("bucket 24 = {:?}", bucket24);
|
||||||
// Try to decrypt a bucket with the wrong key
|
// Try to decrypt a bucket with the wrong key
|
||||||
let key12 = btable.keys[&12u32];
|
let key12 = btable.keys.get(&12u32).unwrap();
|
||||||
let res = btable.decrypt_bucket_id(15, &key12).unwrap_err();
|
let res = btable.decrypt_bucket_id(15, &key12).unwrap_err();
|
||||||
println!("bucket key mismatch = {:?}", res);
|
println!("bucket key mismatch = {:?}", res);
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -300,11 +300,13 @@ impl BridgeAuth {
|
||||||
bridges: [BridgeLine; MAX_BRIDGES_PER_BUCKET],
|
bridges: [BridgeLine; MAX_BRIDGES_PER_BUCKET],
|
||||||
bdb: &mut BridgeDb,
|
bdb: &mut BridgeDb,
|
||||||
) {
|
) {
|
||||||
let bnum = self.bridge_table.new_bucket(&bridges);
|
let index = self.find_next_available_key();
|
||||||
|
let bnum = self.bridge_table.new_bucket(&bridges, index);
|
||||||
let mut single = [BridgeLine::default(); MAX_BRIDGES_PER_BUCKET];
|
let mut single = [BridgeLine::default(); MAX_BRIDGES_PER_BUCKET];
|
||||||
for b in bridges.iter() {
|
for b in bridges.iter() {
|
||||||
|
let index = self.find_next_available_key();
|
||||||
single[0] = *b;
|
single[0] = *b;
|
||||||
let snum = self.bridge_table.new_bucket(&single);
|
let snum = self.bridge_table.new_bucket(&single, index);
|
||||||
self.bridge_table.open_inv_keys.push((snum, self.today()));
|
self.bridge_table.open_inv_keys.push((snum, self.today()));
|
||||||
bdb.insert_openinv(snum);
|
bdb.insert_openinv(snum);
|
||||||
self.trustup_migration_table.table.insert(snum, bnum);
|
self.trustup_migration_table.table.insert(snum, bnum);
|
||||||
|
@ -313,7 +315,8 @@ impl BridgeAuth {
|
||||||
|
|
||||||
/// Insert a hot spare bucket of bridges
|
/// Insert a hot spare bucket of bridges
|
||||||
pub fn add_spare_bucket(&mut self, bucket: [BridgeLine; MAX_BRIDGES_PER_BUCKET]) {
|
pub fn add_spare_bucket(&mut self, bucket: [BridgeLine; MAX_BRIDGES_PER_BUCKET]) {
|
||||||
let bnum = self.bridge_table.new_bucket(&bucket);
|
let index = self.find_next_available_key();
|
||||||
|
let bnum = self.bridge_table.new_bucket(&bucket, index);
|
||||||
self.bridge_table.spares.insert(bnum);
|
self.bridge_table.spares.insert(bnum);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -600,6 +603,117 @@ impl BridgeAuth {
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Since buckets are moved around in the bridge_table, finding a lookup key that
|
||||||
|
// does not overwrite existing bridges could become an issue. We keep a list
|
||||||
|
// of recycleable lookup keys from buckets that have been removed and prioritize
|
||||||
|
// this list before increasing the counter
|
||||||
|
fn find_next_available_key(&mut self) -> u32 {
|
||||||
|
self.clean_up_expired_buckets(); //This function probably should be moved to lib.rs to handle trustup and migration tables too
|
||||||
|
if self.bridge_table.recycleable_keys.is_empty() {
|
||||||
|
let mut test_index = 1;
|
||||||
|
let mut test_counter = self.bridge_table.counter.wrapping_add(test_index);
|
||||||
|
let mut i = 0;
|
||||||
|
while self.bridge_table.buckets.contains_key(&test_counter) && i < 5000 {
|
||||||
|
test_index += i;
|
||||||
|
test_counter = self.bridge_table.counter.wrapping_add(test_index);
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
self.bridge_table.counter = self.bridge_table.counter.wrapping_add(test_index);
|
||||||
|
self.bridge_table.counter
|
||||||
|
} else {
|
||||||
|
self.bridge_table.recycleable_keys.pop().unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function looks for and removes buckets so their indexes can be reused
|
||||||
|
// This should include buckets that have been blocked for a sufficiently long period
|
||||||
|
// that we no longer want to allow migration to, or else, open-entry buckets that
|
||||||
|
// have been unblocked long enough to become trusted and who's users' credentials
|
||||||
|
// would have expired (after 511 days)
|
||||||
|
pub fn clean_up_expired_buckets(&mut self) {
|
||||||
|
// Consider including migration tables and check age of from buckets
|
||||||
|
// If an open-invitation bucket is more than 511 days old, it should be recycled
|
||||||
|
// If a blocked bridge is more than 511 (the maximum validity of a credential in days) days old, it should also be recycled
|
||||||
|
|
||||||
|
// First check if there are any blocked indexes that are old enough to be replaced
|
||||||
|
self.clean_up_blocked();
|
||||||
|
// Next do the same for open_invitations buckets
|
||||||
|
// self.clean_up_open_entry();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clean_up_blocked(&mut self) {
|
||||||
|
if !self.bridge_table.blocked_keys.is_empty()
|
||||||
|
&& self
|
||||||
|
.bridge_table
|
||||||
|
.blocked_keys
|
||||||
|
.iter()
|
||||||
|
.any(|&x| x.1 + 511 < self.today())
|
||||||
|
//Perhaps 511 should be changed to an earlier time
|
||||||
|
{
|
||||||
|
let blocked_keys_clone = self.bridge_table.blocked_keys.clone();
|
||||||
|
// If so, separate them from the fresh blockages
|
||||||
|
let (expired, fresh): (Vec<(u32, u32)>, Vec<(u32, u32)>) = blocked_keys_clone
|
||||||
|
.into_iter()
|
||||||
|
.partition(|&x| x.1 + 511 < self.today());
|
||||||
|
for item in expired {
|
||||||
|
let new_item = item.0;
|
||||||
|
// check each single bridge line and ensure none are still marked as reachable.
|
||||||
|
// if any are still reachable, remove from reachable bridges.
|
||||||
|
// When syncing resources, we will likely have to reallocate this bridge but if it hasn't already been
|
||||||
|
// blocked, this might be fine?
|
||||||
|
let bridgelines = self.bridge_table.buckets.get(&new_item).unwrap();
|
||||||
|
for bridgeline in bridgelines {
|
||||||
|
// If the bridge hasn't been set to default, assume it's still reachable
|
||||||
|
if bridgeline.port > 0 {
|
||||||
|
// Move to unallocated bridges
|
||||||
|
self.bridge_table.unallocated_bridges.push(*bridgeline);
|
||||||
|
// Check if it's still in the reachable bridges. It should be if we've gotten this far.
|
||||||
|
if let Some(_reachable_indexes_for_bridgeline) =
|
||||||
|
self.bridge_table.reachable.get(bridgeline)
|
||||||
|
{
|
||||||
|
// and remove it until it's reallocated
|
||||||
|
self.bridge_table.reachable.remove(bridgeline);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Then remove the bucket and keys at the specified index
|
||||||
|
self.bridge_table.buckets.remove(&new_item);
|
||||||
|
self.bridge_table.keys.remove(&new_item);
|
||||||
|
//and add them to the recyclable keys
|
||||||
|
self.bridge_table.recycleable_keys.push(new_item);
|
||||||
|
}
|
||||||
|
// Finally, update the blocked_keys vector to only include the fresh keys
|
||||||
|
self.bridge_table.blocked_keys = fresh
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clean_up_open_entry(&mut self) {
|
||||||
|
// First check if there are any open invitation indexes that are old enough to be replaced
|
||||||
|
if !self.bridge_table.open_inv_keys.is_empty()
|
||||||
|
&& self
|
||||||
|
.bridge_table
|
||||||
|
.open_inv_keys
|
||||||
|
.iter()
|
||||||
|
.any(|&x| x.1 + 511 < self.today())
|
||||||
|
//Perhaps 511 should be changed to an earlier time
|
||||||
|
{
|
||||||
|
let open_inv_keys_clone = self.bridge_table.open_inv_keys.clone();
|
||||||
|
// If so, separate them from the fresh open invitation indexes
|
||||||
|
let (expired, fresh): (Vec<(u32, u32)>, Vec<(u32, u32)>) = open_inv_keys_clone
|
||||||
|
.into_iter()
|
||||||
|
.partition(|&x| x.1 + 511 < self.today());
|
||||||
|
for item in expired {
|
||||||
|
let new_item = item.0;
|
||||||
|
self.bridge_table.buckets.remove(&new_item);
|
||||||
|
self.bridge_table.keys.remove(&new_item);
|
||||||
|
//and add them to the recyclable keys
|
||||||
|
self.bridge_table.recycleable_keys.push(new_item);
|
||||||
|
}
|
||||||
|
// update the open_inv_keys vector to only include the fresh keys
|
||||||
|
self.bridge_table.open_inv_keys = fresh
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
/// For testing only: manually advance the day by 1 day
|
/// For testing only: manually advance the day by 1 day
|
||||||
pub fn advance_day(&mut self) {
|
pub fn advance_day(&mut self) {
|
||||||
|
|
|
@ -4,7 +4,9 @@ BridgeLine::random() or private fields */
|
||||||
use super::bridge_table::{BridgeLine, BRIDGE_BYTES};
|
use super::bridge_table::{BridgeLine, BRIDGE_BYTES};
|
||||||
use super::proto::*;
|
use super::proto::*;
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use chrono::{DateTime, NaiveTime, Timelike, Utc};
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
|
use std::thread;
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
struct PerfStat {
|
struct PerfStat {
|
||||||
|
@ -173,6 +175,7 @@ impl TestHarness {
|
||||||
let bucket =
|
let bucket =
|
||||||
bridge_table::BridgeTable::decrypt_bucket(id, &key, encbuckets.get(&id).unwrap())
|
bridge_table::BridgeTable::decrypt_bucket(id, &key, encbuckets.get(&id).unwrap())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let reachcred = bucket.1.unwrap();
|
let reachcred = bucket.1.unwrap();
|
||||||
|
|
||||||
// Use the Bucket Reachability credential to advance to the next
|
// Use the Bucket Reachability credential to advance to the next
|
||||||
|
@ -591,6 +594,143 @@ fn test_redeem_invite() {
|
||||||
println!("bob_cred = {:?}", bob_cred);
|
println!("bob_cred = {:?}", bob_cred);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_clean_up_blocked() {
|
||||||
|
let mut th = TestHarness::new_buckets(50, 50);
|
||||||
|
let mut credentials: Vec<cred::Lox> = Vec::new();
|
||||||
|
// Users
|
||||||
|
for _ in 0..100 {
|
||||||
|
let h: NaiveTime = DateTime::time(&Utc::now());
|
||||||
|
if h.hour() == 23 && h.minute() == 59 {
|
||||||
|
println!("Wait for UTC 00:00");
|
||||||
|
thread::sleep(Duration::new(60, 0));
|
||||||
|
println!("Ready to work again");
|
||||||
|
}
|
||||||
|
let cred = th.open_invite().1 .0;
|
||||||
|
th.advance_days(30);
|
||||||
|
let (_, migcred) = th.trust_promotion(&cred);
|
||||||
|
let (_, cred1) = th.level0_migration(&cred, &migcred);
|
||||||
|
th.advance_days(14);
|
||||||
|
let (_, cred2) = th.level_up(&cred1);
|
||||||
|
let (_, (cred2a, invite)) = th.issue_invite(&cred2);
|
||||||
|
let (_, bob_cred) = th.redeem_invite(&invite);
|
||||||
|
th.advance_days(28);
|
||||||
|
let (_, _) = th.level_up(&bob_cred);
|
||||||
|
let (_, cred3) = th.level_up(&cred2a);
|
||||||
|
credentials.push(cred3);
|
||||||
|
}
|
||||||
|
// Block 25% == 25 bridges
|
||||||
|
let blocked = block_bridges(&mut th, 25, credentials);
|
||||||
|
println!("\n**AFTER 25% BLOCKING EVENT**\n");
|
||||||
|
assert!(
|
||||||
|
blocked == th.ba.bridge_table.blocked_keys.len(),
|
||||||
|
"Blocked keys does not equal the number of blocked buckets"
|
||||||
|
);
|
||||||
|
assert!(th.ba.bridge_table.recycleable_keys.is_empty(), "");
|
||||||
|
// Each open invitation bucket creates 4 buckets -> 50*4 = 200 + 50 hotspare buckets = 250 total
|
||||||
|
assert!(
|
||||||
|
th.ba.bridge_table.counter == 250,
|
||||||
|
"Total number of buckets should be 250"
|
||||||
|
);
|
||||||
|
// Advance beyond the time that blocked buckets expire
|
||||||
|
th.advance_days(512);
|
||||||
|
th.ba.clean_up_blocked();
|
||||||
|
assert!(
|
||||||
|
th.ba.bridge_table.blocked_keys.is_empty(),
|
||||||
|
"Blocked keys should be empty after cleanup"
|
||||||
|
);
|
||||||
|
assert!(th.ba.bridge_table.recycleable_keys.len() == blocked, "The number of recycleable keys should be equal to the number of previously blocked buckets");
|
||||||
|
// Each open invitation bucket creates 4 buckets -> 50*4 = 200 + 50 hotspare buckets = 250 total
|
||||||
|
assert!(
|
||||||
|
th.ba.bridge_table.counter == 250,
|
||||||
|
"Total number of buckets should be 250"
|
||||||
|
);
|
||||||
|
for _ in 0..10 {
|
||||||
|
let bucket = [
|
||||||
|
BridgeLine::random(),
|
||||||
|
BridgeLine::random(),
|
||||||
|
BridgeLine::random(),
|
||||||
|
];
|
||||||
|
// Add new bridges to trigger bucket cleanup
|
||||||
|
th.ba.add_openinv_bridges(bucket, &mut th.bdb);
|
||||||
|
}
|
||||||
|
|
||||||
|
println!(
|
||||||
|
"Size of recyclable keys: {:?}",
|
||||||
|
th.ba.bridge_table.recycleable_keys.len()
|
||||||
|
);
|
||||||
|
println!("Counter: {:?}", th.ba.bridge_table.counter);
|
||||||
|
println!("\n**AFTER NEW BUCKETS ADDED**\n");
|
||||||
|
assert!(
|
||||||
|
th.ba.bridge_table.blocked_keys.is_empty(),
|
||||||
|
"After adding new buckets, blocked keys should be empty"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
th.ba.bridge_table.recycleable_keys.is_empty(),
|
||||||
|
"After adding new buckets, recycleable keys should be empty"
|
||||||
|
);
|
||||||
|
// Because of open-entry buckets added and open-entry cleanup, the counter increases to 278
|
||||||
|
println!("Counter: {:?}", th.ba.bridge_table.counter);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_clean_up_open_entry() {}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn find_next_available_key() {}
|
||||||
|
|
||||||
|
/// Blocks a percentage of the bridges for the passed Test Harness
|
||||||
|
/// excluding the hot spare buckets as they will not have been handed out.
|
||||||
|
/// The logic assumes hot spare buckets are appended to the end of the bridge_table
|
||||||
|
/// bucket list.
|
||||||
|
|
||||||
|
fn block_bridges(th: &mut TestHarness, percentage: usize, credentials: Vec<cred::Lox>) -> usize {
|
||||||
|
let blockable_num = th.ba.bridge_table.buckets.len()
|
||||||
|
- th.ba.bridge_table.spares.len()
|
||||||
|
- th.bdb.openinv_buckets.len();
|
||||||
|
let blockable_range = th.ba.bridge_table.buckets.len() - th.ba.bridge_table.spares.len();
|
||||||
|
let to_block: usize = blockable_num * percentage / 100;
|
||||||
|
let mut block_index: HashSet<usize> = HashSet::new();
|
||||||
|
let mut rng = rand::thread_rng();
|
||||||
|
|
||||||
|
while block_index.len() < to_block {
|
||||||
|
let rand_num = rng.gen_range(0, blockable_range);
|
||||||
|
if !th.bdb.openinv_buckets.contains(&(rand_num as u32)) {
|
||||||
|
block_index.insert(rand_num);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for index in block_index {
|
||||||
|
let ba_clone = th.ba.bridge_table.buckets.clone();
|
||||||
|
if let Some(bridgelines) = ba_clone.get(&u32::try_from(index).unwrap()) {
|
||||||
|
for bridgeline in bridgelines {
|
||||||
|
th.ba.bridge_unreachable(&bridgeline, &mut th.bdb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for cred in credentials {
|
||||||
|
let (id, key) = bridge_table::from_scalar(cred.bucket).unwrap();
|
||||||
|
let encbuckets = th.ba.enc_bridge_table();
|
||||||
|
let bucket =
|
||||||
|
bridge_table::BridgeTable::decrypt_bucket(id, &key, &encbuckets.get(&id).unwrap())
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let mut count = 0;
|
||||||
|
for bridge_line in &bucket.0 {
|
||||||
|
if th.ba.bridge_table.reachable.contains_key(bridge_line) {
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if count < 2 {
|
||||||
|
let (_perf_stat, migration) = th.check_blockage(&cred);
|
||||||
|
let (_block_perf_stat, _) = th.blockage_migration(&cred, &migration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
to_block
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_allocate_bridges() {
|
fn test_allocate_bridges() {
|
||||||
let mut th = TestHarness::new();
|
let mut th = TestHarness::new();
|
||||||
|
|
Loading…
Reference in New Issue