use super::{testing::*, *};
use crate::{
endpoint,
event::testing::Publisher,
frame::Frame,
inet::{IpV4Address, SocketAddressV4},
packet::number::PacketNumberSpace,
path::{mtu, mtu::Manager},
recovery::congestion_controller::testing::mock::CongestionController,
time::{clock::testing::now, timer::Provider as _},
transmission::{
writer::{
testing::{OutgoingFrameBuffer, Writer as MockWriteContext},
Writer as _,
},
Provider as _,
},
varint::VarInt,
};
use std::{convert::TryInto, net::SocketAddr};
fn pn(nr: usize) -> PacketNumber {
PacketNumberSpace::ApplicationData.new_packet_number(VarInt::new(nr as u64).unwrap())
}
#[test]
fn mtu_config_is_valid() {
let config = Config {
initial_mtu: 1500.try_into().unwrap(),
base_mtu: 1228.try_into().unwrap(),
max_mtu: 9000.try_into().unwrap(),
};
assert!(config.is_valid());
let config = Config {
initial_mtu: 1500.try_into().unwrap(),
base_mtu: 1500.try_into().unwrap(),
max_mtu: 1500.try_into().unwrap(),
};
assert!(config.is_valid());
let config = Config {
initial_mtu: 1500.try_into().unwrap(),
base_mtu: 1501.try_into().unwrap(),
max_mtu: 9000.try_into().unwrap(),
};
assert!(!config.is_valid());
let config = mtu::Config {
initial_mtu: 1500.try_into().unwrap(),
base_mtu: 1228.try_into().unwrap(),
max_mtu: 1400.try_into().unwrap(),
};
assert!(!config.is_valid());
}
#[test]
fn mtu_config_builder() {
assert!(mtu::Config::builder().build().unwrap().is_valid());
let builder = mtu::Config::builder();
let builder = builder.with_base_mtu(1300).unwrap();
let config = builder.build().unwrap();
assert_eq!(1300_u16, u16::from(config.base_mtu));
assert_eq!(1300_u16, u16::from(config.initial_mtu));
let builder = mtu::Config::builder();
let result = builder
.with_base_mtu(DEFAULT_MAX_MTU.0.get() + 1_u16)
.unwrap()
.build();
assert_eq!(Some(MtuError), result.err());
let builder = mtu::Config::builder();
let result = builder
.with_initial_mtu(DEFAULT_MAX_MTU.0.get() + 1_u16)
.unwrap()
.build();
assert_eq!(Some(MtuError), result.err());
let builder = mtu::Config::builder();
let result = builder.with_initial_mtu(1300).unwrap().with_base_mtu(1301);
assert_eq!(Some(MtuError), result.err());
let builder = mtu::Config::builder();
let result = builder.with_initial_mtu(1300).unwrap().with_max_mtu(1299);
assert_eq!(Some(MtuError), result.err());
let builder = mtu::Config::builder();
let result = builder.with_base_mtu(1300).unwrap().with_initial_mtu(1299);
assert_eq!(Some(MtuError), result.err());
let builder = mtu::Config::builder();
let result = builder.with_max_mtu(1300).unwrap().with_initial_mtu(1301);
assert_eq!(Some(MtuError), result.err());
let builder = mtu::Config::builder();
let result = builder.with_max_mtu(1300).unwrap().with_base_mtu(1301);
assert_eq!(Some(MtuError), result.err());
let builder = mtu::Config::builder();
let result = builder.with_base_mtu(1300).unwrap().with_max_mtu(1299);
assert_eq!(Some(MtuError), result.err());
}
#[test]
fn mtu_manager() {
let remote = inet::SocketAddress::default();
let endpoint_config = mtu::Config::builder().build().unwrap();
assert!(endpoint_config.is_valid());
let mtu_provider = mtu::Config::builder().build().unwrap();
assert!(mtu_provider.is_valid());
let mut manager: Manager<Config> = Manager::new(mtu_provider);
manager.config(&remote).unwrap();
let mtu_provider = mtu::Config::builder()
.with_max_mtu(DEFAULT_MAX_MTU.into())
.unwrap()
.build()
.unwrap();
assert!(mtu_provider.is_valid());
let mut manager: Manager<Config> = Manager::new(mtu_provider);
manager.config(&remote).unwrap();
let mtu_provider = mtu::Config {
initial_mtu: InitialMtu::MIN,
base_mtu: BaseMtu(NonZeroU16::new(1500).unwrap()),
max_mtu: MaxMtu::MIN,
};
assert!(!mtu_provider.is_valid());
let mut manager: Manager<Config> = Manager::new(mtu_provider);
assert_eq!(manager.config(&remote).unwrap_err(), MtuError);
let mtu_provider = mtu::Config::builder()
.with_max_mtu(1501)
.unwrap()
.build()
.unwrap();
assert!(mtu_provider.is_valid());
let mut manager: Manager<Config> = Manager::new(mtu_provider);
assert_eq!(manager.config(&remote).unwrap_err(), MtuError);
}
#[test]
fn base_plpmtu_is_1200() {
let ip = IpV4Address::new([127, 0, 0, 1]);
let addr = inet::SocketAddress::IpV4(SocketAddressV4::new(ip, 443));
let controller = Controller::new(Config::default(), &addr);
assert_eq!(controller.base_plpmtu, 1200);
}
#[test]
fn min_max_mtu() {
let addr: SocketAddr = "[::1]:123".parse().unwrap();
let controller = Controller::new(
Config {
max_mtu: MaxMtu::MIN,
..Default::default()
},
&addr.into(),
);
assert_eq!(MINIMUM_MAX_DATAGRAM_SIZE, controller.plpmtu);
assert_eq!(MINIMUM_MAX_DATAGRAM_SIZE, controller.base_plpmtu);
assert!(controller.is_search_completed());
}
#[test]
fn new_max_mtu_smaller_than_common_mtu() {
let max_mtu = MINIMUM_MAX_DATAGRAM_SIZE + UDP_HEADER_LEN + IPV4_MIN_HEADER_LEN + 1;
let mut controller = new_controller(max_mtu);
assert_eq!(MINIMUM_MAX_DATAGRAM_SIZE + 1, controller.probed_size);
assert_eq!(MINIMUM_MAX_DATAGRAM_SIZE, controller.base_plpmtu);
controller.enable();
assert_eq!(State::SearchComplete, controller.state);
}
#[test]
fn new_ipv4() {
let addr: SocketAddr = "127.0.0.1:443".parse().unwrap();
let controller = Controller::new(
Config {
max_mtu: 1600.try_into().unwrap(),
..Default::default()
},
&addr.into(),
);
assert_eq!(MINIMUM_MAX_DATAGRAM_SIZE, controller.base_plpmtu);
assert_eq!(
1600 - UDP_HEADER_LEN - IPV4_MIN_HEADER_LEN,
controller.max_udp_payload
);
assert_eq!(
1600 - UDP_HEADER_LEN - IPV4_MIN_HEADER_LEN,
controller.max_probe_size
);
assert_eq!(
MINIMUM_MAX_DATAGRAM_SIZE as usize,
controller.max_datagram_size()
);
assert_eq!(0, controller.probe_count);
assert_eq!(State::Disabled, controller.state);
assert!(!controller.pmtu_raise_timer.is_armed());
assert_eq!(
ETHERNET_MTU - UDP_HEADER_LEN - IPV4_MIN_HEADER_LEN,
controller.probed_size
);
}
#[test]
fn new_ipv6() {
let addr: SocketAddr = "[2001:0db8:85a3:0001:0002:8a2e:0370:7334]:9000"
.parse()
.unwrap();
let controller = Controller::new(
Config {
max_mtu: 2000.try_into().unwrap(),
..Default::default()
},
&addr.into(),
);
assert_eq!(MINIMUM_MAX_DATAGRAM_SIZE, controller.base_plpmtu);
assert_eq!(
2000 - UDP_HEADER_LEN - IPV6_MIN_HEADER_LEN,
controller.max_udp_payload
);
assert_eq!(
2000 - UDP_HEADER_LEN - IPV6_MIN_HEADER_LEN,
controller.max_probe_size
);
assert_eq!(
MINIMUM_MAX_DATAGRAM_SIZE as usize,
controller.max_datagram_size()
);
assert_eq!(0, controller.probe_count);
assert_eq!(State::Disabled, controller.state);
assert!(!controller.pmtu_raise_timer.is_armed());
assert_eq!(
ETHERNET_MTU - UDP_HEADER_LEN - IPV6_MIN_HEADER_LEN,
controller.probed_size
);
}
#[test]
fn new_initial_and_base_mtu() {
let addr: SocketAddr = "127.0.0.1:443".parse().unwrap();
let mut controller = Controller::new(
Config {
max_mtu: 2600.try_into().unwrap(),
base_mtu: 1400.try_into().unwrap(),
initial_mtu: 2500.try_into().unwrap(),
},
&addr.into(),
);
assert_eq!(
2600 - UDP_HEADER_LEN - IPV4_MIN_HEADER_LEN,
controller.max_udp_payload
);
assert_eq!(
2600 - UDP_HEADER_LEN - IPV4_MIN_HEADER_LEN,
controller.max_probe_size
);
assert_eq!(
1400 - UDP_HEADER_LEN - IPV4_MIN_HEADER_LEN,
controller.base_plpmtu
);
assert_eq!(
2500 - UDP_HEADER_LEN - IPV4_MIN_HEADER_LEN,
controller.plpmtu
);
assert_eq!(
(2500 - UDP_HEADER_LEN - IPV4_MIN_HEADER_LEN) as usize,
controller.max_datagram_size()
);
assert_eq!(0, controller.probe_count);
assert_eq!(State::EarlySearchRequested, controller.state);
assert!(!controller.pmtu_raise_timer.is_armed());
assert_eq!(
2550 - UDP_HEADER_LEN - IPV4_MIN_HEADER_LEN,
controller.probed_size
);
controller.enable();
assert!(matches!(controller.state, State::SearchRequested));
}
#[test]
fn new_initial_mtu_less_than_ethernet_mtu() {
let addr: SocketAddr = "127.0.0.1:443".parse().unwrap();
let mut controller = Controller::new(
Config {
max_mtu: 9000.try_into().unwrap(),
initial_mtu: 1400.try_into().unwrap(),
..Default::default()
},
&addr.into(),
);
assert_eq!(
ETHERNET_MTU - UDP_HEADER_LEN - IPV4_MIN_HEADER_LEN,
controller.probed_size
);
controller.enable();
assert!(matches!(controller.state, State::SearchRequested));
}
#[test]
fn new_initial_mtu_equal_to_ethernet_mtu() {
let addr: SocketAddr = "127.0.0.1:443".parse().unwrap();
let mut controller = Controller::new(
Config {
max_mtu: 9000.try_into().unwrap(),
initial_mtu: ETHERNET_MTU.try_into().unwrap(),
..Default::default()
},
&addr.into(),
);
assert_eq!(
1500 + (9000 - 1500) / 2 - UDP_HEADER_LEN - IPV4_MIN_HEADER_LEN,
controller.probed_size
);
controller.enable();
assert!(matches!(controller.state, State::SearchRequested));
}
#[test]
fn enable_already_enabled() {
let mut controller = new_controller(1500);
assert_eq!(State::Disabled, controller.state);
controller.enable();
assert_eq!(State::SearchRequested, controller.state);
controller.state = State::SearchComplete;
controller.enable();
assert_eq!(State::SearchComplete, controller.state);
}
#[test]
fn enable() {
let mut controller = new_controller(1500);
assert_eq!(State::Disabled, controller.state);
controller.enable();
assert_eq!(State::SearchRequested, controller.state);
}
#[test]
fn on_packet_ack_within_threshold() {
let mut controller = new_controller(1472 + PROBE_THRESHOLD * 2);
let max_udp_payload = controller.max_udp_payload;
let pn = pn(1);
let mut cc = CongestionController::default();
let now = now();
let mut publisher = Publisher::snapshot();
controller.state = State::Searching(pn, now);
controller.probed_size = MINIMUM_MAX_DATAGRAM_SIZE;
controller.max_probe_size = MINIMUM_MAX_DATAGRAM_SIZE + PROBE_THRESHOLD * 2 - 1;
let result = controller.on_packet_ack(
pn,
MINIMUM_MAX_DATAGRAM_SIZE,
&mut cc,
path::Id::test_id(),
&mut publisher,
);
assert_eq!(MtuResult::MtuUpdated(MINIMUM_MAX_DATAGRAM_SIZE), result);
assert_eq!(
MINIMUM_MAX_DATAGRAM_SIZE + (max_udp_payload - MINIMUM_MAX_DATAGRAM_SIZE) / 2,
controller.probed_size
);
assert_eq!(1, cc.on_mtu_update);
assert_eq!(State::SearchComplete, controller.state);
assert!(controller.pmtu_raise_timer.is_armed());
assert_eq!(
Some(now + PMTU_RAISE_TIMER_DURATION),
controller.next_expiration()
);
assert!(controller.is_search_completed());
let now = now + PMTU_RAISE_TIMER_DURATION;
controller.on_timeout(now);
assert_eq!(State::SearchRequested, controller.state);
assert_eq!(
MINIMUM_MAX_DATAGRAM_SIZE + (max_udp_payload - MINIMUM_MAX_DATAGRAM_SIZE) / 2,
controller.probed_size
);
assert!(!controller.is_search_completed());
}
#[test]
fn on_packet_ack_within_threshold_of_max_plpmtu() {
let mut controller = new_controller(1472 + (PROBE_THRESHOLD * 2 - 1));
let max_udp_payload = controller.max_udp_payload;
let pn = pn(1);
let mut cc = CongestionController::default();
let now = now();
let mut publisher = Publisher::snapshot();
controller.state = State::Searching(pn, now);
let probed_sized = controller.probed_size;
let result = controller.on_packet_ack(
pn,
probed_sized,
&mut cc,
path::Id::test_id(),
&mut publisher,
);
assert_eq!(MtuResult::MtuUpdated(probed_sized), result);
assert_eq!(1472 + (max_udp_payload - 1472) / 2, controller.probed_size);
assert_eq!(1, cc.on_mtu_update);
assert_eq!(State::SearchComplete, controller.state);
assert!(!controller.pmtu_raise_timer.is_armed());
assert!(controller.is_search_completed());
}
#[test]
fn on_packet_ack_search_requested() {
let mut controller = new_controller(1500 + (PROBE_THRESHOLD * 2));
let max_udp_payload = controller.max_udp_payload;
let pn = pn(1);
let mut cc = CongestionController::default();
let now = now();
let mut publisher = Publisher::snapshot();
controller.state = State::Searching(pn, now);
let probed_size = controller.probed_size;
let result = controller.on_packet_ack(
pn,
probed_size,
&mut cc,
path::Id::test_id(),
&mut publisher,
);
assert_eq!(MtuResult::MtuUpdated(probed_size), result);
assert_eq!(1472 + (max_udp_payload - 1472) / 2, controller.probed_size);
assert_eq!(1, cc.on_mtu_update);
assert_eq!(State::SearchRequested, controller.state);
assert!(!controller.pmtu_raise_timer.is_armed());
assert!(!controller.is_search_completed());
}
#[test]
fn on_packet_ack_resets_black_hole_counter() {
let mut controller = new_controller(1500 + (PROBE_THRESHOLD * 2));
let pnum = pn(3);
let mut cc = CongestionController::default();
let mut publisher = Publisher::snapshot();
controller.enable();
controller.black_hole_counter += 1;
let result = controller.on_packet_ack(
pnum,
controller.plpmtu - 1,
&mut cc,
path::Id::test_id(),
&mut publisher,
);
assert_eq!(MtuResult::NoChange, result);
assert_eq!(controller.black_hole_counter, 1);
assert_eq!(None, controller.largest_acked_mtu_sized_packet);
let result = controller.on_packet_ack(
pnum,
controller.plpmtu,
&mut cc,
path::Id::test_id(),
&mut publisher,
);
assert_eq!(MtuResult::NoChange, result);
assert_eq!(controller.black_hole_counter, 0);
assert_eq!(Some(pnum), controller.largest_acked_mtu_sized_packet);
controller.black_hole_counter += 1;
let pnum_2 = pn(2);
let result = controller.on_packet_ack(
pnum_2,
controller.plpmtu,
&mut cc,
path::Id::test_id(),
&mut publisher,
);
assert_eq!(MtuResult::NoChange, result);
assert_eq!(controller.black_hole_counter, 1);
assert_eq!(Some(pnum), controller.largest_acked_mtu_sized_packet);
}
#[test]
fn on_packet_ack_disabled_controller() {
let mut controller = new_controller(1500 + (PROBE_THRESHOLD * 2));
let pnum = pn(3);
let mut cc = CongestionController::default();
let mut publisher = Publisher::snapshot();
controller.black_hole_counter += 1;
controller.largest_acked_mtu_sized_packet = Some(pnum);
let pn = pn(10);
let result = controller.on_packet_ack(
pn,
controller.plpmtu,
&mut cc,
path::Id::test_id(),
&mut publisher,
);
assert_eq!(MtuResult::NoChange, result);
assert_eq!(State::Disabled, controller.state);
assert_eq!(controller.black_hole_counter, 1);
assert_eq!(Some(pnum), controller.largest_acked_mtu_sized_packet);
}
#[test]
fn on_packet_ack_not_application_space() {
let mut controller = new_controller(1500 + (PROBE_THRESHOLD * 2));
let pnum = pn(3);
let mut cc = CongestionController::default();
let mut publisher = Publisher::snapshot();
controller.enable();
controller.black_hole_counter += 1;
controller.largest_acked_mtu_sized_packet = Some(pnum);
let pn = PacketNumberSpace::Handshake.new_packet_number(VarInt::from_u8(10));
let result = controller.on_packet_ack(
pn,
controller.plpmtu,
&mut cc,
path::Id::test_id(),
&mut publisher,
);
assert_eq!(MtuResult::NoChange, result);
assert_eq!(controller.black_hole_counter, 1);
assert_eq!(Some(pnum), controller.largest_acked_mtu_sized_packet);
}
#[test]
fn on_packet_loss() {
let mut controller = new_controller(1500);
let max_udp_payload = controller.max_udp_payload;
let pn = pn(1);
let mut cc = CongestionController::default();
let now = now();
let mut publisher = Publisher::snapshot();
controller.state = State::Searching(pn, now);
let probed_size = controller.probed_size;
let result = controller.on_packet_loss(
pn,
controller.probed_size,
false,
now,
&mut cc,
path::Id::test_id(),
&mut publisher,
);
assert_eq!(MtuResult::NoChange, result);
assert_eq!(0, cc.on_mtu_update);
assert_eq!(max_udp_payload, controller.max_probe_size);
assert_eq!(probed_size, controller.probed_size);
assert_eq!(State::SearchRequested, controller.state);
}
#[test]
fn on_packet_loss_max_probes() {
let mut controller = new_controller(1500);
let max_udp_payload = controller.max_udp_payload;
let pn = pn(1);
let mut cc = CongestionController::default();
let now = now();
let mut publisher = Publisher::snapshot();
controller.state = State::Searching(pn, now);
controller.probe_count = MAX_PROBES;
assert_eq!(max_udp_payload, controller.max_probe_size);
let result = controller.on_packet_loss(
pn,
controller.probed_size,
false,
now,
&mut cc,
path::Id::test_id(),
&mut publisher,
);
assert_eq!(MtuResult::NoChange, result);
assert_eq!(0, cc.on_mtu_update);
assert_eq!(1472, controller.max_probe_size);
assert_eq!(
MINIMUM_MAX_DATAGRAM_SIZE + (1472 - MINIMUM_MAX_DATAGRAM_SIZE) / 2,
controller.probed_size
);
assert_eq!(State::SearchRequested, controller.state);
}
#[test]
fn on_packet_loss_black_hole() {
let mut controller = new_controller(1500);
let mut cc = CongestionController::default();
let now = now();
let mut publisher = Publisher::snapshot();
controller.plpmtu = 1472;
controller.enable();
let base_plpmtu = controller.base_plpmtu;
for i in 0..BLACK_HOLE_THRESHOLD + 1 {
let pn = pn(i as usize);
let result = controller.on_packet_loss(
pn,
base_plpmtu,
true,
now,
&mut cc,
path::Id::test_id(),
&mut publisher,
);
assert_eq!(MtuResult::NoChange, result);
assert_eq!(controller.black_hole_counter, i);
let result = controller.on_packet_loss(
pn,
controller.plpmtu + 1,
true,
now,
&mut cc,
path::Id::test_id(),
&mut publisher,
);
assert_eq!(MtuResult::NoChange, result);
assert_eq!(controller.black_hole_counter, i);
let result = controller.on_packet_loss(
pn,
base_plpmtu + 1,
false,
now,
&mut cc,
path::Id::test_id(),
&mut publisher,
);
assert_eq!(MtuResult::NoChange, result);
assert_eq!(controller.black_hole_counter, i);
let result = controller.on_packet_loss(
pn,
base_plpmtu + 1,
true,
now,
&mut cc,
path::Id::test_id(),
&mut publisher,
);
if i < BLACK_HOLE_THRESHOLD {
assert_eq!(MtuResult::NoChange, result);
assert_eq!(controller.black_hole_counter, i + 1);
} else {
assert_eq!(MtuResult::MtuUpdated(MINIMUM_MAX_DATAGRAM_SIZE), result);
}
}
assert_eq!(controller.black_hole_counter, 0);
assert_eq!(None, controller.largest_acked_mtu_sized_packet);
assert_eq!(1, cc.on_mtu_update);
assert_eq!(base_plpmtu, controller.plpmtu);
assert_eq!(State::SearchComplete, controller.state);
assert_eq!(
Some(now + BLACK_HOLE_COOL_OFF_DURATION),
controller.pmtu_raise_timer.next_expiration()
);
assert!(controller.is_search_completed());
}
#[test]
fn on_packet_loss_disabled_controller() {
let mut controller = new_controller(1500);
let mut cc = CongestionController::default();
let now = now();
let mut publisher = Publisher::snapshot();
let base_plpmtu = controller.base_plpmtu;
for i in 0..BLACK_HOLE_THRESHOLD + 1 {
let pn = pn(i as usize);
assert_eq!(controller.black_hole_counter, 0);
let result = controller.on_packet_loss(
pn,
base_plpmtu + 1,
false,
now,
&mut cc,
path::Id::test_id(),
&mut publisher,
);
assert_eq!(MtuResult::NoChange, result);
}
assert_eq!(State::Disabled, controller.state);
assert_eq!(controller.black_hole_counter, 0);
assert_eq!(0, cc.on_mtu_update);
}
#[test]
fn on_packet_loss_not_application_space() {
let mut controller = new_controller(1500);
let mut cc = CongestionController::default();
let mut publisher = Publisher::snapshot();
let base_plpmtu = controller.base_plpmtu;
for state in [
State::Disabled,
State::SearchRequested,
State::Searching(pn(1), now()),
State::SearchComplete,
] {
controller.state = state;
for i in 0..BLACK_HOLE_THRESHOLD + 1 {
let pn = PacketNumberSpace::Initial.new_packet_number(VarInt::from_u8(i));
let result = controller.on_packet_loss(
pn,
base_plpmtu + 1,
false,
now(),
&mut cc,
path::Id::test_id(),
&mut publisher,
);
assert_eq!(MtuResult::NoChange, result);
assert_eq!(controller.black_hole_counter, 0);
assert_eq!(0, cc.on_mtu_update);
}
}
}
#[test]
fn on_packet_loss_initial_mtu_configured() {
let ip = IpV4Address::new([127, 0, 0, 1]);
let addr = inet::SocketAddress::IpV4(SocketAddressV4::new(ip, 443));
let mut publisher = Publisher::snapshot();
for max_mtu in [
MINIMUM_MTU,
MINIMUM_MTU + 10,
1300,
1450,
1500,
1520,
4000,
9000,
] {
for initial_mtu in [
MINIMUM_MTU,
MINIMUM_MTU + 10,
1300,
1450,
1500,
1520,
4000,
9000,
] {
for base_mtu in [
MINIMUM_MTU,
MINIMUM_MTU + 10,
1300,
1450,
1500,
1520,
4000,
9000,
] {
let mtu_config = Config {
max_mtu: max_mtu.try_into().unwrap(),
initial_mtu: initial_mtu.min(max_mtu).try_into().unwrap(),
base_mtu: base_mtu.min(initial_mtu).min(max_mtu).try_into().unwrap(),
};
let mut controller = Controller::new(mtu_config, &addr);
let base_plpmtu = controller.base_plpmtu;
let original_plpmtu = controller.plpmtu;
let pn = pn(1);
let mut cc = CongestionController::default();
let now = now();
let result = controller.on_packet_loss(
pn,
original_plpmtu,
false,
now,
&mut cc,
path::Id::test_id(),
&mut publisher,
);
if original_plpmtu > base_plpmtu {
assert_eq!(MtuResult::MtuUpdated(base_plpmtu), result);
assert_eq!(
1, cc.on_mtu_update,
"base {base_plpmtu} init {initial_mtu} max {max_mtu} original_plpmtu {original_plpmtu}, base_plpmtu {base_plpmtu}"
);
assert_eq!(base_plpmtu, controller.plpmtu);
} else {
assert_eq!(MtuResult::NoChange, result);
assert_eq!(0, cc.on_mtu_update);
assert_eq!(original_plpmtu, controller.plpmtu);
}
if controller.probed_sized() - controller.max_datagram_size()
< PROBE_THRESHOLD as usize
{
assert_eq!(State::SearchComplete, controller.state);
assert!(controller.is_search_completed());
} else {
assert_eq!(State::Disabled, controller.state);
}
}
}
}
}
#[test]
fn on_transmit_probe_search_not_requested() {
let mut controller = new_controller(1500);
controller.state = State::SearchComplete;
let mut frame_buffer = OutgoingFrameBuffer::new();
let mut write_context = MockWriteContext::new(
now(),
&mut frame_buffer,
transmission::Constraint::None,
transmission::Mode::MtuProbing,
endpoint::Type::Server,
);
controller.on_transmit_probe(&mut write_context);
assert!(frame_buffer.is_empty());
assert_eq!(State::SearchComplete, controller.state);
}
#[test]
fn on_transmit_not_mtu_probing() {
let mut controller = new_controller(1500);
controller.state = State::SearchRequested;
let mut frame_buffer = OutgoingFrameBuffer::new();
let mut write_context = MockWriteContext::new(
now(),
&mut frame_buffer,
transmission::Constraint::None,
transmission::Mode::Normal,
endpoint::Type::Server,
);
controller.on_transmit(&mut write_context);
assert!(frame_buffer.is_empty());
assert_eq!(State::SearchRequested, controller.state);
controller.state = State::SearchComplete;
let mut frame_buffer = OutgoingFrameBuffer::new();
let mut write_context = MockWriteContext::new(
now(),
&mut frame_buffer,
transmission::Constraint::None,
transmission::Mode::Normal,
endpoint::Type::Server,
);
controller.on_transmit(&mut write_context);
assert!(frame_buffer.is_empty());
assert_eq!(State::SearchComplete, controller.state);
}
#[test]
fn on_transmit_mtu_probing_complete_in_normal_mode() {
let mut controller = new_controller(1500);
controller.state = State::SearchComplete;
controller.needs_to_send_completion = true;
controller.plpmtu = 1472;
let mut frame_buffer = OutgoingFrameBuffer::new();
let mut write_context = MockWriteContext::new(
now(),
&mut frame_buffer,
transmission::Constraint::None,
transmission::Mode::Normal,
endpoint::Type::Server,
);
controller.on_transmit(&mut write_context);
assert_eq!(
Frame::MtuProbingComplete(frame::MtuProbingComplete::new(1472)),
write_context.frame_buffer.pop_front().unwrap().as_frame()
);
assert!(!controller.needs_to_send_completion);
assert_eq!(State::SearchComplete, controller.state);
}
#[test]
fn on_transmit_ignored_in_mtu_probing_mode() {
let mut controller = new_controller(1500);
controller.state = State::SearchComplete;
controller.needs_to_send_completion = true;
controller.plpmtu = 1472;
let mut frame_buffer = OutgoingFrameBuffer::new();
let mut write_context = MockWriteContext::new(
now(),
&mut frame_buffer,
transmission::Constraint::None,
transmission::Mode::MtuProbing,
endpoint::Type::Server,
);
controller.on_transmit(&mut write_context);
assert!(write_context.frame_buffer.is_empty());
assert!(controller.needs_to_send_completion);
}
#[test]
fn on_transmit_probe_no_capacity() {
let mut controller = new_controller(1500);
controller.state = State::SearchRequested;
let mut frame_buffer = OutgoingFrameBuffer::new();
frame_buffer.set_max_packet_size(Some(controller.probed_size as usize - 1));
let mut write_context = MockWriteContext::new(
now(),
&mut frame_buffer,
transmission::Constraint::None,
transmission::Mode::MtuProbing,
endpoint::Type::Server,
);
controller.on_transmit_probe(&mut write_context);
assert!(frame_buffer.is_empty());
assert_eq!(State::SearchComplete, controller.state);
}
#[test]
fn on_transmit_probe() {
let mut controller = new_controller(1500);
controller.state = State::SearchRequested;
let now = now();
let mut frame_buffer = OutgoingFrameBuffer::new();
frame_buffer.set_max_packet_size(Some(controller.probed_size as usize));
let mut write_context = MockWriteContext::new(
now,
&mut frame_buffer,
transmission::Constraint::None,
transmission::Mode::MtuProbing,
endpoint::Type::Server,
);
let packet_number = write_context.packet_number();
controller.on_transmit_probe(&mut write_context);
assert_eq!(0, write_context.remaining_capacity());
assert_eq!(
Frame::Ping(frame::Ping),
write_context.frame_buffer.pop_front().unwrap().as_frame()
);
assert_eq!(
Frame::Padding(frame::Padding {
length: controller.probed_size as usize - 1
}),
write_context.frame_buffer.pop_front().unwrap().as_frame()
);
assert!(write_context.frame_buffer.is_empty());
assert_eq!(State::Searching(packet_number, now), controller.state);
}