in quic/s2n-quic-transport/src/recovery/manager/tests.rs [2191:2366]
fn persistent_congestion() {
//= https://www.rfc-editor.org/rfc/rfc9002#section-7.6.2
//= type=test
//# A sender that does not have state for all packet
//# number spaces or an implementation that cannot compare send times
//# across packet number spaces MAY use state for just the packet number
//# space that was acknowledged.
let space = PacketNumberSpace::ApplicationData;
let mut manager = ServerManager::new(space);
let mut path_manager = helper_generate_path_manager(Duration::from_millis(10));
let ecn = ExplicitCongestionNotification::default();
let mut context = MockContext::new(&mut path_manager);
let mut publisher = Publisher::snapshot();
let time_zero = time::now() + Duration::from_secs(10);
// The RFC doesn't mention it, but it is implied that the first RTT sample has already
// been received when this example begins, otherwise packet #2 would not be considered
// part of the persistent congestion period.
context.path_mut().rtt_estimator.update_rtt(
Duration::from_millis(10),
Duration::from_millis(600),
time::now(),
true,
space,
);
let mut outcome = transmission::Outcome {
ack_elicitation: AckElicitation::Eliciting,
is_congestion_controlled: true,
bytes_sent: 1,
bytes_progressed: 0,
};
// t=0: Send packet #1 (app data)
manager.on_packet_sent(
space.new_packet_number(VarInt::from_u8(1)),
outcome,
time_zero,
ecn,
transmission::Mode::Normal,
None,
&mut context,
&mut publisher,
);
// t=1: Send packet #2 (app data)
manager.on_packet_sent(
space.new_packet_number(VarInt::from_u8(2)),
outcome,
time_zero + Duration::from_secs(1),
ecn,
transmission::Mode::Normal,
None,
&mut context,
&mut publisher,
);
// t=1.2: Recv acknowledgement of #1
ack_packets(
1..=1,
time_zero + Duration::from_millis(1200),
&mut context,
&mut manager,
None,
&mut publisher,
);
// t=2-6: Send packets #3 - #7 (app data)
// These packets are NonEliciting, which are allowed to be part of a Persistent Congestion Period
// as long as they are not the start or end of the period.
outcome.ack_elicitation = AckElicitation::NonEliciting;
for t in 2..=6 {
manager.on_packet_sent(
space.new_packet_number(VarInt::from_u8(t + 1)),
outcome,
time_zero + Duration::from_secs(t.into()),
ecn,
transmission::Mode::Normal,
None,
&mut context,
&mut publisher,
);
}
outcome.ack_elicitation = AckElicitation::Eliciting;
// t=8: Send packet #8 (PTO 1)
manager.on_packet_sent(
space.new_packet_number(VarInt::from_u8(8)),
outcome,
time_zero + Duration::from_secs(8),
ecn,
transmission::Mode::Normal,
None,
&mut context,
&mut publisher,
);
// t=12: Send packet #9 (PTO 2)
manager.on_packet_sent(
space.new_packet_number(VarInt::from_u8(9)),
outcome,
time_zero + Duration::from_secs(12),
ecn,
transmission::Mode::Normal,
None,
&mut context,
&mut publisher,
);
// t=12.2: Recv acknowledgement of #9
ack_packets(
9..=9,
time_zero + Duration::from_millis(12200),
&mut context,
&mut manager,
None,
&mut publisher,
);
//= https://www.rfc-editor.org/rfc/rfc9002#section-7.6.3
//# Packets 2 through 8 are declared lost when the acknowledgment for
//# packet 9 is received at "t = 12.2".
assert_eq!(7, context.on_packet_loss_count);
//= https://www.rfc-editor.org/rfc/rfc9002#section-7.6.3
//# The congestion period is calculated as the time between the oldest
//# and newest lost packets: "8 - 1 = 7".
assert!(
context
.path()
.rtt_estimator
.persistent_congestion_threshold()
< Duration::from_secs(7)
);
assert_eq!(
Some(true),
context.path().congestion_controller.persistent_congestion
);
assert_eq!(context.path().rtt_estimator.first_rtt_sample(), None);
assert_eq!(1, context.path().congestion_controller.loss_bursts);
// t=20: Send packet #10
manager.on_packet_sent(
space.new_packet_number(VarInt::from_u8(10)),
outcome,
time_zero + Duration::from_secs(20),
ecn,
transmission::Mode::Normal,
None,
&mut context,
&mut publisher,
);
// t=21: Recv acknowledgement of #10
ack_packets(
10..=10,
time_zero + Duration::from_secs(21),
&mut context,
&mut manager,
None,
&mut publisher,
);
//= https://www.rfc-editor.org/rfc/rfc9002#section-5.2
//= type=test
//# Endpoints SHOULD set the min_rtt to the newest RTT sample after
//# persistent congestion is established.
assert_eq!(
context.path().rtt_estimator.min_rtt(),
Duration::from_secs(1)
);
assert_eq!(
context.path().rtt_estimator.smoothed_rtt(),
Duration::from_secs(1)
);
}