use log::{info, trace}; use rand::{prelude::StdRng, SeedableRng}; use rand_distr::{Bernoulli, Normal}; use srt_protocol::connection::Input; use std::{ cmp::min, str, time::{Duration, Instant}, }; pub mod simulator; use simulator::*; use srt_protocol::options::PacketCount; #[test] fn not_enough_latency() { // once failing seeds do_not_enough_latency(14133229019647651772, 200); do_not_enough_latency(7252484344775749023, 1000); do_not_enough_latency(6785379667375872404, 1000); do_not_enough_latency(12543789221422496569, 1000); for _ in 0..100 { do_not_enough_latency(rand::random(), 1000); } } fn do_not_enough_latency(seed: u64, packets: usize) { println!("not_enough_latency seed is {seed}"); let _ = pretty_env_logger::try_init(); const PACKET_SPACING: Duration = Duration::from_millis(10); let start = Instant::now(); let rng = StdRng::seed_from_u64(seed); // 4% packet loss, 4 sec latency with 0.2 s variance let mut simulation = RandomLossSimulation { rng, delay_dist: Normal::new(1.5, 0.2).unwrap(), drop_dist: Bernoulli::new(0.01).unwrap(), }; let (mut network, mut sender, mut receiver) = simulation.build(start, Duration::from_secs(2), PacketCount(8192)); input_data_simulation(start, packets, PACKET_SPACING, &mut network.sender); let mut now = start; let mut total_recvd = 0; let mut total_dropped = 0; let mut last_data = 0; loop { let sender_next_time = if sender.is_open() { assert_eq!(sender.next_data(now), None); while let Some(packet) = sender.next_packet(now) { match simulation.next_packet_schedule(now) { Some(release_at) => network.send(release_at, packet), None => trace!("Dropping {:?}", packet), } } let next_timer = sender.check_timers(now); let (next_time, input) = network.sender.select_next_input(now, next_timer); match input { Input::Data(data) => sender.handle_data_input(next_time, data), Input::Packet(packet) => sender.handle_packet_input(next_time, packet), _ => {} }; Some(next_time) } else { None }; let receiver_next_time = if receiver.is_open() { while let Some((_, by)) = receiver.next_data(now) { total_recvd += 1; let id = str::from_utf8(&by).unwrap().parse().unwrap(); assert!(id > last_data, "Received {id} after {last_data}"); if last_data + 1 != id { info!("Packets [{}, {}) dropped", last_data + 1, id); total_dropped += id - (last_data + 1); } last_data = id; } while let Some(packet) = receiver.next_packet(now) { match simulation.next_packet_schedule(now) { Some(release_at) => network.send(release_at, packet), None => trace!("Dropping {:?}", packet), } } let next_timer = receiver.check_timers(now); let (next_time, input) = network.receiver.select_next_input(now, next_timer); match input { Input::Data(data) => receiver.handle_data_input(now, data), Input::Packet(packet) => receiver.handle_packet_input(now, packet), _ => {} }; Some(next_time) } else { None }; let next_time = match (sender_next_time, receiver_next_time) { (Some(s), Some(r)) => min(s, r), (Some(s), None) => s, (None, Some(r)) => r, _ => break, }; let delta = next_time - now; trace!("Delta = {:?}", delta); now = next_time; } assert_eq!(total_dropped + total_recvd + (packets - last_data), packets); assert!( total_recvd > packets * 2 / 3, "received {} packtes, expected {}", total_recvd, packets * 2 / 3 ); assert!( total_recvd <= packets, "received all ({total_recvd}) packets, expected < {packets}" ); }