Skip to content

Commit 3f401b8

Browse files
committed
WIP add proptest for SendBuffer
1 parent a4a1c54 commit 3f401b8

File tree

1 file changed

+80
-1
lines changed

1 file changed

+80
-1
lines changed

quinn-proto/src/connection/send_buffer.rs

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,8 @@ impl SendBuffer {
261261
}
262262

263263
pub(super) fn retransmit_all_for_0rtt(&mut self) {
264-
debug_assert_eq!(self.offset(), self.data.len() as u64);
264+
// check that we still got all data - we didn't get any acks.
265+
debug_assert_eq!(self.data.range().start, 0);
265266
self.unsent = 0;
266267
}
267268

@@ -291,6 +292,10 @@ impl SendBuffer {
291292

292293
#[cfg(test)]
293294
mod tests {
295+
use test_strategy::{Arbitrary, proptest};
296+
use proptest::prelude::*;
297+
use rand::{SeedableRng, rngs::StdRng};
298+
294299
use super::*;
295300

296301
#[test]
@@ -501,6 +506,80 @@ mod tests {
501506
let mut buf = Vec::new();
502507
data.get_into(0..1, &mut buf);
503508
}
509+
510+
#[derive(Debug, Clone, Arbitrary)]
511+
enum Op {
512+
// write the given bytes
513+
Write(#[strategy(proptest::collection::vec(any::<u8>(), 0..1024))] Vec<u8>),
514+
// ack a random range, the value is the rng seed
515+
Ack(u64),
516+
// retransmit a random range, the value is the rng seed
517+
Retransmit(u64),
518+
// poll_transmit with the given max len
519+
PollTransmit(#[strategy(16usize..1024)] usize),
520+
}
521+
522+
fn random_range(seed: u64, range: Range<u64>) -> Range<u64> {
523+
if range.is_empty() {
524+
return range;
525+
}
526+
let mut rng = StdRng::seed_from_u64(seed);
527+
let a = rng.random_range(range.clone());
528+
let b = rng.random_range(range);
529+
if a < b { a..b } else { b..a }
530+
}
531+
532+
#[proptest]
533+
fn send_buffer_matches_reference(
534+
#[strategy(proptest::collection::vec(any::<Op>(), 1..100))] ops: Vec<Op>,
535+
) {
536+
let mut sb = SendBuffer::new();
537+
// total bytes written so far
538+
let mut total_bytes = 0u64;
539+
// max offset that has been returned by poll_transmit
540+
let mut max_send_offset = 0u64;
541+
// max offset up to which data has been fully acked
542+
let mut max_full_send_offset = 0u64;
543+
println!("");
544+
for op in ops {
545+
match op {
546+
Op::Write(data) => {
547+
total_bytes += data.len() as u64;
548+
println!("Writing {} bytes", data.len());
549+
sb.write(Bytes::from(data));
550+
}
551+
Op::Ack(seed) => {
552+
// only generate acks for data that has been sent
553+
let range = random_range(seed, 0..max_send_offset + 1);
554+
if range.is_empty() {
555+
continue;
556+
}
557+
// update fully acked range
558+
if range.contains(&max_full_send_offset) {
559+
max_full_send_offset = range.end;
560+
}
561+
println!("Acking range: {:?}", range);
562+
sb.ack(range);
563+
}
564+
Op::Retransmit(seed) => {
565+
let range = random_range(seed, max_full_send_offset..max_send_offset + 1);
566+
if range.is_empty() {
567+
continue;
568+
}
569+
println!("Retransmitting range: {:?}", range);
570+
sb.retransmit(range);
571+
}
572+
Op::PollTransmit(max_len) => {
573+
let (range, _partial) = sb.poll_transmit(max_len);
574+
max_send_offset = max_send_offset.max(range.end);
575+
let mut buf = Vec::new();
576+
println!("Getting data for range: {:?}", range);
577+
sb.get_into(range, &mut buf);
578+
}
579+
}
580+
581+
}
582+
}
504583
}
505584

506585
#[cfg(feature = "bench")]

0 commit comments

Comments
 (0)