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 })