瀏覽代碼

Port stats test changes from lox-extensions branch

Vecna 2 月之前
父節點
當前提交
3a3ed3bee1
共有 2 個文件被更改,包括 53 次插入14 次删除
  1. 34 0
      crates/lox-extensions/src/lib.rs
  2. 19 14
      crates/lox-extensions/src/stats_tests.rs

+ 34 - 0
crates/lox-extensions/src/lib.rs

@@ -136,6 +136,24 @@ pub enum BridgeTableError {
     MissingBucket(u32),
 }
 
+// Note: We do not use these constants for stats testing. Instead, we
+// distribute a random open invitation bucket to each user, regardless
+// of the number of users. This addresses the following issues:
+// 1. Number of users exceeds MAX_DAILY_BRIDGES
+//      Workarounds for this issue include incrementing the date when
+//      we're about to exceed MAX_DAILY_BRIDGES or increasing
+//      MAX_DAILY_BRIDGES. However, see issue 3.
+// 2. Number of users exceeds OPENINV_K * number of bridges
+//      A workaround for this issue is to increase OPENINV_K. However,
+//      see issue 3.
+// 3. Non-uniform distribution of bridges to users
+//      The current implementation distributes number of users /
+//      OPENINV_K total open invitation buckets. This means that
+//      increasing the number of bridges does not change anything. The
+//      original Lox tests ran on a range of bridge pool sizes, so we
+//      also want to vary this parameter and spread the users across the
+//      increased number of bridges.
+
 /// Number of times a given invitation is ditributed
 pub const OPENINV_K: u32 = 10;
 /// TODO: Decide on maximum daily number of invitations to be distributed
@@ -278,6 +296,7 @@ impl BridgeDb {
             self.today = Utc::now();
             self.daily_bridges_distributed = 0;
         }
+        #[cfg(not(all(test, feature = "bridgeauth", feature = "test")))]
         if self.daily_bridges_distributed < MAX_DAILY_BRIDGES {
             if self.current_k < OPENINV_K && !self.distributed_buckets.is_empty() {
                 bucket_num = *self.distributed_buckets.last().unwrap();
@@ -303,6 +322,21 @@ impl BridgeDb {
         } else {
             Err(OpenInvitationError::ExceededMaxBridges)
         }
+
+        // During stats testing, just choose a random open-invitation bucket.
+        #[cfg(all(test, feature = "bridgeauth", feature = "test"))]
+        {
+            let openinv_vec: Vec<&u32> = self.openinv_buckets.iter().collect();
+            bucket_num = *openinv_vec[rng.gen_range(0..openinv_vec.len())];
+            // Mark bucket as distributed but don't remove it from openinv_buckets
+            self.mark_distributed(bucket_num);
+            self.daily_bridges_distributed += 1;
+            res[32..(32 + 4)].copy_from_slice(&bucket_num.to_le_bytes());
+            // Sign the first 36 bytes and serialize it
+            let sig = self.keypair.sign(&res[0..(32 + 4)]);
+            res[(32 + 4)..].copy_from_slice(&sig.to_bytes());
+            Ok(res)
+        }
     }
 
     /// Verify an open invitation. Returns the invitation id and the

+ 19 - 14
crates/lox-extensions/src/stats_tests.rs

@@ -4,7 +4,7 @@ use super::proto::*;
 use super::*;
 use base64::{engine::general_purpose, Engine};
 use chrono::{DateTime, NaiveTime, Timelike, Utc};
-use rand::{CryptoRng, RngCore};
+use rand::{seq::SliceRandom, CryptoRng, RngCore};
 use statistical::{mean, standard_deviation};
 use std::collections::HashSet;
 use std::thread;
@@ -1357,26 +1357,31 @@ fn stats_test_percent_blockage_migration_100() {
 
 /// 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>) {
     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<u32> = HashSet::new();
     let rng = &mut rand::thread_rng();
-
-    while block_index.len() < to_block {
-        let rand_num = rng.gen_range(0..blockable_range).try_into().unwrap();
-        if !th.bdb.openinv_buckets.contains(&rand_num) {
-            block_index.insert(rand_num);
-        }
-    }
-
-    for index in block_index {
+    // Buckets that are not hot spares or openinv buckets
+    let mut blockable_buckets: Vec<u32> = th
+        .ba
+        .bridge_table
+        .buckets
+        .keys()
+        .map(|&v| v)
+        .collect::<HashSet<u32>>()
+        .difference(&th.ba.bridge_table.spares)
+        .map(|&v| v)
+        .collect::<HashSet<u32>>()
+        .difference(&th.bdb.openinv_buckets)
+        .map(|&v| v)
+        .collect();
+    blockable_buckets.shuffle(rng);
+
+    for i in 0..to_block {
+        let index = blockable_buckets[i];
         let b0 = th.ba.bridge_table.buckets.get(&index).unwrap()[0];
         let b1 = th.ba.bridge_table.buckets.get(&index).unwrap()[1];
         let b2 = th.ba.bridge_table.buckets.get(&index).unwrap()[2];