golang.org/x/net@v0.25.1-0.20240516223405-c87a5b62e243/quic/loss_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  	"fmt"
    11  	"testing"
    12  	"time"
    13  )
    14  
    15  func TestLossAntiAmplificationLimit(t *testing.T) {
    16  	test := newLossTest(t, serverSide, lossTestOpts{})
    17  	test.datagramReceived(1200)
    18  	t.Logf("# consume anti-amplification capacity in a mix of packets")
    19  	test.send(initialSpace, 0, sentPacket{
    20  		size:         1200,
    21  		ackEliciting: true,
    22  		inFlight:     true,
    23  	})
    24  	test.send(initialSpace, 1, sentPacket{
    25  		size:         1200,
    26  		ackEliciting: false,
    27  		inFlight:     false,
    28  	})
    29  	test.send(initialSpace, 2, sentPacket{
    30  		size:         1200,
    31  		ackEliciting: false,
    32  		inFlight:     true,
    33  	})
    34  	t.Logf("# send blocked by anti-amplification limit")
    35  	test.wantSendLimit(ccBlocked)
    36  
    37  	t.Logf("# receiving a datagram unblocks server")
    38  	test.datagramReceived(100)
    39  	test.wantSendLimit(ccOK)
    40  
    41  	t.Logf("# validating client address removes anti-amplification limit")
    42  	test.validateClientAddress()
    43  	test.wantSendLimit(ccOK)
    44  }
    45  
    46  func TestLossRTTSampleNotGenerated(t *testing.T) {
    47  	test := newLossTest(t, clientSide, lossTestOpts{})
    48  	test.send(initialSpace, 0, 1)
    49  	test.send(initialSpace, 2, sentPacket{
    50  		ackEliciting: false,
    51  		inFlight:     false,
    52  	})
    53  	test.advance(10 * time.Millisecond)
    54  	test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{1, 2})
    55  	test.wantAck(initialSpace, 1)
    56  	test.wantVar("latest_rtt", 10*time.Millisecond)
    57  	t.Logf("# smoothed_rtt = latest_rtt")
    58  	test.wantVar("smoothed_rtt", 10*time.Millisecond)
    59  	t.Logf("# rttvar = latest_rtt / 2")
    60  	test.wantVar("rttvar", 5*time.Millisecond)
    61  
    62  	// "...an ACK frame SHOULD NOT be used to update RTT estimates if
    63  	// it does not newly acknowledge the largest acknowledged packet."
    64  	// https://www.rfc-editor.org/rfc/rfc9002.html#section-5.1-6
    65  	t.Logf("# acks for older packets do not generate an RTT sample")
    66  	test.advance(1 * time.Millisecond)
    67  	test.ack(initialSpace, 1*time.Millisecond, i64range[packetNumber]{0, 2})
    68  	test.wantAck(initialSpace, 0)
    69  	test.wantVar("smoothed_rtt", 10*time.Millisecond)
    70  
    71  	// "An RTT sample MUST NOT be generated on receiving an ACK frame
    72  	// that does not newly acknowledge at least one ack-eliciting packet."
    73  	// https://www.rfc-editor.org/rfc/rfc9002.html#section-5.1-7
    74  	t.Logf("# acks for non-ack-eliciting packets do not generate an RTT sample")
    75  	test.advance(1 * time.Millisecond)
    76  	test.ack(initialSpace, 1*time.Millisecond, i64range[packetNumber]{0, 3})
    77  	test.wantAck(initialSpace, 2)
    78  	test.wantVar("smoothed_rtt", 10*time.Millisecond)
    79  }
    80  
    81  func TestLossMinRTT(t *testing.T) {
    82  	test := newLossTest(t, clientSide, lossTestOpts{})
    83  
    84  	// "min_rtt MUST be set to the latest_rtt on the first RTT sample."
    85  	// https://www.rfc-editor.org/rfc/rfc9002.html#section-5.2-2
    86  	t.Logf("# min_rtt set on first sample")
    87  	test.send(initialSpace, 0)
    88  	test.advance(10 * time.Millisecond)
    89  	test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 1})
    90  	test.wantAck(initialSpace, 0)
    91  	test.wantVar("min_rtt", 10*time.Millisecond)
    92  
    93  	// "min_rtt MUST be set to the lesser of min_rtt and latest_rtt [...]
    94  	// on all other samples."
    95  	t.Logf("# min_rtt does not increase")
    96  	test.send(initialSpace, 1)
    97  	test.advance(20 * time.Millisecond)
    98  	test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 2})
    99  	test.wantAck(initialSpace, 1)
   100  	test.wantVar("min_rtt", 10*time.Millisecond)
   101  
   102  	t.Logf("# min_rtt decreases")
   103  	test.send(initialSpace, 2)
   104  	test.advance(5 * time.Millisecond)
   105  	test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 3})
   106  	test.wantAck(initialSpace, 2)
   107  	test.wantVar("min_rtt", 5*time.Millisecond)
   108  }
   109  
   110  func TestLossMinRTTAfterCongestion(t *testing.T) {
   111  	// "Endpoints SHOULD set the min_rtt to the newest RTT sample
   112  	// after persistent congestion is established."
   113  	// https://www.rfc-editor.org/rfc/rfc9002.html#section-5.2-5
   114  	test := newLossTest(t, clientSide, lossTestOpts{
   115  		maxDatagramSize: 1200,
   116  	})
   117  	t.Logf("# establish initial RTT sample")
   118  	test.send(initialSpace, 0, testSentPacketSize(1200))
   119  	test.advance(10 * time.Millisecond)
   120  	test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 1})
   121  	test.wantAck(initialSpace, 0)
   122  	test.wantVar("min_rtt", 10*time.Millisecond)
   123  
   124  	t.Logf("# send two packets spanning persistent congestion duration")
   125  	test.send(initialSpace, 1, testSentPacketSize(1200))
   126  	t.Logf("# 2000ms >> persistent congestion duration")
   127  	test.advance(2000 * time.Millisecond)
   128  	test.wantPTOExpired()
   129  	test.send(initialSpace, 2, testSentPacketSize(1200))
   130  
   131  	t.Logf("# trigger loss of previous packets")
   132  	test.advance(10 * time.Millisecond)
   133  	test.send(initialSpace, 3, testSentPacketSize(1200))
   134  	test.advance(20 * time.Millisecond)
   135  	test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{3, 4})
   136  	test.wantAck(initialSpace, 3)
   137  	test.wantLoss(initialSpace, 1, 2)
   138  	t.Logf("# persistent congestion detected")
   139  
   140  	test.send(initialSpace, 4, testSentPacketSize(1200))
   141  	test.advance(20 * time.Millisecond)
   142  	test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{4, 5})
   143  	test.wantAck(initialSpace, 4)
   144  
   145  	t.Logf("# min_rtt set from first sample after persistent congestion")
   146  	test.wantVar("min_rtt", 20*time.Millisecond)
   147  }
   148  
   149  func TestLossInitialRTTSample(t *testing.T) {
   150  	test := newLossTest(t, clientSide, lossTestOpts{})
   151  	test.setMaxAckDelay(2 * time.Millisecond)
   152  	t.Logf("# initial smoothed_rtt and rtt values")
   153  	test.wantVar("smoothed_rtt", 333*time.Millisecond)
   154  	test.wantVar("rttvar", 333*time.Millisecond/2)
   155  
   156  	// https://www.rfc-editor.org/rfc/rfc9002.html#section-5.3-11
   157  	t.Logf("# first RTT sample")
   158  	test.send(initialSpace, 0)
   159  	test.advance(10 * time.Millisecond)
   160  	test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 1})
   161  	test.wantAck(initialSpace, 0)
   162  	test.wantVar("latest_rtt", 10*time.Millisecond)
   163  	t.Logf("# smoothed_rtt = latest_rtt")
   164  	test.wantVar("smoothed_rtt", 10*time.Millisecond)
   165  	t.Logf("# rttvar = latest_rtt / 2")
   166  	test.wantVar("rttvar", 5*time.Millisecond)
   167  }
   168  
   169  func TestLossSmoothedRTTIgnoresMaxAckDelayBeforeHandshakeConfirmed(t *testing.T) {
   170  	test := newLossTest(t, clientSide, lossTestOpts{})
   171  	test.setMaxAckDelay(1 * time.Millisecond)
   172  	test.send(initialSpace, 0)
   173  	test.advance(10 * time.Millisecond)
   174  	test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 1})
   175  	test.wantAck(initialSpace, 0)
   176  	smoothedRTT := 10 * time.Millisecond
   177  	rttvar := 5 * time.Millisecond
   178  
   179  	// "[...] an endpoint [...] SHOULD ignore the peer's max_ack_delay
   180  	// until the handshake is confirmed [...]"
   181  	// https://www.rfc-editor.org/rfc/rfc9002.html#section-5.3-7.2
   182  	t.Logf("# subsequent RTT sample")
   183  	test.send(handshakeSpace, 0)
   184  	test.advance(20 * time.Millisecond)
   185  	test.ack(handshakeSpace, 10*time.Millisecond, i64range[packetNumber]{0, 1})
   186  	test.wantAck(handshakeSpace, 0)
   187  	test.wantVar("latest_rtt", 20*time.Millisecond)
   188  	t.Logf("# ack_delay > max_ack_delay")
   189  	t.Logf("# handshake not confirmed, so ignore max_ack_delay")
   190  	t.Logf("# adjusted_rtt = latest_rtt - ackDelay")
   191  	adjustedRTT := 10 * time.Millisecond
   192  	t.Logf("# smoothed_rtt = 7/8 * smoothed_rtt + 1/8 * adjusted_rtt")
   193  	smoothedRTT = (7*smoothedRTT + adjustedRTT) / 8
   194  	test.wantVar("smoothed_rtt", smoothedRTT)
   195  	rttvarSample := abs(smoothedRTT - adjustedRTT)
   196  	t.Logf("# rttvar_sample = abs(smoothed_rtt - adjusted_rtt) = %v", rttvarSample)
   197  	t.Logf("# rttvar = 3/4 * rttvar + 1/4 * rttvar_sample")
   198  	rttvar = (3*rttvar + rttvarSample) / 4
   199  	test.wantVar("rttvar", rttvar)
   200  }
   201  
   202  func TestLossSmoothedRTTUsesMaxAckDelayAfterHandshakeConfirmed(t *testing.T) {
   203  	test := newLossTest(t, clientSide, lossTestOpts{})
   204  	test.setMaxAckDelay(25 * time.Millisecond)
   205  	test.send(initialSpace, 0)
   206  	test.advance(10 * time.Millisecond)
   207  	test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 1})
   208  	test.wantAck(initialSpace, 0)
   209  	smoothedRTT := 10 * time.Millisecond
   210  	rttvar := 5 * time.Millisecond
   211  
   212  	test.confirmHandshake()
   213  
   214  	// "[...] an endpoint [...] MUST use the lesser of the acknowledgment
   215  	// delay and the peer's max_ack_delay after the handshake is confirmed [...]"
   216  	// https://www.rfc-editor.org/rfc/rfc9002.html#section-5.3-7.3
   217  	t.Logf("# subsequent RTT sample")
   218  	test.send(handshakeSpace, 0)
   219  	test.advance(50 * time.Millisecond)
   220  	test.ack(handshakeSpace, 40*time.Millisecond, i64range[packetNumber]{0, 1})
   221  	test.wantAck(handshakeSpace, 0)
   222  	test.wantVar("latest_rtt", 50*time.Millisecond)
   223  	t.Logf("# ack_delay > max_ack_delay")
   224  	t.Logf("# handshake confirmed, so adjusted_rtt clamps to max_ack_delay")
   225  	t.Logf("# adjusted_rtt = max_ack_delay")
   226  	adjustedRTT := 25 * time.Millisecond
   227  	rttvarSample := abs(smoothedRTT - adjustedRTT)
   228  	t.Logf("# rttvar_sample = abs(smoothed_rtt - adjusted_rtt) = %v", rttvarSample)
   229  	t.Logf("# rttvar = 3/4 * rttvar + 1/4 * rttvar_sample")
   230  	rttvar = (3*rttvar + rttvarSample) / 4
   231  	test.wantVar("rttvar", rttvar)
   232  	t.Logf("# smoothed_rtt = 7/8 * smoothed_rtt + 1/8 * adjusted_rtt")
   233  	smoothedRTT = (7*smoothedRTT + adjustedRTT) / 8
   234  	test.wantVar("smoothed_rtt", smoothedRTT)
   235  }
   236  
   237  func TestLossAckDelayReducesRTTBelowMinRTT(t *testing.T) {
   238  	test := newLossTest(t, clientSide, lossTestOpts{})
   239  	test.send(initialSpace, 0)
   240  	test.advance(10 * time.Millisecond)
   241  	test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 1})
   242  	test.wantAck(initialSpace, 0)
   243  	smoothedRTT := 10 * time.Millisecond
   244  	rttvar := 5 * time.Millisecond
   245  
   246  	// "[...] an endpoint [...] MUST NOT subtract the acknowledgment delay
   247  	// from the RTT sample if the resulting value is smaller than the min_rtt."
   248  	// https://www.rfc-editor.org/rfc/rfc9002.html#section-5.3-7.4
   249  	t.Logf("# subsequent RTT sample")
   250  	test.send(handshakeSpace, 0)
   251  	test.advance(12 * time.Millisecond)
   252  	test.ack(handshakeSpace, 4*time.Millisecond, i64range[packetNumber]{0, 1})
   253  	test.wantAck(handshakeSpace, 0)
   254  	test.wantVar("latest_rtt", 12*time.Millisecond)
   255  	t.Logf("# latest_rtt - ack_delay < min_rtt, so adjusted_rtt = latest_rtt")
   256  	adjustedRTT := 12 * time.Millisecond
   257  	rttvarSample := abs(smoothedRTT - adjustedRTT)
   258  	t.Logf("# rttvar_sample = abs(smoothed_rtt - adjusted_rtt) = %v", rttvarSample)
   259  	t.Logf("# rttvar = 3/4 * rttvar + 1/4 * rttvar_sample")
   260  	rttvar = (3*rttvar + rttvarSample) / 4
   261  	test.wantVar("rttvar", rttvar)
   262  	t.Logf("# smoothed_rtt = 7/8 * smoothed_rtt + 1/8 * adjusted_rtt")
   263  	smoothedRTT = (7*smoothedRTT + adjustedRTT) / 8
   264  	test.wantVar("smoothed_rtt", smoothedRTT)
   265  }
   266  
   267  func TestLossPacketThreshold(t *testing.T) {
   268  	// "[...] the packet was sent kPacketThreshold packets before an
   269  	// acknowledged packet [...]"
   270  	// https://www.rfc-editor.org/rfc/rfc9002.html#section-6.1.1
   271  	test := newLossTest(t, clientSide, lossTestOpts{})
   272  	t.Logf("# acking a packet triggers loss of packets sent kPacketThreshold earlier")
   273  	test.send(appDataSpace, 0, 1, 2, 3, 4, 5, 6)
   274  	test.ack(appDataSpace, 0*time.Millisecond, i64range[packetNumber]{4, 5})
   275  	test.wantAck(appDataSpace, 4)
   276  	test.wantLoss(appDataSpace, 0, 1)
   277  }
   278  
   279  func TestLossOutOfOrderAcks(t *testing.T) {
   280  	test := newLossTest(t, clientSide, lossTestOpts{})
   281  	t.Logf("# out of order acks, no loss")
   282  	test.send(appDataSpace, 0, 1, 2)
   283  	test.ack(appDataSpace, 0*time.Millisecond, i64range[packetNumber]{2, 3})
   284  	test.wantAck(appDataSpace, 2)
   285  
   286  	test.ack(appDataSpace, 0*time.Millisecond, i64range[packetNumber]{1, 2})
   287  	test.wantAck(appDataSpace, 1)
   288  
   289  	test.ack(appDataSpace, 0*time.Millisecond, i64range[packetNumber]{0, 1})
   290  	test.wantAck(appDataSpace, 0)
   291  }
   292  
   293  func TestLossSendAndAck(t *testing.T) {
   294  	test := newLossTest(t, clientSide, lossTestOpts{})
   295  	test.send(appDataSpace, 0, 1, 2)
   296  	test.ack(appDataSpace, 0*time.Millisecond, i64range[packetNumber]{0, 3})
   297  	test.wantAck(appDataSpace, 0, 1, 2)
   298  	// Redundant ACK doesn't trigger more ACK events.
   299  	// (If we did get an extra ACK, the test cleanup would notice and complain.)
   300  	test.ack(appDataSpace, 0*time.Millisecond, i64range[packetNumber]{0, 3})
   301  }
   302  
   303  func TestLossAckEveryOtherPacket(t *testing.T) {
   304  	test := newLossTest(t, clientSide, lossTestOpts{})
   305  	test.send(appDataSpace, 0, 1, 2, 3, 4, 5, 6)
   306  	test.ack(appDataSpace, 0*time.Millisecond, i64range[packetNumber]{0, 1})
   307  	test.wantAck(appDataSpace, 0)
   308  
   309  	test.ack(appDataSpace, 0*time.Millisecond, i64range[packetNumber]{2, 3})
   310  	test.wantAck(appDataSpace, 2)
   311  
   312  	test.ack(appDataSpace, 0*time.Millisecond, i64range[packetNumber]{4, 5})
   313  	test.wantAck(appDataSpace, 4)
   314  	test.wantLoss(appDataSpace, 1)
   315  
   316  	test.ack(appDataSpace, 0*time.Millisecond, i64range[packetNumber]{6, 7})
   317  	test.wantAck(appDataSpace, 6)
   318  	test.wantLoss(appDataSpace, 3)
   319  }
   320  
   321  func TestLossMultipleSpaces(t *testing.T) {
   322  	// "Loss detection is separate per packet number space [...]"
   323  	// https://www.rfc-editor.org/rfc/rfc9002.html#section-6-3
   324  	test := newLossTest(t, clientSide, lossTestOpts{})
   325  	t.Logf("# send packets in different spaces")
   326  	test.send(initialSpace, 0, 1, 2)
   327  	test.send(handshakeSpace, 0, 1, 2)
   328  	test.send(appDataSpace, 0, 1, 2)
   329  
   330  	t.Logf("# ack one packet in each space")
   331  	test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{1, 2})
   332  	test.wantAck(initialSpace, 1)
   333  
   334  	test.ack(handshakeSpace, 0*time.Millisecond, i64range[packetNumber]{1, 2})
   335  	test.wantAck(handshakeSpace, 1)
   336  
   337  	test.ack(appDataSpace, 0*time.Millisecond, i64range[packetNumber]{1, 2})
   338  	test.wantAck(appDataSpace, 1)
   339  
   340  	t.Logf("# send more packets")
   341  	test.send(initialSpace, 3, 4, 5)
   342  	test.send(handshakeSpace, 3, 4, 5)
   343  	test.send(appDataSpace, 3, 4, 5)
   344  
   345  	t.Logf("# ack the last packet, triggering loss")
   346  	test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{5, 6})
   347  	test.wantAck(initialSpace, 5)
   348  	test.wantLoss(initialSpace, 0, 2)
   349  
   350  	test.ack(handshakeSpace, 0*time.Millisecond, i64range[packetNumber]{5, 6})
   351  	test.wantAck(handshakeSpace, 5)
   352  	test.wantLoss(handshakeSpace, 0, 2)
   353  
   354  	test.ack(appDataSpace, 0*time.Millisecond, i64range[packetNumber]{5, 6})
   355  	test.wantAck(appDataSpace, 5)
   356  	test.wantLoss(appDataSpace, 0, 2)
   357  }
   358  
   359  func TestLossTimeThresholdFirstPacketLost(t *testing.T) {
   360  	// "[...] the packet [...] was sent long enough in the past."
   361  	// https://www.rfc-editor.org/rfc/rfc9002.html#section-6.1-3.2
   362  	test := newLossTest(t, clientSide, lossTestOpts{})
   363  	t.Logf("# packet 0 lost after time threshold passes")
   364  	test.send(initialSpace, 0, 1)
   365  	test.advance(10 * time.Millisecond)
   366  	test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{1, 2})
   367  	test.wantAck(initialSpace, 1)
   368  
   369  	t.Logf("# latest_rtt == smoothed_rtt")
   370  	test.wantVar("smoothed_rtt", 10*time.Millisecond)
   371  	test.wantVar("latest_rtt", 10*time.Millisecond)
   372  	t.Logf("# timeout = 9/8 * max(smoothed_rtt, latest_rtt) - time_since_packet_sent")
   373  	test.wantTimeout(((10 * time.Millisecond * 9) / 8) - 10*time.Millisecond)
   374  
   375  	test.advanceToLossTimer()
   376  	test.wantLoss(initialSpace, 0)
   377  }
   378  
   379  func TestLossTimeThreshold(t *testing.T) {
   380  	// "The time threshold is:
   381  	// max(kTimeThreshold * max(smoothed_rtt, latest_rtt), kGranularity)"
   382  	// https://www.rfc-editor.org/rfc/rfc9002.html#section-6.1.2-2
   383  	for _, tc := range []struct {
   384  		name        string
   385  		initialRTT  time.Duration
   386  		latestRTT   time.Duration
   387  		wantTimeout time.Duration
   388  	}{{
   389  		name:        "rtt increasing",
   390  		initialRTT:  10 * time.Millisecond,
   391  		latestRTT:   20 * time.Millisecond,
   392  		wantTimeout: 20 * time.Millisecond * 9 / 8,
   393  	}, {
   394  		name:        "rtt decreasing",
   395  		initialRTT:  10 * time.Millisecond,
   396  		latestRTT:   5 * time.Millisecond,
   397  		wantTimeout: ((7*10*time.Millisecond + 5*time.Millisecond) / 8) * 9 / 8,
   398  	}, {
   399  		name:        "rtt less than timer granularity",
   400  		initialRTT:  500 * time.Microsecond,
   401  		latestRTT:   500 * time.Microsecond,
   402  		wantTimeout: 1 * time.Millisecond,
   403  	}} {
   404  		t.Run(tc.name, func(t *testing.T) {
   405  			test := newLossTest(t, clientSide, lossTestOpts{})
   406  			t.Logf("# first ack establishes smoothed_rtt")
   407  			test.send(initialSpace, 0)
   408  			test.advance(tc.initialRTT)
   409  			test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 1})
   410  			test.wantAck(initialSpace, 0)
   411  
   412  			t.Logf("# ack of packet 2 starts loss timer for packet 1")
   413  			test.send(initialSpace, 1, 2)
   414  			test.advance(tc.latestRTT)
   415  			test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{2, 3})
   416  			test.wantAck(initialSpace, 2)
   417  
   418  			t.Logf("# smoothed_rtt = %v", test.c.rtt.smoothedRTT)
   419  			t.Logf("# latest_rtt = %v", test.c.rtt.latestRTT)
   420  			t.Logf("# timeout = max(9/8 * max(smoothed_rtt, latest_rtt), 1ms)")
   421  			t.Logf("#           (measured since packet 1 sent)")
   422  			test.wantTimeout(tc.wantTimeout - tc.latestRTT)
   423  
   424  			t.Logf("# advancing to the loss time causes loss of packet 1")
   425  			test.advanceToLossTimer()
   426  			test.wantLoss(initialSpace, 1)
   427  		})
   428  	}
   429  }
   430  
   431  func TestLossPTONotAckEliciting(t *testing.T) {
   432  	// "When an ack-eliciting packet is transmitted,
   433  	// the sender schedules a timer for the PTO period [...]"
   434  	// https://www.rfc-editor.org/rfc/rfc9002.html#section-6.2.1-1
   435  	test := newLossTest(t, clientSide, lossTestOpts{})
   436  	t.Logf("# PTO timer for first packet")
   437  	test.send(initialSpace, 0)
   438  	test.wantVar("smoothed_rtt", 333*time.Millisecond) // initial value
   439  	test.wantVar("rttvar", 333*time.Millisecond/2)     // initial value
   440  	t.Logf("# PTO = smoothed_rtt + max(4*rttvar, 1ms)")
   441  	test.wantTimeout(999 * time.Millisecond)
   442  
   443  	t.Logf("# sending a non-ack-eliciting packet doesn't adjust PTO")
   444  	test.advance(333 * time.Millisecond)
   445  	test.send(initialSpace, 1, sentPacket{
   446  		ackEliciting: false,
   447  	})
   448  	test.wantVar("smoothed_rtt", 333*time.Millisecond) // unchanged
   449  	test.wantVar("rttvar", 333*time.Millisecond/2)     // unchanged
   450  	test.wantTimeout(666 * time.Millisecond)
   451  }
   452  
   453  func TestLossPTOMaxAckDelay(t *testing.T) {
   454  	// "When the PTO is armed for Initial or Handshake packet number spaces,
   455  	// the max_ack_delay in the PTO period computation is set to 0 [...]"
   456  	// https://www.rfc-editor.org/rfc/rfc9002.html#section-6.2.1-4
   457  	test := newLossTest(t, clientSide, lossTestOpts{})
   458  	t.Logf("# PTO timer for first packet")
   459  	test.send(initialSpace, 0)
   460  	test.wantVar("smoothed_rtt", 333*time.Millisecond) // initial value
   461  	test.wantVar("rttvar", 333*time.Millisecond/2)     // initial value
   462  	t.Logf("# PTO = smoothed_rtt + max(4*rttvar, 1ms)")
   463  	test.wantTimeout(999 * time.Millisecond)
   464  
   465  	test.advance(10 * time.Millisecond)
   466  	test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 1})
   467  	test.wantAck(initialSpace, 0)
   468  
   469  	t.Logf("# PTO timer for handshake packet")
   470  	test.send(handshakeSpace, 0)
   471  	test.wantVar("smoothed_rtt", 10*time.Millisecond)
   472  	test.wantVar("rttvar", 5*time.Millisecond)
   473  	t.Logf("# PTO = smoothed_rtt + max(4*rttvar, 1ms)")
   474  	test.wantTimeout(30 * time.Millisecond)
   475  
   476  	test.advance(10 * time.Millisecond)
   477  	test.ack(handshakeSpace, 0*time.Millisecond, i64range[packetNumber]{0, 1})
   478  	test.wantAck(handshakeSpace, 0)
   479  	test.confirmHandshake()
   480  
   481  	t.Logf("# PTO timer for appdata packet")
   482  	test.send(appDataSpace, 0)
   483  	test.wantVar("smoothed_rtt", 10*time.Millisecond)
   484  	test.wantVar("rttvar", 3750*time.Microsecond)
   485  	t.Logf("# PTO = smoothed_rtt + max(4*rttvar, 1ms) + max_ack_delay (25ms)")
   486  	test.wantTimeout(50 * time.Millisecond)
   487  }
   488  
   489  func TestLossPTOUnderTimerGranularity(t *testing.T) {
   490  	// "The PTO period MUST be at least kGranularity [...]"
   491  	// https://www.rfc-editor.org/rfc/rfc9002.html#section-6.2.1-5
   492  	test := newLossTest(t, clientSide, lossTestOpts{})
   493  	test.send(initialSpace, 0)
   494  	test.advance(10 * time.Microsecond)
   495  	test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 1})
   496  	test.wantAck(initialSpace, 0)
   497  
   498  	test.send(initialSpace, 1)
   499  	test.wantVar("smoothed_rtt", 10*time.Microsecond)
   500  	test.wantVar("rttvar", 5*time.Microsecond)
   501  	t.Logf("# PTO = smoothed_rtt + max(4*rttvar, 1ms)")
   502  	test.wantTimeout(10*time.Microsecond + 1*time.Millisecond)
   503  }
   504  
   505  func TestLossPTOMultipleSpaces(t *testing.T) {
   506  	// "[...] the timer MUST be set to the earlier value of the Initial and Handshake
   507  	// packet number spaces."
   508  	// https://www.rfc-editor.org/rfc/rfc9002.html#section-6.2.1-6
   509  	test := newLossTest(t, clientSide, lossTestOpts{})
   510  	t.Logf("# PTO timer for first packet")
   511  	test.send(initialSpace, 0)
   512  	test.wantVar("smoothed_rtt", 333*time.Millisecond) // initial value
   513  	test.wantVar("rttvar", 333*time.Millisecond/2)     // initial value
   514  	t.Logf("# PTO = smoothed_rtt + max(4*rttvar, 1ms)")
   515  	test.wantTimeout(999 * time.Millisecond)
   516  
   517  	t.Logf("# Initial and Handshake packets in flight, first takes precedence")
   518  	test.advance(333 * time.Millisecond)
   519  	test.send(handshakeSpace, 0)
   520  	test.wantTimeout(666 * time.Millisecond)
   521  
   522  	t.Logf("# Initial packet acked, Handshake PTO timer armed")
   523  	test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 1})
   524  	test.wantAck(initialSpace, 0)
   525  	test.wantTimeout(999 * time.Millisecond)
   526  
   527  	t.Logf("# send Initial, earlier Handshake PTO takes precedence")
   528  	test.advance(333 * time.Millisecond)
   529  	test.send(initialSpace, 1)
   530  	test.wantTimeout(666 * time.Millisecond)
   531  }
   532  
   533  func TestLossPTOHandshakeConfirmation(t *testing.T) {
   534  	// "An endpoint MUST NOT set its PTO timer for the Application Data
   535  	// packet number space until the handshake is confirmed."
   536  	// https://www.rfc-editor.org/rfc/rfc9002.html#section-6.2.1-7
   537  	test := newLossTest(t, clientSide, lossTestOpts{})
   538  	test.send(initialSpace, 0)
   539  	test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 1})
   540  	test.wantAck(initialSpace, 0)
   541  
   542  	test.send(handshakeSpace, 0)
   543  	test.ack(handshakeSpace, 0*time.Millisecond, i64range[packetNumber]{0, 1})
   544  	test.wantAck(handshakeSpace, 0)
   545  
   546  	test.send(appDataSpace, 0)
   547  	test.wantNoTimeout()
   548  }
   549  
   550  func TestLossPTOBackoffDoubles(t *testing.T) {
   551  	// "When a PTO timer expires, the PTO backoff MUST be increased,
   552  	// resulting in the PTO period being set to twice its current value."
   553  	// https://www.rfc-editor.org/rfc/rfc9002.html#section-6.2.1-9
   554  	test := newLossTest(t, serverSide, lossTestOpts{})
   555  	test.datagramReceived(1200)
   556  	test.send(initialSpace, 0)
   557  	test.wantVar("smoothed_rtt", 333*time.Millisecond) // initial value
   558  	test.wantVar("rttvar", 333*time.Millisecond/2)     // initial value
   559  	t.Logf("# PTO = smoothed_rtt + max(4*rttvar, 1ms)")
   560  	test.wantTimeout(999 * time.Millisecond)
   561  
   562  	t.Logf("# wait for PTO timer expiration")
   563  	test.advanceToLossTimer()
   564  	test.wantPTOExpired()
   565  	test.wantNoTimeout()
   566  
   567  	t.Logf("# PTO timer doubles")
   568  	test.send(initialSpace, 1)
   569  	test.wantTimeout(2 * 999 * time.Millisecond)
   570  	test.advanceToLossTimer()
   571  	test.wantPTOExpired()
   572  	test.wantNoTimeout()
   573  
   574  	t.Logf("# PTO timer doubles again")
   575  	test.send(initialSpace, 2)
   576  	test.wantTimeout(4 * 999 * time.Millisecond)
   577  	test.advanceToLossTimer()
   578  	test.wantPTOExpired()
   579  	test.wantNoTimeout()
   580  }
   581  
   582  func TestLossPTOBackoffResetOnAck(t *testing.T) {
   583  	// "The PTO backoff factor is reset when an acknowledgment is received [...]"
   584  	// https://www.rfc-editor.org/rfc/rfc9002.html#section-6.2.1-9
   585  	test := newLossTest(t, serverSide, lossTestOpts{})
   586  	test.datagramReceived(1200)
   587  
   588  	t.Logf("# first ack establishes smoothed_rtt = 10ms")
   589  	test.send(initialSpace, 0)
   590  	test.advance(10 * time.Millisecond)
   591  	test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 1})
   592  	test.wantAck(initialSpace, 0)
   593  	t.Logf("# set rttvar for simplicity")
   594  	test.setRTTVar(0)
   595  
   596  	t.Logf("# send packet 1 and wait for PTO")
   597  	test.send(initialSpace, 1)
   598  	test.wantTimeout(11 * time.Millisecond)
   599  	test.advanceToLossTimer()
   600  	test.wantPTOExpired()
   601  	test.wantNoTimeout()
   602  
   603  	t.Logf("# send packet 2 & 3, PTO doubles")
   604  	test.send(initialSpace, 2, 3)
   605  	test.wantTimeout(22 * time.Millisecond)
   606  
   607  	test.advance(10 * time.Millisecond)
   608  	t.Logf("# check remaining PTO (22ms - 10ms elapsed)")
   609  	test.wantTimeout(12 * time.Millisecond)
   610  
   611  	t.Logf("# ACK to packet 2 resets PTO")
   612  	test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 3})
   613  	test.wantAck(initialSpace, 1)
   614  	test.wantAck(initialSpace, 2)
   615  
   616  	t.Logf("# check remaining PTO (11ms - 10ms elapsed)")
   617  	test.wantTimeout(1 * time.Millisecond)
   618  }
   619  
   620  func TestLossPTOBackoffNotResetOnClientInitialAck(t *testing.T) {
   621  	// "[...] a client does not reset the PTO backoff factor on
   622  	// receiving acknowledgments in Initial packets."
   623  	// https://www.rfc-editor.org/rfc/rfc9002.html#section-6.2.1-9
   624  	test := newLossTest(t, clientSide, lossTestOpts{})
   625  
   626  	t.Logf("# first ack establishes smoothed_rtt = 10ms")
   627  	test.send(initialSpace, 0)
   628  	test.advance(10 * time.Millisecond)
   629  	test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 1})
   630  	test.wantAck(initialSpace, 0)
   631  	t.Logf("# set rttvar for simplicity")
   632  	test.setRTTVar(0)
   633  
   634  	t.Logf("# send packet 1 and wait for PTO")
   635  	test.send(initialSpace, 1)
   636  	test.wantTimeout(11 * time.Millisecond)
   637  	test.advanceToLossTimer()
   638  	test.wantPTOExpired()
   639  	test.wantNoTimeout()
   640  
   641  	t.Logf("# send more packets, PTO doubles")
   642  	test.send(initialSpace, 2, 3)
   643  	test.send(handshakeSpace, 0)
   644  	test.wantTimeout(22 * time.Millisecond)
   645  
   646  	test.advance(10 * time.Millisecond)
   647  	t.Logf("# check remaining PTO (22ms - 10ms elapsed)")
   648  	test.wantTimeout(12 * time.Millisecond)
   649  
   650  	// TODO: Is this right? 6.2.1-9 says we don't reset the PTO *backoff*, not the PTO.
   651  	// 6.2.1-8 says we reset the PTO timer when an ack-eliciting packet is sent *or
   652  	// acknowledged*, but the pseudocode in appendix A doesn't appear to do the latter.
   653  	t.Logf("# ACK to Initial packet does not reset PTO for client")
   654  	test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 3})
   655  	test.wantAck(initialSpace, 1)
   656  	test.wantAck(initialSpace, 2)
   657  	t.Logf("# check remaining PTO (22ms - 10ms elapsed)")
   658  	test.wantTimeout(12 * time.Millisecond)
   659  
   660  	t.Logf("# ACK to handshake packet does reset PTO")
   661  	test.ack(handshakeSpace, 0*time.Millisecond, i64range[packetNumber]{0, 1})
   662  	test.wantAck(handshakeSpace, 0)
   663  	t.Logf("# check remaining PTO (12ms - 10ms elapsed)")
   664  	test.wantTimeout(1 * time.Millisecond)
   665  }
   666  
   667  func TestLossPTONotSetWhenLossTimerSet(t *testing.T) {
   668  	// "The PTO timer MUST NOT be set if a timer is set
   669  	// for time threshold loss detection [...]"
   670  	// https://www.rfc-editor.org/rfc/rfc9002.html#section-6.2.1-12
   671  	test := newLossTest(t, serverSide, lossTestOpts{})
   672  	test.datagramReceived(1200)
   673  	t.Logf("# PTO timer set for first packets sent")
   674  	test.send(initialSpace, 0, 1)
   675  	test.wantVar("smoothed_rtt", 333*time.Millisecond) // initial value
   676  	test.wantVar("rttvar", 333*time.Millisecond/2)     // initial value
   677  	t.Logf("# PTO = smoothed_rtt + max(4*rttvar, 1ms)")
   678  	test.wantTimeout(999 * time.Millisecond)
   679  
   680  	t.Logf("# ack of packet 1 starts loss timer for 0, PTO overidden")
   681  	test.advance(333 * time.Millisecond)
   682  	test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{1, 2})
   683  	test.wantAck(initialSpace, 1)
   684  
   685  	t.Logf("# latest_rtt == smoothed_rtt")
   686  	test.wantVar("smoothed_rtt", 333*time.Millisecond)
   687  	test.wantVar("latest_rtt", 333*time.Millisecond)
   688  	t.Logf("# timeout = 9/8 * max(smoothed_rtt, latest_rtt) - time_since_packet_sent")
   689  	test.wantTimeout(((333 * time.Millisecond * 9) / 8) - 333*time.Millisecond)
   690  }
   691  
   692  func TestLossDiscardingKeysResetsTimers(t *testing.T) {
   693  	// "When Initial or Handshake keys are discarded,
   694  	// the PTO and loss detection timers MUST be reset"
   695  	// https://www.rfc-editor.org/rfc/rfc9002.html#section-6.2.2-3
   696  	test := newLossTest(t, clientSide, lossTestOpts{})
   697  
   698  	t.Logf("# handshake packet sent 1ms after initial")
   699  	test.send(initialSpace, 0, 1)
   700  	test.advance(1 * time.Millisecond)
   701  	test.send(handshakeSpace, 0, 1)
   702  	test.advance(9 * time.Millisecond)
   703  
   704  	t.Logf("# ack of Initial packet 2 starts loss timer for packet 1")
   705  	test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{1, 2})
   706  	test.wantAck(initialSpace, 1)
   707  
   708  	test.advance(1 * time.Millisecond)
   709  	t.Logf("# smoothed_rtt = %v", 10*time.Millisecond)
   710  	t.Logf("# latest_rtt = %v", 10*time.Millisecond)
   711  	t.Logf("# timeout = max(9/8 * max(smoothed_rtt, latest_rtt), 1ms)")
   712  	t.Logf("#           (measured since Initial packet 1 sent)")
   713  	test.wantTimeout((10 * time.Millisecond * 9 / 8) - 11*time.Millisecond)
   714  
   715  	t.Logf("# ack of Handshake packet 2 starts loss timer for packet 1")
   716  	test.ack(handshakeSpace, 0*time.Millisecond, i64range[packetNumber]{1, 2})
   717  	test.wantAck(handshakeSpace, 1)
   718  
   719  	t.Logf("# dropping Initial keys sets timer to Handshake timeout")
   720  	test.discardKeys(initialSpace)
   721  	test.wantTimeout((10 * time.Millisecond * 9 / 8) - 10*time.Millisecond)
   722  }
   723  
   724  func TestLossNoPTOAtAntiAmplificationLimit(t *testing.T) {
   725  	// "If no additional data can be sent [because the server is at the
   726  	// anti-amplification limit], the server's PTO timer MUST NOT be armed [...]"
   727  	// https://www.rfc-editor.org/rfc/rfc9002.html#section-6.2.2.1-1
   728  	test := newLossTest(t, serverSide, lossTestOpts{
   729  		maxDatagramSize: 1 << 20, // large initial congestion window
   730  	})
   731  	test.datagramReceived(1200)
   732  	test.send(initialSpace, 0, sentPacket{
   733  		ackEliciting: true,
   734  		inFlight:     true,
   735  		size:         1200,
   736  	})
   737  	test.wantTimeout(999 * time.Millisecond)
   738  
   739  	t.Logf("PTO timer should be disabled when at the anti-amplification limit")
   740  	test.send(initialSpace, 1, sentPacket{
   741  		ackEliciting: false,
   742  		inFlight:     true,
   743  		size:         2 * 1200,
   744  	})
   745  	test.wantNoTimeout()
   746  
   747  	// "When the server receives a datagram from the client, the amplification
   748  	// limit is increased and the server resets the PTO timer."
   749  	// https://www.rfc-editor.org/rfc/rfc9002.html#section-6.2.2.1-2
   750  	t.Logf("PTO timer should be reset when datagrams are received")
   751  	test.datagramReceived(1200)
   752  	test.wantTimeout(999 * time.Millisecond)
   753  
   754  	// "If the PTO timer is then set to a time in the past, it is executed immediately."
   755  	// https://www.rfc-editor.org/rfc/rfc9002.html#section-6.2.2.1-2
   756  	test.send(initialSpace, 2, sentPacket{
   757  		ackEliciting: true,
   758  		inFlight:     true,
   759  		size:         3 * 1200,
   760  	})
   761  	test.wantNoTimeout()
   762  	t.Logf("resetting expired PTO timer should exeute immediately")
   763  	test.advance(1000 * time.Millisecond)
   764  	test.datagramReceived(1200)
   765  	test.wantPTOExpired()
   766  	test.wantNoTimeout()
   767  }
   768  
   769  func TestLossClientSetsPTOWhenHandshakeUnacked(t *testing.T) {
   770  	// "[...] the client MUST set the PTO timer if the client has not
   771  	// received an acknowledgment for any of its Handshake packets and
   772  	// the handshake is not confirmed [...]"
   773  	// https://www.rfc-editor.org/rfc/rfc9002.html#section-6.2.2.1-3
   774  	test := newLossTest(t, clientSide, lossTestOpts{})
   775  	test.send(initialSpace, 0)
   776  
   777  	test.wantVar("smoothed_rtt", 333*time.Millisecond) // initial value
   778  	test.wantVar("rttvar", 333*time.Millisecond/2)     // initial value
   779  	t.Logf("# PTO = smoothed_rtt + max(4*rttvar, 1ms)")
   780  	test.wantTimeout(999 * time.Millisecond)
   781  
   782  	test.advance(333 * time.Millisecond)
   783  	test.wantTimeout(666 * time.Millisecond)
   784  	test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 1})
   785  	test.wantAck(initialSpace, 0)
   786  	t.Logf("# PTO timer set for a client before handshake ack even if no packets in flight")
   787  	test.wantTimeout(999 * time.Millisecond)
   788  
   789  	test.advance(333 * time.Millisecond)
   790  	test.wantTimeout(666 * time.Millisecond)
   791  }
   792  
   793  func TestLossKeysDiscarded(t *testing.T) {
   794  	// "The sender MUST discard all recovery state associated with
   795  	// [packets in number spaces with discarded keys] and MUST remove
   796  	// them from the count of bytes in flight."
   797  	// https://www.rfc-editor.org/rfc/rfc9002.html#section-6.4-1
   798  	test := newLossTest(t, clientSide, lossTestOpts{})
   799  	test.send(initialSpace, 0, testSentPacketSize(1200))
   800  	test.send(handshakeSpace, 0, testSentPacketSize(600))
   801  	test.wantVar("bytes_in_flight", 1800)
   802  
   803  	test.discardKeys(initialSpace)
   804  	test.wantVar("bytes_in_flight", 600)
   805  
   806  	test.discardKeys(handshakeSpace)
   807  	test.wantVar("bytes_in_flight", 0)
   808  }
   809  
   810  func TestLossInitialCongestionWindow(t *testing.T) {
   811  	// "Endpoints SHOULD use an initial congestion window of [...]"
   812  	// https://www.rfc-editor.org/rfc/rfc9002.html#section-7.2-1
   813  
   814  	// "[...] 10 times the maximum datagram size [...]"
   815  	test := newLossTest(t, clientSide, lossTestOpts{
   816  		maxDatagramSize: 1200,
   817  	})
   818  	t.Logf("# congestion_window = 10*max_datagram_size (1200)")
   819  	test.wantVar("congestion_window", 12000)
   820  
   821  	// "[...] while limiting the window to the larger of 14720 bytes [...]"
   822  	test = newLossTest(t, clientSide, lossTestOpts{
   823  		maxDatagramSize: 1500,
   824  	})
   825  	t.Logf("# congestion_window limited to 14720 bytes")
   826  	test.wantVar("congestion_window", 14720)
   827  
   828  	// "[...] or twice the maximum datagram size."
   829  	test = newLossTest(t, clientSide, lossTestOpts{
   830  		maxDatagramSize: 10000,
   831  	})
   832  	t.Logf("# congestion_window limited to 2*max_datagram_size (10000)")
   833  	test.wantVar("congestion_window", 20000)
   834  
   835  	for _, tc := range []struct {
   836  		maxDatagramSize  int
   837  		wantInitialBurst int
   838  	}{{
   839  		// "[...] 10 times the maximum datagram size [...]"
   840  		maxDatagramSize:  1200,
   841  		wantInitialBurst: 12000,
   842  	}, {
   843  		// "[...] while limiting the window to the larger of 14720 bytes [...]"
   844  		maxDatagramSize:  1500,
   845  		wantInitialBurst: 14720,
   846  	}, {
   847  		// "[...] or twice the maximum datagram size."
   848  		maxDatagramSize:  10000,
   849  		wantInitialBurst: 20000,
   850  	}} {
   851  		t.Run(fmt.Sprintf("max_datagram_size=%v", tc.maxDatagramSize), func(t *testing.T) {
   852  			test := newLossTest(t, clientSide, lossTestOpts{
   853  				maxDatagramSize: tc.maxDatagramSize,
   854  			})
   855  
   856  			var num packetNumber
   857  			window := tc.wantInitialBurst
   858  			for window >= tc.maxDatagramSize {
   859  				t.Logf("# %v bytes of initial congestion window remain", window)
   860  				test.send(initialSpace, num, sentPacket{
   861  					ackEliciting: true,
   862  					inFlight:     true,
   863  					size:         tc.maxDatagramSize,
   864  				})
   865  				window -= tc.maxDatagramSize
   866  				num++
   867  			}
   868  			t.Logf("# congestion window (%v) < max_datagram_size, congestion control blocks send", window)
   869  			test.wantSendLimit(ccLimited)
   870  		})
   871  	}
   872  }
   873  
   874  func TestLossBytesInFlight(t *testing.T) {
   875  	test := newLossTest(t, clientSide, lossTestOpts{
   876  		maxDatagramSize: 1200,
   877  	})
   878  	t.Logf("# sent packets are added to bytes_in_flight")
   879  	test.wantVar("bytes_in_flight", 0)
   880  	test.send(initialSpace, 0, testSentPacketSize(1200))
   881  	test.wantVar("bytes_in_flight", 1200)
   882  	test.send(initialSpace, 1, testSentPacketSize(800))
   883  	test.wantVar("bytes_in_flight", 2000)
   884  
   885  	t.Logf("# acked packets are removed from bytes_in_flight")
   886  	test.advance(10 * time.Millisecond)
   887  	test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{1, 2})
   888  	test.wantAck(initialSpace, 1)
   889  	test.wantVar("bytes_in_flight", 1200)
   890  
   891  	t.Logf("# lost packets are removed from bytes_in_flight")
   892  	test.advanceToLossTimer()
   893  	test.wantLoss(initialSpace, 0)
   894  	test.wantVar("bytes_in_flight", 0)
   895  }
   896  
   897  func TestLossCongestionWindowLimit(t *testing.T) {
   898  	// "An endpoint MUST NOT send a packet if it would cause bytes_in_flight
   899  	// [...] to be larger than the congestion window [...]"
   900  	// https://www.rfc-editor.org/rfc/rfc9002.html#section-7-7
   901  	test := newLossTest(t, clientSide, lossTestOpts{
   902  		maxDatagramSize: 1200,
   903  	})
   904  	t.Logf("# consume the initial congestion window")
   905  	test.send(initialSpace, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, testSentPacketSize(1200))
   906  	test.wantSendLimit(ccLimited)
   907  
   908  	t.Logf("# give the pacer bucket time to refill")
   909  	test.advance(333 * time.Millisecond) // initial RTT
   910  
   911  	t.Logf("# sending limited by congestion window, not the pacer")
   912  	test.wantVar("congestion_window", 12000)
   913  	test.wantVar("bytes_in_flight", 12000)
   914  	test.wantVar("pacer_bucket", 12000)
   915  	test.wantSendLimit(ccLimited)
   916  
   917  	t.Logf("# receiving an ack opens up the congestion window")
   918  	test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 1})
   919  	test.wantAck(initialSpace, 0)
   920  	test.wantSendLimit(ccOK)
   921  }
   922  
   923  func TestLossCongestionStates(t *testing.T) {
   924  	test := newLossTest(t, clientSide, lossTestOpts{
   925  		maxDatagramSize: 1200,
   926  	})
   927  	t.Logf("# consume the initial congestion window")
   928  	test.send(initialSpace, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, testSentPacketSize(1200))
   929  	test.wantSendLimit(ccLimited)
   930  	test.wantVar("congestion_window", 12000)
   931  
   932  	// "While a sender is in slow start, the congestion window
   933  	// increases by the number of bytes acknowledged [...]"
   934  	// https://www.rfc-editor.org/rfc/rfc9002.html#section-7.3.1-2
   935  	test.advance(333 * time.Millisecond)
   936  	t.Logf("# congestion window increases by number of bytes acked (1200)")
   937  	test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 1})
   938  	test.wantAck(initialSpace, 0)
   939  	test.wantVar("congestion_window", 13200) // 12000 + 1200
   940  
   941  	t.Logf("# congestion window increases by number of bytes acked (2400)")
   942  	test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 3})
   943  	test.wantAck(initialSpace, 1, 2)
   944  	test.wantVar("congestion_window", 15600) // 12000 + 3*1200
   945  
   946  	// TODO: ECN-CE count
   947  
   948  	// "The sender MUST exit slow start and enter a recovery period
   949  	// when a packet is lost [...]"
   950  	// https://www.rfc-editor.org/rfc/rfc9002.html#section-7.3.1-3
   951  	t.Logf("# loss of a packet triggers entry to a recovery period")
   952  	test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{6, 7})
   953  	test.wantAck(initialSpace, 6)
   954  	test.wantLoss(initialSpace, 3)
   955  
   956  	// "On entering a recovery period, a sender MUST set the slow start
   957  	// threshold to half the value of the congestion window when loss is detected."
   958  	// https://www.rfc-editor.org/rfc/rfc9002.html#section-7.3.2-2
   959  	t.Logf("# slow_start_threshold = congestion_window / 2")
   960  	test.wantVar("slow_start_threshold", 7800) // 15600/2
   961  
   962  	// "[...] a single packet can be sent prior to reduction [of the congestion window]."
   963  	// https://www.rfc-editor.org/rfc/rfc9002.html#section-7.3.2-3
   964  	test.send(initialSpace, 10, testSentPacketSize(1200))
   965  
   966  	// "The congestion window MUST be set to the reduced value of the slow start
   967  	// threshold before exiting the recovery period."
   968  	// https://www.rfc-editor.org/rfc/rfc9002.html#section-7.3.2-2
   969  	t.Logf("# congestion window reduced to slow start threshold")
   970  	test.wantVar("congestion_window", 7800)
   971  
   972  	t.Logf("# acks for packets sent before recovery started do not affect congestion")
   973  	test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 10})
   974  	test.wantAck(initialSpace, 4, 5, 7, 8, 9)
   975  	test.wantVar("slow_start_threshold", 7800)
   976  	test.wantVar("congestion_window", 7800)
   977  
   978  	// "A recovery period ends and the sender enters congestion avoidance when
   979  	// a packet sent during the recovery period is acknowledged."
   980  	// https://www.rfc-editor.org/rfc/rfc9002.html#section-7.3.2-5
   981  	t.Logf("# recovery ends and congestion avoidance begins when packet 10 is acked")
   982  	test.advance(333 * time.Millisecond)
   983  	test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 11})
   984  	test.wantAck(initialSpace, 10)
   985  
   986  	// "[...] limit the increase to the congestion window to at most one
   987  	// maximum datagram size for each congestion window that is acknowledged."
   988  	// https://www.rfc-editor.org/rfc/rfc9002.html#section-7.3.3-2
   989  	t.Logf("# after processing acks for one congestion window's worth of data...")
   990  	test.send(initialSpace, 11, 12, 13, 14, 15, 16, testSentPacketSize(1200))
   991  	test.advance(333 * time.Millisecond)
   992  	test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 17})
   993  	test.wantAck(initialSpace, 11, 12, 13, 14, 15, 16)
   994  	t.Logf("# ...congestion window increases by max_datagram_size")
   995  	test.wantVar("congestion_window", 9000) // 7800 + 1200
   996  
   997  	// "The sender exits congestion avoidance and enters a recovery period
   998  	// when a packet is lost [...]"
   999  	// https://www.rfc-editor.org/rfc/rfc9002.html#section-7.3.3-3
  1000  	test.send(initialSpace, 17, 18, 19, 20, 21, testSentPacketSize(1200))
  1001  	test.advance(333 * time.Millisecond)
  1002  	test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{18, 21})
  1003  	test.wantAck(initialSpace, 18, 19, 20)
  1004  	test.wantLoss(initialSpace, 17)
  1005  	t.Logf("# slow_start_threshold = congestion_window / 2")
  1006  	test.wantVar("slow_start_threshold", 4500)
  1007  }
  1008  
  1009  func TestLossMinimumCongestionWindow(t *testing.T) {
  1010  	// "The RECOMMENDED [minimum congestion window] is 2 * max_datagram_size."
  1011  	// https://www.rfc-editor.org/rfc/rfc9002.html#section-7.2-4
  1012  	test := newLossTest(t, clientSide, lossTestOpts{
  1013  		maxDatagramSize: 1200,
  1014  	})
  1015  	test.send(initialSpace, 0, 1, 2, 3, testSentPacketSize(1200))
  1016  	test.wantVar("congestion_window", 12000)
  1017  
  1018  	t.Logf("# enter recovery")
  1019  	test.advance(333 * time.Millisecond)
  1020  	test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{3, 4})
  1021  	test.wantAck(initialSpace, 3)
  1022  	test.wantLoss(initialSpace, 0)
  1023  	test.wantVar("congestion_window", 6000)
  1024  
  1025  	t.Logf("# enter congestion avoidance and return to recovery")
  1026  	test.send(initialSpace, 4, 5, 6, 7)
  1027  	test.advance(333 * time.Millisecond)
  1028  	test.wantLoss(initialSpace, 1, 2)
  1029  	test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{7, 8})
  1030  	test.wantAck(initialSpace, 7)
  1031  	test.wantLoss(initialSpace, 4)
  1032  	test.wantVar("congestion_window", 3000)
  1033  
  1034  	t.Logf("# enter congestion avoidance and return to recovery")
  1035  	test.send(initialSpace, 8, 9, 10, 11)
  1036  	test.advance(333 * time.Millisecond)
  1037  	test.wantLoss(initialSpace, 5, 6)
  1038  	test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{11, 12})
  1039  	test.wantAck(initialSpace, 11)
  1040  	test.wantLoss(initialSpace, 8)
  1041  	t.Logf("# congestion window does not fall below 2*max_datagram_size")
  1042  	test.wantVar("congestion_window", 2400)
  1043  
  1044  	t.Logf("# enter congestion avoidance and return to recovery")
  1045  	test.send(initialSpace, 12, 13, 14, 15)
  1046  	test.advance(333 * time.Millisecond)
  1047  	test.wantLoss(initialSpace, 9, 10)
  1048  	test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{15, 16})
  1049  	test.wantAck(initialSpace, 15)
  1050  	test.wantLoss(initialSpace, 12)
  1051  	t.Logf("# congestion window does not fall below 2*max_datagram_size")
  1052  	test.wantVar("congestion_window", 2400)
  1053  }
  1054  
  1055  func TestLossPersistentCongestion(t *testing.T) {
  1056  	// "When persistent congestion is declared, the sender's congestion
  1057  	// window MUST be reduced to the minimum congestion window [...]"
  1058  	// https://www.rfc-editor.org/rfc/rfc9002.html#section-7.6.2-6
  1059  	test := newLossTest(t, clientSide, lossTestOpts{
  1060  		maxDatagramSize: 1200,
  1061  	})
  1062  	test.send(initialSpace, 0, testSentPacketSize(1200))
  1063  	test.c.cc.setUnderutilized(nil, true)
  1064  
  1065  	test.advance(10 * time.Millisecond)
  1066  	test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 1})
  1067  	test.wantAck(initialSpace, 0)
  1068  
  1069  	t.Logf("# set rttvar for simplicity")
  1070  	test.setRTTVar(0)
  1071  	test.wantVar("smoothed_rtt", 10*time.Millisecond)
  1072  	t.Logf("# persistent congestion duration = 3*(smoothed_rtt + timerGranularity + max_ack_delay)")
  1073  	t.Logf("# persistent congestion duration = 108ms")
  1074  
  1075  	t.Logf("# sending packets 1-5 over 108ms")
  1076  	test.send(initialSpace, 1, testSentPacketSize(1200))
  1077  
  1078  	test.advance(11 * time.Millisecond) // total 11ms
  1079  	test.wantPTOExpired()
  1080  	test.send(initialSpace, 2, testSentPacketSize(1200))
  1081  
  1082  	test.advance(22 * time.Millisecond) // total 33ms
  1083  	test.wantPTOExpired()
  1084  	test.send(initialSpace, 3, testSentPacketSize(1200))
  1085  
  1086  	test.advance(44 * time.Millisecond) // total 77ms
  1087  	test.wantPTOExpired()
  1088  	test.send(initialSpace, 4, testSentPacketSize(1200))
  1089  
  1090  	test.advance(31 * time.Millisecond) // total 108ms
  1091  	test.send(initialSpace, 5, testSentPacketSize(1200))
  1092  	t.Logf("# 108ms between packets 1-5")
  1093  
  1094  	test.wantVar("congestion_window", 12000)
  1095  	t.Logf("# triggering loss of packets 1-5")
  1096  	test.send(initialSpace, 6, 7, 8, testSentPacketSize(1200))
  1097  	test.advance(10 * time.Millisecond)
  1098  	test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{8, 9})
  1099  	test.wantAck(initialSpace, 8)
  1100  	test.wantLoss(initialSpace, 1, 2, 3, 4, 5)
  1101  
  1102  	t.Logf("# lost packets spanning persistent congestion duration")
  1103  	t.Logf("# congestion_window = 2 * max_datagram_size (minimum)")
  1104  	test.wantVar("congestion_window", 2400)
  1105  }
  1106  
  1107  func TestLossSimplePersistentCongestion(t *testing.T) {
  1108  	// Simpler version of TestLossPersistentCongestion which acts as a
  1109  	// base for subsequent tests.
  1110  	test := newLossTest(t, clientSide, lossTestOpts{
  1111  		maxDatagramSize: 1200,
  1112  	})
  1113  
  1114  	t.Logf("# establish initial RTT sample")
  1115  	test.send(initialSpace, 0, testSentPacketSize(1200))
  1116  	test.advance(10 * time.Millisecond)
  1117  	test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 1})
  1118  	test.wantAck(initialSpace, 0)
  1119  
  1120  	t.Logf("# send two packets spanning persistent congestion duration")
  1121  	test.send(initialSpace, 1, testSentPacketSize(1200))
  1122  	t.Logf("# 2000ms >> persistent congestion duration")
  1123  	test.advance(2000 * time.Millisecond)
  1124  	test.wantPTOExpired()
  1125  	test.send(initialSpace, 2, testSentPacketSize(1200))
  1126  
  1127  	t.Logf("# trigger loss of previous packets")
  1128  	test.advance(10 * time.Millisecond)
  1129  	test.send(initialSpace, 3, testSentPacketSize(1200))
  1130  	test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{3, 4})
  1131  	test.wantAck(initialSpace, 3)
  1132  	test.wantLoss(initialSpace, 1, 2)
  1133  
  1134  	t.Logf("# persistent congestion detected")
  1135  	test.wantVar("congestion_window", 2400)
  1136  }
  1137  
  1138  func TestLossPersistentCongestionAckElicitingPackets(t *testing.T) {
  1139  	// "These two packets MUST be ack-eliciting [...]"
  1140  	// https://www.rfc-editor.org/rfc/rfc9002.html#section-7.6.2-3
  1141  	test := newLossTest(t, clientSide, lossTestOpts{
  1142  		maxDatagramSize: 1200,
  1143  	})
  1144  
  1145  	t.Logf("# establish initial RTT sample")
  1146  	test.send(initialSpace, 0, testSentPacketSize(1200))
  1147  	test.advance(10 * time.Millisecond)
  1148  	test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 1})
  1149  	test.wantAck(initialSpace, 0)
  1150  
  1151  	t.Logf("# send two packets spanning persistent congestion duration")
  1152  	test.send(initialSpace, 1, testSentPacketSize(1200))
  1153  	t.Logf("# 2000ms >> persistent congestion duration")
  1154  	test.advance(2000 * time.Millisecond)
  1155  	test.wantPTOExpired()
  1156  	test.send(initialSpace, 2, sentPacket{
  1157  		inFlight:     true,
  1158  		ackEliciting: false,
  1159  		size:         1200,
  1160  	})
  1161  	test.send(initialSpace, 3, testSentPacketSize(1200)) // PTO probe
  1162  
  1163  	t.Logf("# trigger loss of previous packets")
  1164  	test.advance(10 * time.Millisecond)
  1165  	test.send(initialSpace, 4, testSentPacketSize(1200))
  1166  	test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{3, 5})
  1167  	test.wantAck(initialSpace, 3)
  1168  	test.wantAck(initialSpace, 4)
  1169  	test.wantLoss(initialSpace, 1, 2)
  1170  
  1171  	t.Logf("# persistent congestion not detected: packet 2 is not ack-eliciting")
  1172  	test.wantVar("congestion_window", (12000+1200+1200-1200)/2)
  1173  }
  1174  
  1175  func TestLossNoPersistentCongestionWithoutRTTSample(t *testing.T) {
  1176  	// "The persistent congestion period SHOULD NOT start until there
  1177  	// is at least one RTT sample."
  1178  	// https://www.rfc-editor.org/rfc/rfc9002.html#section-7.6.2-4
  1179  	test := newLossTest(t, clientSide, lossTestOpts{
  1180  		maxDatagramSize: 1200,
  1181  	})
  1182  
  1183  	t.Logf("# packets sent before initial RTT sample")
  1184  	test.send(initialSpace, 0, testSentPacketSize(1200))
  1185  	test.advance(2000 * time.Millisecond)
  1186  	test.wantPTOExpired()
  1187  	test.send(initialSpace, 1, testSentPacketSize(1200))
  1188  
  1189  	test.advance(10 * time.Millisecond)
  1190  	test.send(initialSpace, 2, testSentPacketSize(1200))
  1191  
  1192  	t.Logf("# first ack establishes RTT sample")
  1193  	test.advance(10 * time.Millisecond)
  1194  	test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{2, 3})
  1195  	test.wantAck(initialSpace, 2)
  1196  	test.wantLoss(initialSpace, 0, 1)
  1197  
  1198  	t.Logf("# loss of packets before initial RTT sample does not cause persistent congestion")
  1199  	test.wantVar("congestion_window", 12000/2)
  1200  }
  1201  
  1202  func TestLossPacerRefillRate(t *testing.T) {
  1203  	// "A sender SHOULD pace sending of all in-flight packets based on
  1204  	// input from the congestion controller."
  1205  	// https://www.rfc-editor.org/rfc/rfc9002.html#section-7.7-1
  1206  	test := newLossTest(t, clientSide, lossTestOpts{
  1207  		maxDatagramSize: 1200,
  1208  	})
  1209  	t.Logf("# consume the initial congestion window")
  1210  	test.send(initialSpace, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, testSentPacketSize(1200))
  1211  	test.wantSendLimit(ccLimited)
  1212  	test.wantVar("pacer_bucket", 0)
  1213  	test.wantVar("congestion_window", 12000)
  1214  
  1215  	t.Logf("# first RTT sample establishes smoothed_rtt")
  1216  	rtt := 100 * time.Millisecond
  1217  	test.advance(rtt)
  1218  	test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 10})
  1219  	test.wantAck(initialSpace, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
  1220  	test.wantVar("congestion_window", 24000) // 12000 + 10*1200
  1221  	test.wantVar("smoothed_rtt", rtt)
  1222  
  1223  	t.Logf("# advance 1 RTT to let the pacer bucket refill completely")
  1224  	test.advance(100 * time.Millisecond)
  1225  	t.Logf("# pacer_bucket = initial_congestion_window")
  1226  	test.wantVar("pacer_bucket", 12000)
  1227  
  1228  	t.Logf("# consume capacity from the pacer bucket")
  1229  	test.send(initialSpace, 10, testSentPacketSize(1200))
  1230  	test.wantVar("pacer_bucket", 10800) // 12000 - 1200
  1231  	test.send(initialSpace, 11, testSentPacketSize(600))
  1232  	test.wantVar("pacer_bucket", 10200) // 10800 - 600
  1233  	test.send(initialSpace, 12, testSentPacketSize(600))
  1234  	test.wantVar("pacer_bucket", 9600) // 10200 - 600
  1235  	test.send(initialSpace, 13, 14, 15, 16, testSentPacketSize(1200))
  1236  	test.wantVar("pacer_bucket", 4800) // 9600 - 4*1200
  1237  
  1238  	t.Logf("# advance 1/10 of an RTT, bucket refills")
  1239  	test.advance(rtt / 10)
  1240  	t.Logf("# pacer_bucket += 1.25 * (1/10) * congestion_window")
  1241  	t.Logf("#              += 3000")
  1242  	test.wantVar("pacer_bucket", 7800)
  1243  }
  1244  
  1245  func TestLossPacerNextSendTime(t *testing.T) {
  1246  	test := newLossTest(t, clientSide, lossTestOpts{
  1247  		maxDatagramSize: 1200,
  1248  	})
  1249  	t.Logf("# consume the initial congestion window")
  1250  	test.send(initialSpace, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, testSentPacketSize(1200))
  1251  	test.wantSendLimit(ccLimited)
  1252  	test.wantVar("pacer_bucket", 0)
  1253  	test.wantVar("congestion_window", 12000)
  1254  
  1255  	t.Logf("# first RTT sample establishes smoothed_rtt")
  1256  	rtt := 100 * time.Millisecond
  1257  	test.advance(rtt)
  1258  	test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 10})
  1259  	test.wantAck(initialSpace, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
  1260  	test.wantVar("congestion_window", 24000) // 12000 + 10*1200
  1261  	test.wantVar("smoothed_rtt", rtt)
  1262  
  1263  	t.Logf("# advance 1 RTT to let the pacer bucket refill completely")
  1264  	test.advance(100 * time.Millisecond)
  1265  	t.Logf("# pacer_bucket = initial_congestion_window")
  1266  	test.wantVar("pacer_bucket", 12000)
  1267  
  1268  	t.Logf("# consume the refilled pacer bucket")
  1269  	test.send(initialSpace, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, testSentPacketSize(1200))
  1270  	test.wantSendLimit(ccPaced)
  1271  
  1272  	t.Logf("# refill rate = 1.25 * congestion_window / rtt")
  1273  	test.wantSendDelay(rtt / 25) // rtt / (1.25 * 24000 / 1200)
  1274  
  1275  	t.Logf("# no capacity available yet")
  1276  	test.advance(rtt / 50)
  1277  	test.wantVar("pacer_bucket", -600)
  1278  	test.wantSendLimit(ccPaced)
  1279  
  1280  	t.Logf("# capacity available")
  1281  	test.advance(rtt / 50)
  1282  	test.wantVar("pacer_bucket", 0)
  1283  	test.wantSendLimit(ccOK)
  1284  }
  1285  
  1286  func TestLossCongestionWindowUnderutilized(t *testing.T) {
  1287  	// "When bytes in flight is smaller than the congestion window
  1288  	// and sending is not pacing limited [...] the congestion window
  1289  	// SHOULD NOT be increased in either slow start or congestion avoidance."
  1290  	// https://www.rfc-editor.org/rfc/rfc9002.html#section-7.8-1
  1291  	test := newLossTest(t, clientSide, lossTestOpts{
  1292  		maxDatagramSize: 1200,
  1293  	})
  1294  	test.send(initialSpace, 0, testSentPacketSize(1200))
  1295  	test.setUnderutilized(true)
  1296  	t.Logf("# underutilized: %v", test.c.cc.underutilized)
  1297  	test.wantVar("congestion_window", 12000)
  1298  
  1299  	test.advance(10 * time.Millisecond)
  1300  	test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 1})
  1301  	test.wantAck(initialSpace, 0)
  1302  	t.Logf("# congestion window does not increase, because window is underutilized")
  1303  	test.wantVar("congestion_window", 12000)
  1304  
  1305  	t.Logf("# refill pacer bucket")
  1306  	test.advance(10 * time.Millisecond)
  1307  	test.wantVar("pacer_bucket", 12000)
  1308  
  1309  	test.send(initialSpace, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, testSentPacketSize(1200))
  1310  	test.setUnderutilized(false)
  1311  	test.advance(10 * time.Millisecond)
  1312  	test.ack(initialSpace, 0*time.Millisecond, i64range[packetNumber]{0, 11})
  1313  	test.wantAck(initialSpace, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
  1314  	t.Logf("# congestion window increases")
  1315  	test.wantVar("congestion_window", 24000)
  1316  }
  1317  
  1318  type lossTest struct {
  1319  	t      *testing.T
  1320  	c      lossState
  1321  	now    time.Time
  1322  	fates  map[spaceNum]packetFate
  1323  	failed bool
  1324  }
  1325  
  1326  type lossTestOpts struct {
  1327  	maxDatagramSize int
  1328  }
  1329  
  1330  func newLossTest(t *testing.T, side connSide, opts lossTestOpts) *lossTest {
  1331  	c := &lossTest{
  1332  		t:     t,
  1333  		now:   time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC),
  1334  		fates: make(map[spaceNum]packetFate),
  1335  	}
  1336  	maxDatagramSize := 1200
  1337  	if opts.maxDatagramSize != 0 {
  1338  		maxDatagramSize = opts.maxDatagramSize
  1339  	}
  1340  	c.c.init(side, maxDatagramSize, c.now)
  1341  	t.Cleanup(func() {
  1342  		if !c.failed {
  1343  			c.checkUnexpectedEvents()
  1344  		}
  1345  	})
  1346  	return c
  1347  }
  1348  
  1349  type spaceNum struct {
  1350  	space numberSpace
  1351  	num   packetNumber
  1352  }
  1353  
  1354  func (c *lossTest) checkUnexpectedEvents() {
  1355  	c.t.Helper()
  1356  	for sn, fate := range c.fates {
  1357  		c.t.Errorf("ERROR: unexpected %v: %v %v", fate, sn.space, sn.num)
  1358  	}
  1359  	if c.c.ptoExpired {
  1360  		c.t.Errorf("ERROR: PTO timer unexpectedly expired")
  1361  	}
  1362  }
  1363  
  1364  func (c *lossTest) setSmoothedRTT(d time.Duration) {
  1365  	c.t.Helper()
  1366  	c.checkUnexpectedEvents()
  1367  	c.t.Logf("set smoothed_rtt to %v", d)
  1368  	c.c.rtt.smoothedRTT = d
  1369  }
  1370  
  1371  func (c *lossTest) setRTTVar(d time.Duration) {
  1372  	c.t.Helper()
  1373  	c.checkUnexpectedEvents()
  1374  	c.t.Logf("set rttvar to %v", d)
  1375  	c.c.rtt.rttvar = d
  1376  }
  1377  
  1378  func (c *lossTest) setUnderutilized(v bool) {
  1379  	c.t.Logf("set congestion window underutilized: %v", v)
  1380  	c.c.cc.setUnderutilized(nil, v)
  1381  }
  1382  
  1383  func (c *lossTest) advance(d time.Duration) {
  1384  	c.t.Helper()
  1385  	c.checkUnexpectedEvents()
  1386  	c.t.Logf("advance time %v", d)
  1387  	c.now = c.now.Add(d)
  1388  	c.c.advance(c.now, c.onAckOrLoss)
  1389  }
  1390  
  1391  func (c *lossTest) advanceToLossTimer() {
  1392  	c.t.Helper()
  1393  	c.checkUnexpectedEvents()
  1394  	d := c.c.timer.Sub(c.now)
  1395  	c.t.Logf("advance time %v (up to loss timer)", d)
  1396  	if d < 0 {
  1397  		c.t.Fatalf("loss timer is in the past")
  1398  	}
  1399  	c.now = c.c.timer
  1400  	c.c.advance(c.now, c.onAckOrLoss)
  1401  }
  1402  
  1403  type testSentPacketSize int
  1404  
  1405  func (c *lossTest) send(spaceID numberSpace, opts ...any) {
  1406  	c.t.Helper()
  1407  	c.checkUnexpectedEvents()
  1408  	var nums []packetNumber
  1409  	prototype := sentPacket{
  1410  		ackEliciting: true,
  1411  		inFlight:     true,
  1412  	}
  1413  	for _, o := range opts {
  1414  		switch o := o.(type) {
  1415  		case sentPacket:
  1416  			prototype = o
  1417  		case testSentPacketSize:
  1418  			prototype.size = int(o)
  1419  		case int:
  1420  			nums = append(nums, packetNumber(o))
  1421  		case packetNumber:
  1422  			nums = append(nums, o)
  1423  		case i64range[packetNumber]:
  1424  			for num := o.start; num < o.end; num++ {
  1425  				nums = append(nums, num)
  1426  			}
  1427  		}
  1428  	}
  1429  	c.t.Logf("send %v %v", spaceID, nums)
  1430  	limit, _ := c.c.sendLimit(c.now)
  1431  	if prototype.inFlight && limit != ccOK {
  1432  		c.t.Fatalf("congestion control blocks sending packet")
  1433  	}
  1434  	if !prototype.inFlight && limit == ccBlocked {
  1435  		c.t.Fatalf("congestion control blocks sending packet")
  1436  	}
  1437  	for _, num := range nums {
  1438  		sent := &sentPacket{}
  1439  		*sent = prototype
  1440  		sent.num = num
  1441  		c.c.packetSent(c.now, nil, spaceID, sent)
  1442  	}
  1443  }
  1444  
  1445  func (c *lossTest) datagramReceived(size int) {
  1446  	c.t.Helper()
  1447  	c.checkUnexpectedEvents()
  1448  	c.t.Logf("receive %v-byte datagram", size)
  1449  	c.c.datagramReceived(c.now, size)
  1450  }
  1451  
  1452  func (c *lossTest) ack(spaceID numberSpace, ackDelay time.Duration, rs ...i64range[packetNumber]) {
  1453  	c.t.Helper()
  1454  	c.checkUnexpectedEvents()
  1455  	c.c.receiveAckStart()
  1456  	var acked rangeset[packetNumber]
  1457  	for _, r := range rs {
  1458  		c.t.Logf("ack %v delay=%v [%v,%v)", spaceID, ackDelay, r.start, r.end)
  1459  		acked.add(r.start, r.end)
  1460  	}
  1461  	for i, r := range rs {
  1462  		c.t.Logf("ack %v delay=%v [%v,%v)", spaceID, ackDelay, r.start, r.end)
  1463  		c.c.receiveAckRange(c.now, spaceID, i, r.start, r.end, c.onAckOrLoss)
  1464  	}
  1465  	c.c.receiveAckEnd(c.now, nil, spaceID, ackDelay, c.onAckOrLoss)
  1466  }
  1467  
  1468  func (c *lossTest) onAckOrLoss(space numberSpace, sent *sentPacket, fate packetFate) {
  1469  	c.t.Logf("%v %v %v", fate, space, sent.num)
  1470  	if _, ok := c.fates[spaceNum{space, sent.num}]; ok {
  1471  		c.t.Errorf("ERROR: duplicate %v for %v %v", fate, space, sent.num)
  1472  	}
  1473  	c.fates[spaceNum{space, sent.num}] = fate
  1474  }
  1475  
  1476  func (c *lossTest) confirmHandshake() {
  1477  	c.t.Helper()
  1478  	c.checkUnexpectedEvents()
  1479  	c.t.Logf("confirm handshake")
  1480  	c.c.confirmHandshake()
  1481  }
  1482  
  1483  func (c *lossTest) validateClientAddress() {
  1484  	c.t.Helper()
  1485  	c.checkUnexpectedEvents()
  1486  	c.t.Logf("validate client address")
  1487  	c.c.validateClientAddress()
  1488  }
  1489  
  1490  func (c *lossTest) discardKeys(spaceID numberSpace) {
  1491  	c.t.Helper()
  1492  	c.checkUnexpectedEvents()
  1493  	c.t.Logf("discard %s keys", spaceID)
  1494  	c.c.discardKeys(c.now, nil, spaceID)
  1495  }
  1496  
  1497  func (c *lossTest) setMaxAckDelay(d time.Duration) {
  1498  	c.t.Helper()
  1499  	c.checkUnexpectedEvents()
  1500  	c.t.Logf("set max_ack_delay = %v", d)
  1501  	c.c.setMaxAckDelay(d)
  1502  }
  1503  
  1504  func (c *lossTest) wantAck(spaceID numberSpace, nums ...packetNumber) {
  1505  	c.t.Helper()
  1506  	for _, num := range nums {
  1507  		if c.fates[spaceNum{spaceID, num}] != packetAcked {
  1508  			c.t.Fatalf("expected ack for %v %v\n", spaceID, num)
  1509  		}
  1510  		delete(c.fates, spaceNum{spaceID, num})
  1511  	}
  1512  }
  1513  
  1514  func (c *lossTest) wantLoss(spaceID numberSpace, nums ...packetNumber) {
  1515  	c.t.Helper()
  1516  	for _, num := range nums {
  1517  		if c.fates[spaceNum{spaceID, num}] != packetLost {
  1518  			c.t.Fatalf("expected loss of %v %v\n", spaceID, num)
  1519  		}
  1520  		delete(c.fates, spaceNum{spaceID, num})
  1521  	}
  1522  }
  1523  
  1524  func (c *lossTest) wantPTOExpired() {
  1525  	c.t.Helper()
  1526  	if !c.c.ptoExpired {
  1527  		c.t.Fatalf("expected PTO timer to expire")
  1528  	} else {
  1529  		c.t.Logf("PTO TIMER EXPIRED")
  1530  	}
  1531  	c.c.ptoExpired = false
  1532  }
  1533  
  1534  func (l ccLimit) String() string {
  1535  	switch l {
  1536  	case ccOK:
  1537  		return "ccOK"
  1538  	case ccBlocked:
  1539  		return "ccBlocked"
  1540  	case ccLimited:
  1541  		return "ccLimited"
  1542  	case ccPaced:
  1543  		return "ccPaced"
  1544  	}
  1545  	return "BUG"
  1546  }
  1547  
  1548  func (c *lossTest) wantSendLimit(want ccLimit) {
  1549  	c.t.Helper()
  1550  	if got, _ := c.c.sendLimit(c.now); got != want {
  1551  		c.t.Fatalf("congestion control send limit is %v, want %v", got, want)
  1552  	}
  1553  }
  1554  
  1555  func (c *lossTest) wantSendDelay(want time.Duration) {
  1556  	c.t.Helper()
  1557  	limit, next := c.c.sendLimit(c.now)
  1558  	if limit != ccPaced {
  1559  		c.t.Fatalf("congestion control limit is %v, want %v", limit, ccPaced)
  1560  	}
  1561  	got := next.Sub(c.now)
  1562  	if got != want {
  1563  		c.t.Fatalf("delay until next send is %v, want %v", got, want)
  1564  	}
  1565  }
  1566  
  1567  func (c *lossTest) wantVar(name string, want any) {
  1568  	c.t.Helper()
  1569  	var got any
  1570  	switch name {
  1571  	case "latest_rtt":
  1572  		got = c.c.rtt.latestRTT
  1573  	case "min_rtt":
  1574  		got = c.c.rtt.minRTT
  1575  	case "smoothed_rtt":
  1576  		got = c.c.rtt.smoothedRTT
  1577  	case "rttvar":
  1578  		got = c.c.rtt.rttvar
  1579  	case "congestion_window":
  1580  		got = c.c.cc.congestionWindow
  1581  	case "slow_start_threshold":
  1582  		got = c.c.cc.slowStartThreshold
  1583  	case "bytes_in_flight":
  1584  		got = c.c.cc.bytesInFlight
  1585  	case "pacer_bucket":
  1586  		got = c.c.pacer.bucket
  1587  	default:
  1588  		c.t.Fatalf("unknown var %q", name)
  1589  	}
  1590  	if got != want {
  1591  		c.t.Fatalf("%v = %v, want %v\n", name, got, want)
  1592  	} else {
  1593  		c.t.Logf("%v = %v", name, got)
  1594  	}
  1595  }
  1596  
  1597  func (c *lossTest) wantTimeout(want time.Duration) {
  1598  	c.t.Helper()
  1599  	if c.c.timer.IsZero() {
  1600  		c.t.Fatalf("loss detection timer is not set, want %v", want)
  1601  	}
  1602  	got := c.c.timer.Sub(c.now)
  1603  	if got != want {
  1604  		c.t.Fatalf("loss detection timer expires in %v, want %v", got, want)
  1605  	}
  1606  	c.t.Logf("loss detection timer expires in %v", got)
  1607  }
  1608  
  1609  func (c *lossTest) wantNoTimeout() {
  1610  	c.t.Helper()
  1611  	if !c.c.timer.IsZero() {
  1612  		d := c.c.timer.Sub(c.now)
  1613  		c.t.Fatalf("loss detection timer expires in %v, want not set", d)
  1614  	}
  1615  	c.t.Logf("loss detection timer is not set")
  1616  }
  1617  
  1618  func (f packetFate) String() string {
  1619  	switch f {
  1620  	case packetAcked:
  1621  		return "ACK"
  1622  	case packetLost:
  1623  		return "LOSS"
  1624  	default:
  1625  		panic("unknown packetFate")
  1626  	}
  1627  }