use separate streamsMaps for gQUIC and IETF QUIC

This is a lot of duplicate code for now, but it will make moving towards
the new stream ID mapping in IETF QUIC (and unidirectional streams) much
easier.
This commit is contained in:
Marten Seemann 2018-01-04 10:26:02 +07:00
parent 69437a0e78
commit a20e94ee16
5 changed files with 873 additions and 89 deletions

View file

@ -3,6 +3,7 @@ package quic
import (
"errors"
"github.com/golang/mock/gomock"
"github.com/lucas-clemente/quic-go/internal/handshake"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/wire"
@ -12,7 +13,7 @@ import (
. "github.com/onsi/gomega"
)
var _ = Describe("Streams Map", func() {
var _ = Describe("Streams Map (for IETF QUIC)", func() {
var m *streamsMap
newStream := func(id protocol.StreamID) streamI {
@ -21,8 +22,8 @@ var _ = Describe("Streams Map", func() {
return str
}
setNewStreamsMap := func(p protocol.Perspective, v protocol.VersionNumber) {
m = newStreamsMap(newStream, p, v)
setNewStreamsMap := func(p protocol.Perspective) {
m = newStreamsMap(newStream, p).(*streamsMap)
}
deleteStream := func(id protocol.StreamID) {
@ -32,15 +33,15 @@ var _ = Describe("Streams Map", func() {
Context("getting and creating streams", func() {
Context("as a server", func() {
BeforeEach(func() {
setNewStreamsMap(protocol.PerspectiveServer, versionGQUICFrames)
setNewStreamsMap(protocol.PerspectiveServer)
})
Context("client-side streams", func() {
It("gets new streams", func() {
s, err := m.GetOrOpenStream(3)
s, err := m.GetOrOpenStream(1)
Expect(err).NotTo(HaveOccurred())
Expect(s).ToNot(BeNil())
Expect(s.StreamID()).To(Equal(protocol.StreamID(3)))
Expect(s.StreamID()).To(Equal(protocol.StreamID(1)))
Expect(m.streams).To(HaveLen(1))
Expect(m.numIncomingStreams).To(BeEquivalentTo(1))
Expect(m.numOutgoingStreams).To(BeZero())
@ -264,8 +265,7 @@ var _ = Describe("Streams Map", func() {
Consistently(func() bool { return accepted }).Should(BeFalse())
})
It("starts with stream 1, if the crypto stream is stream 0", func() {
setNewStreamsMap(protocol.PerspectiveServer, versionIETFFrames)
It("starts with stream 1", func() {
var str Stream
done := make(chan struct{})
go func() {
@ -281,7 +281,7 @@ var _ = Describe("Streams Map", func() {
Expect(str.StreamID()).To(Equal(protocol.StreamID(1)))
})
It("starts with stream 3, if the crypto stream is stream 1", func() {
It("returns an implicitly opened stream, if a stream number is skipped", func() {
var str Stream
done := make(chan struct{})
go func() {
@ -294,23 +294,7 @@ var _ = Describe("Streams Map", func() {
_, err := m.GetOrOpenStream(3)
Expect(err).ToNot(HaveOccurred())
Eventually(done).Should(BeClosed())
Expect(str.StreamID()).To(Equal(protocol.StreamID(3)))
})
It("returns an implicitly opened stream, if a stream number is skipped", func() {
var str Stream
done := make(chan struct{})
go func() {
defer GinkgoRecover()
var err error
str, err = m.AcceptStream()
Expect(err).ToNot(HaveOccurred())
close(done)
}()
_, err := m.GetOrOpenStream(5)
Expect(err).ToNot(HaveOccurred())
Eventually(done).Should(BeClosed())
Expect(str.StreamID()).To(Equal(protocol.StreamID(3)))
Expect(str.StreamID()).To(Equal(protocol.StreamID(1)))
})
It("returns to multiple accepts", func() {
@ -331,12 +315,12 @@ var _ = Describe("Streams Map", func() {
Expect(err).ToNot(HaveOccurred())
close(done2)
}()
_, err := m.GetOrOpenStream(5) // opens stream 3 and 5
_, err := m.GetOrOpenStream(3) // opens stream 1 and 3
Expect(err).ToNot(HaveOccurred())
Eventually(done1).Should(BeClosed())
Eventually(done2).Should(BeClosed())
Expect(str1.StreamID()).ToNot(Equal(str2.StreamID()))
Expect(str1.StreamID() + str2.StreamID()).To(BeEquivalentTo(3 + 5))
Expect(str1.StreamID() + str2.StreamID()).To(BeEquivalentTo(1 + 3))
})
It("waits until a new stream is available", func() {
@ -350,10 +334,10 @@ var _ = Describe("Streams Map", func() {
close(done)
}()
Consistently(done).ShouldNot(BeClosed())
_, err := m.GetOrOpenStream(3)
_, err := m.GetOrOpenStream(1)
Expect(err).ToNot(HaveOccurred())
Eventually(done).Should(BeClosed())
Expect(str.StreamID()).To(Equal(protocol.StreamID(3)))
Expect(str.StreamID()).To(Equal(protocol.StreamID(1)))
})
It("returns multiple streams on subsequent Accept calls, if available", func() {
@ -366,39 +350,46 @@ var _ = Describe("Streams Map", func() {
Expect(err).ToNot(HaveOccurred())
close(done)
}()
_, err := m.GetOrOpenStream(5)
_, err := m.GetOrOpenStream(3)
Expect(err).ToNot(HaveOccurred())
Eventually(done).Should(BeClosed())
Expect(str.StreamID()).To(Equal(protocol.StreamID(3)))
Expect(str.StreamID()).To(Equal(protocol.StreamID(1)))
str, err = m.AcceptStream()
Expect(err).ToNot(HaveOccurred())
Expect(str.StreamID()).To(Equal(protocol.StreamID(5)))
Expect(str.StreamID()).To(Equal(protocol.StreamID(3)))
})
It("blocks after accepting a stream", func() {
var accepted bool
_, err := m.GetOrOpenStream(3)
_, err := m.GetOrOpenStream(1)
Expect(err).ToNot(HaveOccurred())
str, err := m.AcceptStream()
Expect(err).ToNot(HaveOccurred())
Expect(str.StreamID()).To(Equal(protocol.StreamID(3)))
Expect(str.StreamID()).To(Equal(protocol.StreamID(1)))
done := make(chan struct{})
go func() {
defer GinkgoRecover()
_, _ = m.AcceptStream()
accepted = true
close(done)
}()
Consistently(func() bool { return accepted }).Should(BeFalse())
Consistently(done).ShouldNot(BeClosed())
// make the go routine return
str.(*MockStreamI).EXPECT().closeForShutdown(gomock.Any())
m.CloseWithError(errors.New("shut down"))
Eventually(done).Should(BeClosed())
})
It("stops waiting when an error is registered", func() {
testErr := errors.New("testErr")
var acceptErr error
done := make(chan struct{})
go func() {
_, acceptErr = m.AcceptStream()
defer GinkgoRecover()
_, err := m.AcceptStream()
Expect(err).To(MatchError(testErr))
close(done)
}()
Consistently(func() error { return acceptErr }).ShouldNot(HaveOccurred())
Consistently(done).ShouldNot(BeClosed())
m.CloseWithError(testErr)
Eventually(func() error { return acceptErr }).Should(MatchError(testErr))
Eventually(done).Should(BeClosed())
})
It("immediately returns when Accept is called after an error was registered", func() {
@ -412,7 +403,7 @@ var _ = Describe("Streams Map", func() {
Context("as a client", func() {
BeforeEach(func() {
setNewStreamsMap(protocol.PerspectiveClient, versionGQUICFrames)
setNewStreamsMap(protocol.PerspectiveClient)
m.UpdateLimits(&handshake.TransportParameters{MaxStreams: 10000})
})
@ -451,18 +442,18 @@ var _ = Describe("Streams Map", func() {
It("doesn't reopen an already closed stream", func() {
str, err := m.OpenStream()
Expect(err).ToNot(HaveOccurred())
Expect(str.StreamID()).To(Equal(protocol.StreamID(3)))
deleteStream(3)
Expect(str.StreamID()).To(Equal(protocol.StreamID(1)))
deleteStream(1)
Expect(err).ToNot(HaveOccurred())
str, err = m.GetOrOpenStream(3)
str, err = m.GetOrOpenStream(1)
Expect(err).ToNot(HaveOccurred())
Expect(str).To(BeNil())
})
})
Context("client-side streams", func() {
It("starts with stream 1, if the crypto stream is stream 0", func() {
setNewStreamsMap(protocol.PerspectiveClient, versionIETFFrames)
It("starts with stream 1", func() {
setNewStreamsMap(protocol.PerspectiveClient)
m.UpdateLimits(&handshake.TransportParameters{MaxStreams: 10000})
s, err := m.OpenStream()
Expect(err).ToNot(HaveOccurred())
@ -472,15 +463,6 @@ var _ = Describe("Streams Map", func() {
Expect(m.numIncomingStreams).To(BeZero())
})
It("starts with stream 3, if the crypto stream is stream 1", func() {
s, err := m.OpenStream()
Expect(err).ToNot(HaveOccurred())
Expect(s).ToNot(BeNil())
Expect(s.StreamID()).To(BeEquivalentTo(3))
Expect(m.numOutgoingStreams).To(BeEquivalentTo(1))
Expect(m.numIncomingStreams).To(BeZero())
})
It("opens multiple streams", func() {
s1, err := m.OpenStream()
Expect(err).ToNot(HaveOccurred())
@ -522,17 +504,17 @@ var _ = Describe("Streams Map", func() {
Context("deleting streams", func() {
BeforeEach(func() {
setNewStreamsMap(protocol.PerspectiveServer, versionGQUICFrames)
setNewStreamsMap(protocol.PerspectiveServer)
})
It("deletes an incoming stream", func() {
_, err := m.GetOrOpenStream(5) // open stream 3 and 5
_, err := m.GetOrOpenStream(3) // open stream 1 and 3
Expect(err).ToNot(HaveOccurred())
Expect(m.numIncomingStreams).To(BeEquivalentTo(2))
err = m.DeleteStream(3)
err = m.DeleteStream(1)
Expect(err).ToNot(HaveOccurred())
Expect(m.streams).To(HaveLen(1))
Expect(m.streams).To(HaveKey(protocol.StreamID(5)))
Expect(m.streams).To(HaveKey(protocol.StreamID(3)))
Expect(m.numIncomingStreams).To(BeEquivalentTo(1))
})
@ -555,15 +537,15 @@ var _ = Describe("Streams Map", func() {
})
It("sets the flow control limit", func() {
setNewStreamsMap(protocol.PerspectiveServer, versionGQUICFrames)
_, err := m.GetOrOpenStream(5)
setNewStreamsMap(protocol.PerspectiveServer)
_, err := m.GetOrOpenStream(3)
Expect(err).ToNot(HaveOccurred())
m.streams[3].(*MockStreamI).EXPECT().handleMaxStreamDataFrame(&wire.MaxStreamDataFrame{
StreamID: 3,
m.streams[1].(*MockStreamI).EXPECT().handleMaxStreamDataFrame(&wire.MaxStreamDataFrame{
StreamID: 1,
ByteOffset: 321,
})
m.streams[5].(*MockStreamI).EXPECT().handleMaxStreamDataFrame(&wire.MaxStreamDataFrame{
StreamID: 5,
m.streams[3].(*MockStreamI).EXPECT().handleMaxStreamDataFrame(&wire.MaxStreamDataFrame{
StreamID: 3,
ByteOffset: 321,
})
m.UpdateLimits(&handshake.TransportParameters{StreamFlowControlWindow: 321})