github.com/danielpfeifer02/quic-go-prio-packs@v0.41.0-28/receive_stream_test.go (about)

     1  package quic
     2  
     3  import (
     4  	"errors"
     5  	"io"
     6  	"runtime"
     7  	"sync"
     8  	"sync/atomic"
     9  	"time"
    10  
    11  	"github.com/danielpfeifer02/quic-go-prio-packs/internal/mocks"
    12  	"github.com/danielpfeifer02/quic-go-prio-packs/internal/protocol"
    13  	"github.com/danielpfeifer02/quic-go-prio-packs/internal/wire"
    14  
    15  	. "github.com/onsi/ginkgo/v2"
    16  	. "github.com/onsi/gomega"
    17  	"github.com/onsi/gomega/gbytes"
    18  	"go.uber.org/mock/gomock"
    19  )
    20  
    21  var _ = Describe("Receive Stream", func() {
    22  	const streamID protocol.StreamID = 1337
    23  
    24  	var (
    25  		str            *receiveStream
    26  		strWithTimeout io.Reader // str wrapped with gbytes.TimeoutReader
    27  		mockFC         *mocks.MockStreamFlowController
    28  		mockSender     *MockStreamSender
    29  	)
    30  
    31  	BeforeEach(func() {
    32  		mockSender = NewMockStreamSender(mockCtrl)
    33  		mockFC = mocks.NewMockStreamFlowController(mockCtrl)
    34  		str = newReceiveStream(streamID, mockSender, mockFC)
    35  
    36  		timeout := scaleDuration(250 * time.Millisecond)
    37  		strWithTimeout = gbytes.TimeoutReader(str, timeout)
    38  	})
    39  
    40  	It("gets stream id", func() {
    41  		Expect(str.StreamID()).To(Equal(protocol.StreamID(1337)))
    42  	})
    43  
    44  	Context("reading", func() {
    45  		It("reads a single STREAM frame", func() {
    46  			mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(4), false)
    47  			mockFC.EXPECT().AddBytesRead(protocol.ByteCount(4))
    48  			frame := wire.StreamFrame{
    49  				Offset: 0,
    50  				Data:   []byte{0xDE, 0xAD, 0xBE, 0xEF},
    51  			}
    52  			err := str.handleStreamFrame(&frame)
    53  			Expect(err).ToNot(HaveOccurred())
    54  			b := make([]byte, 4)
    55  			n, err := strWithTimeout.Read(b)
    56  			Expect(err).ToNot(HaveOccurred())
    57  			Expect(n).To(Equal(4))
    58  			Expect(b).To(Equal([]byte{0xDE, 0xAD, 0xBE, 0xEF}))
    59  		})
    60  
    61  		It("reads a single STREAM frame in multiple goes", func() {
    62  			mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(4), false)
    63  			mockFC.EXPECT().AddBytesRead(protocol.ByteCount(2))
    64  			mockFC.EXPECT().AddBytesRead(protocol.ByteCount(2))
    65  			frame := wire.StreamFrame{
    66  				Offset: 0,
    67  				Data:   []byte{0xDE, 0xAD, 0xBE, 0xEF},
    68  			}
    69  			err := str.handleStreamFrame(&frame)
    70  			Expect(err).ToNot(HaveOccurred())
    71  			b := make([]byte, 2)
    72  			n, err := strWithTimeout.Read(b)
    73  			Expect(err).ToNot(HaveOccurred())
    74  			Expect(n).To(Equal(2))
    75  			Expect(b).To(Equal([]byte{0xDE, 0xAD}))
    76  			n, err = strWithTimeout.Read(b)
    77  			Expect(err).ToNot(HaveOccurred())
    78  			Expect(n).To(Equal(2))
    79  			Expect(b).To(Equal([]byte{0xBE, 0xEF}))
    80  		})
    81  
    82  		It("reads all data available", func() {
    83  			mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(2), false)
    84  			mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(4), false)
    85  			mockFC.EXPECT().AddBytesRead(protocol.ByteCount(2)).Times(2)
    86  			frame1 := wire.StreamFrame{
    87  				Offset: 0,
    88  				Data:   []byte{0xDE, 0xAD},
    89  			}
    90  			frame2 := wire.StreamFrame{
    91  				Offset: 2,
    92  				Data:   []byte{0xBE, 0xEF},
    93  			}
    94  			err := str.handleStreamFrame(&frame1)
    95  			Expect(err).ToNot(HaveOccurred())
    96  			err = str.handleStreamFrame(&frame2)
    97  			Expect(err).ToNot(HaveOccurred())
    98  			b := make([]byte, 6)
    99  			n, err := strWithTimeout.Read(b)
   100  			Expect(err).ToNot(HaveOccurred())
   101  			Expect(n).To(Equal(4))
   102  			Expect(b).To(Equal([]byte{0xDE, 0xAD, 0xBE, 0xEF, 0x00, 0x00}))
   103  		})
   104  
   105  		It("assembles multiple STREAM frames", func() {
   106  			mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(2), false)
   107  			mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(4), false)
   108  			mockFC.EXPECT().AddBytesRead(protocol.ByteCount(2)).Times(2)
   109  			frame1 := wire.StreamFrame{
   110  				Offset: 0,
   111  				Data:   []byte{0xDE, 0xAD},
   112  			}
   113  			frame2 := wire.StreamFrame{
   114  				Offset: 2,
   115  				Data:   []byte{0xBE, 0xEF},
   116  			}
   117  			err := str.handleStreamFrame(&frame1)
   118  			Expect(err).ToNot(HaveOccurred())
   119  			err = str.handleStreamFrame(&frame2)
   120  			Expect(err).ToNot(HaveOccurred())
   121  			b := make([]byte, 4)
   122  			n, err := strWithTimeout.Read(b)
   123  			Expect(err).ToNot(HaveOccurred())
   124  			Expect(n).To(Equal(4))
   125  			Expect(b).To(Equal([]byte{0xDE, 0xAD, 0xBE, 0xEF}))
   126  		})
   127  
   128  		It("waits until data is available", func() {
   129  			mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(2), false)
   130  			mockFC.EXPECT().AddBytesRead(protocol.ByteCount(2))
   131  			go func() {
   132  				defer GinkgoRecover()
   133  				frame := wire.StreamFrame{Data: []byte{0xDE, 0xAD}}
   134  				time.Sleep(10 * time.Millisecond)
   135  				err := str.handleStreamFrame(&frame)
   136  				Expect(err).ToNot(HaveOccurred())
   137  			}()
   138  			b := make([]byte, 2)
   139  			n, err := strWithTimeout.Read(b)
   140  			Expect(err).ToNot(HaveOccurred())
   141  			Expect(n).To(Equal(2))
   142  		})
   143  
   144  		It("handles STREAM frames in wrong order", func() {
   145  			mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(2), false)
   146  			mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(4), false)
   147  			mockFC.EXPECT().AddBytesRead(protocol.ByteCount(2)).Times(2)
   148  			frame1 := wire.StreamFrame{
   149  				Offset: 2,
   150  				Data:   []byte{0xBE, 0xEF},
   151  			}
   152  			frame2 := wire.StreamFrame{
   153  				Offset: 0,
   154  				Data:   []byte{0xDE, 0xAD},
   155  			}
   156  			err := str.handleStreamFrame(&frame1)
   157  			Expect(err).ToNot(HaveOccurred())
   158  			err = str.handleStreamFrame(&frame2)
   159  			Expect(err).ToNot(HaveOccurred())
   160  			b := make([]byte, 4)
   161  			n, err := strWithTimeout.Read(b)
   162  			Expect(err).ToNot(HaveOccurred())
   163  			Expect(n).To(Equal(4))
   164  			Expect(b).To(Equal([]byte{0xDE, 0xAD, 0xBE, 0xEF}))
   165  		})
   166  
   167  		It("ignores duplicate STREAM frames", func() {
   168  			mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(2), false)
   169  			mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(2), false)
   170  			mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(4), false)
   171  			mockFC.EXPECT().AddBytesRead(protocol.ByteCount(2)).Times(2)
   172  			frame1 := wire.StreamFrame{
   173  				Offset: 0,
   174  				Data:   []byte{0xDE, 0xAD},
   175  			}
   176  			frame2 := wire.StreamFrame{
   177  				Offset: 0,
   178  				Data:   []byte{0x13, 0x37},
   179  			}
   180  			frame3 := wire.StreamFrame{
   181  				Offset: 2,
   182  				Data:   []byte{0xBE, 0xEF},
   183  			}
   184  			err := str.handleStreamFrame(&frame1)
   185  			Expect(err).ToNot(HaveOccurred())
   186  			err = str.handleStreamFrame(&frame2)
   187  			Expect(err).ToNot(HaveOccurred())
   188  			err = str.handleStreamFrame(&frame3)
   189  			Expect(err).ToNot(HaveOccurred())
   190  			b := make([]byte, 4)
   191  			n, err := strWithTimeout.Read(b)
   192  			Expect(err).ToNot(HaveOccurred())
   193  			Expect(n).To(Equal(4))
   194  			Expect(b).To(Equal([]byte{0xDE, 0xAD, 0xBE, 0xEF}))
   195  		})
   196  
   197  		It("doesn't rejects a STREAM frames with an overlapping data range", func() {
   198  			mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(4), false)
   199  			mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(6), false)
   200  			mockFC.EXPECT().AddBytesRead(protocol.ByteCount(2))
   201  			mockFC.EXPECT().AddBytesRead(protocol.ByteCount(4))
   202  			frame1 := wire.StreamFrame{
   203  				Offset: 0,
   204  				Data:   []byte("foob"),
   205  			}
   206  			frame2 := wire.StreamFrame{
   207  				Offset: 2,
   208  				Data:   []byte("obar"),
   209  			}
   210  			err := str.handleStreamFrame(&frame1)
   211  			Expect(err).ToNot(HaveOccurred())
   212  			err = str.handleStreamFrame(&frame2)
   213  			Expect(err).ToNot(HaveOccurred())
   214  			b := make([]byte, 6)
   215  			n, err := strWithTimeout.Read(b)
   216  			Expect(err).ToNot(HaveOccurred())
   217  			Expect(n).To(Equal(6))
   218  			Expect(b).To(Equal([]byte("foobar")))
   219  		})
   220  
   221  		Context("deadlines", func() {
   222  			It("the deadline error has the right net.Error properties", func() {
   223  				Expect(errDeadline.Timeout()).To(BeTrue())
   224  				Expect(errDeadline).To(MatchError("deadline exceeded"))
   225  			})
   226  
   227  			It("returns an error when Read is called after the deadline", func() {
   228  				mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(6), false).AnyTimes()
   229  				f := &wire.StreamFrame{Data: []byte("foobar")}
   230  				err := str.handleStreamFrame(f)
   231  				Expect(err).ToNot(HaveOccurred())
   232  				str.SetReadDeadline(time.Now().Add(-time.Second))
   233  				b := make([]byte, 6)
   234  				n, err := strWithTimeout.Read(b)
   235  				Expect(err).To(MatchError(errDeadline))
   236  				Expect(n).To(BeZero())
   237  			})
   238  
   239  			It("unblocks when the deadline is changed to the past", func() {
   240  				str.SetReadDeadline(time.Now().Add(time.Hour))
   241  				done := make(chan struct{})
   242  				go func() {
   243  					defer GinkgoRecover()
   244  					_, err := str.Read(make([]byte, 6))
   245  					Expect(err).To(MatchError(errDeadline))
   246  					close(done)
   247  				}()
   248  				Consistently(done).ShouldNot(BeClosed())
   249  				str.SetReadDeadline(time.Now().Add(-time.Hour))
   250  				Eventually(done).Should(BeClosed())
   251  			})
   252  
   253  			It("unblocks after the deadline", func() {
   254  				deadline := time.Now().Add(scaleDuration(50 * time.Millisecond))
   255  				str.SetReadDeadline(deadline)
   256  				b := make([]byte, 6)
   257  				n, err := strWithTimeout.Read(b)
   258  				Expect(err).To(MatchError(errDeadline))
   259  				Expect(n).To(BeZero())
   260  				Expect(time.Now()).To(BeTemporally("~", deadline, scaleDuration(20*time.Millisecond)))
   261  			})
   262  
   263  			It("doesn't unblock if the deadline is changed before the first one expires", func() {
   264  				deadline1 := time.Now().Add(scaleDuration(50 * time.Millisecond))
   265  				deadline2 := time.Now().Add(scaleDuration(100 * time.Millisecond))
   266  				str.SetReadDeadline(deadline1)
   267  				go func() {
   268  					defer GinkgoRecover()
   269  					time.Sleep(scaleDuration(20 * time.Millisecond))
   270  					str.SetReadDeadline(deadline2)
   271  					// make sure that this was actually execute before the deadline expires
   272  					Expect(time.Now()).To(BeTemporally("<", deadline1))
   273  				}()
   274  				runtime.Gosched()
   275  				b := make([]byte, 10)
   276  				n, err := strWithTimeout.Read(b)
   277  				Expect(err).To(MatchError(errDeadline))
   278  				Expect(n).To(BeZero())
   279  				Expect(time.Now()).To(BeTemporally("~", deadline2, scaleDuration(20*time.Millisecond)))
   280  			})
   281  
   282  			It("unblocks earlier, when a new deadline is set", func() {
   283  				deadline1 := time.Now().Add(scaleDuration(200 * time.Millisecond))
   284  				deadline2 := time.Now().Add(scaleDuration(50 * time.Millisecond))
   285  				go func() {
   286  					defer GinkgoRecover()
   287  					time.Sleep(scaleDuration(10 * time.Millisecond))
   288  					str.SetReadDeadline(deadline2)
   289  					// make sure that this was actually execute before the deadline expires
   290  					Expect(time.Now()).To(BeTemporally("<", deadline2))
   291  				}()
   292  				str.SetReadDeadline(deadline1)
   293  				runtime.Gosched()
   294  				b := make([]byte, 10)
   295  				_, err := strWithTimeout.Read(b)
   296  				Expect(err).To(MatchError(errDeadline))
   297  				Expect(time.Now()).To(BeTemporally("~", deadline2, scaleDuration(25*time.Millisecond)))
   298  			})
   299  
   300  			It("doesn't unblock if the deadline is removed", func() {
   301  				deadline := time.Now().Add(scaleDuration(50 * time.Millisecond))
   302  				str.SetReadDeadline(deadline)
   303  				deadlineUnset := make(chan struct{})
   304  				go func() {
   305  					defer GinkgoRecover()
   306  					time.Sleep(scaleDuration(20 * time.Millisecond))
   307  					str.SetReadDeadline(time.Time{})
   308  					// make sure that this was actually execute before the deadline expires
   309  					Expect(time.Now()).To(BeTemporally("<", deadline))
   310  					close(deadlineUnset)
   311  				}()
   312  				done := make(chan struct{})
   313  				go func() {
   314  					defer GinkgoRecover()
   315  					_, err := strWithTimeout.Read(make([]byte, 1))
   316  					Expect(err).To(MatchError("test done"))
   317  					close(done)
   318  				}()
   319  				runtime.Gosched()
   320  				Eventually(deadlineUnset).Should(BeClosed())
   321  				Consistently(done, scaleDuration(100*time.Millisecond)).ShouldNot(BeClosed())
   322  				// make the go routine return
   323  				str.closeForShutdown(errors.New("test done"))
   324  				Eventually(done).Should(BeClosed())
   325  			})
   326  		})
   327  
   328  		Context("closing", func() {
   329  			Context("with FIN bit", func() {
   330  				It("returns EOFs", func() {
   331  					mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(4), true)
   332  					mockFC.EXPECT().AddBytesRead(protocol.ByteCount(4))
   333  					str.handleStreamFrame(&wire.StreamFrame{
   334  						Offset: 0,
   335  						Data:   []byte{0xDE, 0xAD, 0xBE, 0xEF},
   336  						Fin:    true,
   337  					})
   338  					mockSender.EXPECT().onStreamCompleted(streamID)
   339  					b := make([]byte, 4)
   340  					n, err := strWithTimeout.Read(b)
   341  					Expect(err).To(MatchError(io.EOF))
   342  					Expect(n).To(Equal(4))
   343  					Expect(b).To(Equal([]byte{0xDE, 0xAD, 0xBE, 0xEF}))
   344  					n, err = strWithTimeout.Read(b)
   345  					Expect(n).To(BeZero())
   346  					Expect(err).To(MatchError(io.EOF))
   347  				})
   348  
   349  				It("handles out-of-order frames", func() {
   350  					mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(2), false)
   351  					mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(4), true)
   352  					mockFC.EXPECT().AddBytesRead(protocol.ByteCount(2)).Times(2)
   353  					frame1 := wire.StreamFrame{
   354  						Offset: 2,
   355  						Data:   []byte{0xBE, 0xEF},
   356  						Fin:    true,
   357  					}
   358  					frame2 := wire.StreamFrame{
   359  						Offset: 0,
   360  						Data:   []byte{0xDE, 0xAD},
   361  					}
   362  					err := str.handleStreamFrame(&frame1)
   363  					Expect(err).ToNot(HaveOccurred())
   364  					err = str.handleStreamFrame(&frame2)
   365  					Expect(err).ToNot(HaveOccurred())
   366  					mockSender.EXPECT().onStreamCompleted(streamID)
   367  					b := make([]byte, 4)
   368  					n, err := strWithTimeout.Read(b)
   369  					Expect(err).To(MatchError(io.EOF))
   370  					Expect(n).To(Equal(4))
   371  					Expect(b).To(Equal([]byte{0xDE, 0xAD, 0xBE, 0xEF}))
   372  					n, err = strWithTimeout.Read(b)
   373  					Expect(n).To(BeZero())
   374  					Expect(err).To(MatchError(io.EOF))
   375  				})
   376  
   377  				It("returns EOFs with partial read", func() {
   378  					mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(2), true)
   379  					mockFC.EXPECT().AddBytesRead(protocol.ByteCount(2))
   380  					err := str.handleStreamFrame(&wire.StreamFrame{
   381  						Offset: 0,
   382  						Data:   []byte{0xde, 0xad},
   383  						Fin:    true,
   384  					})
   385  					Expect(err).ToNot(HaveOccurred())
   386  					mockSender.EXPECT().onStreamCompleted(streamID)
   387  					b := make([]byte, 4)
   388  					n, err := strWithTimeout.Read(b)
   389  					Expect(err).To(MatchError(io.EOF))
   390  					Expect(n).To(Equal(2))
   391  					Expect(b[:n]).To(Equal([]byte{0xde, 0xad}))
   392  				})
   393  
   394  				It("handles immediate FINs", func() {
   395  					mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(0), true)
   396  					mockFC.EXPECT().AddBytesRead(protocol.ByteCount(0))
   397  					err := str.handleStreamFrame(&wire.StreamFrame{
   398  						Offset: 0,
   399  						Fin:    true,
   400  					})
   401  					Expect(err).ToNot(HaveOccurred())
   402  					mockSender.EXPECT().onStreamCompleted(streamID)
   403  					b := make([]byte, 4)
   404  					n, err := strWithTimeout.Read(b)
   405  					Expect(n).To(BeZero())
   406  					Expect(err).To(MatchError(io.EOF))
   407  				})
   408  
   409  				// Calling Read concurrently doesn't make any sense (and is forbidden),
   410  				// but we still want to make sure that we don't complete the stream more than once
   411  				// if the user misuses our API.
   412  				// This would lead to an INTERNAL_ERROR ("tried to delete unknown outgoing stream"),
   413  				// which can be hard to debug.
   414  				// Note that even without the protection built into the receiveStream, this test
   415  				// is very timing-dependent, and would need to run a few hundred times to trigger the failure.
   416  				It("handles concurrent reads", func() {
   417  					mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(6), gomock.Any()).AnyTimes()
   418  					var bytesRead protocol.ByteCount
   419  					mockFC.EXPECT().AddBytesRead(gomock.Any()).Do(func(n protocol.ByteCount) { bytesRead += n }).AnyTimes()
   420  
   421  					var numCompleted int32
   422  					mockSender.EXPECT().onStreamCompleted(streamID).Do(func(protocol.StreamID) {
   423  						atomic.AddInt32(&numCompleted, 1)
   424  					}).AnyTimes()
   425  					const num = 3
   426  					var wg sync.WaitGroup
   427  					wg.Add(num)
   428  					for i := 0; i < num; i++ {
   429  						go func() {
   430  							defer wg.Done()
   431  							defer GinkgoRecover()
   432  							_, err := str.Read(make([]byte, 8))
   433  							Expect(err).To(MatchError(io.EOF))
   434  						}()
   435  					}
   436  					str.handleStreamFrame(&wire.StreamFrame{
   437  						Offset: 0,
   438  						Data:   []byte("foobar"),
   439  						Fin:    true,
   440  					})
   441  					wg.Wait()
   442  					Expect(bytesRead).To(BeEquivalentTo(6))
   443  					Expect(atomic.LoadInt32(&numCompleted)).To(BeEquivalentTo(1))
   444  				})
   445  			})
   446  
   447  			It("closes when CloseRemote is called", func() {
   448  				mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(0), true)
   449  				mockFC.EXPECT().AddBytesRead(protocol.ByteCount(0))
   450  				str.CloseRemote(0)
   451  				mockSender.EXPECT().onStreamCompleted(streamID)
   452  				b := make([]byte, 8)
   453  				n, err := strWithTimeout.Read(b)
   454  				Expect(n).To(BeZero())
   455  				Expect(err).To(MatchError(io.EOF))
   456  			})
   457  		})
   458  
   459  		Context("closing for shutdown", func() {
   460  			testErr := errors.New("test error")
   461  
   462  			It("immediately returns all reads", func() {
   463  				done := make(chan struct{})
   464  				b := make([]byte, 4)
   465  				go func() {
   466  					defer GinkgoRecover()
   467  					n, err := strWithTimeout.Read(b)
   468  					Expect(n).To(BeZero())
   469  					Expect(err).To(MatchError(testErr))
   470  					close(done)
   471  				}()
   472  				Consistently(done).ShouldNot(BeClosed())
   473  				str.closeForShutdown(testErr)
   474  				Eventually(done).Should(BeClosed())
   475  			})
   476  
   477  			It("errors for all following reads", func() {
   478  				str.closeForShutdown(testErr)
   479  				b := make([]byte, 1)
   480  				n, err := strWithTimeout.Read(b)
   481  				Expect(n).To(BeZero())
   482  				Expect(err).To(MatchError(testErr))
   483  			})
   484  		})
   485  	})
   486  
   487  	Context("stream cancellations", func() {
   488  		Context("canceling read", func() {
   489  			It("unblocks Read", func() {
   490  				mockSender.EXPECT().queueControlFrame(gomock.Any())
   491  				done := make(chan struct{})
   492  				go func() {
   493  					defer GinkgoRecover()
   494  					_, err := strWithTimeout.Read([]byte{0})
   495  					Expect(err).To(Equal(&StreamError{
   496  						StreamID:  streamID,
   497  						ErrorCode: 1234,
   498  						Remote:    false,
   499  					}))
   500  					close(done)
   501  				}()
   502  				Consistently(done).ShouldNot(BeClosed())
   503  				str.CancelRead(1234)
   504  				Eventually(done).Should(BeClosed())
   505  			})
   506  
   507  			It("doesn't allow further calls to Read", func() {
   508  				mockSender.EXPECT().queueControlFrame(gomock.Any())
   509  				str.CancelRead(1234)
   510  				_, err := strWithTimeout.Read([]byte{0})
   511  				Expect(err).To(Equal(&StreamError{
   512  					StreamID:  streamID,
   513  					ErrorCode: 1234,
   514  					Remote:    false,
   515  				}))
   516  			})
   517  
   518  			It("does nothing when CancelRead is called twice", func() {
   519  				mockSender.EXPECT().queueControlFrame(gomock.Any())
   520  				str.CancelRead(1234)
   521  				str.CancelRead(1234)
   522  				_, err := strWithTimeout.Read([]byte{0})
   523  				Expect(err).To(Equal(&StreamError{
   524  					StreamID:  streamID,
   525  					ErrorCode: 1234,
   526  					Remote:    false,
   527  				}))
   528  			})
   529  
   530  			It("queues a STOP_SENDING frame", func() {
   531  				mockSender.EXPECT().queueControlFrame(&wire.StopSendingFrame{
   532  					StreamID:  streamID,
   533  					ErrorCode: 1234,
   534  				})
   535  				str.CancelRead(1234)
   536  			})
   537  
   538  			It("doesn't send a STOP_SENDING frame, if the FIN was already read", func() {
   539  				mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(6), true)
   540  				mockFC.EXPECT().AddBytesRead(protocol.ByteCount(6))
   541  				// no calls to mockSender.queueControlFrame
   542  				Expect(str.handleStreamFrame(&wire.StreamFrame{
   543  					StreamID: streamID,
   544  					Data:     []byte("foobar"),
   545  					Fin:      true,
   546  				})).To(Succeed())
   547  				mockSender.EXPECT().onStreamCompleted(streamID)
   548  				_, err := strWithTimeout.Read(make([]byte, 100))
   549  				Expect(err).To(MatchError(io.EOF))
   550  				str.CancelRead(1234)
   551  			})
   552  
   553  			It("doesn't send a STOP_SENDING frame, if the stream was already reset", func() {
   554  				gomock.InOrder(
   555  					mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(42), true),
   556  					mockFC.EXPECT().Abandon(),
   557  				)
   558  				mockSender.EXPECT().onStreamCompleted(streamID)
   559  				Expect(str.handleResetStreamFrame(&wire.ResetStreamFrame{
   560  					StreamID:  streamID,
   561  					FinalSize: 42,
   562  				})).To(Succeed())
   563  				str.CancelRead(1234)
   564  			})
   565  
   566  			It("sends a STOP_SENDING and completes the stream after receiving the final offset", func() {
   567  				mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(1000), true)
   568  				Expect(str.handleStreamFrame(&wire.StreamFrame{
   569  					Offset: 1000,
   570  					Fin:    true,
   571  				})).To(Succeed())
   572  				mockFC.EXPECT().Abandon()
   573  				mockSender.EXPECT().queueControlFrame(gomock.Any())
   574  				mockSender.EXPECT().onStreamCompleted(streamID)
   575  				str.CancelRead(1234)
   576  			})
   577  
   578  			It("completes the stream when receiving the Fin after the stream was canceled", func() {
   579  				mockSender.EXPECT().queueControlFrame(gomock.Any())
   580  				str.CancelRead(1234)
   581  				gomock.InOrder(
   582  					mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(1000), true),
   583  					mockFC.EXPECT().Abandon(),
   584  				)
   585  				mockSender.EXPECT().onStreamCompleted(streamID)
   586  				Expect(str.handleStreamFrame(&wire.StreamFrame{
   587  					Offset: 1000,
   588  					Fin:    true,
   589  				})).To(Succeed())
   590  			})
   591  
   592  			It("handles duplicate FinBits after the stream was canceled", func() {
   593  				mockSender.EXPECT().queueControlFrame(gomock.Any())
   594  				str.CancelRead(1234)
   595  				gomock.InOrder(
   596  					mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(1000), true),
   597  					mockFC.EXPECT().Abandon(),
   598  					mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(1000), true),
   599  				)
   600  				mockSender.EXPECT().onStreamCompleted(streamID)
   601  				Expect(str.handleStreamFrame(&wire.StreamFrame{
   602  					Offset: 1000,
   603  					Fin:    true,
   604  				})).To(Succeed())
   605  				Expect(str.handleStreamFrame(&wire.StreamFrame{
   606  					Offset: 1000,
   607  					Fin:    true,
   608  				})).To(Succeed())
   609  			})
   610  		})
   611  
   612  		Context("receiving RESET_STREAM frames", func() {
   613  			rst := &wire.ResetStreamFrame{
   614  				StreamID:  streamID,
   615  				FinalSize: 42,
   616  				ErrorCode: 1234,
   617  			}
   618  
   619  			It("unblocks Read", func() {
   620  				done := make(chan struct{})
   621  				go func() {
   622  					defer GinkgoRecover()
   623  					_, err := strWithTimeout.Read([]byte{0})
   624  					Expect(err).To(Equal(&StreamError{
   625  						StreamID:  streamID,
   626  						ErrorCode: 1234,
   627  						Remote:    true,
   628  					}))
   629  					close(done)
   630  				}()
   631  				Consistently(done).ShouldNot(BeClosed())
   632  				mockSender.EXPECT().onStreamCompleted(streamID)
   633  				gomock.InOrder(
   634  					mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(42), true),
   635  					mockFC.EXPECT().Abandon(),
   636  				)
   637  				Expect(str.handleResetStreamFrame(rst)).To(Succeed())
   638  				Eventually(done).Should(BeClosed())
   639  			})
   640  
   641  			It("doesn't allow further calls to Read", func() {
   642  				mockSender.EXPECT().onStreamCompleted(streamID)
   643  				gomock.InOrder(
   644  					mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(42), true),
   645  					mockFC.EXPECT().Abandon(),
   646  				)
   647  				Expect(str.handleResetStreamFrame(rst)).To(Succeed())
   648  				_, err := strWithTimeout.Read([]byte{0})
   649  				Expect(err).To(MatchError(&StreamError{
   650  					StreamID:  streamID,
   651  					ErrorCode: 1234,
   652  				}))
   653  			})
   654  
   655  			It("errors when receiving a RESET_STREAM with an inconsistent offset", func() {
   656  				testErr := errors.New("already received a different final offset before")
   657  				mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(42), true).Return(testErr)
   658  				err := str.handleResetStreamFrame(rst)
   659  				Expect(err).To(MatchError(testErr))
   660  			})
   661  
   662  			It("ignores duplicate RESET_STREAM frames", func() {
   663  				mockSender.EXPECT().onStreamCompleted(streamID)
   664  				mockFC.EXPECT().Abandon()
   665  				mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(42), true).Times(2)
   666  				Expect(str.handleResetStreamFrame(rst)).To(Succeed())
   667  				Expect(str.handleResetStreamFrame(rst)).To(Succeed())
   668  			})
   669  
   670  			It("doesn't call onStreamCompleted again when the final offset was already received via Fin", func() {
   671  				mockSender.EXPECT().queueControlFrame(gomock.Any())
   672  				str.CancelRead(1234)
   673  				mockSender.EXPECT().onStreamCompleted(streamID)
   674  				mockFC.EXPECT().Abandon()
   675  				mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(42), true).Times(2)
   676  				Expect(str.handleStreamFrame(&wire.StreamFrame{
   677  					StreamID: streamID,
   678  					Offset:   rst.FinalSize,
   679  					Fin:      true,
   680  				})).To(Succeed())
   681  				Expect(str.handleResetStreamFrame(rst)).To(Succeed())
   682  			})
   683  
   684  			It("doesn't do anything when it was closed for shutdown", func() {
   685  				str.closeForShutdown(errors.New("shutdown"))
   686  				err := str.handleResetStreamFrame(rst)
   687  				Expect(err).ToNot(HaveOccurred())
   688  			})
   689  		})
   690  	})
   691  
   692  	Context("flow control", func() {
   693  		It("errors when a STREAM frame causes a flow control violation", func() {
   694  			testErr := errors.New("flow control violation")
   695  			mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(8), false).Return(testErr)
   696  			frame := wire.StreamFrame{
   697  				Offset: 2,
   698  				Data:   []byte("foobar"),
   699  			}
   700  			err := str.handleStreamFrame(&frame)
   701  			Expect(err).To(MatchError(testErr))
   702  		})
   703  
   704  		It("gets a window update", func() {
   705  			mockFC.EXPECT().GetWindowUpdate().Return(protocol.ByteCount(0x100))
   706  			Expect(str.getWindowUpdate()).To(Equal(protocol.ByteCount(0x100)))
   707  		})
   708  	})
   709  })