github.com/daeuniverse/quic-go@v0.0.0-20240413031024-943f218e0810/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/daeuniverse/quic-go/internal/mocks"
    12  	"github.com/daeuniverse/quic-go/internal/protocol"
    13  	"github.com/daeuniverse/quic-go/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  
   448  		Context("closing for shutdown", func() {
   449  			testErr := errors.New("test error")
   450  
   451  			It("immediately returns all reads", func() {
   452  				done := make(chan struct{})
   453  				b := make([]byte, 4)
   454  				go func() {
   455  					defer GinkgoRecover()
   456  					n, err := strWithTimeout.Read(b)
   457  					Expect(n).To(BeZero())
   458  					Expect(err).To(MatchError(testErr))
   459  					close(done)
   460  				}()
   461  				Consistently(done).ShouldNot(BeClosed())
   462  				str.closeForShutdown(testErr)
   463  				Eventually(done).Should(BeClosed())
   464  			})
   465  
   466  			It("errors for all following reads", func() {
   467  				str.closeForShutdown(testErr)
   468  				b := make([]byte, 1)
   469  				n, err := strWithTimeout.Read(b)
   470  				Expect(n).To(BeZero())
   471  				Expect(err).To(MatchError(testErr))
   472  			})
   473  		})
   474  	})
   475  
   476  	Context("stream cancellations", func() {
   477  		Context("canceling read", func() {
   478  			It("unblocks Read", func() {
   479  				mockSender.EXPECT().queueControlFrame(gomock.Any())
   480  				done := make(chan struct{})
   481  				go func() {
   482  					defer GinkgoRecover()
   483  					_, err := strWithTimeout.Read([]byte{0})
   484  					Expect(err).To(Equal(&StreamError{
   485  						StreamID:  streamID,
   486  						ErrorCode: 1234,
   487  						Remote:    false,
   488  					}))
   489  					close(done)
   490  				}()
   491  				Consistently(done).ShouldNot(BeClosed())
   492  				str.CancelRead(1234)
   493  				Eventually(done).Should(BeClosed())
   494  			})
   495  
   496  			It("doesn't allow further calls to Read", func() {
   497  				mockSender.EXPECT().queueControlFrame(gomock.Any())
   498  				str.CancelRead(1234)
   499  				_, err := strWithTimeout.Read([]byte{0})
   500  				Expect(err).To(Equal(&StreamError{
   501  					StreamID:  streamID,
   502  					ErrorCode: 1234,
   503  					Remote:    false,
   504  				}))
   505  			})
   506  
   507  			It("does nothing when CancelRead is called twice", func() {
   508  				mockSender.EXPECT().queueControlFrame(gomock.Any())
   509  				str.CancelRead(1234)
   510  				str.CancelRead(1234)
   511  				_, err := strWithTimeout.Read([]byte{0})
   512  				Expect(err).To(Equal(&StreamError{
   513  					StreamID:  streamID,
   514  					ErrorCode: 1234,
   515  					Remote:    false,
   516  				}))
   517  			})
   518  
   519  			It("queues a STOP_SENDING frame", func() {
   520  				mockSender.EXPECT().queueControlFrame(&wire.StopSendingFrame{
   521  					StreamID:  streamID,
   522  					ErrorCode: 1234,
   523  				})
   524  				str.CancelRead(1234)
   525  			})
   526  
   527  			It("doesn't send a STOP_SENDING frame, if the FIN was already read", func() {
   528  				mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(6), true)
   529  				mockFC.EXPECT().AddBytesRead(protocol.ByteCount(6))
   530  				// no calls to mockSender.queueControlFrame
   531  				Expect(str.handleStreamFrame(&wire.StreamFrame{
   532  					StreamID: streamID,
   533  					Data:     []byte("foobar"),
   534  					Fin:      true,
   535  				})).To(Succeed())
   536  				mockSender.EXPECT().onStreamCompleted(streamID)
   537  				_, err := strWithTimeout.Read(make([]byte, 100))
   538  				Expect(err).To(MatchError(io.EOF))
   539  				str.CancelRead(1234)
   540  			})
   541  
   542  			It("doesn't send a STOP_SENDING frame, if the stream was already reset", func() {
   543  				gomock.InOrder(
   544  					mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(42), true),
   545  					mockFC.EXPECT().Abandon(),
   546  				)
   547  				mockSender.EXPECT().onStreamCompleted(streamID)
   548  				Expect(str.handleResetStreamFrame(&wire.ResetStreamFrame{
   549  					StreamID:  streamID,
   550  					FinalSize: 42,
   551  				})).To(Succeed())
   552  				str.CancelRead(1234)
   553  			})
   554  
   555  			It("sends a STOP_SENDING and completes the stream after receiving the final offset", func() {
   556  				mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(1000), true)
   557  				Expect(str.handleStreamFrame(&wire.StreamFrame{
   558  					Offset: 1000,
   559  					Fin:    true,
   560  				})).To(Succeed())
   561  				mockFC.EXPECT().Abandon()
   562  				mockSender.EXPECT().queueControlFrame(gomock.Any())
   563  				mockSender.EXPECT().onStreamCompleted(streamID)
   564  				str.CancelRead(1234)
   565  			})
   566  
   567  			It("completes the stream when receiving the Fin after the stream was canceled", func() {
   568  				mockSender.EXPECT().queueControlFrame(gomock.Any())
   569  				str.CancelRead(1234)
   570  				gomock.InOrder(
   571  					mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(1000), true),
   572  					mockFC.EXPECT().Abandon(),
   573  				)
   574  				mockSender.EXPECT().onStreamCompleted(streamID)
   575  				Expect(str.handleStreamFrame(&wire.StreamFrame{
   576  					Offset: 1000,
   577  					Fin:    true,
   578  				})).To(Succeed())
   579  			})
   580  
   581  			It("handles duplicate FinBits after the stream was canceled", func() {
   582  				mockSender.EXPECT().queueControlFrame(gomock.Any())
   583  				str.CancelRead(1234)
   584  				gomock.InOrder(
   585  					mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(1000), true),
   586  					mockFC.EXPECT().Abandon(),
   587  					mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(1000), true),
   588  				)
   589  				mockSender.EXPECT().onStreamCompleted(streamID)
   590  				Expect(str.handleStreamFrame(&wire.StreamFrame{
   591  					Offset: 1000,
   592  					Fin:    true,
   593  				})).To(Succeed())
   594  				Expect(str.handleStreamFrame(&wire.StreamFrame{
   595  					Offset: 1000,
   596  					Fin:    true,
   597  				})).To(Succeed())
   598  			})
   599  		})
   600  
   601  		Context("receiving RESET_STREAM frames", func() {
   602  			rst := &wire.ResetStreamFrame{
   603  				StreamID:  streamID,
   604  				FinalSize: 42,
   605  				ErrorCode: 1234,
   606  			}
   607  
   608  			It("unblocks Read", func() {
   609  				done := make(chan struct{})
   610  				go func() {
   611  					defer GinkgoRecover()
   612  					_, err := strWithTimeout.Read([]byte{0})
   613  					Expect(err).To(Equal(&StreamError{
   614  						StreamID:  streamID,
   615  						ErrorCode: 1234,
   616  						Remote:    true,
   617  					}))
   618  					close(done)
   619  				}()
   620  				Consistently(done).ShouldNot(BeClosed())
   621  				mockSender.EXPECT().onStreamCompleted(streamID)
   622  				gomock.InOrder(
   623  					mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(42), true),
   624  					mockFC.EXPECT().Abandon(),
   625  				)
   626  				Expect(str.handleResetStreamFrame(rst)).To(Succeed())
   627  				Eventually(done).Should(BeClosed())
   628  			})
   629  
   630  			It("doesn't allow further calls to Read", func() {
   631  				mockSender.EXPECT().onStreamCompleted(streamID)
   632  				gomock.InOrder(
   633  					mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(42), true),
   634  					mockFC.EXPECT().Abandon(),
   635  				)
   636  				Expect(str.handleResetStreamFrame(rst)).To(Succeed())
   637  				_, err := strWithTimeout.Read([]byte{0})
   638  				Expect(err).To(MatchError(&StreamError{
   639  					StreamID:  streamID,
   640  					ErrorCode: 1234,
   641  				}))
   642  			})
   643  
   644  			It("errors when receiving a RESET_STREAM with an inconsistent offset", func() {
   645  				testErr := errors.New("already received a different final offset before")
   646  				mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(42), true).Return(testErr)
   647  				err := str.handleResetStreamFrame(rst)
   648  				Expect(err).To(MatchError(testErr))
   649  			})
   650  
   651  			It("ignores duplicate RESET_STREAM frames", func() {
   652  				mockSender.EXPECT().onStreamCompleted(streamID)
   653  				mockFC.EXPECT().Abandon()
   654  				mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(42), true).Times(2)
   655  				Expect(str.handleResetStreamFrame(rst)).To(Succeed())
   656  				Expect(str.handleResetStreamFrame(rst)).To(Succeed())
   657  			})
   658  
   659  			It("doesn't call onStreamCompleted again when the final offset was already received via Fin", func() {
   660  				mockSender.EXPECT().queueControlFrame(gomock.Any())
   661  				str.CancelRead(1234)
   662  				mockSender.EXPECT().onStreamCompleted(streamID)
   663  				mockFC.EXPECT().Abandon()
   664  				mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(42), true).Times(2)
   665  				Expect(str.handleStreamFrame(&wire.StreamFrame{
   666  					StreamID: streamID,
   667  					Offset:   rst.FinalSize,
   668  					Fin:      true,
   669  				})).To(Succeed())
   670  				Expect(str.handleResetStreamFrame(rst)).To(Succeed())
   671  			})
   672  
   673  			It("doesn't do anything when it was closed for shutdown", func() {
   674  				str.closeForShutdown(errors.New("shutdown"))
   675  				err := str.handleResetStreamFrame(rst)
   676  				Expect(err).ToNot(HaveOccurred())
   677  			})
   678  		})
   679  	})
   680  
   681  	Context("flow control", func() {
   682  		It("errors when a STREAM frame causes a flow control violation", func() {
   683  			testErr := errors.New("flow control violation")
   684  			mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(8), false).Return(testErr)
   685  			frame := wire.StreamFrame{
   686  				Offset: 2,
   687  				Data:   []byte("foobar"),
   688  			}
   689  			err := str.handleStreamFrame(&frame)
   690  			Expect(err).To(MatchError(testErr))
   691  		})
   692  
   693  		It("gets a window update", func() {
   694  			mockFC.EXPECT().GetWindowUpdate().Return(protocol.ByteCount(0x100))
   695  			Expect(str.getWindowUpdate()).To(Equal(protocol.ByteCount(0x100)))
   696  		})
   697  	})
   698  })