uquic/frame_sorter_test.go
Gaukas Wang 95575f5fe7
break: update repo url [ci skip]
uTLS is not yet bumped to the new version, so this commit breaks the dependencies relationship by getting rid of the local replace.
2023-08-03 18:58:52 -06:00

1528 lines
39 KiB
Go

package quic
import (
"bytes"
"fmt"
"math"
"time"
"golang.org/x/exp/rand"
"github.com/refraction-networking/uquic/internal/protocol"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)
var _ = Describe("frame sorter", func() {
var s *frameSorter
checkGaps := func(expectedGaps []byteInterval) {
if s.gaps.Len() != len(expectedGaps) {
fmt.Println("Gaps:")
for gap := s.gaps.Front(); gap != nil; gap = gap.Next() {
fmt.Printf("\t%d - %d\n", gap.Value.Start, gap.Value.End)
}
ExpectWithOffset(1, s.gaps.Len()).To(Equal(len(expectedGaps)))
}
var i int
for gap := s.gaps.Front(); gap != nil; gap = gap.Next() {
ExpectWithOffset(1, gap.Value).To(Equal(expectedGaps[i]))
i++
}
}
type callbackTracker struct {
called *bool
cb func()
}
getCallback := func() (func(), callbackTracker) {
var called bool
cb := func() {
if called {
panic("double free")
}
called = true
}
return cb, callbackTracker{
cb: cb,
called: &called,
}
}
checkCallbackCalled := func(t callbackTracker) {
ExpectWithOffset(1, *t.called).To(BeTrue())
}
checkCallbackNotCalled := func(t callbackTracker) {
ExpectWithOffset(1, *t.called).To(BeFalse())
t.cb()
ExpectWithOffset(1, *t.called).To(BeTrue())
}
BeforeEach(func() {
s = newFrameSorter()
})
It("returns nil when empty", func() {
_, data, doneCb := s.Pop()
Expect(data).To(BeNil())
Expect(doneCb).To(BeNil())
})
It("inserts and pops a single frame", func() {
cb, t := getCallback()
Expect(s.Push([]byte("foobar"), 0, cb)).To(Succeed())
offset, data, doneCb := s.Pop()
Expect(offset).To(BeZero())
Expect(data).To(Equal([]byte("foobar")))
Expect(doneCb).ToNot(BeNil())
checkCallbackNotCalled(t)
offset, data, doneCb = s.Pop()
Expect(offset).To(Equal(protocol.ByteCount(6)))
Expect(data).To(BeNil())
Expect(doneCb).To(BeNil())
})
It("inserts and pops two consecutive frame", func() {
cb1, t1 := getCallback()
cb2, t2 := getCallback()
Expect(s.Push([]byte("bar"), 3, cb2)).To(Succeed())
Expect(s.Push([]byte("foo"), 0, cb1)).To(Succeed())
offset, data, doneCb := s.Pop()
Expect(offset).To(BeZero())
Expect(data).To(Equal([]byte("foo")))
Expect(doneCb).ToNot(BeNil())
doneCb()
checkCallbackCalled(t1)
offset, data, doneCb = s.Pop()
Expect(offset).To(Equal(protocol.ByteCount(3)))
Expect(data).To(Equal([]byte("bar")))
Expect(doneCb).ToNot(BeNil())
doneCb()
checkCallbackCalled(t2)
offset, data, doneCb = s.Pop()
Expect(offset).To(Equal(protocol.ByteCount(6)))
Expect(data).To(BeNil())
Expect(doneCb).To(BeNil())
})
It("ignores empty frames", func() {
Expect(s.Push(nil, 0, nil)).To(Succeed())
_, data, doneCb := s.Pop()
Expect(data).To(BeNil())
Expect(doneCb).To(BeNil())
})
It("says if has more data", func() {
Expect(s.HasMoreData()).To(BeFalse())
Expect(s.Push([]byte("foo"), 0, nil)).To(Succeed())
Expect(s.HasMoreData()).To(BeTrue())
_, data, _ := s.Pop()
Expect(data).To(Equal([]byte("foo")))
Expect(s.HasMoreData()).To(BeFalse())
})
Context("Gap handling", func() {
var dataCounter uint8
BeforeEach(func() {
dataCounter = 0
})
checkQueue := func(m map[protocol.ByteCount][]byte) {
ExpectWithOffset(1, s.queue).To(HaveLen(len(m)))
for offset, data := range m {
ExpectWithOffset(1, s.queue).To(HaveKey(offset))
ExpectWithOffset(1, s.queue[offset].Data).To(Equal(data))
}
}
getData := func(l protocol.ByteCount) []byte {
dataCounter++
return bytes.Repeat([]byte{dataCounter}, int(l))
}
// ---xxx--------------
// ++++++
// =>
// ---xxx++++++--------
It("case 1", func() {
f1 := getData(3)
cb1, t1 := getCallback()
f2 := getData(5)
cb2, t2 := getCallback()
Expect(s.Push(f1, 3, cb1)).To(Succeed()) // 3 - 6
Expect(s.Push(f2, 6, cb2)).To(Succeed()) // 6 - 11
checkQueue(map[protocol.ByteCount][]byte{
3: f1,
6: f2,
})
checkGaps([]byteInterval{
{Start: 0, End: 3},
{Start: 11, End: protocol.MaxByteCount},
})
checkCallbackNotCalled(t1)
checkCallbackNotCalled(t2)
})
// ---xxx-----------------
// +++++++
// =>
// ---xxx---+++++++--------
It("case 2", func() {
f1 := getData(3)
cb1, t1 := getCallback()
f2 := getData(5)
cb2, t2 := getCallback()
Expect(s.Push(f1, 3, cb1)).To(Succeed()) // 3 - 6
Expect(s.Push(f2, 10, cb2)).To(Succeed()) // 10 -15
checkQueue(map[protocol.ByteCount][]byte{
3: f1,
10: f2,
})
checkGaps([]byteInterval{
{Start: 0, End: 3},
{Start: 6, End: 10},
{Start: 15, End: protocol.MaxByteCount},
})
checkCallbackNotCalled(t1)
checkCallbackNotCalled(t2)
})
// ---xxx----xxxxxx-------
// ++++
// =>
// ---xxx++++xxxxx--------
It("case 3", func() {
f1 := getData(3)
cb1, t1 := getCallback()
f2 := getData(4)
cb2, t2 := getCallback()
f3 := getData(5)
cb3, t3 := getCallback()
Expect(s.Push(f1, 3, cb1)).To(Succeed()) // 3 - 6
Expect(s.Push(f3, 10, cb2)).To(Succeed()) // 10 - 15
Expect(s.Push(f2, 6, cb3)).To(Succeed()) // 6 - 10
checkQueue(map[protocol.ByteCount][]byte{
3: f1,
6: f2,
10: f3,
})
checkGaps([]byteInterval{
{Start: 0, End: 3},
{Start: 15, End: protocol.MaxByteCount},
})
checkCallbackNotCalled(t1)
checkCallbackNotCalled(t2)
checkCallbackNotCalled(t3)
})
// ----xxxx-------
// ++++
// =>
// ----xxxx++-----
It("case 4", func() {
f1 := getData(4)
cb1, t1 := getCallback()
f2 := getData(4)
cb2, t2 := getCallback()
Expect(s.Push(f1, 3, cb1)).To(Succeed()) // 3 - 7
Expect(s.Push(f2, 5, cb2)).To(Succeed()) // 5 - 9
checkQueue(map[protocol.ByteCount][]byte{
3: f1,
7: f2[2:],
})
checkGaps([]byteInterval{
{Start: 0, End: 3},
{Start: 9, End: protocol.MaxByteCount},
})
checkCallbackNotCalled(t1)
checkCallbackCalled(t2)
})
It("case 4, for long frames", func() {
mult := protocol.ByteCount(math.Ceil(float64(protocol.MinStreamFrameSize) / 2))
f1 := getData(4 * mult)
cb1, t1 := getCallback()
f2 := getData(4 * mult)
cb2, t2 := getCallback()
Expect(s.Push(f1, 3*mult, cb1)).To(Succeed()) // 3 - 7
Expect(s.Push(f2, 5*mult, cb2)).To(Succeed()) // 5 - 9
checkQueue(map[protocol.ByteCount][]byte{
3 * mult: f1,
7 * mult: f2[2*mult:],
})
checkGaps([]byteInterval{
{Start: 0, End: 3 * mult},
{Start: 9 * mult, End: protocol.MaxByteCount},
})
checkCallbackNotCalled(t1)
checkCallbackNotCalled(t2)
})
// xxxx-------
// ++++
// =>
// xxxx+++-----
It("case 5", func() {
f1 := getData(4)
cb1, t1 := getCallback()
f2 := getData(4)
cb2, t2 := getCallback()
Expect(s.Push(f1, 0, cb1)).To(Succeed()) // 0 - 4
Expect(s.Push(f2, 3, cb2)).To(Succeed()) // 3 - 7
checkQueue(map[protocol.ByteCount][]byte{
0: f1,
4: f2[1:],
})
checkGaps([]byteInterval{
{Start: 7, End: protocol.MaxByteCount},
})
checkCallbackNotCalled(t1)
checkCallbackCalled(t2)
})
It("case 5, for long frames", func() {
mult := protocol.ByteCount(math.Ceil(float64(protocol.MinStreamFrameSize) / 2))
f1 := getData(4 * mult)
cb1, t1 := getCallback()
f2 := getData(4 * mult)
cb2, t2 := getCallback()
Expect(s.Push(f1, 0, cb1)).To(Succeed()) // 0 - 4
Expect(s.Push(f2, 3*mult, cb2)).To(Succeed()) // 3 - 7
checkQueue(map[protocol.ByteCount][]byte{
0: f1,
4 * mult: f2[mult:],
})
checkGaps([]byteInterval{
{Start: 7 * mult, End: protocol.MaxByteCount},
})
checkCallbackNotCalled(t1)
checkCallbackNotCalled(t2)
})
// ----xxxx-------
// ++++
// =>
// --++xxxx-------
It("case 6", func() {
f1 := getData(4)
cb1, t1 := getCallback()
f2 := getData(4)
cb2, t2 := getCallback()
Expect(s.Push(f1, 5, cb1)).To(Succeed()) // 5 - 9
Expect(s.Push(f2, 3, cb2)).To(Succeed()) // 3 - 7
checkQueue(map[protocol.ByteCount][]byte{
3: f2[:2],
5: f1,
})
checkGaps([]byteInterval{
{Start: 0, End: 3},
{Start: 9, End: protocol.MaxByteCount},
})
checkCallbackNotCalled(t1)
checkCallbackCalled(t2)
})
It("case 6, for long frames", func() {
mult := protocol.ByteCount(math.Ceil(float64(protocol.MinStreamFrameSize) / 2))
f1 := getData(4 * mult)
cb1, t1 := getCallback()
f2 := getData(4 * mult)
cb2, t2 := getCallback()
Expect(s.Push(f1, 5*mult, cb1)).To(Succeed()) // 5 - 9
Expect(s.Push(f2, 3*mult, cb2)).To(Succeed()) // 3 - 7
checkQueue(map[protocol.ByteCount][]byte{
3 * mult: f2[:2*mult],
5 * mult: f1,
})
checkGaps([]byteInterval{
{Start: 0, End: 3 * mult},
{Start: 9 * mult, End: protocol.MaxByteCount},
})
checkCallbackNotCalled(t1)
checkCallbackNotCalled(t2)
})
// ---xxx----xxxxxx-------
// ++
// =>
// ---xxx++--xxxxx--------
It("case 7", func() {
f1 := getData(3)
cb1, t1 := getCallback()
f2 := getData(2)
cb2, t2 := getCallback()
f3 := getData(5)
cb3, t3 := getCallback()
Expect(s.Push(f1, 3, cb1)).To(Succeed()) // 3 - 6
Expect(s.Push(f3, 10, cb2)).To(Succeed()) // 10 - 15
Expect(s.Push(f2, 6, cb3)).To(Succeed()) // 6 - 8
checkQueue(map[protocol.ByteCount][]byte{
3: f1,
6: f2,
10: f3,
})
checkGaps([]byteInterval{
{Start: 0, End: 3},
{Start: 8, End: 10},
{Start: 15, End: protocol.MaxByteCount},
})
checkCallbackNotCalled(t1)
checkCallbackNotCalled(t2)
checkCallbackNotCalled(t3)
})
// ---xxx---------xxxxxx--
// ++
// =>
// ---xxx---++----xxxxx--
It("case 8", func() {
f1 := getData(3)
cb1, t1 := getCallback()
f2 := getData(2)
cb2, t2 := getCallback()
f3 := getData(5)
cb3, t3 := getCallback()
Expect(s.Push(f1, 3, cb1)).To(Succeed()) // 3 - 6
Expect(s.Push(f3, 15, cb2)).To(Succeed()) // 15 - 20
Expect(s.Push(f2, 10, cb3)).To(Succeed()) // 10 - 12
checkQueue(map[protocol.ByteCount][]byte{
3: f1,
10: f2,
15: f3,
})
checkGaps([]byteInterval{
{Start: 0, End: 3},
{Start: 6, End: 10},
{Start: 12, End: 15},
{Start: 20, End: protocol.MaxByteCount},
})
checkCallbackNotCalled(t1)
checkCallbackNotCalled(t2)
checkCallbackNotCalled(t3)
})
// ---xxx----xxxxxx-------
// ++
// =>
// ---xxx--++xxxxx--------
It("case 9", func() {
f1 := getData(3)
cb1, t1 := getCallback()
f2 := getData(2)
cb2, t2 := getCallback()
cb3, t3 := getCallback()
f3 := getData(5)
Expect(s.Push(f1, 3, cb1)).To(Succeed()) // 3 - 6
Expect(s.Push(f3, 10, cb2)).To(Succeed()) // 10 - 15
Expect(s.Push(f2, 8, cb3)).To(Succeed()) // 8 - 10
checkQueue(map[protocol.ByteCount][]byte{
3: f1,
8: f2,
10: f3,
})
checkGaps([]byteInterval{
{Start: 0, End: 3},
{Start: 6, End: 8},
{Start: 15, End: protocol.MaxByteCount},
})
checkCallbackNotCalled(t1)
checkCallbackNotCalled(t2)
checkCallbackNotCalled(t3)
})
// ---xxx----=====-------
// +++++++
// =>
// ---xxx++++=====--------
It("case 10", func() {
f1 := getData(3)
cb1, t1 := getCallback()
f2 := getData(5)
cb2, t2 := getCallback()
f3 := getData(6)
cb3, t3 := getCallback()
Expect(s.Push(f1, 3, cb1)).To(Succeed()) // 3 - 6
Expect(s.Push(f2, 10, cb2)).To(Succeed()) // 10 - 15
Expect(s.Push(f3, 5, cb3)).To(Succeed()) // 5 - 11
checkQueue(map[protocol.ByteCount][]byte{
3: f1,
6: f3[1:5],
10: f2,
})
checkGaps([]byteInterval{
{Start: 0, End: 3},
{Start: 15, End: protocol.MaxByteCount},
})
checkCallbackNotCalled(t1)
checkCallbackNotCalled(t2)
checkCallbackCalled(t3)
})
It("case 10, for long frames", func() {
mult := protocol.ByteCount(math.Ceil(float64(protocol.MinStreamFrameSize) / 4))
f1 := getData(3 * mult)
cb1, t1 := getCallback()
f2 := getData(5 * mult)
cb2, t2 := getCallback()
f3 := getData(6 * mult)
cb3, t3 := getCallback()
Expect(s.Push(f1, 3*mult, cb1)).To(Succeed()) // 3 - 6
Expect(s.Push(f2, 10*mult, cb2)).To(Succeed()) // 10 - 15
Expect(s.Push(f3, 5*mult, cb3)).To(Succeed()) // 5 - 11
checkQueue(map[protocol.ByteCount][]byte{
3 * mult: f1,
6 * mult: f3[mult : 5*mult],
10 * mult: f2,
})
checkGaps([]byteInterval{
{Start: 0, End: 3 * mult},
{Start: 15 * mult, End: protocol.MaxByteCount},
})
checkCallbackNotCalled(t1)
checkCallbackNotCalled(t2)
checkCallbackNotCalled(t3)
})
// ---xxxx----=====-------
// ++++++
// =>
// ---xxx++++=====--------
It("case 11", func() {
f1 := getData(4)
cb1, t1 := getCallback()
f2 := getData(5)
cb2, t2 := getCallback()
f3 := getData(5)
cb3, t3 := getCallback()
Expect(s.Push(f1, 3, cb1)).To(Succeed()) // 3 - 7
Expect(s.Push(f2, 10, cb2)).To(Succeed()) // 10 - 15
Expect(s.Push(f3, 5, cb3)).To(Succeed()) // 5 - 10
checkQueue(map[protocol.ByteCount][]byte{
3: f1,
7: f3[2:],
10: f2,
})
checkGaps([]byteInterval{
{Start: 0, End: 3},
{Start: 15, End: protocol.MaxByteCount},
})
checkCallbackNotCalled(t1)
checkCallbackNotCalled(t2)
checkCallbackCalled(t3)
})
// ---xxxx----=====-------
// ++++++
// =>
// ---xxx++++=====--------
It("case 11, for long frames", func() {
mult := protocol.ByteCount(math.Ceil(float64(protocol.MinStreamFrameSize) / 3))
f1 := getData(4 * mult)
cb1, t1 := getCallback()
f2 := getData(5 * mult)
cb2, t2 := getCallback()
f3 := getData(5 * mult)
cb3, t3 := getCallback()
Expect(s.Push(f1, 3*mult, cb1)).To(Succeed()) // 3 - 7
Expect(s.Push(f2, 10*mult, cb2)).To(Succeed()) // 10 - 15
Expect(s.Push(f3, 5*mult, cb3)).To(Succeed()) // 5 - 10
checkQueue(map[protocol.ByteCount][]byte{
3 * mult: f1,
7 * mult: f3[2*mult:],
10 * mult: f2,
})
checkGaps([]byteInterval{
{Start: 0, End: 3 * mult},
{Start: 15 * mult, End: protocol.MaxByteCount},
})
checkCallbackNotCalled(t1)
checkCallbackNotCalled(t2)
checkCallbackNotCalled(t3)
})
// ----xxxx-------
// +++++++
// =>
// ----+++++++-----
It("case 12", func() {
f1 := getData(4)
cb1, t1 := getCallback()
f2 := getData(7)
cb2, t2 := getCallback()
Expect(s.Push(f1, 3, cb1)).To(Succeed()) // 3 - 7
Expect(s.Push(f2, 3, cb2)).To(Succeed()) // 3 - 10
checkQueue(map[protocol.ByteCount][]byte{
3: f2,
})
checkGaps([]byteInterval{
{Start: 0, End: 3},
{Start: 10, End: protocol.MaxByteCount},
})
checkCallbackCalled(t1)
checkCallbackNotCalled(t2)
})
// ----xxx===-------
// +++++++
// =>
// ----+++++++-----
It("case 13", func() {
f1 := getData(3)
cb1, t1 := getCallback()
f2 := getData(3)
cb2, t2 := getCallback()
f3 := getData(7)
cb3, t3 := getCallback()
Expect(s.Push(f1, 3, cb1)).To(Succeed()) // 3 - 6
Expect(s.Push(f2, 6, cb2)).To(Succeed()) // 6 - 9
Expect(s.Push(f3, 3, cb3)).To(Succeed()) // 3 - 10
checkQueue(map[protocol.ByteCount][]byte{
3: f3,
})
checkGaps([]byteInterval{
{Start: 0, End: 3},
{Start: 10, End: protocol.MaxByteCount},
})
checkCallbackCalled(t1)
checkCallbackCalled(t2)
checkCallbackNotCalled(t3)
})
// ----xxx====-------
// +++++
// =>
// ----+++====-----
It("case 14", func() {
f1 := getData(3)
cb1, t1 := getCallback()
f2 := getData(4)
cb2, t2 := getCallback()
f3 := getData(5)
cb3, t3 := getCallback()
Expect(s.Push(f1, 3, cb1)).To(Succeed()) // 3 - 6
Expect(s.Push(f2, 6, cb2)).To(Succeed()) // 6 - 10
Expect(s.Push(f3, 3, cb3)).To(Succeed()) // 3 - 8
checkQueue(map[protocol.ByteCount][]byte{
3: f3[:3],
6: f2,
})
checkGaps([]byteInterval{
{Start: 0, End: 3},
{Start: 10, End: protocol.MaxByteCount},
})
checkCallbackCalled(t1)
checkCallbackNotCalled(t2)
checkCallbackCalled(t3)
})
It("case 14, for long frames", func() {
mult := protocol.ByteCount(math.Ceil(float64(protocol.MinStreamFrameSize) / 3))
f1 := getData(3 * mult)
cb1, t1 := getCallback()
f2 := getData(4 * mult)
cb2, t2 := getCallback()
f3 := getData(5 * mult)
cb3, t3 := getCallback()
Expect(s.Push(f1, 3*mult, cb1)).To(Succeed()) // 3 - 6
Expect(s.Push(f2, 6*mult, cb2)).To(Succeed()) // 6 - 10
Expect(s.Push(f3, 3*mult, cb3)).To(Succeed()) // 3 - 8
checkQueue(map[protocol.ByteCount][]byte{
3 * mult: f3[:3*mult],
6 * mult: f2,
})
checkGaps([]byteInterval{
{Start: 0, End: 3 * mult},
{Start: 10 * mult, End: protocol.MaxByteCount},
})
checkCallbackCalled(t1)
checkCallbackNotCalled(t2)
checkCallbackNotCalled(t3)
})
// ----xxx===-------
// ++++++
// =>
// ----++++++-----
It("case 15", func() {
f1 := getData(3)
cb1, t1 := getCallback()
f2 := getData(3)
cb2, t2 := getCallback()
f3 := getData(6)
cb3, t3 := getCallback()
Expect(s.Push(f1, 3, cb1)).To(Succeed()) // 3 - 6
Expect(s.Push(f2, 6, cb2)).To(Succeed()) // 6 - 9
Expect(s.Push(f3, 3, cb3)).To(Succeed()) // 3 - 9
checkQueue(map[protocol.ByteCount][]byte{
3: f3,
})
checkGaps([]byteInterval{
{Start: 0, End: 3},
{Start: 9, End: protocol.MaxByteCount},
})
checkCallbackCalled(t1)
checkCallbackCalled(t2)
checkCallbackNotCalled(t3)
})
// ---xxxx-------
// ++++
// =>
// ---xxxx-----
It("case 16", func() {
f1 := getData(4)
cb1, t1 := getCallback()
f2 := getData(4)
cb2, t2 := getCallback()
Expect(s.Push(f1, 5, cb1)).To(Succeed()) // 5 - 9
Expect(s.Push(f2, 5, cb2)).To(Succeed()) // 5 - 9
checkQueue(map[protocol.ByteCount][]byte{
5: f1,
})
checkGaps([]byteInterval{
{Start: 0, End: 5},
{Start: 9, End: protocol.MaxByteCount},
})
checkCallbackNotCalled(t1)
checkCallbackCalled(t2)
})
// ----xxx===-------
// +++
// =>
// ----xxx===-----
It("case 17", func() {
f1 := getData(3)
cb1, t1 := getCallback()
f2 := getData(3)
cb2, t2 := getCallback()
f3 := getData(3)
cb3, t3 := getCallback()
Expect(s.Push(f1, 3, cb1)).To(Succeed()) // 3 - 6
Expect(s.Push(f2, 6, cb2)).To(Succeed()) // 6 - 9
Expect(s.Push(f3, 3, cb3)).To(Succeed()) // 3 - 6
checkQueue(map[protocol.ByteCount][]byte{
3: f1,
6: f2,
})
checkGaps([]byteInterval{
{Start: 0, End: 3},
{Start: 9, End: protocol.MaxByteCount},
})
checkCallbackNotCalled(t1)
checkCallbackNotCalled(t2)
checkCallbackCalled(t3)
})
// ---xxxx-------
// ++
// =>
// ---xxxx-----
It("case 18", func() {
f1 := getData(4)
cb1, t1 := getCallback()
f2 := getData(2)
cb2, t2 := getCallback()
Expect(s.Push(f1, 5, cb1)).To(Succeed()) // 5 - 9
Expect(s.Push(f2, 5, cb2)).To(Succeed()) // 5 - 7
checkQueue(map[protocol.ByteCount][]byte{
5: f1,
})
checkGaps([]byteInterval{
{Start: 0, End: 5},
{Start: 9, End: protocol.MaxByteCount},
})
checkCallbackNotCalled(t1)
checkCallbackCalled(t2)
})
// ---xxxxx------
// ++
// =>
// ---xxxxx----
It("case 19", func() {
f1 := getData(5)
cb1, t1 := getCallback()
f2 := getData(2)
cb2, t2 := getCallback()
Expect(s.Push(f1, 5, cb1)).To(Succeed()) // 5 - 10
checkQueue(map[protocol.ByteCount][]byte{
5: f1,
})
Expect(s.Push(f2, 6, cb2)).To(Succeed()) // 6 - 8
checkQueue(map[protocol.ByteCount][]byte{
5: f1,
})
checkGaps([]byteInterval{
{Start: 0, End: 5},
{Start: 10, End: protocol.MaxByteCount},
})
checkCallbackNotCalled(t1)
checkCallbackCalled(t2)
})
// xxxxx------
// ++
// =>
// xxxxx------
It("case 20", func() {
f1 := getData(10)
cb1, t1 := getCallback()
f2 := getData(4)
cb2, t2 := getCallback()
Expect(s.Push(f1, 0, cb1)).To(Succeed()) // 0 - 10
Expect(s.Push(f2, 5, cb2)).To(Succeed()) // 5 - 9
checkQueue(map[protocol.ByteCount][]byte{
0: f1,
})
checkGaps([]byteInterval{
{Start: 10, End: protocol.MaxByteCount},
})
checkCallbackNotCalled(t1)
checkCallbackCalled(t2)
})
// ---xxxxx---
// +++
// =>
// ---xxxxx---
It("case 21", func() {
f1 := getData(5)
cb1, t1 := getCallback()
f2 := getData(3)
cb2, t2 := getCallback()
Expect(s.Push(f1, 5, cb1)).To(Succeed()) // 5 - 10
Expect(s.Push(f2, 7, cb2)).To(Succeed()) // 7 - 10
checkGaps([]byteInterval{
{Start: 0, End: 5},
{Start: 10, End: protocol.MaxByteCount},
})
checkQueue(map[protocol.ByteCount][]byte{
5: f1,
})
checkCallbackNotCalled(t1)
checkCallbackCalled(t2)
})
// ----xxx------
// +++++
// =>
// --+++++----
It("case 22", func() {
f1 := getData(3)
cb1, t1 := getCallback()
f2 := getData(5)
cb2, t2 := getCallback()
Expect(s.Push(f1, 5, cb1)).To(Succeed()) // 5 - 8
Expect(s.Push(f2, 3, cb2)).To(Succeed()) // 3 - 8
checkQueue(map[protocol.ByteCount][]byte{
3: f2,
})
checkGaps([]byteInterval{
{Start: 0, End: 3},
{Start: 8, End: protocol.MaxByteCount},
})
checkCallbackCalled(t1)
checkCallbackNotCalled(t2)
})
// ----xxx===------
// ++++++++
// =>
// --++++++++----
It("case 23", func() {
f1 := getData(3)
cb1, t1 := getCallback()
f2 := getData(3)
cb2, t2 := getCallback()
f3 := getData(8)
cb3, t3 := getCallback()
Expect(s.Push(f1, 5, cb1)).To(Succeed()) // 5 - 8
Expect(s.Push(f2, 8, cb2)).To(Succeed()) // 8 - 11
Expect(s.Push(f3, 3, cb3)).To(Succeed()) // 3 - 11
checkQueue(map[protocol.ByteCount][]byte{
3: f3,
})
checkGaps([]byteInterval{
{Start: 0, End: 3},
{Start: 11, End: protocol.MaxByteCount},
})
checkCallbackCalled(t1)
checkCallbackCalled(t2)
checkCallbackNotCalled(t3)
})
// --xxx---===---
// ++++++
// =>
// --xxx++++++----
It("case 24", func() {
f1 := getData(3)
cb1, t1 := getCallback()
f2 := getData(3)
cb2, t2 := getCallback()
f3 := getData(6)
cb3, t3 := getCallback()
Expect(s.Push(f1, 3, cb1)).To(Succeed()) // 3 - 6
Expect(s.Push(f2, 9, cb2)).To(Succeed()) // 9 - 12
Expect(s.Push(f3, 6, cb3)).To(Succeed()) // 6 - 12
checkQueue(map[protocol.ByteCount][]byte{
3: f1,
6: f3,
})
checkGaps([]byteInterval{
{Start: 0, End: 3},
{Start: 12, End: protocol.MaxByteCount},
})
checkCallbackNotCalled(t1)
checkCallbackCalled(t2)
checkCallbackNotCalled(t3)
})
// --xxx---===---###
// +++++++++
// =>
// --xxx+++++++++###
It("case 25", func() {
f1 := getData(3)
cb1, t1 := getCallback()
f2 := getData(3)
cb2, t2 := getCallback()
f3 := getData(3)
cb3, t3 := getCallback()
f4 := getData(9)
cb4, t4 := getCallback()
Expect(s.Push(f1, 3, cb1)).To(Succeed()) // 3 - 6
Expect(s.Push(f2, 9, cb2)).To(Succeed()) // 9 - 12
Expect(s.Push(f3, 15, cb3)).To(Succeed()) // 15 - 18
Expect(s.Push(f4, 6, cb4)).To(Succeed()) // 6 - 15
checkQueue(map[protocol.ByteCount][]byte{
3: f1,
6: f4,
15: f3,
})
checkGaps([]byteInterval{
{Start: 0, End: 3},
{Start: 18, End: protocol.MaxByteCount},
})
checkCallbackNotCalled(t1)
checkCallbackCalled(t2)
checkCallbackNotCalled(t3)
checkCallbackNotCalled(t4)
})
// ----xxx------
// +++++++
// =>
// --+++++++---
It("case 26", func() {
f1 := getData(3)
cb1, t1 := getCallback()
f2 := getData(10)
cb2, t2 := getCallback()
Expect(s.Push(f1, 5, cb1)).To(Succeed()) // 5 - 8
Expect(s.Push(f2, 3, cb2)).To(Succeed()) // 3 - 13
checkQueue(map[protocol.ByteCount][]byte{
3: f2,
})
checkGaps([]byteInterval{
{Start: 0, End: 3},
{Start: 13, End: protocol.MaxByteCount},
})
checkCallbackCalled(t1)
checkCallbackNotCalled(t2)
})
// ---xxx====---
// ++++
// =>
// --+xxx====---
It("case 27", func() {
f1 := getData(3)
cb1, t1 := getCallback()
f2 := getData(4)
cb2, t2 := getCallback()
f3 := getData(4)
cb3, t3 := getCallback()
Expect(s.Push(f1, 3, cb1)).To(Succeed()) // 3 - 6
Expect(s.Push(f2, 6, cb2)).To(Succeed()) // 6 - 10
Expect(s.Push(f3, 2, cb3)).To(Succeed()) // 2 - 6
checkQueue(map[protocol.ByteCount][]byte{
2: f3[:1],
3: f1,
6: f2,
})
checkGaps([]byteInterval{
{Start: 0, End: 2},
{Start: 10, End: protocol.MaxByteCount},
})
checkCallbackNotCalled(t1)
checkCallbackNotCalled(t2)
checkCallbackCalled(t3)
})
It("case 27, for long frames", func() {
const mult = protocol.MinStreamFrameSize
f1 := getData(3 * mult)
cb1, t1 := getCallback()
f2 := getData(4 * mult)
cb2, t2 := getCallback()
f3 := getData(4 * mult)
cb3, t3 := getCallback()
Expect(s.Push(f1, 3*mult, cb1)).To(Succeed()) // 3 - 6
Expect(s.Push(f2, 6*mult, cb2)).To(Succeed()) // 6 - 10
Expect(s.Push(f3, 2*mult, cb3)).To(Succeed()) // 2 - 6
checkQueue(map[protocol.ByteCount][]byte{
2 * mult: f3[:mult],
3 * mult: f1,
6 * mult: f2,
})
checkGaps([]byteInterval{
{Start: 0, End: 2 * mult},
{Start: 10 * mult, End: protocol.MaxByteCount},
})
checkCallbackNotCalled(t1)
checkCallbackNotCalled(t2)
checkCallbackNotCalled(t3)
})
// ---xxx====---
// ++++++
// =>
// --+xxx====---
It("case 28", func() {
f1 := getData(3)
cb1, t1 := getCallback()
f2 := getData(4)
cb2, t2 := getCallback()
f3 := getData(6)
cb3, t3 := getCallback()
Expect(s.Push(f1, 3, cb1)).To(Succeed()) // 3 - 6
Expect(s.Push(f2, 6, cb2)).To(Succeed()) // 6 - 10
Expect(s.Push(f3, 2, cb3)).To(Succeed()) // 2 - 8
checkQueue(map[protocol.ByteCount][]byte{
2: f3[:1],
3: f1,
6: f2,
})
checkGaps([]byteInterval{
{Start: 0, End: 2},
{Start: 10, End: protocol.MaxByteCount},
})
checkCallbackNotCalled(t1)
checkCallbackNotCalled(t2)
checkCallbackCalled(t3)
})
It("case 28, for long frames", func() {
const mult = protocol.MinStreamFrameSize
f1 := getData(3 * mult)
cb1, t1 := getCallback()
f2 := getData(4 * mult)
cb2, t2 := getCallback()
f3 := getData(6 * mult)
cb3, t3 := getCallback()
Expect(s.Push(f1, 3*mult, cb1)).To(Succeed()) // 3 - 6
Expect(s.Push(f2, 6*mult, cb2)).To(Succeed()) // 6 - 10
Expect(s.Push(f3, 2*mult, cb3)).To(Succeed()) // 2 - 8
checkQueue(map[protocol.ByteCount][]byte{
2 * mult: f3[:mult],
3 * mult: f1,
6 * mult: f2,
})
checkGaps([]byteInterval{
{Start: 0, End: 2 * mult},
{Start: 10 * mult, End: protocol.MaxByteCount},
})
checkCallbackNotCalled(t1)
checkCallbackNotCalled(t2)
checkCallbackNotCalled(t3)
})
// ---xxx===-----
// +++++
// =>
// ---xxx+++++---
It("case 29", func() {
f1 := getData(3)
cb1, t1 := getCallback()
f2 := getData(3)
cb2, t2 := getCallback()
f3 := getData(5)
cb3, t3 := getCallback()
Expect(s.Push(f1, 3, cb1)).To(Succeed()) // 3 - 6
Expect(s.Push(f2, 6, cb2)).To(Succeed()) // 6 - 9
Expect(s.Push(f3, 6, cb3)).To(Succeed()) // 6 - 11
checkQueue(map[protocol.ByteCount][]byte{
3: f1,
6: f3,
})
checkGaps([]byteInterval{
{Start: 0, End: 3},
{Start: 11, End: protocol.MaxByteCount},
})
checkCallbackNotCalled(t1)
checkCallbackCalled(t2)
checkCallbackNotCalled(t3)
})
// ---xxx===----
// ++++++
// =>
// ---xxx===++--
It("case 30", func() {
f1 := getData(3)
cb1, t1 := getCallback()
f2 := getData(3)
cb2, t2 := getCallback()
f3 := getData(6)
cb3, t3 := getCallback()
Expect(s.Push(f1, 3, cb1)).To(Succeed()) // 3 - 6
Expect(s.Push(f2, 6, cb2)).To(Succeed()) // 6 - 9
Expect(s.Push(f3, 5, cb3)).To(Succeed()) // 5 - 11
checkQueue(map[protocol.ByteCount][]byte{
3: f1,
6: f2,
9: f3[4:],
})
checkGaps([]byteInterval{
{Start: 0, End: 3},
{Start: 11, End: protocol.MaxByteCount},
})
checkCallbackNotCalled(t1)
checkCallbackNotCalled(t2)
checkCallbackCalled(t3)
})
It("case 30, for long frames", func() {
mult := protocol.ByteCount(math.Ceil(float64(protocol.MinStreamFrameSize) / 2))
f1 := getData(3 * mult)
cb1, t1 := getCallback()
f2 := getData(3 * mult)
cb2, t2 := getCallback()
f3 := getData(6 * mult)
cb3, t3 := getCallback()
Expect(s.Push(f1, 3*mult, cb1)).To(Succeed()) // 3 - 6
Expect(s.Push(f2, 6*mult, cb2)).To(Succeed()) // 6 - 9
Expect(s.Push(f3, 5*mult, cb3)).To(Succeed()) // 5 - 11
checkQueue(map[protocol.ByteCount][]byte{
3 * mult: f1,
6 * mult: f2,
9 * mult: f3[4*mult:],
})
checkGaps([]byteInterval{
{Start: 0, End: 3 * mult},
{Start: 11 * mult, End: protocol.MaxByteCount},
})
checkCallbackNotCalled(t1)
checkCallbackNotCalled(t2)
checkCallbackNotCalled(t3)
})
// ---xxx---===-----
// ++++++++++
// =>
// ---xxx++++++++---
It("case 31", func() {
f1 := getData(3)
cb1, t1 := getCallback()
f2 := getData(3)
cb2, t2 := getCallback()
f3 := getData(10)
cb3, t3 := getCallback()
Expect(s.Push(f1, 3, cb1)).To(Succeed()) // 3 - 6
Expect(s.Push(f2, 9, cb2)).To(Succeed()) // 9 - 12
Expect(s.Push(f3, 5, cb3)).To(Succeed()) // 5 - 15
checkQueue(map[protocol.ByteCount][]byte{
3: f1,
6: f3[1:],
})
checkGaps([]byteInterval{
{Start: 0, End: 3},
{Start: 15, End: protocol.MaxByteCount},
})
checkCallbackNotCalled(t1)
checkCallbackCalled(t2)
checkCallbackCalled(t3)
})
It("case 31, for long frames", func() {
mult := protocol.ByteCount(math.Ceil(float64(protocol.MinStreamFrameSize) / 9))
f1 := getData(3 * mult)
cb1, t1 := getCallback()
f2 := getData(3 * mult)
cb2, t2 := getCallback()
f3 := getData(10 * mult)
cb3, t3 := getCallback()
Expect(s.Push(f1, 3*mult, cb1)).To(Succeed()) // 3 - 6
Expect(s.Push(f2, 9*mult, cb2)).To(Succeed()) // 9 - 12
Expect(s.Push(f3, 5*mult, cb3)).To(Succeed()) // 5 - 15
checkQueue(map[protocol.ByteCount][]byte{
3 * mult: f1,
6 * mult: f3[mult:],
})
checkGaps([]byteInterval{
{Start: 0, End: 3 * mult},
{Start: 15 * mult, End: protocol.MaxByteCount},
})
checkCallbackNotCalled(t1)
checkCallbackCalled(t2)
checkCallbackNotCalled(t3)
})
// ---xxx---===-----
// +++++++++
// =>
// ---+++++++++---
It("case 32", func() {
f1 := getData(3)
cb1, t1 := getCallback()
f2 := getData(3)
cb2, t2 := getCallback()
f3 := getData(9)
cb3, t3 := getCallback()
Expect(s.Push(f1, 3, cb1)).To(Succeed()) // 3 - 6
Expect(s.Push(f2, 9, cb2)).To(Succeed()) // 9 - 12
Expect(s.Push(f3, 3, cb3)).To(Succeed()) // 3 - 12
checkQueue(map[protocol.ByteCount][]byte{
3: f3,
})
checkGaps([]byteInterval{
{Start: 0, End: 3},
{Start: 12, End: protocol.MaxByteCount},
})
checkCallbackCalled(t1)
checkCallbackCalled(t2)
checkCallbackNotCalled(t3)
})
// ---xxx---===###-----
// ++++++++++++
// =>
// ---xxx++++++++++---
It("case 33", func() {
f1 := getData(3)
cb1, t1 := getCallback()
f2 := getData(3)
cb2, t2 := getCallback()
f3 := getData(3)
cb3, t3 := getCallback()
f4 := getData(12)
cb4, t4 := getCallback()
Expect(s.Push(f1, 3, cb1)).To(Succeed()) // 3 - 6
Expect(s.Push(f2, 9, cb2)).To(Succeed()) // 9 - 12
Expect(s.Push(f3, 9, cb3)).To(Succeed()) // 12 - 15
Expect(s.Push(f4, 5, cb4)).To(Succeed()) // 5 - 17
checkQueue(map[protocol.ByteCount][]byte{
3: f1,
6: f4[1:],
})
checkGaps([]byteInterval{
{Start: 0, End: 3},
{Start: 17, End: protocol.MaxByteCount},
})
checkCallbackNotCalled(t1)
checkCallbackCalled(t2)
checkCallbackCalled(t3)
checkCallbackCalled(t4)
})
It("case 33, for long frames", func() {
mult := protocol.ByteCount(math.Ceil(float64(protocol.MinStreamFrameSize) / 11))
f1 := getData(3 * mult)
cb1, t1 := getCallback()
f2 := getData(3 * mult)
cb2, t2 := getCallback()
f3 := getData(3 * mult)
cb3, t3 := getCallback()
f4 := getData(12 * mult)
cb4, t4 := getCallback()
Expect(s.Push(f1, 3*mult, cb1)).To(Succeed()) // 3 - 6
Expect(s.Push(f2, 9*mult, cb2)).To(Succeed()) // 9 - 12
Expect(s.Push(f3, 9*mult, cb3)).To(Succeed()) // 12 - 15
Expect(s.Push(f4, 5*mult, cb4)).To(Succeed()) // 5 - 17
checkQueue(map[protocol.ByteCount][]byte{
3 * mult: f1,
6 * mult: f4[mult:],
})
checkGaps([]byteInterval{
{Start: 0, End: 3 * mult},
{Start: 17 * mult, End: protocol.MaxByteCount},
})
checkCallbackNotCalled(t1)
checkCallbackCalled(t2)
checkCallbackCalled(t3)
checkCallbackNotCalled(t4)
})
// ---xxx===---###
// ++++++
// =>
// ---xxx++++++###
It("case 34", func() {
f1 := getData(5)
cb1, t1 := getCallback()
f2 := getData(5)
cb2, t2 := getCallback()
f3 := getData(10)
cb3, t3 := getCallback()
f4 := getData(5)
cb4, t4 := getCallback()
Expect(s.Push(f1, 5, cb1)).To(Succeed()) // 5 - 10
Expect(s.Push(f2, 10, cb2)).To(Succeed()) // 10 - 15
Expect(s.Push(f4, 20, cb3)).To(Succeed()) // 20 - 25
Expect(s.Push(f3, 10, cb4)).To(Succeed()) // 10 - 20
checkQueue(map[protocol.ByteCount][]byte{
5: f1,
10: f3,
20: f4,
})
checkGaps([]byteInterval{
{Start: 0, End: 5},
{Start: 25, End: protocol.MaxByteCount},
})
checkCallbackNotCalled(t1)
checkCallbackCalled(t2)
checkCallbackNotCalled(t3)
checkCallbackNotCalled(t4)
})
// ---xxx---####---
// ++++++++
// =>
// ---++++++####---
It("case 35", func() {
f1 := getData(3)
cb1, t1 := getCallback()
f2 := getData(4)
cb2, t2 := getCallback()
f3 := getData(8)
cb3, t3 := getCallback()
Expect(s.Push(f1, 3, cb1)).To(Succeed()) // 3 - 6
Expect(s.Push(f2, 9, cb2)).To(Succeed()) // 9 - 13
Expect(s.Push(f3, 3, cb3)).To(Succeed()) // 3 - 11
checkGaps([]byteInterval{
{Start: 0, End: 3},
{Start: 13, End: protocol.MaxByteCount},
})
checkQueue(map[protocol.ByteCount][]byte{
3: f3[:6],
9: f2,
})
checkCallbackCalled(t1)
checkCallbackNotCalled(t2)
checkCallbackCalled(t3)
})
It("case 35, for long frames", func() {
mult := protocol.ByteCount(math.Ceil(float64(protocol.MinStreamFrameSize) / 6))
f1 := getData(3 * mult)
cb1, t1 := getCallback()
f2 := getData(4 * mult)
cb2, t2 := getCallback()
f3 := getData(8 * mult)
cb3, t3 := getCallback()
Expect(s.Push(f1, 3*mult, cb1)).To(Succeed()) // 3 - 6
Expect(s.Push(f2, 9*mult, cb2)).To(Succeed()) // 9 - 13
Expect(s.Push(f3, 3*mult, cb3)).To(Succeed()) // 3 - 11
checkGaps([]byteInterval{
{Start: 0, End: 3 * mult},
{Start: 13 * mult, End: protocol.MaxByteCount},
})
checkQueue(map[protocol.ByteCount][]byte{
3 * mult: f3[:6*mult],
9 * mult: f2,
})
checkCallbackCalled(t1)
checkCallbackNotCalled(t2)
checkCallbackNotCalled(t3)
})
Context("receiving data after reads", func() {
It("ignores duplicate frames", func() {
Expect(s.Push([]byte("foobar"), 0, nil)).To(Succeed())
offset, data, _ := s.Pop()
Expect(offset).To(BeZero())
Expect(data).To(Equal([]byte("foobar")))
// now receive the duplicate
Expect(s.Push([]byte("foobar"), 0, nil)).To(Succeed())
Expect(s.queue).To(BeEmpty())
checkGaps([]byteInterval{
{Start: 6, End: protocol.MaxByteCount},
})
})
It("ignores parts of frames that have already been read", func() {
Expect(s.Push([]byte("foo"), 0, nil)).To(Succeed())
offset, data, _ := s.Pop()
Expect(offset).To(BeZero())
Expect(data).To(Equal([]byte("foo")))
// now receive the duplicate
Expect(s.Push([]byte("foobar"), 0, nil)).To(Succeed())
offset, data, _ = s.Pop()
Expect(offset).To(Equal(protocol.ByteCount(3)))
Expect(data).To(Equal([]byte("bar")))
Expect(s.queue).To(BeEmpty())
checkGaps([]byteInterval{
{Start: 6, End: protocol.MaxByteCount},
})
})
})
Context("DoS protection", func() {
It("errors when too many gaps are created", func() {
for i := 0; i < protocol.MaxStreamFrameSorterGaps; i++ {
Expect(s.Push([]byte("foobar"), protocol.ByteCount(i*7), nil)).To(Succeed())
}
Expect(s.gaps.Len()).To(Equal(protocol.MaxStreamFrameSorterGaps))
err := s.Push([]byte("foobar"), protocol.ByteCount(protocol.MaxStreamFrameSorterGaps*7)+100, nil)
Expect(err).To(MatchError("too many gaps in received data"))
})
})
})
Context("stress testing", func() {
type frame struct {
offset protocol.ByteCount
data []byte
}
for _, lf := range []bool{true, false} {
longFrames := lf
const num = 1000
name := "short"
if longFrames {
name = "long"
}
Context(fmt.Sprintf("using %s frames", name), func() {
var data []byte
var dataLen protocol.ByteCount
var callbacks []callbackTracker
BeforeEach(func() {
seed := time.Now().UnixNano()
fmt.Fprintf(GinkgoWriter, "Seed: %d\n", seed)
rand.Seed(uint64(seed))
callbacks = nil
dataLen = 25
if longFrames {
dataLen = 2 * protocol.MinStreamFrameSize
}
data = make([]byte, num*dataLen)
for i := 0; i < num; i++ {
for j := protocol.ByteCount(0); j < dataLen; j++ {
data[protocol.ByteCount(i)*dataLen+j] = uint8(i)
}
}
})
getRandomFrames := func() []frame {
frames := make([]frame, num)
for i := protocol.ByteCount(0); i < num; i++ {
b := make([]byte, dataLen)
Expect(copy(b, data[i*dataLen:])).To(BeEquivalentTo(dataLen))
frames[i] = frame{
offset: i * dataLen,
data: b,
}
}
rand.Shuffle(len(frames), func(i, j int) { frames[i], frames[j] = frames[j], frames[i] })
return frames
}
getData := func() []byte {
var data []byte
for {
offset, b, cb := s.Pop()
if b == nil {
break
}
Expect(offset).To(BeEquivalentTo(len(data)))
data = append(data, b...)
if cb != nil {
cb()
}
}
return data
}
// push pushes data to the frame sorter
// It creates a new callback and adds the
push := func(data []byte, offset protocol.ByteCount) {
cb, t := getCallback()
ExpectWithOffset(1, s.Push(data, offset, cb)).To(Succeed())
callbacks = append(callbacks, t)
}
checkCallbacks := func() {
ExpectWithOffset(1, callbacks).ToNot(BeEmpty())
for _, t := range callbacks {
checkCallbackCalled(t)
}
}
It("inserting frames in a random order", func() {
frames := getRandomFrames()
for _, f := range frames {
push(f.data, f.offset)
}
checkGaps([]byteInterval{{Start: num * dataLen, End: protocol.MaxByteCount}})
Expect(getData()).To(Equal(data))
Expect(s.queue).To(BeEmpty())
checkCallbacks()
})
It("inserting frames in a random order, with some duplicates", func() {
frames := getRandomFrames()
for _, f := range frames {
push(f.data, f.offset)
if rand.Intn(10) < 5 {
df := frames[rand.Intn(len(frames))]
push(df.data, df.offset)
}
}
checkGaps([]byteInterval{{Start: num * dataLen, End: protocol.MaxByteCount}})
Expect(getData()).To(Equal(data))
Expect(s.queue).To(BeEmpty())
checkCallbacks()
})
It("inserting frames in a random order, with randomly cut retransmissions", func() {
frames := getRandomFrames()
for _, f := range frames {
push(f.data, f.offset)
if rand.Intn(10) < 5 {
length := protocol.ByteCount(1 + rand.Intn(int(4*dataLen)))
if length >= num*dataLen {
length = num*dataLen - 1
}
b := make([]byte, length)
offset := protocol.ByteCount(rand.Intn(int(num*dataLen - length)))
Expect(copy(b, data[offset:offset+length])).To(BeEquivalentTo(length))
push(b, offset)
}
}
checkGaps([]byteInterval{{Start: num * dataLen, End: protocol.MaxByteCount}})
Expect(getData()).To(Equal(data))
Expect(s.queue).To(BeEmpty())
checkCallbacks()
})
})
}
})
})