Add homework 01 guarantees assignment
This commit is contained in:
@@ -0,0 +1,158 @@
|
||||
use std::fs;
|
||||
|
||||
use assertables::assume;
|
||||
use rand::prelude::*;
|
||||
use rand_pcg::Pcg64;
|
||||
|
||||
use anysystem::test::TestResult;
|
||||
use anysystem::Message;
|
||||
|
||||
use crate::common::{build_system, check_guarantees, check_overhead, send_messages, TestConfig};
|
||||
|
||||
pub fn test_normal(config: &TestConfig) -> TestResult {
|
||||
let mut sys = build_system(config, false);
|
||||
let messages = send_messages(&mut sys, 5);
|
||||
sys.step_until_no_events();
|
||||
check_guarantees(&mut sys, &messages, config)?;
|
||||
// We expect no more than 5 messages from sender in normal network conditions
|
||||
let sent_count = sys.sent_message_count("sender");
|
||||
assume!(
|
||||
sent_count <= 5,
|
||||
format!("Sender sent {} messages, expected at most 5", sent_count)
|
||||
)
|
||||
}
|
||||
|
||||
pub fn test_normal_non_unique(config: &TestConfig) -> TestResult {
|
||||
let mut sys = build_system(config, false);
|
||||
let messages = send_messages(&mut sys, 10);
|
||||
sys.step_until_no_events();
|
||||
check_guarantees(&mut sys, &messages, config)?;
|
||||
// We expect no more than 10 messages from sender in normal network conditions (stable delay, no loss).
|
||||
// If solution sends multiple messages without or with too small (<RTT) delay, this results in extra redundant
|
||||
// traffic. We want to avoid wasting network resources, assuming that normal conditions happen most of the time.
|
||||
let sent_count = sys.sent_message_count("sender");
|
||||
assume!(
|
||||
sent_count <= 10,
|
||||
format!("Sender sent {} messages, expected at most 10", sent_count)
|
||||
)
|
||||
}
|
||||
|
||||
pub fn test_delayed(config: &TestConfig) -> TestResult {
|
||||
let mut sys = build_system(config, false);
|
||||
sys.network().set_delays(1., 3.);
|
||||
let messages = send_messages(&mut sys, 5);
|
||||
sys.step_until_no_events();
|
||||
check_guarantees(&mut sys, &messages, config)
|
||||
}
|
||||
|
||||
pub fn test_duplicated(config: &TestConfig) -> TestResult {
|
||||
let mut sys = build_system(config, false);
|
||||
sys.network().set_dupl_rate(0.3);
|
||||
let messages = send_messages(&mut sys, 5);
|
||||
sys.step_until_no_events();
|
||||
check_guarantees(&mut sys, &messages, config)
|
||||
}
|
||||
|
||||
pub fn test_delayed_duplicated(config: &TestConfig) -> TestResult {
|
||||
let mut sys = build_system(config, false);
|
||||
sys.network().set_delays(1., 3.);
|
||||
sys.network().set_dupl_rate(0.3);
|
||||
let messages = send_messages(&mut sys, 5);
|
||||
sys.step_until_no_events();
|
||||
check_guarantees(&mut sys, &messages, config)
|
||||
}
|
||||
|
||||
pub fn test_old_duplicate(config: &TestConfig) -> TestResult {
|
||||
let mut sys = build_system(config, false);
|
||||
sys.network().set_delays(1., 3.);
|
||||
sys.network().set_dupl_rate(1.);
|
||||
|
||||
let first = Message::new("MESSAGE", r#"{"text": "first"}"#);
|
||||
let mut messages = vec![first.clone()];
|
||||
sys.send_local_message("sender", first);
|
||||
|
||||
// Stop after the first copy is delivered.
|
||||
while sys.local_outbox("receiver").is_empty() {
|
||||
if !sys.step() {
|
||||
return Err("The first message was not delivered".to_string());
|
||||
}
|
||||
}
|
||||
|
||||
// Keep the old duplicate pending while newer messages are delivered first.
|
||||
// Zero-delay messages are processed before the delayed copy.
|
||||
sys.network().set_dupl_rate(0.);
|
||||
sys.network().set_delay(0.);
|
||||
for i in 0..50 {
|
||||
let msg = Message::new("MESSAGE", &format!(r#"{{"text": "message-{i}"}}"#));
|
||||
sys.send_local_message("sender", msg.clone());
|
||||
messages.push(msg);
|
||||
}
|
||||
|
||||
sys.step_until_no_events();
|
||||
check_guarantees(&mut sys, &messages, config)
|
||||
}
|
||||
|
||||
pub fn test_dropped(config: &TestConfig) -> TestResult {
|
||||
let mut sys = build_system(config, false);
|
||||
sys.network().set_drop_rate(0.3);
|
||||
let messages = send_messages(&mut sys, 5);
|
||||
sys.step_until_no_events();
|
||||
check_guarantees(&mut sys, &messages, config)
|
||||
}
|
||||
|
||||
pub fn test_chaos_monkey(config: &TestConfig) -> TestResult {
|
||||
let mut rand = Pcg64::seed_from_u64(config.seed);
|
||||
for i in 1..=config.monkeys {
|
||||
let mut run_config = *config;
|
||||
run_config.seed = rand.next_u64();
|
||||
println!("Run {} (seed: {})", i, run_config.seed);
|
||||
let mut sys = build_system(&run_config, false);
|
||||
sys.network().set_delays(1., 3.);
|
||||
sys.network().set_dupl_rate(0.3);
|
||||
sys.network().set_drop_rate(0.3);
|
||||
let messages = send_messages(&mut sys, 50);
|
||||
sys.step_until_no_events();
|
||||
let res = check_guarantees(&mut sys, &messages, &run_config);
|
||||
res.as_ref()?;
|
||||
}
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
pub fn test_overhead(config: &TestConfig, guarantee: &str, faulty: bool) -> TestResult {
|
||||
for message_count in [100, 500, 1000] {
|
||||
let mut sys = build_system(config, true);
|
||||
if faulty {
|
||||
sys.network().set_delays(1., 3.);
|
||||
sys.network().set_dupl_rate(0.3);
|
||||
sys.network().set_drop_rate(0.3);
|
||||
}
|
||||
let messages = send_messages(&mut sys, message_count);
|
||||
sys.step_until_no_events();
|
||||
let res = check_guarantees(&mut sys, &messages, config);
|
||||
res.as_ref()?;
|
||||
let sender_mem = sys.max_size("sender");
|
||||
let receiver_mem = sys.max_size("receiver");
|
||||
let net_message_count = sys.network().network_message_count();
|
||||
let net_traffic = sys.network().traffic();
|
||||
let throughput = message_count as f64 / sys.time();
|
||||
println!(
|
||||
"{message_count:<6} Send Mem: {sender_mem:<8} Recv Mem: {receiver_mem:<8} Messages: {net_message_count:<8} Traffic: {net_traffic:<8} Throughput: {throughput:.3}"
|
||||
);
|
||||
check_overhead(
|
||||
guarantee,
|
||||
faulty,
|
||||
message_count,
|
||||
sender_mem,
|
||||
receiver_mem,
|
||||
net_message_count,
|
||||
net_traffic,
|
||||
throughput,
|
||||
)?;
|
||||
}
|
||||
let impl_code = fs::read_to_string(config.impl_path).unwrap();
|
||||
assume!(
|
||||
!impl_code.contains("<<") && !impl_code.contains(">>"),
|
||||
"Implementation contains bitwise shift operators"
|
||||
)?;
|
||||
Ok(true)
|
||||
}
|
||||
Reference in New Issue
Block a user