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