github.com/TugasAkhir-QUIC/quic-go@v0.0.2-0.20240215011318-d20e25a9054c/framer_test.go (about)

     1  package quic
     2  
     3  import (
     4  	"bytes"
     5  
     6  	"golang.org/x/exp/rand"
     7  
     8  	"github.com/TugasAkhir-QUIC/quic-go/internal/ackhandler"
     9  	"github.com/TugasAkhir-QUIC/quic-go/internal/protocol"
    10  	"github.com/TugasAkhir-QUIC/quic-go/internal/wire"
    11  
    12  	. "github.com/onsi/ginkgo/v2"
    13  	. "github.com/onsi/gomega"
    14  	"go.uber.org/mock/gomock"
    15  )
    16  
    17  var _ = Describe("Framer", func() {
    18  	const (
    19  		id1 = protocol.StreamID(10)
    20  		id2 = protocol.StreamID(11)
    21  		id3 = protocol.StreamID(12)
    22  	)
    23  
    24  	var (
    25  		framer                    framer
    26  		stream1, stream2, stream3 *MockSendStreamI
    27  		streamGetter              *MockStreamGetter
    28  		version                   protocol.Version
    29  	)
    30  
    31  	BeforeEach(func() {
    32  		streamGetter = NewMockStreamGetter(mockCtrl)
    33  		stream1 = NewMockSendStreamI(mockCtrl)
    34  		stream1.EXPECT().StreamID().Return(id1).AnyTimes()
    35  		stream2 = NewMockSendStreamI(mockCtrl)
    36  		stream2.EXPECT().StreamID().Return(id2).AnyTimes()
    37  		stream3 = NewMockSendStreamI(mockCtrl)
    38  		stream3.EXPECT().StreamID().Return(id3).AnyTimes()
    39  		framer = newFramer(streamGetter)
    40  	})
    41  
    42  	Context("handling control frames", func() {
    43  		It("adds control frames", func() {
    44  			mdf := &wire.MaxDataFrame{MaximumData: 0x42}
    45  			msf := &wire.MaxStreamsFrame{MaxStreamNum: 0x1337}
    46  			framer.QueueControlFrame(mdf)
    47  			framer.QueueControlFrame(msf)
    48  			frames, length := framer.AppendControlFrames(nil, 1000, protocol.Version1)
    49  			Expect(frames).To(HaveLen(2))
    50  			fs := []wire.Frame{frames[0].Frame, frames[1].Frame}
    51  			Expect(fs).To(ContainElement(mdf))
    52  			Expect(fs).To(ContainElement(msf))
    53  			Expect(length).To(Equal(mdf.Length(version) + msf.Length(version)))
    54  		})
    55  
    56  		It("says if it has data", func() {
    57  			Expect(framer.HasData()).To(BeFalse())
    58  			f := &wire.MaxDataFrame{MaximumData: 0x42}
    59  			framer.QueueControlFrame(f)
    60  			Expect(framer.HasData()).To(BeTrue())
    61  			frames, _ := framer.AppendControlFrames(nil, 1000, protocol.Version1)
    62  			Expect(frames).To(HaveLen(1))
    63  			Expect(framer.HasData()).To(BeFalse())
    64  		})
    65  
    66  		It("appends to the slice given", func() {
    67  			ping := &wire.PingFrame{}
    68  			mdf := &wire.MaxDataFrame{MaximumData: 0x42}
    69  			framer.QueueControlFrame(mdf)
    70  			frames, length := framer.AppendControlFrames([]ackhandler.Frame{{Frame: ping}}, 1000, protocol.Version1)
    71  			Expect(frames).To(HaveLen(2))
    72  			Expect(frames[0].Frame).To(Equal(ping))
    73  			Expect(frames[1].Frame).To(Equal(mdf))
    74  			Expect(length).To(Equal(mdf.Length(version)))
    75  		})
    76  
    77  		It("adds the right number of frames", func() {
    78  			maxSize := protocol.ByteCount(1000)
    79  			bf := &wire.DataBlockedFrame{MaximumData: 0x1337}
    80  			bfLen := bf.Length(version)
    81  			numFrames := int(maxSize / bfLen) // max number of frames that fit into maxSize
    82  			for i := 0; i < numFrames+1; i++ {
    83  				framer.QueueControlFrame(bf)
    84  			}
    85  			frames, length := framer.AppendControlFrames(nil, maxSize, protocol.Version1)
    86  			Expect(frames).To(HaveLen(numFrames))
    87  			Expect(length).To(BeNumerically(">", maxSize-bfLen))
    88  			frames, length = framer.AppendControlFrames(nil, maxSize, protocol.Version1)
    89  			Expect(frames).To(HaveLen(1))
    90  			Expect(length).To(Equal(bfLen))
    91  		})
    92  
    93  		It("drops *_BLOCKED frames when 0-RTT is rejected", func() {
    94  			ping := &wire.PingFrame{}
    95  			ncid := &wire.NewConnectionIDFrame{
    96  				SequenceNumber: 10,
    97  				ConnectionID:   protocol.ParseConnectionID([]byte{0xde, 0xad, 0xbe, 0xef}),
    98  			}
    99  			frames := []wire.Frame{
   100  				&wire.DataBlockedFrame{MaximumData: 1337},
   101  				&wire.StreamDataBlockedFrame{StreamID: 42, MaximumStreamData: 1337},
   102  				&wire.StreamsBlockedFrame{StreamLimit: 13},
   103  				ping,
   104  				ncid,
   105  			}
   106  			rand.Shuffle(len(frames), func(i, j int) { frames[i], frames[j] = frames[j], frames[i] })
   107  			for _, f := range frames {
   108  				framer.QueueControlFrame(f)
   109  			}
   110  			Expect(framer.Handle0RTTRejection()).To(Succeed())
   111  			fs, length := framer.AppendControlFrames(nil, protocol.MaxByteCount, protocol.Version1)
   112  			Expect(fs).To(HaveLen(2))
   113  			Expect(length).To(Equal(ping.Length(version) + ncid.Length(version)))
   114  		})
   115  	})
   116  
   117  	Context("handling PATH_RESPONSE frames", func() {
   118  		It("packs a single PATH_RESPONSE per packet", func() {
   119  			f1 := &wire.PathResponseFrame{Data: [8]byte{1, 2, 3, 4, 5, 6, 7, 8}}
   120  			f2 := &wire.PathResponseFrame{Data: [8]byte{2, 3, 4, 5, 6, 7, 8, 9}}
   121  			cf1 := &wire.DataBlockedFrame{MaximumData: 1337}
   122  			cf2 := &wire.HandshakeDoneFrame{}
   123  			framer.QueueControlFrame(f1)
   124  			framer.QueueControlFrame(f2)
   125  			framer.QueueControlFrame(cf1)
   126  			framer.QueueControlFrame(cf2)
   127  			// the first packet should contain a single PATH_RESPONSE frame, but all the other control frames
   128  			Expect(framer.HasData()).To(BeTrue())
   129  			frames, length := framer.AppendControlFrames(nil, protocol.MaxByteCount, protocol.Version1)
   130  			Expect(frames).To(HaveLen(3))
   131  			Expect(frames[0].Frame).To(Equal(f1))
   132  			Expect([]wire.Frame{frames[1].Frame, frames[2].Frame}).To(ContainElement(cf1))
   133  			Expect([]wire.Frame{frames[1].Frame, frames[2].Frame}).To(ContainElement(cf2))
   134  			Expect(length).To(Equal(f1.Length(protocol.Version1) + cf1.Length(protocol.Version1) + cf2.Length(protocol.Version1)))
   135  			// the second packet should contain the other PATH_RESPONSE frame
   136  			Expect(framer.HasData()).To(BeTrue())
   137  			frames, length = framer.AppendControlFrames(nil, protocol.MaxByteCount, protocol.Version1)
   138  			Expect(frames).To(HaveLen(1))
   139  			Expect(frames[0].Frame).To(Equal(f2))
   140  			Expect(length).To(Equal(f2.Length(protocol.Version1)))
   141  			Expect(framer.HasData()).To(BeFalse())
   142  		})
   143  
   144  		It("limits the number of queued PATH_RESPONSE frames", func() {
   145  			var pathResponses []*wire.PathResponseFrame
   146  			for i := 0; i < 2*maxPathResponses; i++ {
   147  				var f wire.PathResponseFrame
   148  				rand.Read(f.Data[:])
   149  				pathResponses = append(pathResponses, &f)
   150  				framer.QueueControlFrame(&f)
   151  			}
   152  			for i := 0; i < maxPathResponses; i++ {
   153  				Expect(framer.HasData()).To(BeTrue())
   154  				frames, length := framer.AppendControlFrames(nil, protocol.MaxByteCount, protocol.Version1)
   155  				Expect(frames).To(HaveLen(1))
   156  				Expect(frames[0].Frame).To(Equal(pathResponses[i]))
   157  				Expect(length).To(Equal(pathResponses[i].Length(protocol.Version1)))
   158  			}
   159  			Expect(framer.HasData()).To(BeFalse())
   160  			frames, length := framer.AppendControlFrames(nil, protocol.MaxByteCount, protocol.Version1)
   161  			Expect(frames).To(BeEmpty())
   162  			Expect(length).To(BeZero())
   163  		})
   164  	})
   165  
   166  	Context("popping STREAM frames", func() {
   167  		It("returns nil when popping an empty framer", func() {
   168  			Expect(framer.AppendStreamFrames(nil, 1000, protocol.Version1)).To(BeEmpty())
   169  		})
   170  
   171  		It("returns STREAM frames", func() {
   172  			streamGetter.EXPECT().GetOrOpenSendStream(id1).Return(stream1, nil)
   173  			f := &wire.StreamFrame{
   174  				StreamID:       id1,
   175  				Data:           []byte("foobar"),
   176  				Offset:         42,
   177  				DataLenPresent: true,
   178  			}
   179  			stream1.EXPECT().getPriority().Return(0).MinTimes(1)
   180  			stream1.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f}, true, false)
   181  			framer.AddActiveStream(id1)
   182  			fs, length := framer.AppendStreamFrames(nil, 1000, protocol.Version1)
   183  			Expect(fs).To(HaveLen(1))
   184  			Expect(fs[0].Frame.DataLenPresent).To(BeFalse())
   185  			Expect(length).To(Equal(f.Length(version)))
   186  		})
   187  
   188  		It("says if it has data", func() {
   189  			streamGetter.EXPECT().GetOrOpenSendStream(id1).Return(stream1, nil).Times(2)
   190  			Expect(framer.HasData()).To(BeFalse())
   191  			framer.AddActiveStream(id1)
   192  			Expect(framer.HasData()).To(BeTrue())
   193  			f1 := &wire.StreamFrame{StreamID: id1, Data: []byte("foo")}
   194  			f2 := &wire.StreamFrame{StreamID: id1, Data: []byte("bar")}
   195  			stream1.EXPECT().getPriority().Return(0).MinTimes(1)
   196  			stream1.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f1}, true, true)
   197  			stream1.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f2}, true, false)
   198  			frames, _ := framer.AppendStreamFrames(nil, protocol.MaxByteCount, protocol.Version1)
   199  			Expect(frames).To(HaveLen(1))
   200  			Expect(frames[0].Frame).To(Equal(f1))
   201  			Expect(framer.HasData()).To(BeTrue())
   202  			frames, _ = framer.AppendStreamFrames(nil, protocol.MaxByteCount, protocol.Version1)
   203  			Expect(frames).To(HaveLen(1))
   204  			Expect(frames[0].Frame).To(Equal(f2))
   205  			Expect(framer.HasData()).To(BeFalse())
   206  		})
   207  
   208  		It("appends to a frame slice", func() {
   209  			streamGetter.EXPECT().GetOrOpenSendStream(id1).Return(stream1, nil)
   210  			f := &wire.StreamFrame{
   211  				StreamID:       id1,
   212  				Data:           []byte("foobar"),
   213  				DataLenPresent: true,
   214  			}
   215  			stream1.EXPECT().getPriority().Return(0).MinTimes(1)
   216  			stream1.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f}, true, false)
   217  			framer.AddActiveStream(id1)
   218  			f0 := ackhandler.StreamFrame{Frame: &wire.StreamFrame{StreamID: 9999}}
   219  			frames := []ackhandler.StreamFrame{f0}
   220  			fs, length := framer.AppendStreamFrames(frames, 1000, protocol.Version1)
   221  			Expect(fs).To(HaveLen(2))
   222  			Expect(fs[0]).To(Equal(f0))
   223  			Expect(fs[1].Frame.Data).To(Equal([]byte("foobar")))
   224  			Expect(fs[1].Frame.DataLenPresent).To(BeFalse())
   225  			Expect(length).To(Equal(f.Length(version)))
   226  		})
   227  
   228  		It("skips a stream that was reported active, but was completed shortly after", func() {
   229  			streamGetter.EXPECT().GetOrOpenSendStream(id1).Return(nil, nil).MinTimes(1)
   230  			streamGetter.EXPECT().GetOrOpenSendStream(id2).Return(stream2, nil).MinTimes(1)
   231  			f := &wire.StreamFrame{
   232  				StreamID:       id2,
   233  				Data:           []byte("foobar"),
   234  				DataLenPresent: true,
   235  			}
   236  			stream2.EXPECT().getPriority().Return(0)
   237  			stream2.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f}, true, false)
   238  			framer.AddActiveStream(id1)
   239  			framer.AddActiveStream(id2)
   240  			frames, _ := framer.AppendStreamFrames(nil, 1000, protocol.Version1)
   241  			Expect(frames).To(HaveLen(1))
   242  			Expect(frames[0].Frame).To(Equal(f))
   243  		})
   244  
   245  		It("skips a stream that was reported active, but doesn't have any data", func() {
   246  			streamGetter.EXPECT().GetOrOpenSendStream(id1).Return(stream1, nil).MinTimes(1)
   247  			streamGetter.EXPECT().GetOrOpenSendStream(id2).Return(stream2, nil).MinTimes(1)
   248  			f := &wire.StreamFrame{
   249  				StreamID:       id2,
   250  				Data:           []byte("foobar"),
   251  				DataLenPresent: true,
   252  			}
   253  			stream1.EXPECT().getPriority().Return(0).MinTimes(1)
   254  			stream1.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{}, false, false)
   255  			stream2.EXPECT().getPriority().Return(0).MinTimes(1)
   256  			stream2.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f}, true, false)
   257  			framer.AddActiveStream(id1)
   258  			framer.AddActiveStream(id2)
   259  			frames, _ := framer.AppendStreamFrames(nil, 1000, protocol.Version1)
   260  			Expect(frames).To(HaveLen(1))
   261  			Expect(frames[0].Frame).To(Equal(f))
   262  		})
   263  
   264  		It("pops from a stream multiple times, if it has enough data", func() {
   265  			streamGetter.EXPECT().GetOrOpenSendStream(id1).Return(stream1, nil).Times(2)
   266  			f1 := &wire.StreamFrame{StreamID: id1, Data: []byte("foobar")}
   267  			f2 := &wire.StreamFrame{StreamID: id1, Data: []byte("foobaz")}
   268  			stream1.EXPECT().getPriority().Return(0).MinTimes(1)
   269  			stream1.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f1}, true, true)
   270  			stream1.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f2}, true, false)
   271  			framer.AddActiveStream(id1) // only add it once
   272  			frames, _ := framer.AppendStreamFrames(nil, protocol.MinStreamFrameSize, protocol.Version1)
   273  			Expect(frames).To(HaveLen(1))
   274  			Expect(frames[0].Frame).To(Equal(f1))
   275  			frames, _ = framer.AppendStreamFrames(nil, protocol.MinStreamFrameSize, protocol.Version1)
   276  			Expect(frames).To(HaveLen(1))
   277  			Expect(frames[0].Frame).To(Equal(f2))
   278  			// no further calls to popStreamFrame, after popStreamFrame said there's no more data
   279  			frames, _ = framer.AppendStreamFrames(nil, protocol.MinStreamFrameSize, protocol.Version1)
   280  			Expect(frames).To(BeNil())
   281  		})
   282  
   283  		It("re-queues a stream at the end, if it has enough data", func() {
   284  			streamGetter.EXPECT().GetOrOpenSendStream(id1).Return(stream1, nil).MinTimes(1)
   285  			streamGetter.EXPECT().GetOrOpenSendStream(id2).Return(stream2, nil).MinTimes(1)
   286  			f11 := &wire.StreamFrame{StreamID: id1, Data: []byte("foobar")}
   287  			f12 := &wire.StreamFrame{StreamID: id1, Data: []byte("foobaz")}
   288  			f2 := &wire.StreamFrame{StreamID: id2, Data: []byte("raboof")}
   289  			stream1.EXPECT().getPriority().Return(0).MinTimes(1)
   290  			stream1.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f11}, true, true)
   291  			stream1.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f12}, true, false)
   292  			stream2.EXPECT().getPriority().Return(0).MinTimes(1)
   293  			stream2.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f2}, true, false)
   294  			framer.AddActiveStream(id1) // only add it once
   295  			framer.AddActiveStream(id2)
   296  			// first a frame from stream 1
   297  			frames, _ := framer.AppendStreamFrames(nil, protocol.MinStreamFrameSize, protocol.Version1)
   298  			Expect(frames).To(HaveLen(1))
   299  			Expect(frames[0].Frame).To(Equal(f11))
   300  			// then a frame from stream 2
   301  			frames, _ = framer.AppendStreamFrames(nil, protocol.MinStreamFrameSize, protocol.Version1)
   302  			Expect(frames).To(HaveLen(1))
   303  			Expect(frames[0].Frame).To(Equal(f2))
   304  			// then another frame from stream 1
   305  			frames, _ = framer.AppendStreamFrames(nil, protocol.MinStreamFrameSize, protocol.Version1)
   306  			Expect(frames).To(HaveLen(1))
   307  			Expect(frames[0].Frame).To(Equal(f12))
   308  		})
   309  
   310  		It("only dequeues data from each stream once per packet", func() {
   311  			streamGetter.EXPECT().GetOrOpenSendStream(id1).Return(stream1, nil).MinTimes(1)
   312  			streamGetter.EXPECT().GetOrOpenSendStream(id2).Return(stream2, nil).MinTimes(1)
   313  			f1 := &wire.StreamFrame{StreamID: id1, Data: []byte("foobar")}
   314  			f2 := &wire.StreamFrame{StreamID: id2, Data: []byte("raboof")}
   315  			// both streams have more data, and will be re-queued
   316  			stream1.EXPECT().getPriority().Return(0).MinTimes(1)
   317  			stream1.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f1}, true, true)
   318  			stream2.EXPECT().getPriority().Return(0).MinTimes(1)
   319  			stream2.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f2}, true, true)
   320  			framer.AddActiveStream(id1)
   321  			framer.AddActiveStream(id2)
   322  			frames, length := framer.AppendStreamFrames(nil, 1000, protocol.Version1)
   323  			Expect(frames).To(HaveLen(2))
   324  			Expect(frames[0].Frame).To(Equal(f1))
   325  			Expect(frames[1].Frame).To(Equal(f2))
   326  			Expect(length).To(Equal(f1.Length(version) + f2.Length(version)))
   327  		})
   328  
   329  		It("returns multiple normal frames in the order they were reported active", func() {
   330  			streamGetter.EXPECT().GetOrOpenSendStream(id1).Return(stream1, nil).MinTimes(1)
   331  			streamGetter.EXPECT().GetOrOpenSendStream(id2).Return(stream2, nil).MinTimes(1)
   332  			f1 := &wire.StreamFrame{Data: []byte("foobar")}
   333  			f2 := &wire.StreamFrame{Data: []byte("foobaz")}
   334  			stream1.EXPECT().getPriority().Return(0).MinTimes(1)
   335  			stream1.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f1}, true, false)
   336  			stream2.EXPECT().getPriority().Return(0).MinTimes(1)
   337  			stream2.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f2}, true, false)
   338  			framer.AddActiveStream(id2)
   339  			framer.AddActiveStream(id1)
   340  			frames, _ := framer.AppendStreamFrames(nil, 1000, protocol.Version1)
   341  			Expect(frames).To(HaveLen(2))
   342  			Expect(frames[0].Frame).To(Equal(f2))
   343  			Expect(frames[1].Frame).To(Equal(f1))
   344  		})
   345  
   346  		It("only asks a stream for data once, even if it was reported active multiple times", func() {
   347  			streamGetter.EXPECT().GetOrOpenSendStream(id1).Return(stream1, nil)
   348  			f := &wire.StreamFrame{Data: []byte("foobar")}
   349  			stream1.EXPECT().getPriority().Return(0).MinTimes(1)
   350  			stream1.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f}, true, false) // only one call to this function
   351  			framer.AddActiveStream(id1)
   352  			framer.AddActiveStream(id1)
   353  			frames, _ := framer.AppendStreamFrames(nil, 1000, protocol.Version1)
   354  			Expect(frames).To(HaveLen(1))
   355  		})
   356  
   357  		It("does not pop empty frames", func() {
   358  			fs, length := framer.AppendStreamFrames(nil, 500, protocol.Version1)
   359  			Expect(fs).To(BeEmpty())
   360  			Expect(length).To(BeZero())
   361  		})
   362  
   363  		It("pops maximum size STREAM frames", func() {
   364  			for i := protocol.MinStreamFrameSize; i < 2000; i++ {
   365  				streamGetter.EXPECT().GetOrOpenSendStream(id1).Return(stream1, nil)
   366  				stream1.EXPECT().getPriority().Return(0)
   367  				stream1.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).DoAndReturn(func(size protocol.ByteCount, v protocol.Version) (ackhandler.StreamFrame, bool, bool) {
   368  					f := &wire.StreamFrame{
   369  						StreamID:       id1,
   370  						DataLenPresent: true,
   371  					}
   372  					f.Data = make([]byte, f.MaxDataLen(size, v))
   373  					Expect(f.Length(version)).To(Equal(size))
   374  					return ackhandler.StreamFrame{Frame: f}, true, false
   375  				})
   376  				framer.AddActiveStream(id1)
   377  				frames, _ := framer.AppendStreamFrames(nil, i, protocol.Version1)
   378  				Expect(frames).To(HaveLen(1))
   379  				f := frames[0].Frame
   380  				Expect(f.DataLenPresent).To(BeFalse())
   381  				Expect(f.Length(version)).To(Equal(i))
   382  			}
   383  		})
   384  
   385  		It("pops multiple STREAM frames", func() {
   386  			for i := 2 * protocol.MinStreamFrameSize; i < 2000; i++ {
   387  				// TODO I'm not sure why AnyTimes is needed instead of MinTimes
   388  				streamGetter.EXPECT().GetOrOpenSendStream(id1).Return(stream1, nil).AnyTimes()
   389  				streamGetter.EXPECT().GetOrOpenSendStream(id2).Return(stream2, nil).AnyTimes()
   390  				stream1.EXPECT().getPriority().Return(0).AnyTimes()
   391  				stream1.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).DoAndReturn(func(size protocol.ByteCount, v protocol.Version) (ackhandler.StreamFrame, bool, bool) {
   392  					f := &wire.StreamFrame{
   393  						StreamID:       id2,
   394  						DataLenPresent: true,
   395  					}
   396  					f.Data = make([]byte, f.MaxDataLen(protocol.MinStreamFrameSize, v))
   397  					return ackhandler.StreamFrame{Frame: f}, true, false
   398  				})
   399  				stream2.EXPECT().getPriority().Return(0).AnyTimes()
   400  				stream2.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).DoAndReturn(func(size protocol.ByteCount, v protocol.Version) (ackhandler.StreamFrame, bool, bool) {
   401  					f := &wire.StreamFrame{
   402  						StreamID:       id2,
   403  						DataLenPresent: true,
   404  					}
   405  					f.Data = make([]byte, f.MaxDataLen(size, v))
   406  					Expect(f.Length(version)).To(Equal(size))
   407  					return ackhandler.StreamFrame{Frame: f}, true, false
   408  				})
   409  				framer.AddActiveStream(id1)
   410  				framer.AddActiveStream(id2)
   411  				frames, _ := framer.AppendStreamFrames(nil, i, protocol.Version1)
   412  				Expect(frames).To(HaveLen(2))
   413  				f1 := frames[0].Frame
   414  				f2 := frames[1].Frame
   415  				Expect(f1.DataLenPresent).To(BeTrue())
   416  				Expect(f2.DataLenPresent).To(BeFalse())
   417  				Expect(f1.Length(version) + f2.Length(version)).To(Equal(i))
   418  			}
   419  		})
   420  
   421  		It("pops frames that when asked for the the minimum STREAM frame size", func() {
   422  			streamGetter.EXPECT().GetOrOpenSendStream(id1).Return(stream1, nil)
   423  			f := &wire.StreamFrame{Data: []byte("foobar")}
   424  			stream1.EXPECT().getPriority().Return(0).MinTimes(1)
   425  			stream1.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f}, true, false)
   426  			framer.AddActiveStream(id1)
   427  			framer.AppendStreamFrames(nil, protocol.MinStreamFrameSize, protocol.Version1)
   428  		})
   429  
   430  		It("does not pop frames smaller than the minimum size", func() {
   431  			// don't expect a call to PopStreamFrame()
   432  			framer.AppendStreamFrames(nil, protocol.MinStreamFrameSize-1, protocol.Version1)
   433  		})
   434  
   435  		It("stops iterating when the remaining size is smaller than the minimum STREAM frame size", func() {
   436  			streamGetter.EXPECT().GetOrOpenSendStream(id1).Return(stream1, nil)
   437  			// pop a frame such that the remaining size is one byte less than the minimum STREAM frame size
   438  			f := &wire.StreamFrame{
   439  				StreamID:       id1,
   440  				Data:           bytes.Repeat([]byte("f"), int(500-protocol.MinStreamFrameSize)),
   441  				DataLenPresent: true,
   442  			}
   443  			stream1.EXPECT().getPriority().Return(0).MinTimes(1)
   444  			stream1.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f}, true, false)
   445  			framer.AddActiveStream(id1)
   446  			fs, length := framer.AppendStreamFrames(nil, 500, protocol.Version1)
   447  			Expect(fs).To(HaveLen(1))
   448  			Expect(fs[0].Frame).To(Equal(f))
   449  			Expect(length).To(Equal(f.Length(version)))
   450  		})
   451  
   452  		It("drops all STREAM frames when 0-RTT is rejected", func() {
   453  			framer.AddActiveStream(id1)
   454  			Expect(framer.Handle0RTTRejection()).To(Succeed())
   455  			fs, length := framer.AppendStreamFrames(nil, protocol.MaxByteCount, protocol.Version1)
   456  			Expect(fs).To(BeEmpty())
   457  			Expect(length).To(BeZero())
   458  		})
   459  
   460  		It("pops streams in priority order", func() {
   461  			streamGetter.EXPECT().GetOrOpenSendStream(id1).Return(stream1, nil).MinTimes(1)
   462  			streamGetter.EXPECT().GetOrOpenSendStream(id2).Return(stream2, nil).MinTimes(1)
   463  			streamGetter.EXPECT().GetOrOpenSendStream(id3).Return(stream3, nil).MinTimes(1)
   464  
   465  			f1 := &wire.StreamFrame{StreamID: id1, Data: []byte("foobar")}
   466  			f2 := &wire.StreamFrame{StreamID: id2, Data: []byte("raboof")}
   467  			f3 := &wire.StreamFrame{StreamID: id3, Data: []byte("kixel4")}
   468  
   469  			stream1.EXPECT().getPriority().Return(1).MinTimes(1) // lowest priority
   470  			stream1.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f1}, true, false)
   471  
   472  			stream2.EXPECT().getPriority().Return(3).MinTimes(1) // highest priority
   473  			stream2.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f2}, true, false)
   474  
   475  			stream3.EXPECT().getPriority().Return(2).MinTimes(1) // middle priority
   476  			stream3.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f3}, true, false)
   477  
   478  			framer.AddActiveStream(id1)
   479  			framer.AddActiveStream(id2)
   480  			framer.AddActiveStream(id3)
   481  
   482  			// stream 2
   483  			frames, _ := framer.AppendStreamFrames(nil, protocol.MinStreamFrameSize, protocol.Version1)
   484  			Expect(frames).To(HaveLen(1))
   485  			Expect(frames[0].Frame).To(Equal(f2))
   486  
   487  			// stream 3
   488  			frames, _ = framer.AppendStreamFrames(nil, protocol.MinStreamFrameSize, protocol.Version1)
   489  			Expect(frames).To(HaveLen(1))
   490  			Expect(frames[0].Frame).To(Equal(f3))
   491  
   492  			// stream 1
   493  			frames, _ = framer.AppendStreamFrames(nil, protocol.MinStreamFrameSize, protocol.Version1)
   494  			Expect(frames).To(HaveLen(1))
   495  			Expect(frames[0].Frame).To(Equal(f1))
   496  		})
   497  
   498  		It("reorders when priority is changed", func() {
   499  			streamGetter.EXPECT().GetOrOpenSendStream(id1).Return(stream1, nil).MinTimes(1)
   500  			streamGetter.EXPECT().GetOrOpenSendStream(id2).Return(stream2, nil).MinTimes(1)
   501  
   502  			f11 := &wire.StreamFrame{StreamID: id1, Data: []byte("foobar")}
   503  			f12 := &wire.StreamFrame{StreamID: id1, Data: []byte("foobaz")}
   504  			f21 := &wire.StreamFrame{StreamID: id2, Data: []byte("raboof")}
   505  			f22 := &wire.StreamFrame{StreamID: id2, Data: []byte("zaboof")}
   506  
   507  			stream1.EXPECT().getPriority().Return(2).MinTimes(2) // lowest priority
   508  			stream1.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f11}, true, true)
   509  			stream1.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f12}, true, false)
   510  
   511  			priority := 3
   512  			stream2.EXPECT().getPriority().DoAndReturn(func() int { return priority }).MinTimes(1) // highest priority... for now
   513  			stream2.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f21}, true, true)
   514  			stream2.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f22}, true, false)
   515  
   516  			framer.AddActiveStream(id1)
   517  			framer.AddActiveStream(id2)
   518  
   519  			// stream 2
   520  			frames, _ := framer.AppendStreamFrames(nil, protocol.MinStreamFrameSize, protocol.Version1)
   521  			Expect(frames).To(HaveLen(1))
   522  			Expect(frames[0].Frame).To(Equal(f21))
   523  
   524  			priority = 1 // now stream 2 is the lowest priority
   525  
   526  			// stream 1
   527  			frames, _ = framer.AppendStreamFrames(nil, protocol.MinStreamFrameSize, protocol.Version1)
   528  			Expect(frames).To(HaveLen(1))
   529  			Expect(frames[0].Frame).To(Equal(f11))
   530  
   531  			// stream 1
   532  			frames, _ = framer.AppendStreamFrames(nil, protocol.MinStreamFrameSize, protocol.Version1)
   533  			Expect(frames).To(HaveLen(1))
   534  			Expect(frames[0].Frame).To(Equal(f12))
   535  
   536  			// stream 2
   537  			frames, _ = framer.AppendStreamFrames(nil, protocol.MinStreamFrameSize, protocol.Version1)
   538  			Expect(frames).To(HaveLen(1))
   539  			Expect(frames[0].Frame).To(Equal(f22))
   540  		})
   541  
   542  		It("round-robins when priority is equal", func() {
   543  			streamGetter.EXPECT().GetOrOpenSendStream(id1).Return(stream1, nil).MinTimes(1)
   544  			streamGetter.EXPECT().GetOrOpenSendStream(id2).Return(stream2, nil).MinTimes(1)
   545  			streamGetter.EXPECT().GetOrOpenSendStream(id3).Return(stream3, nil).MinTimes(1)
   546  
   547  			f11 := &wire.StreamFrame{StreamID: id1, Data: []byte("foobar")}
   548  			f12 := &wire.StreamFrame{StreamID: id1, Data: []byte("foobaz")}
   549  			f21 := &wire.StreamFrame{StreamID: id2, Data: []byte("raboof")}
   550  			f22 := &wire.StreamFrame{StreamID: id2, Data: []byte("zaboof")}
   551  			f31 := &wire.StreamFrame{StreamID: id3, Data: []byte("kixel4")}
   552  			f32 := &wire.StreamFrame{StreamID: id3, Data: []byte("pogger")}
   553  
   554  			stream1.EXPECT().getPriority().Return(2).MinTimes(2) // highest priority
   555  			stream1.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f11}, true, true)
   556  			stream1.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f12}, true, false)
   557  
   558  			stream2.EXPECT().getPriority().Return(1).MinTimes(1) // lowest priority
   559  			stream2.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f21}, true, true)
   560  			stream2.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f22}, true, false)
   561  
   562  			stream3.EXPECT().getPriority().Return(2).MinTimes(1) // highest priority
   563  			stream3.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f31}, true, true)
   564  			stream3.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f32}, true, false)
   565  
   566  			framer.AddActiveStream(id1)
   567  			framer.AddActiveStream(id2)
   568  			framer.AddActiveStream(id3)
   569  
   570  			// stream 1 was added first
   571  			frames, _ := framer.AppendStreamFrames(nil, protocol.MinStreamFrameSize, protocol.Version1)
   572  			Expect(frames).To(HaveLen(1))
   573  			Expect(frames[0].Frame).To(Equal(f11))
   574  
   575  			// stream 3 is equal priority so it goes next
   576  			frames, _ = framer.AppendStreamFrames(nil, protocol.MinStreamFrameSize, protocol.Version1)
   577  			Expect(frames).To(HaveLen(1))
   578  			Expect(frames[0].Frame).To(Equal(f31))
   579  
   580  			// stream 1 is equal priority so it goes next
   581  			frames, _ = framer.AppendStreamFrames(nil, protocol.MinStreamFrameSize, protocol.Version1)
   582  			Expect(frames).To(HaveLen(1))
   583  			Expect(frames[0].Frame).To(Equal(f12))
   584  
   585  			// stream 3 is highest priority
   586  			frames, _ = framer.AppendStreamFrames(nil, protocol.MinStreamFrameSize, protocol.Version1)
   587  			Expect(frames).To(HaveLen(1))
   588  			Expect(frames[0].Frame).To(Equal(f32))
   589  
   590  			// stream 2 finally gets a chance
   591  			frames, _ = framer.AppendStreamFrames(nil, protocol.MinStreamFrameSize, protocol.Version1)
   592  			Expect(frames).To(HaveLen(1))
   593  			Expect(frames[0].Frame).To(Equal(f21))
   594  
   595  			// stream 2 finishes
   596  			frames, _ = framer.AppendStreamFrames(nil, protocol.MinStreamFrameSize, protocol.Version1)
   597  			Expect(frames).To(HaveLen(1))
   598  			Expect(frames[0].Frame).To(Equal(f22))
   599  		})
   600  	})
   601  })