Add basic tests for bridgetable sync with rdsys

This commit is contained in:
onyinyang 2024-03-12 15:21:23 -04:00
parent 5f34f49d17
commit 76bb8757f5
No known key found for this signature in database
GPG Key ID: 156A6435430C2036
4 changed files with 429 additions and 267 deletions

539
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,6 @@
{
"watched_blockages": [
"RU"
],
"percent_spares": 50
}

View File

@ -67,7 +67,10 @@ impl LoxServerContext {
for bridge in blocked_bridgelines {
let res = self.mark_blocked(bridge);
if res {
println!("BridgeLine {:?} successfully marked unreachable", bridge);
println!(
"BridgeLine {:?} successfully marked unreachable",
bridge.uid_fingerprint
);
self.metrics.blocked_bridges.inc();
} else {
println!(
@ -139,6 +142,7 @@ impl LoxServerContext {
// Next, handle the failing bridges. If resource last passed tests >= ACCEPTED_HOURS_OF_FAILURE ago,
// it should be replaced with a working resource and be removed from the bridgetable.
for bridge in failing {
println!("Got here with Resource {:?}", bridge.uid_fingerprint);
let res = self.replace_with_new(bridge);
if res == lox_library::ReplaceSuccess::Replaced {
println!(
@ -702,3 +706,142 @@ fn prepare_header(response: String) -> Response<Body> {
.insert("Access-Control-Allow-Origin", HeaderValue::from_static("*"));
resp
}
#[cfg(test)]
mod tests {
use crate::{fake_resource_state::TestResourceState, metrics::Metrics, BridgeConfig};
use lox_library::{bridge_table::MAX_BRIDGES_PER_BUCKET, BridgeAuth, BridgeDb};
use std::{
env, fs,
sync::{Arc, Mutex},
};
use super::LoxServerContext;
struct TestHarness {
context: LoxServerContext,
}
impl TestHarness {
fn new() -> Self {
let bridgedb = BridgeDb::new();
let mut lox_auth = BridgeAuth::new(bridgedb.pubkey);
lox_auth.enc_bridge_table();
let context = LoxServerContext {
db: Arc::new(Mutex::new(bridgedb)),
ba: Arc::new(Mutex::new(lox_auth)),
extra_bridges: Arc::new(Mutex::new(Vec::new())),
metrics: Metrics::default(),
};
Self { context }
}
fn new_with_bridges() -> Self {
let mut bridgedb = BridgeDb::new();
let mut lox_auth = BridgeAuth::new(bridgedb.pubkey);
// Make 3 x num_buckets open invitation bridges, in sets of 3
for _ in 0..5 {
let bucket = [
lox_utils::random(),
lox_utils::random(),
lox_utils::random(),
];
let _ = lox_auth.add_openinv_bridges(bucket, &mut bridgedb);
}
// Add hot_spare more hot spare buckets
for _ in 0..5 {
let bucket = [
lox_utils::random(),
lox_utils::random(),
lox_utils::random(),
];
let _ = lox_auth.add_spare_bucket(bucket, &mut bridgedb);
}
// Create the encrypted bridge table
lox_auth.enc_bridge_table();
let context = LoxServerContext {
db: Arc::new(Mutex::new(bridgedb)),
ba: Arc::new(Mutex::new(lox_auth)),
extra_bridges: Arc::new(Mutex::new(Vec::new())),
metrics: Metrics::default(),
};
Self { context }
}
}
fn get_config()-> BridgeConfig {
env::set_var("BRIDGE_CONFIG_PATH", "bridge_config.json");
let path = env::var("BRIDGE_CONFIG_PATH").unwrap();
let config_file = fs::File::open(&path).unwrap();
serde_json::from_reader(config_file).unwrap()
}
#[test]
fn test_sync_with_bridgetable_only_working_resources() {
let bridge_config = get_config();
// Add bridges to empty bridge table and update with changed bridge state
let th = TestHarness::new();
let mut rs = TestResourceState::default();
for _ in 0..5 {
rs.add_working_resource();
}
assert_ne!(rs.rstate.working, None);
assert_eq!(rs.rstate.not_working, None);
th.context
.sync_with_bridgetable(bridge_config.watched_blockages.clone(), rs.rstate.clone());
let mut reachable_expected_length = rs.rstate.clone().working.unwrap().len();
let expected_extra_bridges = reachable_expected_length % MAX_BRIDGES_PER_BUCKET;
if expected_extra_bridges != 0 {
reachable_expected_length = reachable_expected_length - expected_extra_bridges;
}
assert_eq!(
th.context.ba.lock().unwrap().bridge_table.reachable.len(),
reachable_expected_length,
"Unexpected number of reachable bridges"
);
assert_eq!(
th.context.extra_bridges.lock().unwrap().len(),
expected_extra_bridges,
"Unexpected number of extra bridges"
);
}
#[test]
fn test_sync_with_bridgetable_working_and_not_working_resources() {
let bridge_config = get_config();
// Add bridges to empty bridge table and update with changed bridge state
let th = TestHarness::new();
let mut rs = TestResourceState::default();
for _ in 0..5 {
rs.add_working_resource();
}
for _ in 0..5 {
rs.add_not_working_resource()
}
assert_ne!(rs.rstate.working, None);
assert_ne!(rs.rstate.not_working, None);
th.context
.sync_with_bridgetable(bridge_config.watched_blockages.clone(), rs.rstate.clone());
let mut reachable_expected_length = rs.rstate.clone().working.unwrap().len();
let expected_extra_bridges = reachable_expected_length % MAX_BRIDGES_PER_BUCKET;
if expected_extra_bridges != 0 {
reachable_expected_length = reachable_expected_length - expected_extra_bridges;
}
assert_eq!(
th.context.ba.lock().unwrap().bridge_table.reachable.len(),
reachable_expected_length,
"Unexpected number of reachable bridges"
);
assert_eq!(
th.context.extra_bridges.lock().unwrap().len(),
expected_extra_bridges,
"Unexpected number of extra bridges"
);
}
}

View File

@ -10,13 +10,13 @@ pub struct ResourceRequest {
pub resource_types: Vec<String>,
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
pub struct TestResults {
pub last_passed: DateTime<Utc>,
}
/// Representation of a bridge resource
#[derive(Deserialize, PartialEq, Eq, Debug)]
#[derive(Clone, Deserialize, PartialEq, Eq, Debug)]
pub struct Resource {
pub r#type: String,
pub blocked_in: HashMap<String, bool>,
@ -57,7 +57,7 @@ impl Resource {
}
/// A ResourceState holds information about new, changed, or pruned resources
#[derive(Deserialize, Default, PartialEq, Eq, Debug)]
#[derive(Clone, Deserialize, Default, PartialEq, Eq, Debug)]
pub struct ResourceState {
pub working: Option<Vec<Resource>>,
pub not_working: Option<Vec<Resource>>,