github.com/apernet/quic-go@v0.43.1-0.20240515053213-5e9e635fd9f0/stream_test.go (about) 1 package quic 2 3 import ( 4 "context" 5 "errors" 6 "io" 7 "os" 8 "strconv" 9 "time" 10 11 "github.com/apernet/quic-go/internal/mocks" 12 "github.com/apernet/quic-go/internal/protocol" 13 "github.com/apernet/quic-go/internal/wire" 14 15 . "github.com/onsi/ginkgo/v2" 16 . "github.com/onsi/gomega" 17 "github.com/onsi/gomega/gbytes" 18 ) 19 20 // in the tests for the stream deadlines we set a deadline 21 // and wait to make an assertion when Read / Write was unblocked 22 // on the CIs, the timing is a lot less precise, so scale every duration by this factor 23 func scaleDuration(t time.Duration) time.Duration { 24 scaleFactor := 1 25 if f, err := strconv.Atoi(os.Getenv("TIMESCALE_FACTOR")); err == nil { // parsing "" errors, so this works fine if the env is not set 26 scaleFactor = f 27 } 28 Expect(scaleFactor).ToNot(BeZero()) 29 return time.Duration(scaleFactor) * t 30 } 31 32 var _ = Describe("Stream", func() { 33 const streamID protocol.StreamID = 1337 34 35 var ( 36 str *stream 37 strWithTimeout io.ReadWriter // str wrapped with gbytes.Timeout{Reader,Writer} 38 mockFC *mocks.MockStreamFlowController 39 mockSender *MockStreamSender 40 ) 41 42 BeforeEach(func() { 43 mockSender = NewMockStreamSender(mockCtrl) 44 mockFC = mocks.NewMockStreamFlowController(mockCtrl) 45 str = newStream(context.Background(), streamID, mockSender, mockFC) 46 47 timeout := scaleDuration(250 * time.Millisecond) 48 strWithTimeout = struct { 49 io.Reader 50 io.Writer 51 }{ 52 gbytes.TimeoutReader(str, timeout), 53 gbytes.TimeoutWriter(str, timeout), 54 } 55 }) 56 57 It("gets stream id", func() { 58 Expect(str.StreamID()).To(Equal(protocol.StreamID(1337))) 59 }) 60 61 Context("deadlines", func() { 62 It("sets a write deadline, when SetDeadline is called", func() { 63 str.SetDeadline(time.Now().Add(-time.Second)) 64 n, err := strWithTimeout.Write([]byte("foobar")) 65 Expect(err).To(MatchError(errDeadline)) 66 Expect(n).To(BeZero()) 67 }) 68 69 It("sets a read deadline, when SetDeadline is called", func() { 70 mockFC.EXPECT().UpdateHighestReceived(protocol.ByteCount(6), false).AnyTimes() 71 f := &wire.StreamFrame{Data: []byte("foobar")} 72 err := str.handleStreamFrame(f) 73 Expect(err).ToNot(HaveOccurred()) 74 str.SetDeadline(time.Now().Add(-time.Second)) 75 b := make([]byte, 6) 76 n, err := strWithTimeout.Read(b) 77 Expect(err).To(MatchError(errDeadline)) 78 Expect(n).To(BeZero()) 79 }) 80 }) 81 82 Context("completing", func() { 83 It("is not completed when only the receive side is completed", func() { 84 // don't EXPECT a call to mockSender.onStreamCompleted() 85 str.receiveStream.sender.onStreamCompleted(streamID) 86 }) 87 88 It("is not completed when only the send side is completed", func() { 89 // don't EXPECT a call to mockSender.onStreamCompleted() 90 str.sendStream.sender.onStreamCompleted(streamID) 91 }) 92 93 It("is completed when both sides are completed", func() { 94 mockSender.EXPECT().onStreamCompleted(streamID) 95 str.sendStream.sender.onStreamCompleted(streamID) 96 str.receiveStream.sender.onStreamCompleted(streamID) 97 }) 98 }) 99 }) 100 101 var _ = Describe("Deadline Error", func() { 102 It("is a net.Error that wraps os.ErrDeadlineError", func() { 103 err := deadlineError{} 104 Expect(err.Timeout()).To(BeTrue()) 105 Expect(errors.Is(err, os.ErrDeadlineExceeded)).To(BeTrue()) 106 Expect(errors.Unwrap(err)).To(Equal(os.ErrDeadlineExceeded)) 107 }) 108 })