gfe-relnote: (n/a) Add unit tests for quic::MaxAckHeightTracker. Test only. PiperOrigin-RevId: 272305887 Change-Id: I099e8b16d765c52e2e8c893c95911bce0f6e40c7
diff --git a/quic/core/congestion_control/bandwidth_sampler_test.cc b/quic/core/congestion_control/bandwidth_sampler_test.cc index aeff976..558971a 100644 --- a/quic/core/congestion_control/bandwidth_sampler_test.cc +++ b/quic/core/congestion_control/bandwidth_sampler_test.cc
@@ -4,6 +4,8 @@ #include "net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler.h" +#include "net/third_party/quiche/src/quic/core/quic_bandwidth.h" +#include "net/third_party/quiche/src/quic/core/quic_time.h" #include "net/third_party/quiche/src/quic/core/quic_types.h" #include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" @@ -462,5 +464,132 @@ EXPECT_EQ(0u, BandwidthSamplerPeer::GetNumberOfTrackedPackets(sampler_)); } +class MaxAckHeightTrackerTest : public QuicTest { + protected: + MaxAckHeightTrackerTest() : tracker_(/*initial_filter_window=*/10) {} + + // Run a full aggregation episode, which is one or more aggregated acks, + // followed by a quiet period in which no ack happens. + // After this function returns, the time is set to the earliest point at which + // any ack event will cause tracker_.Update() to start a new aggregation. + void AggregationEpisode(QuicBandwidth aggregation_bandwidth, + QuicTime::Delta aggregation_duration, + QuicByteCount bytes_per_ack, + bool expect_new_aggregation_epoch) { + ASSERT_GE(aggregation_bandwidth, bandwidth_); + const QuicTime start_time = now_; + + const QuicByteCount aggregation_bytes = + aggregation_bandwidth * aggregation_duration; + + const int num_acks = aggregation_bytes / bytes_per_ack; + ASSERT_EQ(aggregation_bytes, num_acks * bytes_per_ack) + << "aggregation_bytes: " << aggregation_bytes << " [" + << aggregation_bandwidth << " in " << aggregation_duration + << "], bytes_per_ack: " << bytes_per_ack; + + const QuicTime::Delta time_between_acks = QuicTime::Delta::FromMicroseconds( + aggregation_duration.ToMicroseconds() / num_acks); + ASSERT_EQ(aggregation_duration, num_acks * time_between_acks) + << "aggregation_bytes: " << aggregation_bytes + << ", num_acks: " << num_acks + << ", time_between_acks: " << time_between_acks; + + // The total duration of aggregation time and quiet period. + const QuicTime::Delta total_duration = QuicTime::Delta::FromMicroseconds( + aggregation_bytes * 8 * 1000000 / bandwidth_.ToBitsPerSecond()); + ASSERT_EQ(aggregation_bytes, total_duration * bandwidth_) + << "total_duration: " << total_duration + << ", bandwidth_: " << bandwidth_; + + QuicByteCount last_extra_acked = 0; + for (QuicByteCount bytes = 0; bytes < aggregation_bytes; + bytes += bytes_per_ack) { + QuicByteCount extra_acked = + tracker_.Update(bandwidth_, RoundTripCount(), now_, bytes_per_ack); + QUIC_VLOG(1) << "T" << now_ << ": Update after " << bytes_per_ack + << " bytes acked, " << extra_acked << " extra bytes acked"; + // |extra_acked| should be 0 if either + // [1] We are at the beginning of a aggregation epoch(bytes==0) and the + // the current tracker implementation can identify it, or + // [2] We are not really aggregating acks. + if ((bytes == 0 && expect_new_aggregation_epoch) || // [1] + (aggregation_bandwidth == bandwidth_)) { // [2] + EXPECT_EQ(0u, extra_acked); + } else { + EXPECT_LT(last_extra_acked, extra_acked); + } + now_ = now_ + time_between_acks; + last_extra_acked = extra_acked; + } + + // Advance past the quiet period. + const QuicTime time_after_aggregation = now_; + now_ = start_time + total_duration; + QUIC_VLOG(1) << "Advanced time from " << time_after_aggregation << " to " + << now_ << ". Aggregation time[" + << (time_after_aggregation - start_time) << "], Quiet time[" + << (now_ - time_after_aggregation) << "]."; + } + + QuicRoundTripCount RoundTripCount() const { + return (now_ - QuicTime::Zero()).ToMicroseconds() / rtt_.ToMicroseconds(); + } + + MaxAckHeightTracker tracker_; + QuicBandwidth bandwidth_ = QuicBandwidth::FromBytesPerSecond(10 * 1000); + QuicTime now_ = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(1); + QuicTime::Delta rtt_ = QuicTime::Delta::FromMilliseconds(60); +}; + +TEST_F(MaxAckHeightTrackerTest, VeryAggregatedLargeAck) { + AggregationEpisode(bandwidth_ * 20, QuicTime::Delta::FromMilliseconds(6), + 1200, true); + AggregationEpisode(bandwidth_ * 20, QuicTime::Delta::FromMilliseconds(6), + 1200, true); + now_ = now_ - QuicTime::Delta::FromMilliseconds(1); + + AggregationEpisode(bandwidth_ * 20, QuicTime::Delta::FromMilliseconds(6), + 1200, false); +} + +TEST_F(MaxAckHeightTrackerTest, VeryAggregatedSmallAcks) { + AggregationEpisode(bandwidth_ * 20, QuicTime::Delta::FromMilliseconds(6), 300, + true); + AggregationEpisode(bandwidth_ * 20, QuicTime::Delta::FromMilliseconds(6), 300, + true); + now_ = now_ - QuicTime::Delta::FromMilliseconds(1); + + AggregationEpisode(bandwidth_ * 20, QuicTime::Delta::FromMilliseconds(6), 300, + false); +} + +TEST_F(MaxAckHeightTrackerTest, SomewhatAggregatedLargeAck) { + AggregationEpisode(bandwidth_ * 2, QuicTime::Delta::FromMilliseconds(50), + 1000, true); + AggregationEpisode(bandwidth_ * 2, QuicTime::Delta::FromMilliseconds(50), + 1000, true); + now_ = now_ - QuicTime::Delta::FromMilliseconds(1); + + AggregationEpisode(bandwidth_ * 2, QuicTime::Delta::FromMilliseconds(50), + 1000, false); +} + +TEST_F(MaxAckHeightTrackerTest, SomewhatAggregatedSmallAcks) { + AggregationEpisode(bandwidth_ * 2, QuicTime::Delta::FromMilliseconds(50), 100, + true); + AggregationEpisode(bandwidth_ * 2, QuicTime::Delta::FromMilliseconds(50), 100, + true); + now_ = now_ - QuicTime::Delta::FromMilliseconds(1); + + AggregationEpisode(bandwidth_ * 2, QuicTime::Delta::FromMilliseconds(50), 100, + false); +} + +TEST_F(MaxAckHeightTrackerTest, NotAggregated) { + AggregationEpisode(bandwidth_, QuicTime::Delta::FromMilliseconds(100), 100, + true); +} + } // namespace test } // namespace quic