use crate::{
assert_delta,
counter::Counter,
event, path,
path::MINIMUM_MAX_DATAGRAM_SIZE,
random,
recovery::{
bandwidth::{Bandwidth, PacketInfo, RateSample},
bbr,
bbr::{
probe_bw, probe_bw::CyclePhase, probe_rtt, BbrCongestionController, State, LOSS_THRESH,
},
congestion_controller::{PathPublisher, Publisher},
CongestionController,
},
time::{Clock, NoopClock},
};
use num_rational::Ratio;
use num_traits::{Inv, One, ToPrimitive};
use std::time::Duration;
#[test]
fn initial_window_with_app_settings() {
let mut app_settings = Default::default();
let max_datagram_size = 1350;
assert_eq!(
(max_datagram_size * 10) as u32,
BbrCongestionController::initial_window(max_datagram_size, &app_settings)
);
app_settings.initial_congestion_window = Some(20_000);
assert_eq!(
20_000,
BbrCongestionController::initial_window(max_datagram_size, &app_settings)
);
app_settings.initial_congestion_window = Some(0);
assert_eq!(
BbrCongestionController::minimum_window(max_datagram_size),
BbrCongestionController::initial_window(max_datagram_size, &app_settings)
);
}
#[test]
fn is_probing_for_bandwidth() {
let mut bbr = BbrCongestionController::new(MINIMUM_MAX_DATAGRAM_SIZE, Default::default());
let mut publisher = event::testing::Publisher::snapshot();
let mut publisher = PathPublisher::new(&mut publisher, path::Id::test_id());
assert!(!State::Drain.is_probing_for_bandwidth());
assert!(!State::ProbeRtt(probe_rtt::State::default()).is_probing_for_bandwidth());
enter_probe_bw_state(&mut bbr, CyclePhase::Down, &mut publisher);
assert!(!bbr.state.is_probing_for_bandwidth());
enter_probe_bw_state(&mut bbr, CyclePhase::Cruise, &mut publisher);
assert!(!bbr.state.is_probing_for_bandwidth());
assert!(State::Startup.is_probing_for_bandwidth());
enter_probe_bw_state(&mut bbr, CyclePhase::Up, &mut publisher);
assert!(bbr.state.is_probing_for_bandwidth());
enter_probe_bw_state(&mut bbr, CyclePhase::Refill, &mut publisher);
assert!(bbr.state.is_probing_for_bandwidth());
}
#[test]
fn inflight_hi_from_lost_packet() {
let now = NoopClock.get_time();
let packet_info = PacketInfo {
delivered_bytes: 0,
delivered_time: now,
lost_bytes: 0,
ecn_ce_count: 0,
first_sent_time: now,
bytes_in_flight: 3000,
is_app_limited: false,
};
let inflight_prev = packet_info.bytes_in_flight - MINIMUM_MAX_DATAGRAM_SIZE as u32;
assert_eq!(inflight_prev, 1800);
assert_eq!(
inflight_prev + 26,
BbrCongestionController::inflight_hi_from_lost_packet(
MINIMUM_MAX_DATAGRAM_SIZE as u32,
1210,
packet_info,
&Default::default()
)
);
assert_eq!(
inflight_prev,
BbrCongestionController::inflight_hi_from_lost_packet(
MINIMUM_MAX_DATAGRAM_SIZE as u32,
3000,
packet_info,
&Default::default()
)
);
let packet_info = PacketInfo {
delivered_bytes: 0,
delivered_time: now,
lost_bytes: 0,
ecn_ce_count: 0,
first_sent_time: now,
bytes_in_flight: 0,
is_app_limited: false,
};
let inflight_prev = 0;
assert_eq!(
inflight_prev,
BbrCongestionController::inflight_hi_from_lost_packet(
MINIMUM_MAX_DATAGRAM_SIZE as u32,
MINIMUM_MAX_DATAGRAM_SIZE as u32,
packet_info,
&Default::default()
)
);
}
#[test]
fn loss_threshold_with_app_settings() {
let mut app_settings = Default::default();
assert_eq!(
BbrCongestionController::loss_thresh(&app_settings),
LOSS_THRESH
);
app_settings.loss_threshold = Some(500);
assert_eq!(
BbrCongestionController::loss_thresh(&app_settings),
Ratio::new_raw(500, 100)
);
}
#[test]
fn pacing_cwnd_gain() {
let mut publisher = event::testing::Publisher::snapshot();
let mut publisher = PathPublisher::new(&mut publisher, path::Id::test_id());
assert_delta!(
State::Startup
.pacing_gain(&Default::default())
.to_f32()
.unwrap(),
2.77,
0.001
);
assert_delta!(
State::Startup
.cwnd_gain(&Default::default())
.to_f32()
.unwrap(),
2.0,
0.001
);
assert_eq!(
State::Drain.pacing_gain(&Default::default()),
State::Startup.cwnd_gain(&Default::default()).inv()
);
assert_eq!(
State::Drain.cwnd_gain(&Default::default()),
State::Startup.cwnd_gain(&Default::default())
);
let mut bbr = BbrCongestionController::new(MINIMUM_MAX_DATAGRAM_SIZE, Default::default());
let now = NoopClock.get_time();
bbr.enter_drain(&mut publisher);
bbr.enter_probe_bw(
false,
&mut random::testing::Generator::default(),
now,
&mut publisher,
);
assert!(bbr.state.is_probing_bw());
assert_delta!(
bbr.state.cwnd_gain(&Default::default()).to_f32().unwrap(),
2.0,
0.001
);
assert_delta!(
bbr.state.pacing_gain(&Default::default()).to_f32().unwrap(),
0.9,
0.001
);
assert_delta!(
State::ProbeRtt(probe_rtt::State::default())
.pacing_gain(&Default::default())
.to_f32()
.unwrap(),
1.0,
0.001
);
assert_delta!(
State::ProbeRtt(probe_rtt::State::default())
.cwnd_gain(&Default::default())
.to_f32()
.unwrap(),
0.5,
0.001
);
}
#[test]
fn cwnd_gain_with_app_settings() {
let mut app_settings = Default::default();
let state = State::ProbeBw(probe_bw::State::new());
assert_eq!(state.cwnd_gain(&app_settings), probe_bw::CWND_GAIN);
app_settings.probe_bw_cwnd_gain = Some(500);
assert_eq!(state.cwnd_gain(&app_settings), Ratio::new_raw(500, 100));
}
#[test]
fn new() {
let bbr = BbrCongestionController::new(MINIMUM_MAX_DATAGRAM_SIZE, Default::default());
assert_eq!(Bandwidth::ZERO, bbr.data_rate_model.max_bw());
assert_eq!(None, bbr.data_volume_model.min_rtt());
assert_eq!(0, bbr.prior_cwnd);
assert!(!bbr.idle_restart);
assert_eq!(0, bbr.data_volume_model.extra_acked());
bbr::congestion::testing::assert_reset(bbr.congestion_state);
assert_eq!(u64::MAX, bbr.data_volume_model.inflight_lo());
assert_eq!(Bandwidth::INFINITY, bbr.data_rate_model.bw_lo());
assert!(!bbr.round_counter.round_start());
assert_eq!(0, bbr.round_counter.round_count());
assert!(!bbr.full_pipe_estimator.filled_pipe());
assert!(bbr.state.is_startup());
}
#[test]
fn bdp_multiple() {
let mut bbr = BbrCongestionController::new(MINIMUM_MAX_DATAGRAM_SIZE, Default::default());
let now = NoopClock.get_time();
assert_eq!(12_000, bbr.bdp_multiple(Bandwidth::ZERO, Ratio::one()));
let rtt = Duration::from_millis(100);
bbr.data_volume_model.update_min_rtt(rtt, now);
assert_eq!(Some(rtt), bbr.data_volume_model.min_rtt());
let bandwidth = Bandwidth::new(1000, Duration::from_millis(1));
let gain = Ratio::new(2, 1);
assert_eq!(200000, bbr.bdp_multiple(bandwidth, gain));
assert_eq!(u64::MAX, bbr.bdp_multiple(Bandwidth::INFINITY, gain));
assert_eq!(0, bbr.bdp_multiple(Bandwidth::ZERO, gain));
}
#[test]
fn target_inflight() {
let mut bbr = BbrCongestionController::new(MINIMUM_MAX_DATAGRAM_SIZE, Default::default());
let now = NoopClock.get_time();
let rate_sample = RateSample {
delivered_bytes: 1000,
interval: Duration::from_millis(1),
..Default::default()
};
bbr.data_rate_model.update_max_bw(rate_sample);
bbr.data_rate_model.bound_bw_for_model();
let rtt = Duration::from_millis(100);
bbr.data_volume_model.update_min_rtt(rtt, now);
assert_eq!(Some(rtt), bbr.data_volume_model.min_rtt());
assert_eq!(12000, bbr.target_inflight());
bbr.cwnd = 200000;
assert_eq!(100000, bbr.target_inflight());
}
#[test]
fn max_inflight() {
let mut bbr = BbrCongestionController::new(MINIMUM_MAX_DATAGRAM_SIZE, Default::default());
bbr.data_volume_model.set_extra_acked_for_test(1000, 0);
assert_eq!(36000, bbr.max_inflight());
}
#[test]
fn inflight() {
let mut bbr = BbrCongestionController::new(MINIMUM_MAX_DATAGRAM_SIZE, Default::default());
let now = NoopClock.get_time();
let rtt = Duration::from_millis(100);
bbr.data_volume_model.update_min_rtt(rtt, now);
assert_eq!(Some(rtt), bbr.data_volume_model.min_rtt());
let bandwidth = Bandwidth::new(2000, Duration::from_millis(1));
assert_eq!(200000, bbr.inflight(bandwidth, Ratio::one()));
assert_eq!(
u32::MAX,
bbr.inflight(Bandwidth::INFINITY, Ratio::new(2, 1))
);
}
#[test]
fn inflight_with_headroom() {
let mut bbr = BbrCongestionController::new(MINIMUM_MAX_DATAGRAM_SIZE, Default::default());
assert_eq!(u32::MAX, bbr.inflight_with_headroom());
bbr.data_volume_model.update_upper_bound(10_000);
assert_eq!(8500, bbr.inflight_with_headroom());
bbr.data_volume_model.update_upper_bound(1000);
assert_eq!(4800, bbr.inflight_with_headroom());
}
#[test]
fn quantization_budget() {
let mut bbr = BbrCongestionController::new(MINIMUM_MAX_DATAGRAM_SIZE, Default::default());
let mut publisher = event::testing::Publisher::snapshot();
let mut publisher = PathPublisher::new(&mut publisher, path::Id::test_id());
bbr.pacer.set_send_quantum_for_test(4000);
let send_quantum = bbr.pacer.send_quantum();
assert_eq!(3 * send_quantum as u64, bbr.quantization_budget(6000));
assert_eq!(14000, bbr.quantization_budget(14000));
bbr.pacer.set_send_quantum_for_test(1000);
assert_eq!(4800, bbr.quantization_budget(2000));
enter_probe_bw_state(&mut bbr, CyclePhase::Up, &mut publisher);
assert!(bbr.state.is_probing_bw_up());
assert_eq!(
4800 + 2 * MINIMUM_MAX_DATAGRAM_SIZE as u64,
bbr.quantization_budget(2000)
);
}
#[test]
fn is_inflight_too_high() {
let rate_sample = RateSample {
lost_bytes: 3,
bytes_in_flight: 100,
..Default::default()
};
assert!(BbrCongestionController::is_inflight_too_high(
rate_sample,
MINIMUM_MAX_DATAGRAM_SIZE,
2,
2,
&Default::default()
));
assert!(!BbrCongestionController::is_inflight_too_high(
rate_sample,
MINIMUM_MAX_DATAGRAM_SIZE,
1,
2,
&Default::default()
));
let rate_sample = RateSample {
lost_bytes: 2,
bytes_in_flight: 100,
..Default::default()
};
assert!(!BbrCongestionController::is_inflight_too_high(
rate_sample,
MINIMUM_MAX_DATAGRAM_SIZE,
2,
2,
&Default::default()
));
let rate_sample = RateSample {
delivered_bytes: 100 * MINIMUM_MAX_DATAGRAM_SIZE as u64,
ecn_ce_count: 51,
..Default::default()
};
assert!(BbrCongestionController::is_inflight_too_high(
rate_sample,
MINIMUM_MAX_DATAGRAM_SIZE,
0,
2,
&Default::default()
));
let rate_sample = RateSample {
delivered_bytes: 100 * MINIMUM_MAX_DATAGRAM_SIZE as u64,
ecn_ce_count: 50,
..Default::default()
};
assert!(!BbrCongestionController::is_inflight_too_high(
rate_sample,
MINIMUM_MAX_DATAGRAM_SIZE,
0,
2,
&Default::default()
));
}
#[test]
fn bound_cwnd_for_model() {
let mut bbr = BbrCongestionController::new(MINIMUM_MAX_DATAGRAM_SIZE, Default::default());
let mut publisher = event::testing::Publisher::snapshot();
let mut publisher = PathPublisher::new(&mut publisher, path::Id::test_id());
enter_probe_bw_state(&mut bbr, CyclePhase::Down, &mut publisher);
bbr.data_volume_model.update_upper_bound(10000);
assert_eq!(10000, bbr.bound_cwnd_for_model());
enter_probe_bw_state(&mut bbr, CyclePhase::Cruise, &mut publisher);
assert_eq!(8500, bbr.bound_cwnd_for_model());
bbr.state = State::ProbeRtt(probe_rtt::State::default());
assert_eq!(8500, bbr.bound_cwnd_for_model());
bbr.state = State::Startup;
bbr.data_volume_model
.update_lower_bound(1000, 5000, true, false, 0.0);
assert_eq!(5000, bbr.data_volume_model.inflight_lo());
assert_eq!(5000, bbr.bound_cwnd_for_model());
bbr.data_volume_model
.update_lower_bound(1000, 4000, true, false, 0.0);
assert_eq!(4000, bbr.data_volume_model.inflight_lo());
assert_eq!(4800, bbr.bound_cwnd_for_model());
}
#[test]
fn set_cwnd_filled_pipe() {
let mut bbr = BbrCongestionController::new(MINIMUM_MAX_DATAGRAM_SIZE, Default::default());
assert_eq!(36_000, bbr.max_inflight());
bbr.full_pipe_estimator.set_filled_pipe_for_test(true);
assert!(bbr.full_pipe_estimator.filled_pipe());
bbr.cwnd = 12_000;
bbr.set_cwnd(1000);
assert_eq!(13_000, bbr.cwnd);
assert!(!bbr.try_fast_path);
bbr.cwnd = 40_000;
bbr.set_cwnd(1000);
assert_eq!(36_000, bbr.cwnd);
assert!(bbr.try_fast_path);
}
#[test]
fn set_cwnd_not_filled_pipe() {
let mut bbr = BbrCongestionController::new(MINIMUM_MAX_DATAGRAM_SIZE, Default::default());
let mut publisher = event::testing::Publisher::snapshot();
let mut publisher = PathPublisher::new(&mut publisher, path::Id::test_id());
let now = NoopClock.get_time();
assert_eq!(36_000, bbr.max_inflight());
assert!(!bbr.full_pipe_estimator.filled_pipe());
bbr.cwnd = 12_000;
bbr.set_cwnd(1000);
assert_eq!(13_000, bbr.cwnd);
bbr.cwnd = 40_000;
bbr.set_cwnd(1000);
assert_eq!(41_000, bbr.cwnd);
let packet_info = PacketInfo {
delivered_bytes: 0,
delivered_time: now,
lost_bytes: 0,
ecn_ce_count: 0,
first_sent_time: now,
bytes_in_flight: 0,
is_app_limited: false,
};
let initial_cwnd =
BbrCongestionController::initial_window(MINIMUM_MAX_DATAGRAM_SIZE, &Default::default());
bbr.bw_estimator.on_ack(
2 * initial_cwnd as usize + 1,
now,
packet_info,
now,
&mut publisher,
);
bbr.cwnd = 12_000;
bbr.set_cwnd(1000);
assert_eq!(13_000, bbr.cwnd);
assert!(!bbr.try_fast_path);
bbr.cwnd = 40_000;
bbr.set_cwnd(1000);
assert_eq!(40_000, bbr.cwnd); assert!(bbr.try_fast_path);
}
#[test]
fn set_cwnd_probing_rtt() {
let mut bbr = BbrCongestionController::new(MINIMUM_MAX_DATAGRAM_SIZE, Default::default());
assert_eq!(36_000, bbr.max_inflight());
assert_eq!(12_000, bbr.probe_rtt_cwnd());
bbr.state = State::ProbeRtt(probe_rtt::State::default());
bbr.cwnd = 13_000;
bbr.set_cwnd(1000);
assert_eq!(12_000, bbr.cwnd);
bbr.cwnd = 10_000;
bbr.set_cwnd(1000);
assert_eq!(11_000, bbr.cwnd);
}
#[test]
fn set_cwnd_clamp() {
let mut bbr = BbrCongestionController::new(MINIMUM_MAX_DATAGRAM_SIZE, Default::default());
assert_eq!(36_000, bbr.max_inflight());
bbr.cwnd = BbrCongestionController::minimum_window(bbr.max_datagram_size) - 1000;
bbr.set_cwnd(500);
assert_eq!(
BbrCongestionController::minimum_window(bbr.max_datagram_size),
bbr.cwnd
);
bbr.data_volume_model.set_inflight_lo_for_test(30_000);
assert_eq!(30_000, bbr.bound_cwnd_for_model());
bbr.cwnd = 40_000;
bbr.set_cwnd(1000);
assert_eq!(30_000, bbr.cwnd);
}
#[test]
fn save_cwnd() {
let mut bbr = BbrCongestionController::new(MINIMUM_MAX_DATAGRAM_SIZE, Default::default());
bbr.state = State::ProbeRtt(probe_rtt::State::default());
bbr.prior_cwnd = 2000;
bbr.cwnd = 1000;
bbr.save_cwnd();
assert_eq!(2000, bbr.prior_cwnd);
bbr.prior_cwnd = 4000;
bbr.cwnd = 5000;
bbr.save_cwnd();
assert_eq!(5000, bbr.prior_cwnd);
}
#[test]
fn restore_cwnd() {
let mut bbr = BbrCongestionController::new(MINIMUM_MAX_DATAGRAM_SIZE, Default::default());
bbr.state = State::ProbeRtt(probe_rtt::State::default());
bbr.prior_cwnd = 1000;
bbr.cwnd = 2000;
bbr.restore_cwnd();
assert_eq!(2000, bbr.cwnd);
bbr.prior_cwnd = 2000;
bbr.cwnd = 1000;
bbr.restore_cwnd();
assert_eq!(2000, bbr.cwnd);
}
#[test]
fn handle_lost_packet() {
let mut bbr = BbrCongestionController::new(MINIMUM_MAX_DATAGRAM_SIZE, Default::default());
let now = NoopClock.get_time();
let mut publisher = event::testing::Publisher::snapshot();
let mut publisher = PathPublisher::new(&mut publisher, path::Id::test_id());
bbr.bw_probe_samples = true;
bbr.bw_estimator.on_loss(1000);
let lost_packet = PacketInfo {
delivered_bytes: 0,
delivered_time: now,
lost_bytes: 0,
ecn_ce_count: 0,
first_sent_time: now,
bytes_in_flight: 10000,
is_app_limited: false,
};
enter_probe_bw_state(&mut bbr, CyclePhase::Up, &mut publisher);
bbr.congestion_state.on_packet_lost(500, true);
bbr.congestion_state.on_packet_lost(500, true);
bbr.handle_lost_packet(
1000,
lost_packet,
&mut random::testing::Generator::default(),
now,
&mut publisher,
);
let inflight_hi_from_lost_packet = BbrCongestionController::inflight_hi_from_lost_packet(
1000,
1000,
lost_packet,
&Default::default(),
) as u64;
assert!(!bbr.bw_probe_samples);
assert!(inflight_hi_from_lost_packet > (bbr::BETA * bbr.target_inflight() as u64).to_integer());
assert_eq!(
inflight_hi_from_lost_packet,
bbr.data_volume_model.inflight_hi()
);
if let State::ProbeBw(probe_bw_state) = bbr.state {
assert_eq!(CyclePhase::Down, probe_bw_state.cycle_phase());
} else {
panic!("Must be in ProbeBw Down state");
}
let mut bbr = BbrCongestionController::new(MINIMUM_MAX_DATAGRAM_SIZE, Default::default());
bbr.bw_estimator.on_loss(1000);
bbr.bw_probe_samples = true;
bbr.cwnd = 100_000;
let rate_sample = RateSample {
delivered_bytes: 100_000,
interval: Duration::from_millis(1),
..Default::default()
};
bbr.data_volume_model
.update_min_rtt(Duration::from_millis(10), now);
bbr.data_rate_model.update_max_bw(rate_sample);
bbr.data_rate_model.bound_bw_for_model();
bbr.congestion_state.on_packet_lost(500, true);
bbr.congestion_state.on_packet_lost(500, true);
bbr.handle_lost_packet(
1000,
lost_packet,
&mut random::testing::Generator::default(),
now,
&mut publisher,
);
let inflight_hi_from_lost_packet = BbrCongestionController::inflight_hi_from_lost_packet(
1000,
1000,
lost_packet,
&Default::default(),
) as u64;
assert!(!bbr.bw_probe_samples);
assert!(inflight_hi_from_lost_packet < (bbr::BETA * bbr.target_inflight() as u64).to_integer());
assert_eq!(
(bbr::BETA * bbr.target_inflight() as u64).to_integer(),
bbr.data_volume_model.inflight_hi()
);
}
#[test]
fn handle_restart_from_idle() {
let mut bbr = BbrCongestionController::new(MINIMUM_MAX_DATAGRAM_SIZE, Default::default());
let mut publisher = event::testing::Publisher::snapshot();
let mut publisher = PathPublisher::new(&mut publisher, path::Id::test_id());
let now = NoopClock.get_time();
let pacing_rate = bbr.pacer.pacing_rate();
bbr.handle_restart_from_idle(now, &mut publisher);
assert!(!bbr.idle_restart);
bbr.bytes_in_flight = Counter::new(1);
bbr.bw_estimator.on_app_limited(100);
bbr.handle_restart_from_idle(now, &mut publisher);
assert!(!bbr.idle_restart);
bbr.bytes_in_flight = Counter::default();
bbr.handle_restart_from_idle(now, &mut publisher);
assert!(bbr.idle_restart);
assert_eq!(
Some(now),
bbr.data_volume_model.extra_acked_interval_start()
);
assert_eq!(pacing_rate, bbr.pacer.pacing_rate());
enter_probe_bw_state(&mut bbr, CyclePhase::Down, &mut publisher);
let rate_sample = RateSample {
delivered_bytes: 100_000,
interval: Duration::from_millis(1),
..Default::default()
};
bbr.data_rate_model.update_max_bw(rate_sample);
bbr.data_rate_model.bound_bw_for_model();
assert!(bbr.data_rate_model.bw() > bbr.pacer.pacing_rate());
let now = now + Duration::from_secs(5);
bbr.handle_restart_from_idle(now, &mut publisher);
assert!(bbr.idle_restart);
assert_eq!(
Some(now),
bbr.data_volume_model.extra_acked_interval_start()
);
assert!(bbr.pacer.pacing_rate() > pacing_rate);
}
#[test]
fn model_update_required() {
let mut bbr = BbrCongestionController::new(MINIMUM_MAX_DATAGRAM_SIZE, Default::default());
let rate_sample = RateSample {
delivered_bytes: 100_000,
interval: Duration::from_millis(1),
..Default::default()
};
bbr.data_rate_model.update_max_bw(rate_sample);
bbr.data_rate_model.bound_bw_for_model();
let rate_sample = RateSample {
delivered_bytes: 10_000,
interval: Duration::from_millis(1),
is_app_limited: true,
..Default::default()
};
bbr.bw_estimator.set_rate_sample_for_test(rate_sample);
assert!(bbr.bw_estimator.rate_sample().is_app_limited);
assert!(bbr.bw_estimator.rate_sample().delivery_rate() < bbr.data_rate_model.max_bw());
assert!(!bbr.congestion_state.loss_in_round());
assert!(!bbr.congestion_state.ecn_in_round());
bbr.try_fast_path = false;
assert!(bbr.model_update_required());
bbr.try_fast_path = true;
assert!(!bbr.model_update_required());
let rate_sample = RateSample {
delivered_bytes: 10_000,
interval: Duration::from_millis(1),
is_app_limited: false,
..Default::default()
};
bbr.bw_estimator.set_rate_sample_for_test(rate_sample);
assert!(bbr.model_update_required());
let rate_sample = RateSample {
delivered_bytes: 10_000,
interval: Duration::from_millis(1),
is_app_limited: true,
..Default::default()
};
bbr.bw_estimator.set_rate_sample_for_test(rate_sample);
assert!(!bbr.model_update_required());
let rate_sample = RateSample {
delivered_bytes: 500_000,
interval: Duration::from_millis(1),
is_app_limited: true,
..Default::default()
};
bbr.bw_estimator.set_rate_sample_for_test(rate_sample);
assert!(bbr.bw_estimator.rate_sample().delivery_rate() >= bbr.data_rate_model.max_bw());
assert!(bbr.model_update_required());
let rate_sample = RateSample {
delivered_bytes: 10_000,
interval: Duration::from_millis(1),
is_app_limited: true,
..Default::default()
};
bbr.bw_estimator.set_rate_sample_for_test(rate_sample);
assert!(bbr.bw_estimator.rate_sample().delivery_rate() < bbr.data_rate_model.max_bw());
assert!(!bbr.model_update_required());
bbr.congestion_state.on_packet_lost(100, true);
assert!(bbr.model_update_required());
bbr.congestion_state.reset();
assert!(!bbr.model_update_required());
bbr.congestion_state.on_explicit_congestion();
assert!(bbr.model_update_required());
bbr.congestion_state.reset();
assert!(!bbr.model_update_required());
}
#[test]
fn control_update_required() {
let mut bbr = BbrCongestionController::new(MINIMUM_MAX_DATAGRAM_SIZE, Default::default());
let now = NoopClock.get_time();
bbr.try_fast_path = true;
let mut model_updated = false;
assert!(bbr.data_volume_model.min_rtt().is_none());
assert!(!bbr.control_update_required(model_updated, None));
bbr.try_fast_path = false;
assert!(bbr.control_update_required(model_updated, None));
bbr.try_fast_path = true;
assert!(!bbr.control_update_required(model_updated, None));
model_updated = true;
assert!(bbr.control_update_required(model_updated, None));
model_updated = false;
assert!(!bbr.control_update_required(model_updated, None));
assert!(bbr.control_update_required(model_updated, Some(Duration::from_millis(100))));
bbr.data_volume_model
.update_min_rtt(Duration::from_millis(100), now);
assert!(bbr.control_update_required(model_updated, None));
assert!(bbr.control_update_required(model_updated, Some(Duration::from_millis(200))));
assert!(!bbr.control_update_required(model_updated, Some(Duration::from_millis(100))));
}
#[test]
fn on_mtu_update_increase() {
let mut mtu = 5000;
let mut bbr = BbrCongestionController::new(mtu, Default::default());
let mut publisher = event::testing::Publisher::snapshot();
let mut publisher = PathPublisher::new(&mut publisher, path::Id::test_id());
bbr.cwnd = 100_000;
mtu = 10000;
bbr.on_mtu_update(mtu, &mut publisher);
assert_eq!(bbr.max_datagram_size, mtu);
assert_eq!(bbr.cwnd, 200_000);
}
#[test]
fn on_mtu_update_decrease_smaller_than_initial_window() {
let mut mtu = 9000;
let mut bbr = BbrCongestionController::new(mtu, Default::default());
let mut publisher = event::testing::Publisher::snapshot();
let mut publisher = PathPublisher::new(&mut publisher, path::Id::test_id());
bbr.cwnd = 18_000;
mtu = 1350;
bbr.on_mtu_update(mtu, &mut publisher);
assert_eq!(bbr.max_datagram_size, mtu);
assert_eq!(bbr.cwnd, 13_500);
}
#[test]
fn on_mtu_update_decrease_larger_than_initial_window() {
let mut mtu = 9000;
let mut bbr = BbrCongestionController::new(mtu, Default::default());
let mut publisher = event::testing::Publisher::snapshot();
let mut publisher = PathPublisher::new(&mut publisher, path::Id::test_id());
bbr.cwnd = 180_000;
mtu = 1350;
bbr.on_mtu_update(mtu, &mut publisher);
assert_eq!(bbr.max_datagram_size, mtu);
assert_eq!(bbr.cwnd, 27_000);
}
fn enter_probe_bw_state<Pub: Publisher>(
bbr: &mut BbrCongestionController,
cycle_phase: CyclePhase,
publisher: &mut Pub,
) {
let now = NoopClock.get_time();
match bbr.state {
State::Startup => {
bbr.enter_drain(publisher);
bbr.enter_probe_bw(
false,
&mut random::testing::Generator::default(),
now,
publisher,
);
}
State::Drain | State::ProbeRtt(_) => {
bbr.enter_probe_bw(
false,
&mut random::testing::Generator::default(),
now,
publisher,
);
}
State::ProbeBw(_) => {}
}
if let State::ProbeBw(ref mut probe_bw_state) = bbr.state {
probe_bw_state.set_cycle_phase_for_test(cycle_phase);
}
}