github.com/tumi8/quic-go@v0.37.4-tum/noninternal/flowcontrol/connection_flow_controller_test.go (about)

     1  package flowcontrol
     2  
     3  import (
     4  	"time"
     5  
     6  	"github.com/tumi8/quic-go/noninternal/protocol"
     7  	"github.com/tumi8/quic-go/noninternal/utils"
     8  	. "github.com/onsi/ginkgo/v2"
     9  	. "github.com/onsi/gomega"
    10  )
    11  
    12  var _ = Describe("Connection Flow controller", func() {
    13  	var (
    14  		controller         *connectionFlowController
    15  		queuedWindowUpdate bool
    16  	)
    17  
    18  	// update the congestion such that it returns a given value for the smoothed RTT
    19  	setRtt := func(t time.Duration) {
    20  		controller.rttStats.UpdateRTT(t, 0, time.Now())
    21  		Expect(controller.rttStats.SmoothedRTT()).To(Equal(t)) // make sure it worked
    22  	}
    23  
    24  	BeforeEach(func() {
    25  		queuedWindowUpdate = false
    26  		controller = &connectionFlowController{}
    27  		controller.rttStats = &utils.RTTStats{}
    28  		controller.logger = utils.DefaultLogger
    29  		controller.queueWindowUpdate = func() { queuedWindowUpdate = true }
    30  		controller.allowWindowIncrease = func(protocol.ByteCount) bool { return true }
    31  	})
    32  
    33  	Context("Constructor", func() {
    34  		rttStats := &utils.RTTStats{}
    35  
    36  		It("sets the send and receive windows", func() {
    37  			receiveWindow := protocol.ByteCount(2000)
    38  			maxReceiveWindow := protocol.ByteCount(3000)
    39  
    40  			fc := NewConnectionFlowController(
    41  				receiveWindow,
    42  				maxReceiveWindow,
    43  				nil,
    44  				func(protocol.ByteCount) bool { return true },
    45  				rttStats,
    46  				utils.DefaultLogger).(*connectionFlowController)
    47  			Expect(fc.receiveWindow).To(Equal(receiveWindow))
    48  			Expect(fc.maxReceiveWindowSize).To(Equal(maxReceiveWindow))
    49  		})
    50  	})
    51  
    52  	Context("receive flow control", func() {
    53  		It("increases the highestReceived by a given window size", func() {
    54  			controller.highestReceived = 1337
    55  			controller.IncrementHighestReceived(123)
    56  			Expect(controller.highestReceived).To(Equal(protocol.ByteCount(1337 + 123)))
    57  		})
    58  
    59  		Context("getting window updates", func() {
    60  			BeforeEach(func() {
    61  				controller.receiveWindow = 100
    62  				controller.receiveWindowSize = 60
    63  				controller.maxReceiveWindowSize = 1000
    64  				controller.bytesRead = 100 - 60
    65  			})
    66  
    67  			It("queues window updates", func() {
    68  				controller.AddBytesRead(1)
    69  				Expect(queuedWindowUpdate).To(BeFalse())
    70  				controller.AddBytesRead(29)
    71  				Expect(queuedWindowUpdate).To(BeTrue())
    72  				Expect(controller.GetWindowUpdate()).ToNot(BeZero())
    73  				queuedWindowUpdate = false
    74  				controller.AddBytesRead(1)
    75  				Expect(queuedWindowUpdate).To(BeFalse())
    76  			})
    77  
    78  			It("gets a window update", func() {
    79  				windowSize := controller.receiveWindowSize
    80  				oldOffset := controller.bytesRead
    81  				dataRead := windowSize/2 - 1 // make sure not to trigger auto-tuning
    82  				controller.AddBytesRead(dataRead)
    83  				offset := controller.GetWindowUpdate()
    84  				Expect(offset).To(Equal(oldOffset + dataRead + 60))
    85  			})
    86  
    87  			It("auto-tunes the window", func() {
    88  				var allowed protocol.ByteCount
    89  				controller.allowWindowIncrease = func(size protocol.ByteCount) bool {
    90  					allowed = size
    91  					return true
    92  				}
    93  				oldOffset := controller.bytesRead
    94  				oldWindowSize := controller.receiveWindowSize
    95  				rtt := scaleDuration(20 * time.Millisecond)
    96  				setRtt(rtt)
    97  				controller.epochStartTime = time.Now().Add(-time.Millisecond)
    98  				controller.epochStartOffset = oldOffset
    99  				dataRead := oldWindowSize/2 + 1
   100  				controller.AddBytesRead(dataRead)
   101  				offset := controller.GetWindowUpdate()
   102  				newWindowSize := controller.receiveWindowSize
   103  				Expect(newWindowSize).To(Equal(2 * oldWindowSize))
   104  				Expect(offset).To(Equal(oldOffset + dataRead + newWindowSize))
   105  				Expect(allowed).To(Equal(oldWindowSize))
   106  			})
   107  
   108  			It("doesn't auto-tune the window if it's not allowed", func() {
   109  				controller.allowWindowIncrease = func(protocol.ByteCount) bool { return false }
   110  				oldOffset := controller.bytesRead
   111  				oldWindowSize := controller.receiveWindowSize
   112  				rtt := scaleDuration(20 * time.Millisecond)
   113  				setRtt(rtt)
   114  				controller.epochStartTime = time.Now().Add(-time.Millisecond)
   115  				controller.epochStartOffset = oldOffset
   116  				dataRead := oldWindowSize/2 + 1
   117  				controller.AddBytesRead(dataRead)
   118  				offset := controller.GetWindowUpdate()
   119  				newWindowSize := controller.receiveWindowSize
   120  				Expect(newWindowSize).To(Equal(oldWindowSize))
   121  				Expect(offset).To(Equal(oldOffset + dataRead + newWindowSize))
   122  			})
   123  		})
   124  	})
   125  
   126  	Context("setting the minimum window size", func() {
   127  		var (
   128  			oldWindowSize     protocol.ByteCount
   129  			receiveWindow     protocol.ByteCount = 10000
   130  			receiveWindowSize protocol.ByteCount = 1000
   131  		)
   132  
   133  		BeforeEach(func() {
   134  			controller.receiveWindow = receiveWindow
   135  			controller.receiveWindowSize = receiveWindowSize
   136  			oldWindowSize = controller.receiveWindowSize
   137  			controller.maxReceiveWindowSize = 3000
   138  		})
   139  
   140  		It("sets the minimum window window size", func() {
   141  			controller.EnsureMinimumWindowSize(1800)
   142  			Expect(controller.receiveWindowSize).To(Equal(protocol.ByteCount(1800)))
   143  		})
   144  
   145  		It("doesn't reduce the window window size", func() {
   146  			controller.EnsureMinimumWindowSize(1)
   147  			Expect(controller.receiveWindowSize).To(Equal(oldWindowSize))
   148  		})
   149  
   150  		It("doesn't increase the window size beyond the maxReceiveWindowSize", func() {
   151  			max := controller.maxReceiveWindowSize
   152  			controller.EnsureMinimumWindowSize(2 * max)
   153  			Expect(controller.receiveWindowSize).To(Equal(max))
   154  		})
   155  
   156  		It("starts a new epoch after the window size was increased", func() {
   157  			controller.EnsureMinimumWindowSize(1912)
   158  			Expect(controller.epochStartTime).To(BeTemporally("~", time.Now(), 100*time.Millisecond))
   159  		})
   160  	})
   161  
   162  	Context("resetting", func() {
   163  		It("resets", func() {
   164  			const initialWindow protocol.ByteCount = 1337
   165  			controller.UpdateSendWindow(initialWindow)
   166  			controller.AddBytesSent(1000)
   167  			Expect(controller.SendWindowSize()).To(Equal(initialWindow - 1000))
   168  			Expect(controller.Reset()).To(Succeed())
   169  			Expect(controller.SendWindowSize()).To(Equal(initialWindow))
   170  		})
   171  
   172  		It("says if is blocked after resetting", func() {
   173  			const initialWindow protocol.ByteCount = 1337
   174  			controller.UpdateSendWindow(initialWindow)
   175  			controller.AddBytesSent(initialWindow)
   176  			blocked, _ := controller.IsNewlyBlocked()
   177  			Expect(blocked).To(BeTrue())
   178  			Expect(controller.Reset()).To(Succeed())
   179  			controller.AddBytesSent(initialWindow)
   180  			blocked, blockedAt := controller.IsNewlyBlocked()
   181  			Expect(blocked).To(BeTrue())
   182  			Expect(blockedAt).To(Equal(initialWindow))
   183  		})
   184  	})
   185  })