github.com/mikelsr/quic-go@v0.36.1-0.20230701132136-1d9415b66898/send_stream_test.go (about)

     1  package quic
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"io"
     7  	mrand "math/rand"
     8  	"runtime"
     9  	"time"
    10  
    11  	"github.com/golang/mock/gomock"
    12  	"github.com/mikelsr/quic-go/internal/ackhandler"
    13  	"github.com/mikelsr/quic-go/internal/mocks"
    14  	"github.com/mikelsr/quic-go/internal/protocol"
    15  	"github.com/mikelsr/quic-go/internal/wire"
    16  
    17  	. "github.com/onsi/ginkgo/v2"
    18  	. "github.com/onsi/gomega"
    19  	"github.com/onsi/gomega/gbytes"
    20  )
    21  
    22  var _ = Describe("Send Stream", func() {
    23  	const streamID protocol.StreamID = 1337
    24  
    25  	var (
    26  		str            *sendStream
    27  		strWithTimeout io.Writer // str wrapped with gbytes.TimeoutWriter
    28  		mockFC         *mocks.MockStreamFlowController
    29  		mockSender     *MockStreamSender
    30  	)
    31  
    32  	BeforeEach(func() {
    33  		mockSender = NewMockStreamSender(mockCtrl)
    34  		mockFC = mocks.NewMockStreamFlowController(mockCtrl)
    35  		str = newSendStream(streamID, mockSender, mockFC)
    36  
    37  		timeout := scaleDuration(250 * time.Millisecond)
    38  		strWithTimeout = gbytes.TimeoutWriter(str, timeout)
    39  	})
    40  
    41  	expectedFrameHeaderLen := func(offset protocol.ByteCount) protocol.ByteCount {
    42  		return (&wire.StreamFrame{
    43  			StreamID:       streamID,
    44  			Offset:         offset,
    45  			DataLenPresent: true,
    46  		}).Length(protocol.Version1)
    47  	}
    48  
    49  	waitForWrite := func() {
    50  		EventuallyWithOffset(0, func() bool {
    51  			str.mutex.Lock()
    52  			hasData := str.dataForWriting != nil || str.nextFrame != nil
    53  			str.mutex.Unlock()
    54  			return hasData
    55  		}).Should(BeTrue())
    56  	}
    57  
    58  	getDataAtOffset := func(offset, length protocol.ByteCount) []byte {
    59  		b := make([]byte, length)
    60  		for i := protocol.ByteCount(0); i < length; i++ {
    61  			b[i] = uint8(offset + i)
    62  		}
    63  		return b
    64  	}
    65  
    66  	getData := func(length protocol.ByteCount) []byte {
    67  		return getDataAtOffset(0, length)
    68  	}
    69  
    70  	It("gets stream id", func() {
    71  		Expect(str.StreamID()).To(Equal(protocol.StreamID(1337)))
    72  	})
    73  
    74  	Context("writing", func() {
    75  		It("writes and gets all data at once", func() {
    76  			done := make(chan struct{})
    77  			go func() {
    78  				defer GinkgoRecover()
    79  				defer close(done)
    80  				mockSender.EXPECT().onHasStreamData(streamID)
    81  				n, err := strWithTimeout.Write([]byte("foobar"))
    82  				Expect(err).ToNot(HaveOccurred())
    83  				Expect(n).To(Equal(6))
    84  			}()
    85  			waitForWrite()
    86  			mockFC.EXPECT().SendWindowSize().Return(protocol.MaxByteCount)
    87  			mockFC.EXPECT().AddBytesSent(protocol.ByteCount(6))
    88  			frame, ok, _ := str.popStreamFrame(protocol.MaxByteCount, protocol.Version1)
    89  			Expect(ok).To(BeTrue())
    90  			f := frame.Frame
    91  			Expect(f.Data).To(Equal([]byte("foobar")))
    92  			Expect(f.Fin).To(BeFalse())
    93  			Expect(f.Offset).To(BeZero())
    94  			Expect(f.DataLenPresent).To(BeTrue())
    95  			Expect(str.writeOffset).To(Equal(protocol.ByteCount(6)))
    96  			Expect(str.dataForWriting).To(BeNil())
    97  			Eventually(done).Should(BeClosed())
    98  		})
    99  
   100  		It("writes and gets data in two turns", func() {
   101  			done := make(chan struct{})
   102  			go func() {
   103  				defer GinkgoRecover()
   104  				mockSender.EXPECT().onHasStreamData(streamID)
   105  				n, err := strWithTimeout.Write([]byte("foobar"))
   106  				Expect(err).ToNot(HaveOccurred())
   107  				Expect(n).To(Equal(6))
   108  				close(done)
   109  			}()
   110  			waitForWrite()
   111  			mockFC.EXPECT().SendWindowSize().Return(protocol.MaxByteCount).Times(2)
   112  			mockFC.EXPECT().AddBytesSent(protocol.ByteCount(3)).Times(2)
   113  			frame, ok, _ := str.popStreamFrame(expectedFrameHeaderLen(0)+3, protocol.Version1)
   114  			Expect(ok).To(BeTrue())
   115  			f := frame.Frame
   116  			Expect(f.Offset).To(BeZero())
   117  			Expect(f.Fin).To(BeFalse())
   118  			Expect(f.Data).To(Equal([]byte("foo")))
   119  			Expect(f.DataLenPresent).To(BeTrue())
   120  			frame, ok, _ = str.popStreamFrame(protocol.MaxByteCount, protocol.Version1)
   121  			Expect(ok).To(BeTrue())
   122  			f = frame.Frame
   123  			Expect(f.Data).To(Equal([]byte("bar")))
   124  			Expect(f.Fin).To(BeFalse())
   125  			Expect(f.Offset).To(Equal(protocol.ByteCount(3)))
   126  			Expect(f.DataLenPresent).To(BeTrue())
   127  			_, ok, _ = str.popStreamFrame(1000, protocol.Version1)
   128  			Expect(ok).To(BeFalse())
   129  			Eventually(done).Should(BeClosed())
   130  		})
   131  
   132  		It("bundles small writes", func() {
   133  			done := make(chan struct{})
   134  			go func() {
   135  				defer GinkgoRecover()
   136  				mockSender.EXPECT().onHasStreamData(streamID).Times(2)
   137  				n, err := strWithTimeout.Write([]byte("foo"))
   138  				Expect(err).ToNot(HaveOccurred())
   139  				Expect(n).To(Equal(3))
   140  				n, err = strWithTimeout.Write([]byte("bar"))
   141  				Expect(err).ToNot(HaveOccurred())
   142  				Expect(n).To(Equal(3))
   143  				close(done)
   144  			}()
   145  			Eventually(done).Should(BeClosed()) // both Write calls returned without any data having been dequeued yet
   146  			mockFC.EXPECT().SendWindowSize().Return(protocol.MaxByteCount)
   147  			mockFC.EXPECT().AddBytesSent(protocol.ByteCount(6))
   148  			frame, ok, _ := str.popStreamFrame(protocol.MaxByteCount, protocol.Version1)
   149  			Expect(ok).To(BeTrue())
   150  			f := frame.Frame
   151  			Expect(f.Offset).To(BeZero())
   152  			Expect(f.Fin).To(BeFalse())
   153  			Expect(f.Data).To(Equal([]byte("foobar")))
   154  		})
   155  
   156  		It("writes and gets data in multiple turns, for large writes", func() {
   157  			mockFC.EXPECT().SendWindowSize().Return(protocol.MaxByteCount).Times(5)
   158  			var totalBytesSent protocol.ByteCount
   159  			mockFC.EXPECT().AddBytesSent(gomock.Any()).Do(func(l protocol.ByteCount) { totalBytesSent += l }).Times(5)
   160  			done := make(chan struct{})
   161  			go func() {
   162  				defer GinkgoRecover()
   163  				mockSender.EXPECT().onHasStreamData(streamID)
   164  				n, err := strWithTimeout.Write(getData(5000))
   165  				Expect(err).ToNot(HaveOccurred())
   166  				Expect(n).To(Equal(5000))
   167  				close(done)
   168  			}()
   169  			waitForWrite()
   170  			for i := 0; i < 5; i++ {
   171  				frame, ok, _ := str.popStreamFrame(1100, protocol.Version1)
   172  				Expect(ok).To(BeTrue())
   173  				f := frame.Frame
   174  				Expect(f.Offset).To(BeNumerically("~", 1100*i, 10*i))
   175  				Expect(f.Fin).To(BeFalse())
   176  				Expect(f.Data).To(Equal(getDataAtOffset(f.Offset, f.DataLen())))
   177  				Expect(f.DataLenPresent).To(BeTrue())
   178  			}
   179  			Expect(totalBytesSent).To(Equal(protocol.ByteCount(5000)))
   180  			Eventually(done).Should(BeClosed())
   181  		})
   182  
   183  		It("unblocks Write as soon as a STREAM frame can be buffered", func() {
   184  			done := make(chan struct{})
   185  			go func() {
   186  				defer GinkgoRecover()
   187  				defer close(done)
   188  				mockSender.EXPECT().onHasStreamData(streamID)
   189  				_, err := strWithTimeout.Write(getData(protocol.MaxPacketBufferSize + 3))
   190  				Expect(err).ToNot(HaveOccurred())
   191  			}()
   192  			waitForWrite()
   193  			mockFC.EXPECT().SendWindowSize().Return(protocol.MaxByteCount).Times(2)
   194  			mockFC.EXPECT().AddBytesSent(protocol.ByteCount(2))
   195  			frame, ok, hasMoreData := str.popStreamFrame(expectedFrameHeaderLen(0)+2, protocol.Version1)
   196  			Expect(ok).To(BeTrue())
   197  			Expect(hasMoreData).To(BeTrue())
   198  			f := frame.Frame
   199  			Expect(f.DataLen()).To(Equal(protocol.ByteCount(2)))
   200  			Consistently(done).ShouldNot(BeClosed())
   201  			mockFC.EXPECT().AddBytesSent(protocol.ByteCount(1))
   202  			frame, ok, hasMoreData = str.popStreamFrame(expectedFrameHeaderLen(1)+1, protocol.Version1)
   203  			Expect(ok).To(BeTrue())
   204  			Expect(hasMoreData).To(BeTrue())
   205  			f = frame.Frame
   206  			Expect(f.DataLen()).To(Equal(protocol.ByteCount(1)))
   207  			Eventually(done).Should(BeClosed())
   208  		})
   209  
   210  		It("only unblocks Write once a previously buffered STREAM frame has been fully dequeued", func() {
   211  			mockSender.EXPECT().onHasStreamData(streamID)
   212  			_, err := strWithTimeout.Write([]byte("foobar"))
   213  			Expect(err).ToNot(HaveOccurred())
   214  			done := make(chan struct{})
   215  			go func() {
   216  				defer GinkgoRecover()
   217  				defer close(done)
   218  				mockSender.EXPECT().onHasStreamData(streamID)
   219  				_, err := str.Write(getData(protocol.MaxPacketBufferSize))
   220  				Expect(err).ToNot(HaveOccurred())
   221  			}()
   222  			waitForWrite()
   223  			mockFC.EXPECT().SendWindowSize().Return(protocol.MaxByteCount).Times(2)
   224  			mockFC.EXPECT().AddBytesSent(protocol.ByteCount(2))
   225  			frame, ok, hasMoreData := str.popStreamFrame(expectedFrameHeaderLen(0)+2, protocol.Version1)
   226  			Expect(ok).To(BeTrue())
   227  			Expect(hasMoreData).To(BeTrue())
   228  			f := frame.Frame
   229  			Expect(f.Data).To(Equal([]byte("fo")))
   230  			Consistently(done).ShouldNot(BeClosed())
   231  			mockFC.EXPECT().AddBytesSent(protocol.ByteCount(4))
   232  			frame, ok, hasMoreData = str.popStreamFrame(expectedFrameHeaderLen(2)+4, protocol.Version1)
   233  			Expect(ok).To(BeTrue())
   234  			Expect(hasMoreData).To(BeTrue())
   235  			f = frame.Frame
   236  			Expect(f.Data).To(Equal([]byte("obar")))
   237  			Eventually(done).Should(BeClosed())
   238  		})
   239  
   240  		It("popStreamFrame returns nil if no data is available", func() {
   241  			_, ok, hasMoreData := str.popStreamFrame(1000, protocol.Version1)
   242  			Expect(ok).To(BeFalse())
   243  			Expect(hasMoreData).To(BeFalse())
   244  		})
   245  
   246  		It("says if it has more data for writing", func() {
   247  			done := make(chan struct{})
   248  			go func() {
   249  				defer GinkgoRecover()
   250  				defer close(done)
   251  				mockSender.EXPECT().onHasStreamData(streamID)
   252  				n, err := strWithTimeout.Write(bytes.Repeat([]byte{0}, 100))
   253  				Expect(err).ToNot(HaveOccurred())
   254  				Expect(n).To(Equal(100))
   255  			}()
   256  			waitForWrite()
   257  			mockFC.EXPECT().SendWindowSize().Return(protocol.MaxByteCount).Times(2)
   258  			mockFC.EXPECT().AddBytesSent(gomock.Any()).Times(2)
   259  			frame, ok, hasMoreData := str.popStreamFrame(50, protocol.Version1)
   260  			Expect(ok).To(BeTrue())
   261  			Expect(frame.Frame.Fin).To(BeFalse())
   262  			Expect(hasMoreData).To(BeTrue())
   263  			frame, ok, hasMoreData = str.popStreamFrame(protocol.MaxByteCount, protocol.Version1)
   264  			Expect(ok).To(BeTrue())
   265  			Expect(frame.Frame.Fin).To(BeFalse())
   266  			Expect(hasMoreData).To(BeFalse())
   267  			_, ok, _ = str.popStreamFrame(protocol.MaxByteCount, protocol.Version1)
   268  			Expect(ok).To(BeFalse())
   269  			Eventually(done).Should(BeClosed())
   270  		})
   271  
   272  		It("copies the slice while writing", func() {
   273  			frameHeaderSize := protocol.ByteCount(4)
   274  			mockFC.EXPECT().SendWindowSize().Return(protocol.MaxByteCount).Times(2)
   275  			mockFC.EXPECT().AddBytesSent(protocol.ByteCount(1))
   276  			mockFC.EXPECT().AddBytesSent(protocol.ByteCount(2))
   277  			s := []byte("foo")
   278  			done := make(chan struct{})
   279  			go func() {
   280  				defer GinkgoRecover()
   281  				defer close(done)
   282  				mockSender.EXPECT().onHasStreamData(streamID)
   283  				n, err := strWithTimeout.Write(s)
   284  				Expect(err).ToNot(HaveOccurred())
   285  				Expect(n).To(Equal(3))
   286  			}()
   287  			waitForWrite()
   288  			frame, ok, _ := str.popStreamFrame(frameHeaderSize+1, protocol.Version1)
   289  			Expect(ok).To(BeTrue())
   290  			f := frame.Frame
   291  			Expect(f.Data).To(Equal([]byte("f")))
   292  			frame, ok, _ = str.popStreamFrame(100, protocol.Version1)
   293  			Expect(ok).To(BeTrue())
   294  			Expect(frame).ToNot(BeNil())
   295  			f = frame.Frame
   296  			Expect(f.Data).To(Equal([]byte("oo")))
   297  			s[1] = 'e'
   298  			Expect(f.Data).To(Equal([]byte("oo")))
   299  			Eventually(done).Should(BeClosed())
   300  		})
   301  
   302  		It("returns when given a nil input", func() {
   303  			n, err := strWithTimeout.Write(nil)
   304  			Expect(n).To(BeZero())
   305  			Expect(err).ToNot(HaveOccurred())
   306  		})
   307  
   308  		It("returns when given an empty slice", func() {
   309  			n, err := strWithTimeout.Write([]byte(""))
   310  			Expect(n).To(BeZero())
   311  			Expect(err).ToNot(HaveOccurred())
   312  		})
   313  
   314  		It("cancels the context when Close is called", func() {
   315  			mockSender.EXPECT().onHasStreamData(streamID)
   316  			Expect(str.Context().Done()).ToNot(BeClosed())
   317  			Expect(str.Close()).To(Succeed())
   318  			Expect(str.Context().Done()).To(BeClosed())
   319  		})
   320  
   321  		Context("flow control blocking", func() {
   322  			It("queues a BLOCKED frame if the stream is flow control blocked", func() {
   323  				mockFC.EXPECT().SendWindowSize().Return(protocol.ByteCount(0))
   324  				mockFC.EXPECT().IsNewlyBlocked().Return(true, protocol.ByteCount(12))
   325  				mockSender.EXPECT().queueControlFrame(&wire.StreamDataBlockedFrame{
   326  					StreamID:          streamID,
   327  					MaximumStreamData: 12,
   328  				})
   329  				done := make(chan struct{})
   330  				go func() {
   331  					defer GinkgoRecover()
   332  					defer close(done)
   333  					mockSender.EXPECT().onHasStreamData(streamID)
   334  					_, err := str.Write([]byte("foobar"))
   335  					Expect(err).ToNot(HaveOccurred())
   336  				}()
   337  				waitForWrite()
   338  				_, ok, hasMoreData := str.popStreamFrame(1000, protocol.Version1)
   339  				Expect(ok).To(BeFalse())
   340  				Expect(hasMoreData).To(BeFalse())
   341  				// make the Write go routine return
   342  				str.closeForShutdown(nil)
   343  				Eventually(done).Should(BeClosed())
   344  			})
   345  
   346  			It("says that it doesn't have any more data, when it is flow control blocked", func() {
   347  				done := make(chan struct{})
   348  				go func() {
   349  					defer GinkgoRecover()
   350  					defer close(done)
   351  					mockSender.EXPECT().onHasStreamData(streamID)
   352  					_, err := str.Write([]byte("foobar"))
   353  					Expect(err).ToNot(HaveOccurred())
   354  				}()
   355  				waitForWrite()
   356  
   357  				// first pop a STREAM frame of the maximum size allowed by flow control
   358  				mockFC.EXPECT().SendWindowSize().Return(protocol.ByteCount(3))
   359  				mockFC.EXPECT().AddBytesSent(protocol.ByteCount(3))
   360  				f, ok, hasMoreData := str.popStreamFrame(expectedFrameHeaderLen(0)+3, protocol.Version1)
   361  				Expect(ok).To(BeTrue())
   362  				Expect(f).ToNot(BeNil())
   363  				Expect(hasMoreData).To(BeTrue())
   364  
   365  				// try to pop again, this time noticing that we're blocked
   366  				mockFC.EXPECT().SendWindowSize()
   367  				// don't use offset 3 here, to make sure the BLOCKED frame contains the number returned by the flow controller
   368  				mockFC.EXPECT().IsNewlyBlocked().Return(true, protocol.ByteCount(10))
   369  				mockSender.EXPECT().queueControlFrame(&wire.StreamDataBlockedFrame{
   370  					StreamID:          streamID,
   371  					MaximumStreamData: 10,
   372  				})
   373  				_, ok, hasMoreData = str.popStreamFrame(1000, protocol.Version1)
   374  				Expect(ok).To(BeFalse())
   375  				Expect(hasMoreData).To(BeFalse())
   376  				// make the Write go routine return
   377  				str.closeForShutdown(nil)
   378  				Eventually(done).Should(BeClosed())
   379  			})
   380  		})
   381  
   382  		Context("deadlines", func() {
   383  			It("returns an error when Write is called after the deadline", func() {
   384  				str.SetWriteDeadline(time.Now().Add(-time.Second))
   385  				n, err := strWithTimeout.Write([]byte("foobar"))
   386  				Expect(err).To(MatchError(errDeadline))
   387  				Expect(n).To(BeZero())
   388  			})
   389  
   390  			It("unblocks after the deadline", func() {
   391  				mockSender.EXPECT().onHasStreamData(streamID)
   392  				deadline := time.Now().Add(scaleDuration(50 * time.Millisecond))
   393  				str.SetWriteDeadline(deadline)
   394  				n, err := strWithTimeout.Write(getData(5000))
   395  				Expect(err).To(MatchError(errDeadline))
   396  				Expect(n).To(BeZero())
   397  				Expect(time.Now()).To(BeTemporally("~", deadline, scaleDuration(20*time.Millisecond)))
   398  			})
   399  
   400  			It("unblocks when the deadline is changed to the past", func() {
   401  				mockSender.EXPECT().onHasStreamData(streamID)
   402  				str.SetWriteDeadline(time.Now().Add(time.Hour))
   403  				done := make(chan struct{})
   404  				go func() {
   405  					defer GinkgoRecover()
   406  					_, err := str.Write(getData(5000))
   407  					Expect(err).To(MatchError(errDeadline))
   408  					close(done)
   409  				}()
   410  				Consistently(done).ShouldNot(BeClosed())
   411  				str.SetWriteDeadline(time.Now().Add(-time.Hour))
   412  				Eventually(done).Should(BeClosed())
   413  			})
   414  
   415  			It("returns the number of bytes written, when the deadline expires", func() {
   416  				mockFC.EXPECT().SendWindowSize().Return(protocol.MaxByteCount).AnyTimes()
   417  				mockFC.EXPECT().AddBytesSent(gomock.Any())
   418  				deadline := time.Now().Add(scaleDuration(50 * time.Millisecond))
   419  				str.SetWriteDeadline(deadline)
   420  				var n int
   421  				writeReturned := make(chan struct{})
   422  				go func() {
   423  					defer GinkgoRecover()
   424  					defer close(writeReturned)
   425  					mockSender.EXPECT().onHasStreamData(streamID)
   426  					var err error
   427  					n, err = strWithTimeout.Write(getData(5000))
   428  					Expect(err).To(MatchError(errDeadline))
   429  					Expect(time.Now()).To(BeTemporally("~", deadline, scaleDuration(20*time.Millisecond)))
   430  				}()
   431  				waitForWrite()
   432  				frame, ok, hasMoreData := str.popStreamFrame(50, protocol.Version1)
   433  				Expect(ok).To(BeTrue())
   434  				Expect(frame).ToNot(BeNil())
   435  				Expect(hasMoreData).To(BeTrue())
   436  				Eventually(writeReturned, scaleDuration(80*time.Millisecond)).Should(BeClosed())
   437  				Expect(n).To(BeEquivalentTo(frame.Frame.DataLen()))
   438  			})
   439  
   440  			It("doesn't pop any data after the deadline expired", func() {
   441  				mockFC.EXPECT().SendWindowSize().Return(protocol.MaxByteCount).AnyTimes()
   442  				mockFC.EXPECT().AddBytesSent(gomock.Any())
   443  				deadline := time.Now().Add(scaleDuration(50 * time.Millisecond))
   444  				str.SetWriteDeadline(deadline)
   445  				writeReturned := make(chan struct{})
   446  				go func() {
   447  					defer GinkgoRecover()
   448  					defer close(writeReturned)
   449  					mockSender.EXPECT().onHasStreamData(streamID)
   450  					_, err := strWithTimeout.Write(getData(5000))
   451  					Expect(err).To(MatchError(errDeadline))
   452  				}()
   453  				waitForWrite()
   454  				frame, ok, hasMoreData := str.popStreamFrame(50, protocol.Version1)
   455  				Expect(ok).To(BeTrue())
   456  				Expect(frame).ToNot(BeNil())
   457  				Expect(hasMoreData).To(BeTrue())
   458  				Eventually(writeReturned, scaleDuration(80*time.Millisecond)).Should(BeClosed())
   459  				_, ok, hasMoreData = str.popStreamFrame(50, protocol.Version1)
   460  				Expect(ok).To(BeFalse())
   461  				Expect(hasMoreData).To(BeFalse())
   462  			})
   463  
   464  			It("doesn't unblock if the deadline is changed before the first one expires", func() {
   465  				mockSender.EXPECT().onHasStreamData(streamID)
   466  				deadline1 := time.Now().Add(scaleDuration(50 * time.Millisecond))
   467  				deadline2 := time.Now().Add(scaleDuration(100 * time.Millisecond))
   468  				str.SetWriteDeadline(deadline1)
   469  				done := make(chan struct{})
   470  				go func() {
   471  					defer GinkgoRecover()
   472  					time.Sleep(scaleDuration(20 * time.Millisecond))
   473  					str.SetWriteDeadline(deadline2)
   474  					// make sure that this was actually execute before the deadline expires
   475  					Expect(time.Now()).To(BeTemporally("<", deadline1))
   476  					close(done)
   477  				}()
   478  				runtime.Gosched()
   479  				n, err := strWithTimeout.Write(getData(5000))
   480  				Expect(err).To(MatchError(errDeadline))
   481  				Expect(n).To(BeZero())
   482  				Expect(time.Now()).To(BeTemporally("~", deadline2, scaleDuration(20*time.Millisecond)))
   483  				Eventually(done).Should(BeClosed())
   484  			})
   485  
   486  			It("unblocks earlier, when a new deadline is set", func() {
   487  				mockSender.EXPECT().onHasStreamData(streamID)
   488  				deadline1 := time.Now().Add(scaleDuration(200 * time.Millisecond))
   489  				deadline2 := time.Now().Add(scaleDuration(50 * time.Millisecond))
   490  				done := make(chan struct{})
   491  				go func() {
   492  					defer GinkgoRecover()
   493  					time.Sleep(scaleDuration(10 * time.Millisecond))
   494  					str.SetWriteDeadline(deadline2)
   495  					// make sure that this was actually execute before the deadline expires
   496  					Expect(time.Now()).To(BeTemporally("<", deadline2))
   497  					close(done)
   498  				}()
   499  				str.SetWriteDeadline(deadline1)
   500  				runtime.Gosched()
   501  				_, err := strWithTimeout.Write(getData(5000))
   502  				Expect(err).To(MatchError(errDeadline))
   503  				Expect(time.Now()).To(BeTemporally("~", deadline2, scaleDuration(20*time.Millisecond)))
   504  				Eventually(done).Should(BeClosed())
   505  			})
   506  
   507  			It("doesn't unblock if the deadline is removed", func() {
   508  				mockSender.EXPECT().onHasStreamData(streamID)
   509  				deadline := time.Now().Add(scaleDuration(50 * time.Millisecond))
   510  				str.SetWriteDeadline(deadline)
   511  				deadlineUnset := make(chan struct{})
   512  				go func() {
   513  					defer GinkgoRecover()
   514  					time.Sleep(scaleDuration(20 * time.Millisecond))
   515  					str.SetWriteDeadline(time.Time{})
   516  					// make sure that this was actually execute before the deadline expires
   517  					Expect(time.Now()).To(BeTemporally("<", deadline))
   518  					close(deadlineUnset)
   519  				}()
   520  				done := make(chan struct{})
   521  				go func() {
   522  					defer GinkgoRecover()
   523  					_, err := strWithTimeout.Write(getData(5000))
   524  					Expect(err).To(MatchError("test done"))
   525  					close(done)
   526  				}()
   527  				runtime.Gosched()
   528  				Eventually(deadlineUnset).Should(BeClosed())
   529  				Consistently(done, scaleDuration(100*time.Millisecond)).ShouldNot(BeClosed())
   530  				// make the go routine return
   531  				str.closeForShutdown(errors.New("test done"))
   532  				Eventually(done).Should(BeClosed())
   533  			})
   534  		})
   535  
   536  		Context("closing", func() {
   537  			It("doesn't allow writes after it has been closed", func() {
   538  				mockSender.EXPECT().onHasStreamData(streamID)
   539  				str.Close()
   540  				_, err := strWithTimeout.Write([]byte("foobar"))
   541  				Expect(err).To(MatchError("write on closed stream 1337"))
   542  			})
   543  
   544  			It("allows FIN", func() {
   545  				mockSender.EXPECT().onHasStreamData(streamID)
   546  				str.Close()
   547  				frame, ok, hasMoreData := str.popStreamFrame(1000, protocol.Version1)
   548  				Expect(ok).To(BeTrue())
   549  				Expect(frame).ToNot(BeNil())
   550  				f := frame.Frame
   551  				Expect(f.Data).To(BeEmpty())
   552  				Expect(f.Fin).To(BeTrue())
   553  				Expect(f.DataLenPresent).To(BeTrue())
   554  				Expect(hasMoreData).To(BeFalse())
   555  			})
   556  
   557  			It("doesn't send a FIN when there's still data", func() {
   558  				const frameHeaderLen protocol.ByteCount = 4
   559  				mockSender.EXPECT().onHasStreamData(streamID).Times(2)
   560  				_, err := strWithTimeout.Write([]byte("foobar"))
   561  				Expect(err).ToNot(HaveOccurred())
   562  				Expect(str.Close()).To(Succeed())
   563  				mockFC.EXPECT().SendWindowSize().Return(protocol.MaxByteCount).Times(2)
   564  				mockFC.EXPECT().AddBytesSent(gomock.Any()).Times(2)
   565  				frame, ok, _ := str.popStreamFrame(3+frameHeaderLen, protocol.Version1)
   566  				Expect(ok).To(BeTrue())
   567  				Expect(frame).ToNot(BeNil())
   568  				f := frame.Frame
   569  				Expect(f.Data).To(Equal([]byte("foo")))
   570  				Expect(f.Fin).To(BeFalse())
   571  				frame, ok, _ = str.popStreamFrame(protocol.MaxByteCount, protocol.Version1)
   572  				Expect(ok).To(BeTrue())
   573  				f = frame.Frame
   574  				Expect(f.Data).To(Equal([]byte("bar")))
   575  				Expect(f.Fin).To(BeTrue())
   576  			})
   577  
   578  			It("doesn't send a FIN when there's still data, for long writes", func() {
   579  				done := make(chan struct{})
   580  				go func() {
   581  					defer GinkgoRecover()
   582  					defer close(done)
   583  					mockSender.EXPECT().onHasStreamData(streamID)
   584  					_, err := strWithTimeout.Write(getData(5000))
   585  					Expect(err).ToNot(HaveOccurred())
   586  					mockSender.EXPECT().onHasStreamData(streamID)
   587  					Expect(str.Close()).To(Succeed())
   588  				}()
   589  				waitForWrite()
   590  				for i := 1; i <= 5; i++ {
   591  					mockFC.EXPECT().SendWindowSize().Return(protocol.MaxByteCount)
   592  					mockFC.EXPECT().AddBytesSent(gomock.Any())
   593  					if i == 5 {
   594  						Eventually(done).Should(BeClosed())
   595  					}
   596  					frame, ok, _ := str.popStreamFrame(1100, protocol.Version1)
   597  					Expect(ok).To(BeTrue())
   598  					Expect(frame).ToNot(BeNil())
   599  					f := frame.Frame
   600  					Expect(f.Data).To(Equal(getDataAtOffset(f.Offset, f.DataLen())))
   601  					Expect(f.Fin).To(Equal(i == 5)) // the last frame should have the FIN bit set
   602  				}
   603  			})
   604  
   605  			It("doesn't allow FIN after it is closed for shutdown", func() {
   606  				str.closeForShutdown(errors.New("test"))
   607  				_, ok, hasMoreData := str.popStreamFrame(1000, protocol.Version1)
   608  				Expect(ok).To(BeFalse())
   609  				Expect(hasMoreData).To(BeFalse())
   610  
   611  				Expect(str.Close()).To(Succeed())
   612  				_, ok, hasMoreData = str.popStreamFrame(1000, protocol.Version1)
   613  				Expect(ok).To(BeFalse())
   614  				Expect(hasMoreData).To(BeFalse())
   615  			})
   616  
   617  			It("doesn't allow FIN twice", func() {
   618  				mockSender.EXPECT().onHasStreamData(streamID)
   619  				str.Close()
   620  				frame, ok, _ := str.popStreamFrame(1000, protocol.Version1)
   621  				Expect(ok).To(BeTrue())
   622  				Expect(frame).ToNot(BeNil())
   623  				f := frame.Frame
   624  				Expect(f.Data).To(BeEmpty())
   625  				Expect(f.Fin).To(BeTrue())
   626  				_, ok, hasMoreData := str.popStreamFrame(1000, protocol.Version1)
   627  				Expect(ok).To(BeFalse())
   628  				Expect(hasMoreData).To(BeFalse())
   629  			})
   630  		})
   631  
   632  		Context("closing for shutdown", func() {
   633  			testErr := errors.New("test")
   634  
   635  			It("returns errors when the stream is cancelled", func() {
   636  				str.closeForShutdown(testErr)
   637  				n, err := strWithTimeout.Write([]byte("foo"))
   638  				Expect(n).To(BeZero())
   639  				Expect(err).To(MatchError(testErr))
   640  			})
   641  
   642  			It("doesn't get data for writing if an error occurred", func() {
   643  				mockFC.EXPECT().SendWindowSize().Return(protocol.MaxByteCount)
   644  				mockFC.EXPECT().AddBytesSent(gomock.Any())
   645  				mockSender.EXPECT().onHasStreamData(streamID)
   646  				done := make(chan struct{})
   647  				go func() {
   648  					defer GinkgoRecover()
   649  					_, err := strWithTimeout.Write(getData(5000))
   650  					Expect(err).To(MatchError(testErr))
   651  					close(done)
   652  				}()
   653  				waitForWrite()
   654  				frame, ok, hasMoreData := str.popStreamFrame(50, protocol.Version1) // get a STREAM frame containing some data, but not all
   655  				Expect(ok).To(BeTrue())
   656  				Expect(frame).ToNot(BeNil())
   657  				Expect(hasMoreData).To(BeTrue())
   658  				str.closeForShutdown(testErr)
   659  				_, ok, hasMoreData = str.popStreamFrame(1000, protocol.Version1)
   660  				Expect(ok).To(BeFalse())
   661  				Expect(hasMoreData).To(BeFalse())
   662  				Eventually(done).Should(BeClosed())
   663  			})
   664  
   665  			It("cancels the context", func() {
   666  				Expect(str.Context().Done()).ToNot(BeClosed())
   667  				str.closeForShutdown(testErr)
   668  				Expect(str.Context().Done()).To(BeClosed())
   669  			})
   670  		})
   671  	})
   672  
   673  	Context("handling MAX_STREAM_DATA frames", func() {
   674  		It("informs the flow controller", func() {
   675  			mockFC.EXPECT().UpdateSendWindow(protocol.ByteCount(0x1337))
   676  			str.updateSendWindow(0x1337)
   677  		})
   678  
   679  		It("says when it has data for sending", func() {
   680  			mockFC.EXPECT().UpdateSendWindow(gomock.Any())
   681  			mockSender.EXPECT().onHasStreamData(streamID)
   682  			done := make(chan struct{})
   683  			go func() {
   684  				defer GinkgoRecover()
   685  				_, err := str.Write([]byte("foobar"))
   686  				Expect(err).ToNot(HaveOccurred())
   687  				close(done)
   688  			}()
   689  			waitForWrite()
   690  			mockSender.EXPECT().onHasStreamData(streamID)
   691  			str.updateSendWindow(42)
   692  			// make sure the Write go routine returns
   693  			str.closeForShutdown(nil)
   694  			Eventually(done).Should(BeClosed())
   695  		})
   696  	})
   697  
   698  	Context("stream cancellations", func() {
   699  		Context("canceling writing", func() {
   700  			It("queues a RESET_STREAM frame", func() {
   701  				gomock.InOrder(
   702  					mockSender.EXPECT().queueControlFrame(&wire.ResetStreamFrame{
   703  						StreamID:  streamID,
   704  						FinalSize: 1234,
   705  						ErrorCode: 9876,
   706  					}),
   707  					mockSender.EXPECT().onStreamCompleted(streamID),
   708  				)
   709  				str.writeOffset = 1234
   710  				str.CancelWrite(9876)
   711  			})
   712  
   713  			// This test is inherently racy, as it tests a concurrent call to Write() and CancelRead().
   714  			// A single successful run of this test therefore doesn't mean a lot,
   715  			// for reliable results it has to be run many times.
   716  			It("returns a nil error when the whole slice has been sent out", func() {
   717  				mockSender.EXPECT().queueControlFrame(gomock.Any()).MaxTimes(1)
   718  				mockSender.EXPECT().onHasStreamData(streamID).MaxTimes(1)
   719  				mockSender.EXPECT().onStreamCompleted(streamID).MaxTimes(1)
   720  				mockFC.EXPECT().SendWindowSize().Return(protocol.MaxByteCount).MaxTimes(1)
   721  				mockFC.EXPECT().AddBytesSent(gomock.Any()).MaxTimes(1)
   722  				errChan := make(chan error)
   723  				go func() {
   724  					defer GinkgoRecover()
   725  					n, err := strWithTimeout.Write(getData(100))
   726  					if n == 0 {
   727  						errChan <- nil
   728  						return
   729  					}
   730  					errChan <- err
   731  				}()
   732  
   733  				runtime.Gosched()
   734  				go str.popStreamFrame(protocol.MaxByteCount, protocol.Version1)
   735  				go str.CancelWrite(1234)
   736  				Eventually(errChan).Should(Receive(Not(HaveOccurred())))
   737  			})
   738  
   739  			It("unblocks Write", func() {
   740  				mockSender.EXPECT().queueControlFrame(gomock.Any())
   741  				mockSender.EXPECT().onHasStreamData(streamID)
   742  				mockFC.EXPECT().SendWindowSize().Return(protocol.MaxByteCount)
   743  				mockFC.EXPECT().AddBytesSent(gomock.Any())
   744  				writeReturned := make(chan struct{})
   745  				var n int
   746  				go func() {
   747  					defer GinkgoRecover()
   748  					var err error
   749  					n, err = strWithTimeout.Write(getData(5000))
   750  					Expect(err).To(Equal(&StreamError{
   751  						StreamID:  streamID,
   752  						ErrorCode: 1234,
   753  						Remote:    false,
   754  					}))
   755  					close(writeReturned)
   756  				}()
   757  				waitForWrite()
   758  				frame, ok, _ := str.popStreamFrame(50, protocol.Version1)
   759  				Expect(ok).To(BeTrue())
   760  				Expect(frame).ToNot(BeNil())
   761  				mockSender.EXPECT().onStreamCompleted(streamID)
   762  				str.CancelWrite(1234)
   763  				Eventually(writeReturned).Should(BeClosed())
   764  				Expect(n).To(BeEquivalentTo(frame.Frame.DataLen()))
   765  			})
   766  
   767  			It("doesn't pop STREAM frames after being canceled", func() {
   768  				mockSender.EXPECT().queueControlFrame(gomock.Any())
   769  				mockSender.EXPECT().onHasStreamData(streamID)
   770  				mockFC.EXPECT().SendWindowSize().Return(protocol.MaxByteCount)
   771  				mockFC.EXPECT().AddBytesSent(gomock.Any())
   772  				writeReturned := make(chan struct{})
   773  				go func() {
   774  					defer GinkgoRecover()
   775  					strWithTimeout.Write(getData(100))
   776  					close(writeReturned)
   777  				}()
   778  				waitForWrite()
   779  				frame, ok, hasMoreData := str.popStreamFrame(50, protocol.Version1)
   780  				Expect(ok).To(BeTrue())
   781  				Expect(hasMoreData).To(BeTrue())
   782  				Expect(frame).ToNot(BeNil())
   783  				mockSender.EXPECT().onStreamCompleted(streamID)
   784  				str.CancelWrite(1234)
   785  				_, ok, hasMoreData = str.popStreamFrame(10, protocol.Version1)
   786  				Expect(ok).To(BeFalse())
   787  				Expect(hasMoreData).To(BeFalse())
   788  				Eventually(writeReturned).Should(BeClosed())
   789  			})
   790  
   791  			It("doesn't pop STREAM frames after being canceled, for large writes", func() {
   792  				mockSender.EXPECT().queueControlFrame(gomock.Any())
   793  				mockSender.EXPECT().onHasStreamData(streamID)
   794  				mockFC.EXPECT().SendWindowSize().Return(protocol.MaxByteCount)
   795  				mockFC.EXPECT().AddBytesSent(gomock.Any())
   796  				writeReturned := make(chan struct{})
   797  				go func() {
   798  					defer GinkgoRecover()
   799  					_, err := strWithTimeout.Write(getData(5000))
   800  					Expect(err).To(Equal(&StreamError{
   801  						StreamID:  streamID,
   802  						ErrorCode: 1234,
   803  						Remote:    false,
   804  					}))
   805  					close(writeReturned)
   806  				}()
   807  				waitForWrite()
   808  				frame, ok, hasMoreData := str.popStreamFrame(50, protocol.Version1)
   809  				Expect(ok).To(BeTrue())
   810  				Expect(hasMoreData).To(BeTrue())
   811  				Expect(frame).ToNot(BeNil())
   812  				mockSender.EXPECT().onStreamCompleted(streamID)
   813  				str.CancelWrite(1234)
   814  				_, ok, hasMoreData = str.popStreamFrame(10, protocol.Version1)
   815  				Expect(ok).To(BeFalse())
   816  				Expect(hasMoreData).To(BeFalse())
   817  				Eventually(writeReturned).Should(BeClosed())
   818  			})
   819  
   820  			It("ignores acknowledgements for STREAM frames after it was cancelled", func() {
   821  				mockSender.EXPECT().queueControlFrame(gomock.Any())
   822  				mockSender.EXPECT().onHasStreamData(streamID)
   823  				mockFC.EXPECT().SendWindowSize().Return(protocol.MaxByteCount)
   824  				mockFC.EXPECT().AddBytesSent(gomock.Any())
   825  				writeReturned := make(chan struct{})
   826  				go func() {
   827  					defer GinkgoRecover()
   828  					strWithTimeout.Write(getData(100))
   829  					close(writeReturned)
   830  				}()
   831  				waitForWrite()
   832  				frame, ok, hasMoreData := str.popStreamFrame(50, protocol.Version1)
   833  				Expect(ok).To(BeTrue())
   834  				Expect(hasMoreData).To(BeTrue())
   835  				Expect(frame).ToNot(BeNil())
   836  				mockSender.EXPECT().onStreamCompleted(streamID)
   837  				str.CancelWrite(1234)
   838  				frame.Handler.OnAcked(frame.Frame)
   839  			})
   840  
   841  			It("cancels the context", func() {
   842  				mockSender.EXPECT().queueControlFrame(gomock.Any())
   843  				mockSender.EXPECT().onStreamCompleted(gomock.Any())
   844  				Expect(str.Context().Done()).ToNot(BeClosed())
   845  				str.CancelWrite(1234)
   846  				Expect(str.Context().Done()).To(BeClosed())
   847  			})
   848  
   849  			It("doesn't allow further calls to Write", func() {
   850  				mockSender.EXPECT().queueControlFrame(gomock.Any())
   851  				mockSender.EXPECT().onStreamCompleted(gomock.Any())
   852  				str.CancelWrite(1234)
   853  				_, err := strWithTimeout.Write([]byte("foobar"))
   854  				Expect(err).To(MatchError(&StreamError{
   855  					StreamID:  streamID,
   856  					ErrorCode: 1234,
   857  					Remote:    false,
   858  				}))
   859  			})
   860  
   861  			It("only cancels once", func() {
   862  				mockSender.EXPECT().queueControlFrame(&wire.ResetStreamFrame{StreamID: streamID, ErrorCode: 1234})
   863  				mockSender.EXPECT().onStreamCompleted(gomock.Any())
   864  				str.CancelWrite(1234)
   865  				str.CancelWrite(4321)
   866  			})
   867  
   868  			It("queues a RESET_STREAM frame, even if the stream was already closed", func() {
   869  				mockSender.EXPECT().onHasStreamData(streamID)
   870  				mockSender.EXPECT().queueControlFrame(gomock.Any()).Do(func(f wire.Frame) {
   871  					Expect(f).To(BeAssignableToTypeOf(&wire.ResetStreamFrame{}))
   872  				})
   873  				mockSender.EXPECT().onStreamCompleted(gomock.Any())
   874  				Expect(str.Close()).To(Succeed())
   875  				// don't EXPECT any calls to queueControlFrame
   876  				str.CancelWrite(123)
   877  			})
   878  		})
   879  
   880  		Context("receiving STOP_SENDING frames", func() {
   881  			It("queues a RESET_STREAM frames, and copies the error code from the STOP_SENDING frame", func() {
   882  				mockSender.EXPECT().queueControlFrame(&wire.ResetStreamFrame{
   883  					StreamID:  streamID,
   884  					ErrorCode: 101,
   885  				})
   886  				mockSender.EXPECT().onStreamCompleted(gomock.Any())
   887  
   888  				str.handleStopSendingFrame(&wire.StopSendingFrame{
   889  					StreamID:  streamID,
   890  					ErrorCode: 101,
   891  				})
   892  			})
   893  
   894  			It("unblocks Write", func() {
   895  				mockSender.EXPECT().onHasStreamData(streamID)
   896  				mockSender.EXPECT().queueControlFrame(gomock.Any())
   897  				mockSender.EXPECT().onStreamCompleted(gomock.Any())
   898  				done := make(chan struct{})
   899  				go func() {
   900  					defer GinkgoRecover()
   901  					_, err := str.Write(getData(5000))
   902  					Expect(err).To(Equal(&StreamError{
   903  						StreamID:  streamID,
   904  						ErrorCode: 123,
   905  						Remote:    true,
   906  					}))
   907  					close(done)
   908  				}()
   909  				waitForWrite()
   910  				str.handleStopSendingFrame(&wire.StopSendingFrame{
   911  					StreamID:  streamID,
   912  					ErrorCode: 123,
   913  				})
   914  				Eventually(done).Should(BeClosed())
   915  			})
   916  
   917  			It("doesn't allow further calls to Write", func() {
   918  				mockSender.EXPECT().queueControlFrame(gomock.Any())
   919  				mockSender.EXPECT().onStreamCompleted(gomock.Any())
   920  				str.handleStopSendingFrame(&wire.StopSendingFrame{
   921  					StreamID:  streamID,
   922  					ErrorCode: 123,
   923  				})
   924  				_, err := str.Write([]byte("foobar"))
   925  				Expect(err).To(Equal(&StreamError{
   926  					StreamID:  streamID,
   927  					ErrorCode: 123,
   928  					Remote:    true,
   929  				}))
   930  			})
   931  		})
   932  	})
   933  
   934  	Context("retransmissions", func() {
   935  		It("queues and retrieves frames", func() {
   936  			str.numOutstandingFrames = 1
   937  			f := &wire.StreamFrame{
   938  				Data:           []byte("foobar"),
   939  				Offset:         0x42,
   940  				DataLenPresent: false,
   941  			}
   942  			mockSender.EXPECT().onHasStreamData(streamID)
   943  			(*sendStreamAckHandler)(str).OnLost(f)
   944  			frame, ok, _ := str.popStreamFrame(protocol.MaxByteCount, protocol.Version1)
   945  			Expect(ok).To(BeTrue())
   946  			Expect(frame).ToNot(BeNil())
   947  			f = frame.Frame
   948  			Expect(f.Offset).To(Equal(protocol.ByteCount(0x42)))
   949  			Expect(f.Data).To(Equal([]byte("foobar")))
   950  			Expect(f.DataLenPresent).To(BeTrue())
   951  		})
   952  
   953  		It("splits a retransmission", func() {
   954  			str.numOutstandingFrames = 1
   955  			sf := &wire.StreamFrame{
   956  				Data:           []byte("foobar"),
   957  				Offset:         0x42,
   958  				DataLenPresent: false,
   959  			}
   960  			mockSender.EXPECT().onHasStreamData(streamID)
   961  			(*sendStreamAckHandler)(str).OnLost(sf)
   962  			frame, ok, hasMoreData := str.popStreamFrame(sf.Length(protocol.Version1)-3, protocol.Version1)
   963  			Expect(ok).To(BeTrue())
   964  			Expect(frame).ToNot(BeNil())
   965  			f := frame.Frame
   966  			Expect(hasMoreData).To(BeTrue())
   967  			Expect(f.Offset).To(Equal(protocol.ByteCount(0x42)))
   968  			Expect(f.Data).To(Equal([]byte("foo")))
   969  			Expect(f.DataLenPresent).To(BeTrue())
   970  			frame, ok, _ = str.popStreamFrame(protocol.MaxByteCount, protocol.Version1)
   971  			Expect(ok).To(BeTrue())
   972  			Expect(frame).ToNot(BeNil())
   973  			f = frame.Frame
   974  			Expect(f.Offset).To(Equal(protocol.ByteCount(0x45)))
   975  			Expect(f.Data).To(Equal([]byte("bar")))
   976  			Expect(f.DataLenPresent).To(BeTrue())
   977  		})
   978  
   979  		It("returns nil if the size is too small", func() {
   980  			str.numOutstandingFrames = 1
   981  			f := &wire.StreamFrame{
   982  				Data:           []byte("foobar"),
   983  				Offset:         0x42,
   984  				DataLenPresent: false,
   985  			}
   986  			mockSender.EXPECT().onHasStreamData(streamID)
   987  			(*sendStreamAckHandler)(str).OnLost(f)
   988  			_, ok, hasMoreData := str.popStreamFrame(2, protocol.Version1)
   989  			Expect(ok).To(BeFalse())
   990  			Expect(hasMoreData).To(BeTrue())
   991  		})
   992  
   993  		It("queues lost STREAM frames", func() {
   994  			mockSender.EXPECT().onHasStreamData(streamID)
   995  			mockFC.EXPECT().SendWindowSize().Return(protocol.ByteCount(9999))
   996  			mockFC.EXPECT().AddBytesSent(protocol.ByteCount(6))
   997  			done := make(chan struct{})
   998  			go func() {
   999  				defer GinkgoRecover()
  1000  				_, err := strWithTimeout.Write([]byte("foobar"))
  1001  				Expect(err).ToNot(HaveOccurred())
  1002  				close(done)
  1003  			}()
  1004  			waitForWrite()
  1005  			frame, ok, _ := str.popStreamFrame(protocol.MaxByteCount, protocol.Version1)
  1006  			Expect(ok).To(BeTrue())
  1007  			Eventually(done).Should(BeClosed())
  1008  			Expect(frame).ToNot(BeNil())
  1009  			Expect(frame.Frame.Data).To(Equal([]byte("foobar")))
  1010  
  1011  			// now lose the frame
  1012  			mockSender.EXPECT().onHasStreamData(streamID)
  1013  			frame.Handler.OnLost(frame.Frame)
  1014  			newFrame, ok, _ := str.popStreamFrame(protocol.MaxByteCount, protocol.Version1)
  1015  			Expect(ok).To(BeTrue())
  1016  			Expect(newFrame).ToNot(BeNil())
  1017  			Expect(newFrame.Frame.Data).To(Equal([]byte("foobar")))
  1018  		})
  1019  
  1020  		It("doesn't queue retransmissions for a stream that was canceled", func() {
  1021  			mockSender.EXPECT().onHasStreamData(streamID)
  1022  			mockFC.EXPECT().SendWindowSize().Return(protocol.MaxByteCount)
  1023  			mockFC.EXPECT().AddBytesSent(protocol.ByteCount(6))
  1024  			done := make(chan struct{})
  1025  			go func() {
  1026  				defer GinkgoRecover()
  1027  				_, err := str.Write([]byte("foobar"))
  1028  				Expect(err).ToNot(HaveOccurred())
  1029  				close(done)
  1030  			}()
  1031  			waitForWrite()
  1032  			f, ok, _ := str.popStreamFrame(100, protocol.Version1)
  1033  			Expect(ok).To(BeTrue())
  1034  			Eventually(done).Should(BeClosed())
  1035  			Expect(f).ToNot(BeNil())
  1036  			gomock.InOrder(
  1037  				mockSender.EXPECT().queueControlFrame(gomock.Any()),
  1038  				mockSender.EXPECT().onStreamCompleted(streamID),
  1039  			)
  1040  			str.CancelWrite(9876)
  1041  			// don't EXPECT any calls to onHasStreamData
  1042  			f.Handler.OnLost(f.Frame)
  1043  			Expect(str.retransmissionQueue).To(BeEmpty())
  1044  		})
  1045  	})
  1046  
  1047  	Context("determining when a stream is completed", func() {
  1048  		BeforeEach(func() {
  1049  			mockFC.EXPECT().SendWindowSize().Return(protocol.MaxByteCount).AnyTimes()
  1050  			mockFC.EXPECT().AddBytesSent(gomock.Any()).AnyTimes()
  1051  		})
  1052  
  1053  		It("says when a stream is completed", func() {
  1054  			mockSender.EXPECT().onHasStreamData(streamID)
  1055  			done := make(chan struct{})
  1056  			go func() {
  1057  				defer GinkgoRecover()
  1058  				_, err := strWithTimeout.Write(make([]byte, 100))
  1059  				Expect(err).ToNot(HaveOccurred())
  1060  				close(done)
  1061  			}()
  1062  			waitForWrite()
  1063  
  1064  			// get a bunch of small frames (max. 20 bytes)
  1065  			var frames []ackhandler.StreamFrame
  1066  			for {
  1067  				frame, ok, hasMoreData := str.popStreamFrame(20, protocol.Version1)
  1068  				if !ok {
  1069  					continue
  1070  				}
  1071  				frames = append(frames, frame)
  1072  				if !hasMoreData {
  1073  					break
  1074  				}
  1075  			}
  1076  			Eventually(done).Should(BeClosed())
  1077  
  1078  			// Acknowledge all frames.
  1079  			// We don't expect the stream to be completed, since we still need to send the FIN.
  1080  			for _, f := range frames {
  1081  				f.Handler.OnAcked(f.Frame)
  1082  			}
  1083  
  1084  			// Now close the stream and acknowledge the FIN.
  1085  			mockSender.EXPECT().onHasStreamData(streamID)
  1086  			Expect(str.Close()).To(Succeed())
  1087  			frame, ok, _ := str.popStreamFrame(protocol.MaxByteCount, protocol.Version1)
  1088  			Expect(ok).To(BeTrue())
  1089  			Expect(frame).ToNot(BeNil())
  1090  			mockSender.EXPECT().onStreamCompleted(streamID)
  1091  			frame.Handler.OnAcked(frame.Frame)
  1092  		})
  1093  
  1094  		It("says when a stream is completed, if Close() is called before popping the frame", func() {
  1095  			mockSender.EXPECT().onHasStreamData(streamID).Times(2)
  1096  			done := make(chan struct{})
  1097  			go func() {
  1098  				defer GinkgoRecover()
  1099  				_, err := strWithTimeout.Write(make([]byte, 100))
  1100  				Expect(err).ToNot(HaveOccurred())
  1101  				close(done)
  1102  			}()
  1103  			waitForWrite()
  1104  			Eventually(done).Should(BeClosed())
  1105  			Expect(str.Close()).To(Succeed())
  1106  
  1107  			frame, ok, hasMoreData := str.popStreamFrame(protocol.MaxByteCount, protocol.Version1)
  1108  			Expect(ok).To(BeTrue())
  1109  			Expect(hasMoreData).To(BeFalse())
  1110  			Expect(frame).ToNot(BeNil())
  1111  			Expect(frame.Frame.Fin).To(BeTrue())
  1112  
  1113  			mockSender.EXPECT().onStreamCompleted(streamID)
  1114  			frame.Handler.OnAcked(frame.Frame)
  1115  		})
  1116  
  1117  		It("doesn't say it's completed when there are frames waiting to be retransmitted", func() {
  1118  			mockSender.EXPECT().onHasStreamData(streamID)
  1119  			done := make(chan struct{})
  1120  			go func() {
  1121  				defer GinkgoRecover()
  1122  				_, err := strWithTimeout.Write(getData(100))
  1123  				Expect(err).ToNot(HaveOccurred())
  1124  				mockSender.EXPECT().onHasStreamData(streamID)
  1125  				Expect(str.Close()).To(Succeed())
  1126  				close(done)
  1127  			}()
  1128  			waitForWrite()
  1129  
  1130  			// get a bunch of small frames (max. 20 bytes)
  1131  			var frames []ackhandler.StreamFrame
  1132  			for {
  1133  				frame, ok, _ := str.popStreamFrame(20, protocol.Version1)
  1134  				if !ok {
  1135  					continue
  1136  				}
  1137  				frames = append(frames, frame)
  1138  				if frame.Frame.Fin {
  1139  					break
  1140  				}
  1141  			}
  1142  			Eventually(done).Should(BeClosed())
  1143  
  1144  			// lose the first frame, acknowledge all others
  1145  			for _, f := range frames[1:] {
  1146  				f.Handler.OnAcked(f.Frame)
  1147  			}
  1148  			mockSender.EXPECT().onHasStreamData(streamID)
  1149  			frames[0].Handler.OnLost(frames[0].Frame)
  1150  
  1151  			// get the retransmission and acknowledge it
  1152  			ret, ok, _ := str.popStreamFrame(protocol.MaxByteCount, protocol.Version1)
  1153  			Expect(ok).To(BeTrue())
  1154  			Expect(ret).ToNot(BeNil())
  1155  			mockSender.EXPECT().onStreamCompleted(streamID)
  1156  			ret.Handler.OnAcked(ret.Frame)
  1157  		})
  1158  
  1159  		// This test is kind of an integration test.
  1160  		// It writes 4 MB of data, and pops STREAM frames that sometimes are and sometimes aren't limited by flow control.
  1161  		// Half of these STREAM frames are then received and their content saved, while the other half is reported lost
  1162  		// and has to be retransmitted.
  1163  		It("retransmits data until everything has been acknowledged", func() {
  1164  			const dataLen = 1 << 22 // 4 MB
  1165  			mockSender.EXPECT().onHasStreamData(streamID).AnyTimes()
  1166  			mockFC.EXPECT().SendWindowSize().DoAndReturn(func() protocol.ByteCount {
  1167  				return protocol.ByteCount(mrand.Intn(500)) + 50
  1168  			}).AnyTimes()
  1169  			mockFC.EXPECT().AddBytesSent(gomock.Any()).AnyTimes()
  1170  
  1171  			data := make([]byte, dataLen)
  1172  			_, err := mrand.Read(data)
  1173  			Expect(err).ToNot(HaveOccurred())
  1174  			done := make(chan struct{})
  1175  			go func() {
  1176  				defer GinkgoRecover()
  1177  				defer close(done)
  1178  				_, err := str.Write(data)
  1179  				Expect(err).ToNot(HaveOccurred())
  1180  				str.Close()
  1181  			}()
  1182  
  1183  			var completed bool
  1184  			mockSender.EXPECT().onStreamCompleted(streamID).Do(func(protocol.StreamID) { completed = true })
  1185  
  1186  			received := make([]byte, dataLen)
  1187  			for {
  1188  				if completed {
  1189  					break
  1190  				}
  1191  				f, ok, _ := str.popStreamFrame(protocol.ByteCount(mrand.Intn(300)+100), protocol.Version1)
  1192  				if !ok {
  1193  					continue
  1194  				}
  1195  				sf := f.Frame
  1196  				// 50%: acknowledge the frame and save the data
  1197  				// 50%: lose the frame
  1198  				if mrand.Intn(100) < 50 {
  1199  					copy(received[sf.Offset:sf.Offset+sf.DataLen()], sf.Data)
  1200  					f.Handler.OnAcked(f.Frame)
  1201  				} else {
  1202  					f.Handler.OnLost(f.Frame)
  1203  				}
  1204  			}
  1205  			Expect(received).To(Equal(data))
  1206  		})
  1207  	})
  1208  })