use moonpool_sim::{
ChaosConfiguration, NetworkConfiguration, NetworkProvider, SimWorld, TcpListenerTrait,
};
use std::time::Duration;
use tokio::io::AsyncWriteExt;
async fn simple_network_test<P>(provider: P, addr: &str) -> std::io::Result<()>
where
P: NetworkProvider + Clone,
{
let listener = provider.bind(addr).await?;
let _client = provider.connect(addr).await?; let (mut stream, _peer_addr) = listener.accept().await?;
let test_data = b"test data for latency measurement";
stream.write_all(test_data).await?;
Ok(())
}
#[test]
fn test_fast_local_configuration() {
let local_runtime = tokio::runtime::Builder::new_current_thread()
.enable_io()
.enable_time()
.build_local(Default::default())
.expect("Failed to build local runtime");
local_runtime.block_on(async move {
let fast_config = NetworkConfiguration::fast_local();
let mut sim = SimWorld::new_with_network_config(fast_config);
let provider = sim.network_provider();
let start_time = std::time::Instant::now();
simple_network_test(provider, "fast-test").await.unwrap();
let elapsed = start_time.elapsed();
sim.run_until_empty();
let sim_time = sim.current_time();
assert!(
sim_time < Duration::from_millis(1),
"Fast local should be under 1ms, got {:?}",
sim_time
);
println!(
"Fast local test completed in real time: {:?}, sim time: {:?}",
elapsed, sim_time
);
});
}
#[test]
fn test_default_simulation_configuration() {
let local_runtime = tokio::runtime::Builder::new_current_thread()
.enable_io()
.enable_time()
.build_local(Default::default())
.expect("Failed to build local runtime");
local_runtime.block_on(async move {
let wan_config = NetworkConfiguration::default(); let mut sim = SimWorld::new_with_network_config(wan_config);
let provider = sim.network_provider();
let start_time = std::time::Instant::now();
simple_network_test(provider, "wan-test").await.unwrap();
let elapsed = start_time.elapsed();
sim.run_until_empty();
let sim_time = sim.current_time();
assert!(
sim_time > Duration::from_millis(5),
"Default config should be over 5ms, got {:?}",
sim_time
);
println!(
"Default config test completed in real time: {:?}, sim time: {:?}",
elapsed, sim_time
);
});
}
#[test]
fn test_custom_latency_configuration() {
let local_runtime = tokio::runtime::Builder::new_current_thread()
.enable_io()
.enable_time()
.build_local(Default::default())
.expect("Failed to build local runtime");
local_runtime.block_on(async move {
let config = NetworkConfiguration {
bind_latency: Duration::from_millis(5)..Duration::from_millis(5),
accept_latency: Duration::from_millis(10)..Duration::from_millis(10),
connect_latency: Duration::from_millis(1)..Duration::from_millis(1),
read_latency: Duration::from_micros(10)..Duration::from_micros(10),
write_latency: Duration::from_millis(2)..Duration::from_millis(2),
chaos: ChaosConfiguration::disabled(),
};
let mut sim = SimWorld::new_with_network_config(config);
let provider = sim.network_provider();
simple_network_test(provider, "custom-test").await.unwrap();
sim.run_until_empty();
let sim_time = sim.current_time();
assert!(
sim_time > Duration::ZERO,
"Custom config should advance simulation time, got {:?}",
sim_time
);
assert!(
sim_time >= Duration::from_millis(1),
"Custom config should have at least 1ms latency, got {:?}",
sim_time
);
println!("Custom test completed in sim time: {:?}", sim_time);
});
}
#[test]
fn test_latency_range_sampling() {
let local_runtime = tokio::runtime::Builder::new_current_thread()
.enable_io()
.enable_time()
.build_local(Default::default())
.expect("Failed to build local runtime");
local_runtime.block_on(async move {
let config = NetworkConfiguration {
bind_latency: Duration::from_millis(1)..Duration::from_millis(6), accept_latency: Duration::from_millis(1)..Duration::from_millis(6),
connect_latency: Duration::from_millis(1)..Duration::from_millis(6),
read_latency: Duration::from_micros(10)..Duration::from_micros(10),
write_latency: Duration::from_millis(1)..Duration::from_millis(6),
chaos: ChaosConfiguration::disabled(),
};
let mut execution_times = Vec::new();
for _run in 0..5 {
let mut sim = SimWorld::new_with_network_config(config.clone());
let provider = sim.network_provider();
simple_network_test(provider, "jitter-test").await.unwrap();
sim.run_until_empty();
execution_times.push(sim.current_time());
}
let first_time = execution_times[0];
let all_same = execution_times.iter().all(|&t| t == first_time);
println!("Execution times with jitter: {:?}", execution_times);
for &time in &execution_times {
assert!(time > Duration::ZERO, "Time should be positive: {:?}", time);
}
if !all_same {
println!("✓ Latency jitter working - execution times vary");
} else {
println!("⚠ All execution times were identical (could happen by chance)");
}
});
}
#[test]
fn test_network_randomization_ranges() {
let local_runtime = tokio::runtime::Builder::new_current_thread()
.enable_io()
.enable_time()
.build_local(Default::default())
.expect("Failed to build local runtime");
local_runtime.block_on(async move {
let config = NetworkConfiguration {
bind_latency: Duration::from_millis(1)..Duration::from_millis(1),
accept_latency: Duration::from_millis(2)..Duration::from_millis(2),
connect_latency: Duration::from_millis(3)..Duration::from_millis(3),
read_latency: Duration::from_micros(100)..Duration::from_micros(100),
write_latency: Duration::from_micros(500)..Duration::from_micros(500),
chaos: ChaosConfiguration::disabled(),
};
let mut sim = SimWorld::new_with_network_config(config);
let provider = sim.network_provider();
simple_network_test(provider, "custom-ranges-test")
.await
.unwrap();
sim.run_until_empty();
let sim_time = sim.current_time();
assert!(
sim_time >= Duration::from_millis(3),
"Expected at least 3ms with custom ranges, got {:?}",
sim_time
);
assert!(
sim_time <= Duration::from_millis(10),
"Expected less than 10ms with custom ranges, got {:?}",
sim_time
);
println!("Custom ranges test completed in sim time: {:?}", sim_time);
});
}