golang.org/x/net@v0.25.1-0.20240516223405-c87a5b62e243/quic/congestion_reno_test.go (about)

     1  // Copyright 2023 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  //go:build go1.21
     6  
     7  package quic
     8  
     9  import (
    10  	"testing"
    11  	"time"
    12  )
    13  
    14  func TestRenoInitialCongestionWindow(t *testing.T) {
    15  	// https://www.rfc-editor.org/rfc/rfc9002#section-7.2-1
    16  	for _, test := range []struct {
    17  		maxDatagramSize int
    18  		wantWindow      int
    19  	}{{
    20  		// "[...] ten times the maximum datagram size [...]"
    21  		maxDatagramSize: 1200,
    22  		wantWindow:      12000,
    23  	}, {
    24  		// [...] limiting the window to the larger of 14,720 bytes [...]"
    25  		maxDatagramSize: 1500,
    26  		wantWindow:      14720,
    27  	}, {
    28  		// [...] or twice the maximum datagram size."
    29  		maxDatagramSize: 15000,
    30  		wantWindow:      30000,
    31  	}} {
    32  		c := newReno(test.maxDatagramSize)
    33  		if got, want := c.congestionWindow, test.wantWindow; got != want {
    34  			t.Errorf("newReno(max_datagram_size=%v): congestion_window = %v, want %v",
    35  				test.maxDatagramSize, got, want)
    36  		}
    37  	}
    38  }
    39  
    40  func TestRenoSlowStartWindowIncreases(t *testing.T) {
    41  	// "[...] the congestion window increases by the number of bytes acknowledged [...]"
    42  	// https://www.rfc-editor.org/rfc/rfc9002#section-7.3.1-2
    43  	test := newRenoTest(t, 1200)
    44  
    45  	p0 := test.packetSent(initialSpace, 1200)
    46  	test.wantVar("congestion_window", 12000)
    47  	test.packetAcked(initialSpace, p0)
    48  	test.packetBatchEnd(initialSpace)
    49  	test.wantVar("congestion_window", 12000+1200)
    50  
    51  	p1 := test.packetSent(handshakeSpace, 600)
    52  	p2 := test.packetSent(handshakeSpace, 300)
    53  	test.packetAcked(handshakeSpace, p1)
    54  	test.packetAcked(handshakeSpace, p2)
    55  	test.packetBatchEnd(handshakeSpace)
    56  	test.wantVar("congestion_window", 12000+1200+600+300)
    57  }
    58  
    59  func TestRenoSlowStartToRecovery(t *testing.T) {
    60  	// "The sender MUST exit slow start and enter a recovery period
    61  	// when a packet is lost [...]"
    62  	// https://www.rfc-editor.org/rfc/rfc9002#section-7.3.1-3
    63  	test := newRenoTest(t, 1200)
    64  
    65  	p0 := test.packetSent(initialSpace, 1200)
    66  	p1 := test.packetSent(initialSpace, 1200)
    67  	p2 := test.packetSent(initialSpace, 1200)
    68  	p3 := test.packetSent(initialSpace, 1200)
    69  	test.wantVar("congestion_window", 12000)
    70  
    71  	t.Logf("# ACK triggers packet loss, sender enters recovery")
    72  	test.advance(1 * time.Millisecond)
    73  	test.packetAcked(initialSpace, p3)
    74  	test.packetLost(initialSpace, p0)
    75  	test.packetBatchEnd(initialSpace)
    76  
    77  	// "[...] set the slow start threshold to half the value of
    78  	// the congestion window when loss is detected."
    79  	// https://www.rfc-editor.org/rfc/rfc9002#section-7.3.2-2
    80  	test.wantVar("slow_start_threshold", 6000)
    81  
    82  	t.Logf("# packet loss in recovery does not change congestion window")
    83  	test.packetLost(initialSpace, p1)
    84  	test.packetBatchEnd(initialSpace)
    85  
    86  	t.Logf("# ack of packet from before recovery does not change congestion window")
    87  	test.packetAcked(initialSpace, p2)
    88  	test.packetBatchEnd(initialSpace)
    89  
    90  	p4 := test.packetSent(initialSpace, 1200)
    91  	test.packetAcked(initialSpace, p4)
    92  	test.packetBatchEnd(initialSpace)
    93  
    94  	// "The congestion window MUST be set to the reduced value of
    95  	// the slow start threshold before exiting the recovery period."
    96  	// https://www.rfc-editor.org/rfc/rfc9002#section-7.3.2-2
    97  	test.wantVar("congestion_window", 6000)
    98  }
    99  
   100  func TestRenoRecoveryToCongestionAvoidance(t *testing.T) {
   101  	// "A sender in congestion avoidance [limits] the increase
   102  	// to the congestion window to at most one maximum datagram size
   103  	// for each congestion window that is acknowledged."
   104  	// https://www.rfc-editor.org/rfc/rfc9002#section-7.3.3-2
   105  	test := newRenoTest(t, 1200)
   106  
   107  	p0 := test.packetSent(initialSpace, 1200)
   108  	p1 := test.packetSent(initialSpace, 1200)
   109  	p2 := test.packetSent(initialSpace, 1200)
   110  	test.advance(1 * time.Millisecond)
   111  	test.packetAcked(initialSpace, p1)
   112  	test.packetLost(initialSpace, p0)
   113  	test.packetBatchEnd(initialSpace)
   114  
   115  	p3 := test.packetSent(initialSpace, 1000)
   116  	test.advance(1 * time.Millisecond)
   117  	test.packetAcked(initialSpace, p3)
   118  	test.packetBatchEnd(initialSpace)
   119  
   120  	test.wantVar("congestion_window", 6000)
   121  	test.wantVar("slow_start_threshold", 6000)
   122  	test.wantVar("congestion_pending_acks", 1000)
   123  
   124  	t.Logf("# ack of packet from before recovery does not change congestion window")
   125  	test.packetAcked(initialSpace, p2)
   126  	test.packetBatchEnd(initialSpace)
   127  	test.wantVar("congestion_pending_acks", 1000)
   128  
   129  	for i := 0; i < 6; i++ {
   130  		p := test.packetSent(initialSpace, 1000)
   131  		test.packetAcked(initialSpace, p)
   132  	}
   133  	test.packetBatchEnd(initialSpace)
   134  	t.Logf("# congestion window increased by max_datagram_size")
   135  	test.wantVar("congestion_window", 6000+1200)
   136  	test.wantVar("congestion_pending_acks", 1000)
   137  }
   138  
   139  func TestRenoMinimumCongestionWindow(t *testing.T) {
   140  	// "The RECOMMENDED [minimum congestion window] is 2 * max_datagram_size."
   141  	// https://www.rfc-editor.org/rfc/rfc9002.html#section-7.2-4
   142  	test := newRenoTest(t, 1200)
   143  
   144  	p0 := test.packetSent(handshakeSpace, 1200)
   145  	p1 := test.packetSent(handshakeSpace, 1200)
   146  	test.advance(1 * time.Millisecond)
   147  	test.packetAcked(handshakeSpace, p1)
   148  	test.packetLost(handshakeSpace, p0)
   149  	test.packetBatchEnd(handshakeSpace)
   150  	test.wantVar("slow_start_threshold", 6000)
   151  	test.wantVar("congestion_window", 6000)
   152  
   153  	test.advance(1 * time.Millisecond)
   154  	p2 := test.packetSent(handshakeSpace, 1200)
   155  	p3 := test.packetSent(handshakeSpace, 1200)
   156  	test.advance(1 * time.Millisecond)
   157  	test.packetAcked(handshakeSpace, p3)
   158  	test.packetLost(handshakeSpace, p2)
   159  	test.packetBatchEnd(handshakeSpace)
   160  	test.wantVar("slow_start_threshold", 3000)
   161  	test.wantVar("congestion_window", 3000)
   162  
   163  	p4 := test.packetSent(handshakeSpace, 1200)
   164  	p5 := test.packetSent(handshakeSpace, 1200)
   165  	test.advance(1 * time.Millisecond)
   166  	test.packetAcked(handshakeSpace, p4)
   167  	test.packetLost(handshakeSpace, p5)
   168  	test.packetBatchEnd(handshakeSpace)
   169  	test.wantVar("slow_start_threshold", 1500)
   170  	test.wantVar("congestion_window", 2400) // minimum
   171  
   172  	p6 := test.packetSent(handshakeSpace, 1200)
   173  	p7 := test.packetSent(handshakeSpace, 1200)
   174  	test.advance(1 * time.Millisecond)
   175  	test.packetAcked(handshakeSpace, p7)
   176  	test.packetLost(handshakeSpace, p6)
   177  	test.packetBatchEnd(handshakeSpace)
   178  	test.wantVar("slow_start_threshold", 1200) // half congestion window
   179  	test.wantVar("congestion_window", 2400)    // minimum
   180  }
   181  
   182  func TestRenoSlowStartToCongestionAvoidance(t *testing.T) {
   183  	test := newRenoTest(t, 1200)
   184  	test.setRTT(1*time.Millisecond, 0)
   185  
   186  	t.Logf("# enter recovery with persistent congestion")
   187  	p0 := test.packetSent(handshakeSpace, 1200)
   188  	test.advance(1 * time.Second) // larger than persistent congestion duration
   189  	p1 := test.packetSent(handshakeSpace, 1200)
   190  	p2 := test.packetSent(handshakeSpace, 1200)
   191  	test.advance(1 * time.Millisecond)
   192  	test.packetAcked(handshakeSpace, p2)
   193  	test.packetLost(handshakeSpace, p0)
   194  	test.packetLost(handshakeSpace, p1)
   195  	test.packetBatchEnd(handshakeSpace)
   196  	test.wantVar("slow_start_threshold", 6000)
   197  	test.wantVar("congestion_window", 2400) // minimum in persistent congestion
   198  	test.wantVar("congestion_pending_acks", 0)
   199  
   200  	t.Logf("# enter slow start on new ack")
   201  	p3 := test.packetSent(handshakeSpace, 1200)
   202  	test.packetAcked(handshakeSpace, p3)
   203  	test.packetBatchEnd(handshakeSpace)
   204  	test.wantVar("congestion_window", 3600)
   205  	test.wantVar("congestion_pending_acks", 0)
   206  
   207  	t.Logf("# enter congestion avoidance after reaching slow_start_threshold")
   208  	p4 := test.packetSent(handshakeSpace, 1200)
   209  	p5 := test.packetSent(handshakeSpace, 1200)
   210  	p6 := test.packetSent(handshakeSpace, 1200)
   211  	test.packetAcked(handshakeSpace, p4)
   212  	test.packetAcked(handshakeSpace, p5)
   213  	test.packetAcked(handshakeSpace, p6)
   214  	test.packetBatchEnd(handshakeSpace)
   215  	test.wantVar("congestion_window", 6000)
   216  	test.wantVar("congestion_pending_acks", 1200)
   217  }
   218  
   219  func TestRenoPersistentCongestionDurationExceeded(t *testing.T) {
   220  	// "When persistent congestion is declared, the sender's congestion
   221  	// window MUST be reduced to the minimum congestion window [...]"
   222  	// https://www.rfc-editor.org/rfc/rfc9002.html#section-7.6.2-6
   223  	test := newRenoTest(t, 1200)
   224  	test.setRTT(10*time.Millisecond, 3*time.Millisecond)
   225  	test.maxAckDelay = 25 * time.Millisecond
   226  
   227  	t.Logf("persistent congesion duration is 3 * (10ms + 4*3ms + 25ms) = 141ms")
   228  	p0 := test.packetSent(handshakeSpace, 1200)
   229  	test.advance(142 * time.Millisecond) // larger than persistent congestion duration
   230  	p1 := test.packetSent(handshakeSpace, 1200)
   231  	p2 := test.packetSent(handshakeSpace, 1200)
   232  	test.packetAcked(handshakeSpace, p2)
   233  	test.packetLost(handshakeSpace, p0)
   234  	test.packetLost(handshakeSpace, p1)
   235  	test.packetBatchEnd(handshakeSpace)
   236  	test.wantVar("slow_start_threshold", 6000)
   237  	test.wantVar("congestion_window", 2400) // minimum in persistent congestion
   238  }
   239  
   240  func TestRenoPersistentCongestionDurationNotExceeded(t *testing.T) {
   241  	test := newRenoTest(t, 1200)
   242  	test.setRTT(10*time.Millisecond, 3*time.Millisecond)
   243  	test.maxAckDelay = 25 * time.Millisecond
   244  
   245  	t.Logf("persistent congesion duration is 3 * (10ms + 4*3ms + 25ms) = 141ms")
   246  	p0 := test.packetSent(handshakeSpace, 1200)
   247  	test.advance(140 * time.Millisecond) // smaller than persistent congestion duration
   248  	p1 := test.packetSent(handshakeSpace, 1200)
   249  	p2 := test.packetSent(handshakeSpace, 1200)
   250  	test.packetAcked(handshakeSpace, p2)
   251  	test.packetLost(handshakeSpace, p0)
   252  	test.packetLost(handshakeSpace, p1)
   253  	test.packetBatchEnd(handshakeSpace)
   254  	test.wantVar("slow_start_threshold", 6000)
   255  	test.wantVar("congestion_window", 6000) // no persistent congestion
   256  }
   257  
   258  func TestRenoPersistentCongestionInterveningAck(t *testing.T) {
   259  	// "[...] none of the packets sent between the send times
   260  	// of these two packets are acknowledged [...]"
   261  	// https://www.rfc-editor.org/rfc/rfc9002#section-7.6.2-2.1
   262  	test := newRenoTest(t, 1200)
   263  
   264  	test.setRTT(10*time.Millisecond, 3*time.Millisecond)
   265  	test.maxAckDelay = 25 * time.Millisecond
   266  
   267  	t.Logf("persistent congesion duration is 3 * (10ms + 4*3ms + 25ms) = 141ms")
   268  	p0 := test.packetSent(handshakeSpace, 1200)
   269  	test.advance(100 * time.Millisecond)
   270  	p1 := test.packetSent(handshakeSpace, 1200)
   271  	test.advance(42 * time.Millisecond)
   272  	p2 := test.packetSent(handshakeSpace, 1200)
   273  	p3 := test.packetSent(handshakeSpace, 1200)
   274  	test.packetAcked(handshakeSpace, p1)
   275  	test.packetAcked(handshakeSpace, p3)
   276  	test.packetLost(handshakeSpace, p0)
   277  	test.packetLost(handshakeSpace, p2)
   278  	test.packetBatchEnd(handshakeSpace)
   279  	test.wantVar("slow_start_threshold", 6000)
   280  	test.wantVar("congestion_window", 6000) // no persistent congestion
   281  }
   282  
   283  func TestRenoPersistentCongestionInterveningLosses(t *testing.T) {
   284  	test := newRenoTest(t, 1200)
   285  
   286  	test.setRTT(10*time.Millisecond, 3*time.Millisecond)
   287  	test.maxAckDelay = 25 * time.Millisecond
   288  
   289  	t.Logf("persistent congesion duration is 3 * (10ms + 4*3ms + 25ms) = 141ms")
   290  	p0 := test.packetSent(handshakeSpace, 1200)
   291  	test.advance(50 * time.Millisecond)
   292  	p1 := test.packetSent(handshakeSpace, 1200, func(p *sentPacket) {
   293  		p.inFlight = false
   294  		p.ackEliciting = false
   295  	})
   296  	test.advance(50 * time.Millisecond)
   297  	p2 := test.packetSent(handshakeSpace, 1200, func(p *sentPacket) {
   298  		p.ackEliciting = false
   299  	})
   300  	test.advance(42 * time.Millisecond)
   301  	p3 := test.packetSent(handshakeSpace, 1200)
   302  	p4 := test.packetSent(handshakeSpace, 1200)
   303  	test.packetAcked(handshakeSpace, p4)
   304  	test.packetLost(handshakeSpace, p0)
   305  	test.packetLost(handshakeSpace, p1)
   306  	test.packetLost(handshakeSpace, p2)
   307  	test.packetBatchEnd(handshakeSpace)
   308  	test.wantVar("congestion_window", 6000) // no persistent congestion yet
   309  	test.packetLost(handshakeSpace, p3)
   310  	test.packetBatchEnd(handshakeSpace)
   311  	test.wantVar("congestion_window", 2400) // persistent congestion
   312  }
   313  
   314  func TestRenoPersistentCongestionNoRTTSample(t *testing.T) {
   315  	// "[...] a prior RTT sample existed when these two packets were sent."
   316  	// https://www.rfc-editor.org/rfc/rfc9002#section-7.6.2-2.3
   317  	test := newRenoTest(t, 1200)
   318  
   319  	t.Logf("first packet sent prior to first RTT sample")
   320  	p0 := test.packetSent(handshakeSpace, 1200)
   321  
   322  	test.advance(1 * time.Millisecond)
   323  	test.setRTT(10*time.Millisecond, 3*time.Millisecond)
   324  	test.maxAckDelay = 25 * time.Millisecond
   325  
   326  	t.Logf("persistent congesion duration is 3 * (10ms + 4*3ms + 25ms) = 141ms")
   327  	test.advance(142 * time.Millisecond) // larger than persistent congestion duration
   328  	p1 := test.packetSent(handshakeSpace, 1200)
   329  	p2 := test.packetSent(handshakeSpace, 1200)
   330  	test.packetAcked(handshakeSpace, p2)
   331  	test.packetLost(handshakeSpace, p0)
   332  	test.packetLost(handshakeSpace, p1)
   333  	test.packetBatchEnd(handshakeSpace)
   334  	test.wantVar("slow_start_threshold", 6000)
   335  	test.wantVar("congestion_window", 6000) // no persistent congestion
   336  }
   337  
   338  func TestRenoPersistentCongestionPacketNotAckEliciting(t *testing.T) {
   339  	// "These two packets MUST be ack-eliciting [...]"
   340  	// https://www.rfc-editor.org/rfc/rfc9002.html#section-7.6.2-3
   341  	test := newRenoTest(t, 1200)
   342  
   343  	t.Logf("first packet set prior to first RTT sample")
   344  	p0 := test.packetSent(handshakeSpace, 1200)
   345  
   346  	test.advance(1 * time.Millisecond)
   347  	test.setRTT(10*time.Millisecond, 3*time.Millisecond)
   348  	test.maxAckDelay = 25 * time.Millisecond
   349  
   350  	t.Logf("persistent congesion duration is 3 * (10ms + 4*3ms + 25ms) = 141ms")
   351  	test.advance(142 * time.Millisecond) // larger than persistent congestion duration
   352  	p1 := test.packetSent(handshakeSpace, 1200)
   353  	p2 := test.packetSent(handshakeSpace, 1200)
   354  	test.packetAcked(handshakeSpace, p2)
   355  	test.packetLost(handshakeSpace, p0)
   356  	test.packetLost(handshakeSpace, p1)
   357  	test.packetBatchEnd(handshakeSpace)
   358  	test.wantVar("slow_start_threshold", 6000)
   359  	test.wantVar("congestion_window", 6000) // no persistent congestion
   360  }
   361  
   362  func TestRenoCanSend(t *testing.T) {
   363  	test := newRenoTest(t, 1200)
   364  	test.wantVar("congestion_window", 12000)
   365  
   366  	t.Logf("controller permits sending until congestion window is full")
   367  	var packets []*sentPacket
   368  	for i := 0; i < 10; i++ {
   369  		test.wantVar("bytes_in_flight", i*1200)
   370  		test.wantCanSend(true)
   371  		p := test.packetSent(initialSpace, 1200)
   372  		packets = append(packets, p)
   373  	}
   374  	test.wantVar("bytes_in_flight", 12000)
   375  
   376  	t.Logf("controller blocks sending when congestion window is consumed")
   377  	test.wantCanSend(false)
   378  
   379  	t.Logf("loss of packet moves to recovery, reduces window")
   380  	test.packetLost(initialSpace, packets[0])
   381  	test.packetAcked(initialSpace, packets[1])
   382  	test.packetBatchEnd(initialSpace)
   383  	test.wantVar("bytes_in_flight", 9600)   // 12000 - 2*1200
   384  	test.wantVar("congestion_window", 6000) // 12000 / 2
   385  
   386  	t.Logf("one packet permitted on entry to recovery")
   387  	test.wantCanSend(true)
   388  	test.packetSent(initialSpace, 1200)
   389  	test.wantVar("bytes_in_flight", 10800)
   390  	test.wantCanSend(false)
   391  }
   392  
   393  func TestRenoNonAckEliciting(t *testing.T) {
   394  	test := newRenoTest(t, 1200)
   395  	test.wantVar("congestion_window", 12000)
   396  
   397  	t.Logf("in-flight packet")
   398  	p0 := test.packetSent(initialSpace, 1200)
   399  	test.wantVar("bytes_in_flight", 1200)
   400  	test.packetAcked(initialSpace, p0)
   401  	test.packetBatchEnd(initialSpace)
   402  	test.wantVar("bytes_in_flight", 0)
   403  	test.wantVar("congestion_window", 12000+1200)
   404  
   405  	t.Logf("non-in-flight packet")
   406  	p1 := test.packetSent(initialSpace, 1200, func(p *sentPacket) {
   407  		p.inFlight = false
   408  		p.ackEliciting = false
   409  	})
   410  	test.wantVar("bytes_in_flight", 0)
   411  	test.packetAcked(initialSpace, p1)
   412  	test.packetBatchEnd(initialSpace)
   413  	test.wantVar("bytes_in_flight", 0)
   414  	test.wantVar("congestion_window", 12000+1200)
   415  }
   416  
   417  func TestRenoUnderutilizedCongestionWindow(t *testing.T) {
   418  	test := newRenoTest(t, 1200)
   419  	test.setUnderutilized(true)
   420  	test.wantVar("congestion_window", 12000)
   421  
   422  	t.Logf("congestion window does not increase when application limited")
   423  	p0 := test.packetSent(initialSpace, 1200)
   424  	test.packetAcked(initialSpace, p0)
   425  	test.wantVar("congestion_window", 12000)
   426  }
   427  
   428  func TestRenoDiscardKeys(t *testing.T) {
   429  	test := newRenoTest(t, 1200)
   430  
   431  	p0 := test.packetSent(initialSpace, 1200)
   432  	p1 := test.packetSent(handshakeSpace, 1200)
   433  	test.wantVar("bytes_in_flight", 2400)
   434  
   435  	test.packetDiscarded(initialSpace, p0)
   436  	test.wantVar("bytes_in_flight", 1200)
   437  
   438  	test.packetDiscarded(handshakeSpace, p1)
   439  	test.wantVar("bytes_in_flight", 0)
   440  }
   441  
   442  type ccTest struct {
   443  	t           *testing.T
   444  	cc          *ccReno
   445  	rtt         rttState
   446  	maxAckDelay time.Duration
   447  	now         time.Time
   448  	nextNum     [numberSpaceCount]packetNumber
   449  }
   450  
   451  func newRenoTest(t *testing.T, maxDatagramSize int) *ccTest {
   452  	test := &ccTest{
   453  		t:   t,
   454  		now: time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC),
   455  	}
   456  	test.cc = newReno(maxDatagramSize)
   457  	return test
   458  }
   459  
   460  func (c *ccTest) setRTT(smoothedRTT, rttvar time.Duration) {
   461  	c.t.Helper()
   462  	c.t.Logf("set smoothed_rtt=%v rttvar=%v", smoothedRTT, rttvar)
   463  	c.rtt.smoothedRTT = smoothedRTT
   464  	c.rtt.rttvar = rttvar
   465  	if c.rtt.firstSampleTime.IsZero() {
   466  		c.rtt.firstSampleTime = c.now
   467  	}
   468  }
   469  
   470  func (c *ccTest) setUnderutilized(v bool) {
   471  	c.t.Helper()
   472  	c.t.Logf("set underutilized = %v", v)
   473  	c.cc.setUnderutilized(nil, v)
   474  }
   475  
   476  func (c *ccTest) packetSent(space numberSpace, size int, fns ...func(*sentPacket)) *sentPacket {
   477  	c.t.Helper()
   478  	num := c.nextNum[space]
   479  	c.nextNum[space]++
   480  	sent := &sentPacket{
   481  		inFlight:     true,
   482  		ackEliciting: true,
   483  		num:          num,
   484  		size:         size,
   485  		time:         c.now,
   486  	}
   487  	for _, f := range fns {
   488  		f(sent)
   489  	}
   490  	c.t.Logf("packet sent:  num=%v.%v, size=%v", space, sent.num, sent.size)
   491  	c.cc.packetSent(c.now, nil, space, sent)
   492  	return sent
   493  }
   494  
   495  func (c *ccTest) advance(d time.Duration) {
   496  	c.t.Helper()
   497  	c.t.Logf("advance time %v", d)
   498  	c.now = c.now.Add(d)
   499  }
   500  
   501  func (c *ccTest) packetAcked(space numberSpace, sent *sentPacket) {
   502  	c.t.Helper()
   503  	c.t.Logf("packet acked: num=%v.%v, size=%v", space, sent.num, sent.size)
   504  	c.cc.packetAcked(c.now, sent)
   505  }
   506  
   507  func (c *ccTest) packetLost(space numberSpace, sent *sentPacket) {
   508  	c.t.Helper()
   509  	c.t.Logf("packet lost:  num=%v.%v, size=%v", space, sent.num, sent.size)
   510  	c.cc.packetLost(c.now, space, sent, &c.rtt)
   511  }
   512  
   513  func (c *ccTest) packetDiscarded(space numberSpace, sent *sentPacket) {
   514  	c.t.Helper()
   515  	c.t.Logf("packet number space discarded: num=%v.%v, size=%v", space, sent.num, sent.size)
   516  	c.cc.packetDiscarded(sent)
   517  }
   518  
   519  func (c *ccTest) packetBatchEnd(space numberSpace) {
   520  	c.t.Helper()
   521  	c.t.Logf("(end of batch)")
   522  	c.cc.packetBatchEnd(c.now, nil, space, &c.rtt, c.maxAckDelay)
   523  }
   524  
   525  func (c *ccTest) wantCanSend(want bool) {
   526  	if got := c.cc.canSend(); got != want {
   527  		c.t.Fatalf("canSend() = %v, want %v", got, want)
   528  	}
   529  }
   530  
   531  func (c *ccTest) wantVar(name string, want int) {
   532  	c.t.Helper()
   533  	var got int
   534  	switch name {
   535  	case "bytes_in_flight":
   536  		got = c.cc.bytesInFlight
   537  	case "congestion_pending_acks":
   538  		got = c.cc.congestionPendingAcks
   539  	case "congestion_window":
   540  		got = c.cc.congestionWindow
   541  	case "slow_start_threshold":
   542  		got = c.cc.slowStartThreshold
   543  	default:
   544  		c.t.Fatalf("unknown var %q", name)
   545  	}
   546  	if got != want {
   547  		c.t.Fatalf("ERROR: %v = %v, want %v", name, got, want)
   548  	}
   549  	c.t.Logf("# %v = %v", name, got)
   550  }