in quic/s2n-quic-transport/src/recovery/manager/tests.rs [1591:1733]
fn detect_and_remove_lost_packets() {
let space = PacketNumberSpace::ApplicationData;
let mut manager = ServerManager::new(space);
let now = time::now();
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 random = &mut random::testing::Generator::default();
manager.largest_acked_packet = Some(space.new_packet_number(VarInt::from_u8(10)));
let mut time_sent = time::now();
let outcome = transmission::Outcome {
ack_elicitation: AckElicitation::Eliciting,
is_congestion_controlled: true,
bytes_sent: 1,
bytes_progressed: 0,
};
// Send a packet that was sent too long ago (lost)
let old_packet_time_sent = space.new_packet_number(VarInt::from_u8(0));
manager.on_packet_sent(
old_packet_time_sent,
outcome,
time_sent,
ecn,
transmission::Mode::Normal,
None,
&mut context,
&mut publisher,
);
// time threshold = max(kTimeThreshold * max(smoothed_rtt, latest_rtt), kGranularity)
// time threshold = max(9/8 * 8) = 9
context.path_mut().rtt_estimator.update_rtt(
Duration::from_secs(0),
Duration::from_secs(8),
now,
true,
space,
);
let expected_time_threshold = Duration::from_secs(9);
assert_eq!(
expected_time_threshold,
context.path().rtt_estimator.loss_time_threshold(),
);
time_sent += Duration::from_secs(10);
// Send a packet that was sent within the time threshold but is with a packet number
// K_PACKET_THRESHOLD away from the largest (lost)
let old_packet_packet_number =
space.new_packet_number(VarInt::new(10 - K_PACKET_THRESHOLD).unwrap());
manager.on_packet_sent(
old_packet_packet_number,
outcome,
time_sent,
ecn,
transmission::Mode::Normal,
None,
&mut context,
&mut publisher,
);
// Send a packet that is less than the largest acked but not lost
let not_lost = space.new_packet_number(VarInt::from_u8(9));
manager.on_packet_sent(
not_lost,
outcome,
time_sent,
ecn,
transmission::Mode::Normal,
None,
&mut context,
&mut publisher,
);
// Send a packet larger than the largest acked (not lost)
let larger_than_largest = manager.largest_acked_packet.unwrap().next().unwrap();
manager.on_packet_sent(
larger_than_largest,
outcome,
time_sent,
ecn,
transmission::Mode::Normal,
None,
&mut context,
&mut publisher,
);
// Four packets sent, each size 1 byte
let bytes_in_flight: u16 = manager
.sent_packets
.iter()
.map(|(_, info)| info.sent_bytes)
.sum();
assert_eq!(bytes_in_flight, 4);
let now = time_sent;
manager.detect_and_remove_lost_packets(now, random, &mut context, &mut publisher);
//= https://www.rfc-editor.org/rfc/rfc9002#section-6.1.2
//= type=test
//# Once a later packet within the same packet number space has been
//# acknowledged, an endpoint SHOULD declare an earlier packet lost if it
//# was sent a threshold amount of time in the past.
// Two packets lost, each size 1 byte
assert_eq!(context.path().congestion_controller.lost_bytes, 2);
// Two packets remaining
let bytes_in_flight: u16 = manager
.sent_packets
.iter()
.map(|(_, info)| info.sent_bytes)
.sum();
assert_eq!(bytes_in_flight, 2);
let sent_packets = &manager.sent_packets;
assert!(context.lost_packets.contains(&old_packet_time_sent));
assert!(sent_packets.get(old_packet_time_sent).is_none());
assert!(context.lost_packets.contains(&old_packet_packet_number));
assert!(sent_packets.get(old_packet_packet_number).is_none());
assert!(!context.lost_packets.contains(&larger_than_largest));
assert!(sent_packets.get(larger_than_largest).is_some());
assert!(!context.lost_packets.contains(¬_lost));
assert!(sent_packets.get(not_lost).is_some());
let expected_loss_time =
sent_packets.get(not_lost).unwrap().time_sent + expected_time_threshold;
//= https://www.rfc-editor.org/rfc/rfc9002#section-6.1.2
//= type=test
//# If packets sent prior to the largest acknowledged packet cannot yet
//# be declared lost, then a timer SHOULD be set for the remaining time.
assert!(manager.loss_timer.is_armed());
assert_eq!(
Some(expected_loss_time),
manager.loss_timer.next_expiration()
);
}