github.com/apernet/quic-go@v0.43.1-0.20240515053213-5e9e635fd9f0/framer_test.go (about)

     1  package quic
     2  
     3  import (
     4  	"bytes"
     5  
     6  	"golang.org/x/exp/rand"
     7  
     8  	"github.com/apernet/quic-go/internal/ackhandler"
     9  	"github.com/apernet/quic-go/internal/protocol"
    10  	"github.com/apernet/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  	)
    22  
    23  	var (
    24  		framer           framer
    25  		stream1, stream2 *MockSendStreamI
    26  		streamGetter     *MockStreamGetter
    27  		version          protocol.Version
    28  	)
    29  
    30  	BeforeEach(func() {
    31  		streamGetter = NewMockStreamGetter(mockCtrl)
    32  		stream1 = NewMockSendStreamI(mockCtrl)
    33  		stream1.EXPECT().StreamID().Return(protocol.StreamID(5)).AnyTimes()
    34  		stream2 = NewMockSendStreamI(mockCtrl)
    35  		stream2.EXPECT().StreamID().Return(protocol.StreamID(6)).AnyTimes()
    36  		framer = newFramer(streamGetter)
    37  	})
    38  
    39  	Context("handling control frames", func() {
    40  		It("adds control frames", func() {
    41  			mdf := &wire.MaxDataFrame{MaximumData: 0x42}
    42  			msf := &wire.MaxStreamsFrame{MaxStreamNum: 0x1337}
    43  			framer.QueueControlFrame(mdf)
    44  			framer.QueueControlFrame(msf)
    45  			frames, length := framer.AppendControlFrames(nil, 1000, protocol.Version1)
    46  			Expect(frames).To(HaveLen(2))
    47  			fs := []wire.Frame{frames[0].Frame, frames[1].Frame}
    48  			Expect(fs).To(ContainElement(mdf))
    49  			Expect(fs).To(ContainElement(msf))
    50  			Expect(length).To(Equal(mdf.Length(version) + msf.Length(version)))
    51  		})
    52  
    53  		It("says if it has data", func() {
    54  			Expect(framer.HasData()).To(BeFalse())
    55  			f := &wire.MaxDataFrame{MaximumData: 0x42}
    56  			framer.QueueControlFrame(f)
    57  			Expect(framer.HasData()).To(BeTrue())
    58  			frames, _ := framer.AppendControlFrames(nil, 1000, protocol.Version1)
    59  			Expect(frames).To(HaveLen(1))
    60  			Expect(framer.HasData()).To(BeFalse())
    61  		})
    62  
    63  		It("appends to the slice given", func() {
    64  			ping := &wire.PingFrame{}
    65  			mdf := &wire.MaxDataFrame{MaximumData: 0x42}
    66  			framer.QueueControlFrame(mdf)
    67  			frames, length := framer.AppendControlFrames([]ackhandler.Frame{{Frame: ping}}, 1000, protocol.Version1)
    68  			Expect(frames).To(HaveLen(2))
    69  			Expect(frames[0].Frame).To(Equal(ping))
    70  			Expect(frames[1].Frame).To(Equal(mdf))
    71  			Expect(length).To(Equal(mdf.Length(version)))
    72  		})
    73  
    74  		It("adds the right number of frames", func() {
    75  			maxSize := protocol.ByteCount(1000)
    76  			bf := &wire.DataBlockedFrame{MaximumData: 0x1337}
    77  			bfLen := bf.Length(version)
    78  			numFrames := int(maxSize / bfLen) // max number of frames that fit into maxSize
    79  			for i := 0; i < numFrames+1; i++ {
    80  				framer.QueueControlFrame(bf)
    81  			}
    82  			frames, length := framer.AppendControlFrames(nil, maxSize, protocol.Version1)
    83  			Expect(frames).To(HaveLen(numFrames))
    84  			Expect(length).To(BeNumerically(">", maxSize-bfLen))
    85  			frames, length = framer.AppendControlFrames(nil, maxSize, protocol.Version1)
    86  			Expect(frames).To(HaveLen(1))
    87  			Expect(length).To(Equal(bfLen))
    88  		})
    89  
    90  		It("drops *_BLOCKED frames when 0-RTT is rejected", func() {
    91  			ping := &wire.PingFrame{}
    92  			ncid := &wire.NewConnectionIDFrame{
    93  				SequenceNumber: 10,
    94  				ConnectionID:   protocol.ParseConnectionID([]byte{0xde, 0xad, 0xbe, 0xef}),
    95  			}
    96  			frames := []wire.Frame{
    97  				&wire.DataBlockedFrame{MaximumData: 1337},
    98  				&wire.StreamDataBlockedFrame{StreamID: 42, MaximumStreamData: 1337},
    99  				&wire.StreamsBlockedFrame{StreamLimit: 13},
   100  				ping,
   101  				ncid,
   102  			}
   103  			rand.Shuffle(len(frames), func(i, j int) { frames[i], frames[j] = frames[j], frames[i] })
   104  			for _, f := range frames {
   105  				framer.QueueControlFrame(f)
   106  			}
   107  			Expect(framer.Handle0RTTRejection()).To(Succeed())
   108  			fs, length := framer.AppendControlFrames(nil, protocol.MaxByteCount, protocol.Version1)
   109  			Expect(fs).To(HaveLen(2))
   110  			Expect(length).To(Equal(ping.Length(version) + ncid.Length(version)))
   111  		})
   112  
   113  		It("detects when too many frames are queued", func() {
   114  			for i := 0; i < maxControlFrames-1; i++ {
   115  				framer.QueueControlFrame(&wire.PingFrame{})
   116  				framer.QueueControlFrame(&wire.PingFrame{})
   117  				Expect(framer.QueuedTooManyControlFrames()).To(BeFalse())
   118  				frames, _ := framer.AppendControlFrames([]ackhandler.Frame{}, 1, protocol.Version1)
   119  				Expect(frames).To(HaveLen(1))
   120  				Expect(framer.(*framerI).controlFrames).To(HaveLen(i + 1))
   121  			}
   122  			framer.QueueControlFrame(&wire.PingFrame{})
   123  			Expect(framer.QueuedTooManyControlFrames()).To(BeFalse())
   124  			Expect(framer.(*framerI).controlFrames).To(HaveLen(maxControlFrames))
   125  			framer.QueueControlFrame(&wire.PingFrame{})
   126  			Expect(framer.QueuedTooManyControlFrames()).To(BeTrue())
   127  			Expect(framer.(*framerI).controlFrames).To(HaveLen(maxControlFrames))
   128  		})
   129  	})
   130  
   131  	Context("handling PATH_RESPONSE frames", func() {
   132  		It("packs a single PATH_RESPONSE per packet", func() {
   133  			f1 := &wire.PathResponseFrame{Data: [8]byte{1, 2, 3, 4, 5, 6, 7, 8}}
   134  			f2 := &wire.PathResponseFrame{Data: [8]byte{2, 3, 4, 5, 6, 7, 8, 9}}
   135  			cf1 := &wire.DataBlockedFrame{MaximumData: 1337}
   136  			cf2 := &wire.HandshakeDoneFrame{}
   137  			framer.QueueControlFrame(f1)
   138  			framer.QueueControlFrame(f2)
   139  			framer.QueueControlFrame(cf1)
   140  			framer.QueueControlFrame(cf2)
   141  			// the first packet should contain a single PATH_RESPONSE frame, but all the other control frames
   142  			Expect(framer.HasData()).To(BeTrue())
   143  			frames, length := framer.AppendControlFrames(nil, protocol.MaxByteCount, protocol.Version1)
   144  			Expect(frames).To(HaveLen(3))
   145  			Expect(frames[0].Frame).To(Equal(f1))
   146  			Expect([]wire.Frame{frames[1].Frame, frames[2].Frame}).To(ContainElement(cf1))
   147  			Expect([]wire.Frame{frames[1].Frame, frames[2].Frame}).To(ContainElement(cf2))
   148  			Expect(length).To(Equal(f1.Length(protocol.Version1) + cf1.Length(protocol.Version1) + cf2.Length(protocol.Version1)))
   149  			// the second packet should contain the other PATH_RESPONSE frame
   150  			Expect(framer.HasData()).To(BeTrue())
   151  			frames, length = framer.AppendControlFrames(nil, protocol.MaxByteCount, protocol.Version1)
   152  			Expect(frames).To(HaveLen(1))
   153  			Expect(frames[0].Frame).To(Equal(f2))
   154  			Expect(length).To(Equal(f2.Length(protocol.Version1)))
   155  			Expect(framer.HasData()).To(BeFalse())
   156  		})
   157  
   158  		It("limits the number of queued PATH_RESPONSE frames", func() {
   159  			var pathResponses []*wire.PathResponseFrame
   160  			for i := 0; i < 2*maxPathResponses; i++ {
   161  				var f wire.PathResponseFrame
   162  				rand.Read(f.Data[:])
   163  				pathResponses = append(pathResponses, &f)
   164  				framer.QueueControlFrame(&f)
   165  			}
   166  			for i := 0; i < maxPathResponses; i++ {
   167  				Expect(framer.HasData()).To(BeTrue())
   168  				frames, length := framer.AppendControlFrames(nil, protocol.MaxByteCount, protocol.Version1)
   169  				Expect(frames).To(HaveLen(1))
   170  				Expect(frames[0].Frame).To(Equal(pathResponses[i]))
   171  				Expect(length).To(Equal(pathResponses[i].Length(protocol.Version1)))
   172  			}
   173  			Expect(framer.HasData()).To(BeFalse())
   174  			frames, length := framer.AppendControlFrames(nil, protocol.MaxByteCount, protocol.Version1)
   175  			Expect(frames).To(BeEmpty())
   176  			Expect(length).To(BeZero())
   177  		})
   178  	})
   179  
   180  	Context("popping STREAM frames", func() {
   181  		It("returns nil when popping an empty framer", func() {
   182  			Expect(framer.AppendStreamFrames(nil, 1000, protocol.Version1)).To(BeEmpty())
   183  		})
   184  
   185  		It("returns STREAM frames", func() {
   186  			streamGetter.EXPECT().GetOrOpenSendStream(id1).Return(stream1, nil)
   187  			f := &wire.StreamFrame{
   188  				StreamID:       id1,
   189  				Data:           []byte("foobar"),
   190  				Offset:         42,
   191  				DataLenPresent: true,
   192  			}
   193  			stream1.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f}, true, false)
   194  			framer.AddActiveStream(id1)
   195  			fs, length := framer.AppendStreamFrames(nil, 1000, protocol.Version1)
   196  			Expect(fs).To(HaveLen(1))
   197  			Expect(fs[0].Frame.DataLenPresent).To(BeFalse())
   198  			Expect(length).To(Equal(f.Length(version)))
   199  		})
   200  
   201  		It("says if it has data", func() {
   202  			streamGetter.EXPECT().GetOrOpenSendStream(id1).Return(stream1, nil).Times(2)
   203  			Expect(framer.HasData()).To(BeFalse())
   204  			framer.AddActiveStream(id1)
   205  			Expect(framer.HasData()).To(BeTrue())
   206  			f1 := &wire.StreamFrame{StreamID: id1, Data: []byte("foo")}
   207  			f2 := &wire.StreamFrame{StreamID: id1, Data: []byte("bar")}
   208  			stream1.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f1}, true, true)
   209  			stream1.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f2}, true, false)
   210  			frames, _ := framer.AppendStreamFrames(nil, protocol.MaxByteCount, protocol.Version1)
   211  			Expect(frames).To(HaveLen(1))
   212  			Expect(frames[0].Frame).To(Equal(f1))
   213  			Expect(framer.HasData()).To(BeTrue())
   214  			frames, _ = framer.AppendStreamFrames(nil, protocol.MaxByteCount, protocol.Version1)
   215  			Expect(frames).To(HaveLen(1))
   216  			Expect(frames[0].Frame).To(Equal(f2))
   217  			Expect(framer.HasData()).To(BeFalse())
   218  		})
   219  
   220  		It("appends to a frame slice", func() {
   221  			streamGetter.EXPECT().GetOrOpenSendStream(id1).Return(stream1, nil)
   222  			f := &wire.StreamFrame{
   223  				StreamID:       id1,
   224  				Data:           []byte("foobar"),
   225  				DataLenPresent: true,
   226  			}
   227  			stream1.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f}, true, false)
   228  			framer.AddActiveStream(id1)
   229  			f0 := ackhandler.StreamFrame{Frame: &wire.StreamFrame{StreamID: 9999}}
   230  			frames := []ackhandler.StreamFrame{f0}
   231  			fs, length := framer.AppendStreamFrames(frames, 1000, protocol.Version1)
   232  			Expect(fs).To(HaveLen(2))
   233  			Expect(fs[0]).To(Equal(f0))
   234  			Expect(fs[1].Frame.Data).To(Equal([]byte("foobar")))
   235  			Expect(fs[1].Frame.DataLenPresent).To(BeFalse())
   236  			Expect(length).To(Equal(f.Length(version)))
   237  		})
   238  
   239  		It("skips a stream that was reported active, but was completed shortly after", func() {
   240  			streamGetter.EXPECT().GetOrOpenSendStream(id1).Return(nil, nil)
   241  			streamGetter.EXPECT().GetOrOpenSendStream(id2).Return(stream2, nil)
   242  			f := &wire.StreamFrame{
   243  				StreamID:       id2,
   244  				Data:           []byte("foobar"),
   245  				DataLenPresent: true,
   246  			}
   247  			stream2.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f}, true, false)
   248  			framer.AddActiveStream(id1)
   249  			framer.AddActiveStream(id2)
   250  			frames, _ := framer.AppendStreamFrames(nil, 1000, protocol.Version1)
   251  			Expect(frames).To(HaveLen(1))
   252  			Expect(frames[0].Frame).To(Equal(f))
   253  		})
   254  
   255  		It("skips a stream that was reported active, but doesn't have any data", func() {
   256  			streamGetter.EXPECT().GetOrOpenSendStream(id1).Return(stream1, nil)
   257  			streamGetter.EXPECT().GetOrOpenSendStream(id2).Return(stream2, nil)
   258  			f := &wire.StreamFrame{
   259  				StreamID:       id2,
   260  				Data:           []byte("foobar"),
   261  				DataLenPresent: true,
   262  			}
   263  			stream1.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{}, false, false)
   264  			stream2.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f}, true, false)
   265  			framer.AddActiveStream(id1)
   266  			framer.AddActiveStream(id2)
   267  			frames, _ := framer.AppendStreamFrames(nil, 1000, protocol.Version1)
   268  			Expect(frames).To(HaveLen(1))
   269  			Expect(frames[0].Frame).To(Equal(f))
   270  		})
   271  
   272  		It("pops from a stream multiple times, if it has enough data", func() {
   273  			streamGetter.EXPECT().GetOrOpenSendStream(id1).Return(stream1, nil).Times(2)
   274  			f1 := &wire.StreamFrame{StreamID: id1, Data: []byte("foobar")}
   275  			f2 := &wire.StreamFrame{StreamID: id1, Data: []byte("foobaz")}
   276  			stream1.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f1}, true, true)
   277  			stream1.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f2}, true, false)
   278  			framer.AddActiveStream(id1) // only add it once
   279  			frames, _ := framer.AppendStreamFrames(nil, protocol.MinStreamFrameSize, protocol.Version1)
   280  			Expect(frames).To(HaveLen(1))
   281  			Expect(frames[0].Frame).To(Equal(f1))
   282  			frames, _ = framer.AppendStreamFrames(nil, protocol.MinStreamFrameSize, protocol.Version1)
   283  			Expect(frames).To(HaveLen(1))
   284  			Expect(frames[0].Frame).To(Equal(f2))
   285  			// no further calls to popStreamFrame, after popStreamFrame said there's no more data
   286  			frames, _ = framer.AppendStreamFrames(nil, protocol.MinStreamFrameSize, protocol.Version1)
   287  			Expect(frames).To(BeNil())
   288  		})
   289  
   290  		It("re-queues a stream at the end, if it has enough data", func() {
   291  			streamGetter.EXPECT().GetOrOpenSendStream(id1).Return(stream1, nil).Times(2)
   292  			streamGetter.EXPECT().GetOrOpenSendStream(id2).Return(stream2, nil)
   293  			f11 := &wire.StreamFrame{StreamID: id1, Data: []byte("foobar")}
   294  			f12 := &wire.StreamFrame{StreamID: id1, Data: []byte("foobaz")}
   295  			f2 := &wire.StreamFrame{StreamID: id2, Data: []byte("raboof")}
   296  			stream1.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f11}, true, true)
   297  			stream1.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f12}, true, false)
   298  			stream2.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f2}, true, false)
   299  			framer.AddActiveStream(id1) // only add it once
   300  			framer.AddActiveStream(id2)
   301  			// first a frame from stream 1
   302  			frames, _ := framer.AppendStreamFrames(nil, protocol.MinStreamFrameSize, protocol.Version1)
   303  			Expect(frames).To(HaveLen(1))
   304  			Expect(frames[0].Frame).To(Equal(f11))
   305  			// then a frame from stream 2
   306  			frames, _ = framer.AppendStreamFrames(nil, protocol.MinStreamFrameSize, protocol.Version1)
   307  			Expect(frames).To(HaveLen(1))
   308  			Expect(frames[0].Frame).To(Equal(f2))
   309  			// then another frame from stream 1
   310  			frames, _ = framer.AppendStreamFrames(nil, protocol.MinStreamFrameSize, protocol.Version1)
   311  			Expect(frames).To(HaveLen(1))
   312  			Expect(frames[0].Frame).To(Equal(f12))
   313  		})
   314  
   315  		It("only dequeues data from each stream once per packet", func() {
   316  			streamGetter.EXPECT().GetOrOpenSendStream(id1).Return(stream1, nil)
   317  			streamGetter.EXPECT().GetOrOpenSendStream(id2).Return(stream2, nil)
   318  			f1 := &wire.StreamFrame{StreamID: id1, Data: []byte("foobar")}
   319  			f2 := &wire.StreamFrame{StreamID: id2, Data: []byte("raboof")}
   320  			// both streams have more data, and will be re-queued
   321  			stream1.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f1}, true, true)
   322  			stream2.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f2}, true, true)
   323  			framer.AddActiveStream(id1)
   324  			framer.AddActiveStream(id2)
   325  			frames, length := framer.AppendStreamFrames(nil, 1000, protocol.Version1)
   326  			Expect(frames).To(HaveLen(2))
   327  			Expect(frames[0].Frame).To(Equal(f1))
   328  			Expect(frames[1].Frame).To(Equal(f2))
   329  			Expect(length).To(Equal(f1.Length(version) + f2.Length(version)))
   330  		})
   331  
   332  		It("returns multiple normal frames in the order they were reported active", func() {
   333  			streamGetter.EXPECT().GetOrOpenSendStream(id1).Return(stream1, nil)
   334  			streamGetter.EXPECT().GetOrOpenSendStream(id2).Return(stream2, nil)
   335  			f1 := &wire.StreamFrame{Data: []byte("foobar")}
   336  			f2 := &wire.StreamFrame{Data: []byte("foobaz")}
   337  			stream1.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f1}, true, false)
   338  			stream2.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f2}, true, false)
   339  			framer.AddActiveStream(id2)
   340  			framer.AddActiveStream(id1)
   341  			frames, _ := framer.AppendStreamFrames(nil, 1000, protocol.Version1)
   342  			Expect(frames).To(HaveLen(2))
   343  			Expect(frames[0].Frame).To(Equal(f2))
   344  			Expect(frames[1].Frame).To(Equal(f1))
   345  		})
   346  
   347  		It("only asks a stream for data once, even if it was reported active multiple times", func() {
   348  			streamGetter.EXPECT().GetOrOpenSendStream(id1).Return(stream1, nil)
   349  			f := &wire.StreamFrame{Data: []byte("foobar")}
   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().popStreamFrame(gomock.Any(), protocol.Version1).DoAndReturn(func(size protocol.ByteCount, v protocol.Version) (ackhandler.StreamFrame, bool, bool) {
   367  					f := &wire.StreamFrame{
   368  						StreamID:       id1,
   369  						DataLenPresent: true,
   370  					}
   371  					f.Data = make([]byte, f.MaxDataLen(size, v))
   372  					Expect(f.Length(version)).To(Equal(size))
   373  					return ackhandler.StreamFrame{Frame: f}, true, false
   374  				})
   375  				framer.AddActiveStream(id1)
   376  				frames, _ := framer.AppendStreamFrames(nil, i, protocol.Version1)
   377  				Expect(frames).To(HaveLen(1))
   378  				f := frames[0].Frame
   379  				Expect(f.DataLenPresent).To(BeFalse())
   380  				Expect(f.Length(version)).To(Equal(i))
   381  			}
   382  		})
   383  
   384  		It("pops multiple STREAM frames", func() {
   385  			for i := 2 * protocol.MinStreamFrameSize; i < 2000; i++ {
   386  				streamGetter.EXPECT().GetOrOpenSendStream(id1).Return(stream1, nil)
   387  				streamGetter.EXPECT().GetOrOpenSendStream(id2).Return(stream2, nil)
   388  				stream1.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).DoAndReturn(func(size protocol.ByteCount, v protocol.Version) (ackhandler.StreamFrame, bool, bool) {
   389  					f := &wire.StreamFrame{
   390  						StreamID:       id2,
   391  						DataLenPresent: true,
   392  					}
   393  					f.Data = make([]byte, f.MaxDataLen(protocol.MinStreamFrameSize, v))
   394  					return ackhandler.StreamFrame{Frame: f}, true, false
   395  				})
   396  				stream2.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).DoAndReturn(func(size protocol.ByteCount, v protocol.Version) (ackhandler.StreamFrame, bool, bool) {
   397  					f := &wire.StreamFrame{
   398  						StreamID:       id2,
   399  						DataLenPresent: true,
   400  					}
   401  					f.Data = make([]byte, f.MaxDataLen(size, v))
   402  					Expect(f.Length(version)).To(Equal(size))
   403  					return ackhandler.StreamFrame{Frame: f}, true, false
   404  				})
   405  				framer.AddActiveStream(id1)
   406  				framer.AddActiveStream(id2)
   407  				frames, _ := framer.AppendStreamFrames(nil, i, protocol.Version1)
   408  				Expect(frames).To(HaveLen(2))
   409  				f1 := frames[0].Frame
   410  				f2 := frames[1].Frame
   411  				Expect(f1.DataLenPresent).To(BeTrue())
   412  				Expect(f2.DataLenPresent).To(BeFalse())
   413  				Expect(f1.Length(version) + f2.Length(version)).To(Equal(i))
   414  			}
   415  		})
   416  
   417  		It("pops frames that when asked for the the minimum STREAM frame size", func() {
   418  			streamGetter.EXPECT().GetOrOpenSendStream(id1).Return(stream1, nil)
   419  			f := &wire.StreamFrame{Data: []byte("foobar")}
   420  			stream1.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f}, true, false)
   421  			framer.AddActiveStream(id1)
   422  			framer.AppendStreamFrames(nil, protocol.MinStreamFrameSize, protocol.Version1)
   423  		})
   424  
   425  		It("does not pop frames smaller than the minimum size", func() {
   426  			// don't expect a call to PopStreamFrame()
   427  			framer.AppendStreamFrames(nil, protocol.MinStreamFrameSize-1, protocol.Version1)
   428  		})
   429  
   430  		It("stops iterating when the remaining size is smaller than the minimum STREAM frame size", func() {
   431  			streamGetter.EXPECT().GetOrOpenSendStream(id1).Return(stream1, nil)
   432  			// pop a frame such that the remaining size is one byte less than the minimum STREAM frame size
   433  			f := &wire.StreamFrame{
   434  				StreamID:       id1,
   435  				Data:           bytes.Repeat([]byte("f"), int(500-protocol.MinStreamFrameSize)),
   436  				DataLenPresent: true,
   437  			}
   438  			stream1.EXPECT().popStreamFrame(gomock.Any(), protocol.Version1).Return(ackhandler.StreamFrame{Frame: f}, true, false)
   439  			framer.AddActiveStream(id1)
   440  			fs, length := framer.AppendStreamFrames(nil, 500, protocol.Version1)
   441  			Expect(fs).To(HaveLen(1))
   442  			Expect(fs[0].Frame).To(Equal(f))
   443  			Expect(length).To(Equal(f.Length(version)))
   444  		})
   445  
   446  		It("drops all STREAM frames when 0-RTT is rejected", func() {
   447  			framer.AddActiveStream(id1)
   448  			Expect(framer.Handle0RTTRejection()).To(Succeed())
   449  			fs, length := framer.AppendStreamFrames(nil, protocol.MaxByteCount, protocol.Version1)
   450  			Expect(fs).To(BeEmpty())
   451  			Expect(length).To(BeZero())
   452  		})
   453  	})
   454  })