@@ -13,10 +13,8 @@ import (
1313 "fmt"
1414 "io"
1515 "net/http"
16- "os"
1716 "reflect"
1817 "runtime"
19- "slices"
2018 "sync/atomic"
2119 "testing"
2220 "time"
@@ -62,6 +60,7 @@ func TestTestClientConn(t *testing.T) {
6260 streamID : rt .streamID (),
6361 endStream : true ,
6462 size : 10 ,
63+ multiple : true ,
6564 })
6665
6766 // tc.writeHeaders sends a HEADERS frame back to the client.
@@ -97,6 +96,7 @@ type testClientConn struct {
9796 fr * Framer
9897 cc * ClientConn
9998 group * synctestGroup
99+ testConnFramer
100100
101101 encbuf bytes.Buffer
102102 enc * hpack.Encoder
@@ -115,6 +115,7 @@ func newTestClientConnFromClientConn(t *testing.T, cc *ClientConn) *testClientCo
115115 }
116116 cli , srv := synctestNetPipe (tc .group )
117117 srv .SetReadDeadline (tc .group .Now ())
118+ srv .autoWait = true
118119 tc .netconn = srv
119120 tc .enc = hpack .NewEncoder (& tc .encbuf )
120121
@@ -123,8 +124,12 @@ func newTestClientConnFromClientConn(t *testing.T, cc *ClientConn) *testClientCo
123124 // cli is the ClientConn's side, srv is the side controlled by the test.
124125 cc .tconn = cli
125126 tc .fr = NewFramer (srv , srv )
127+ tc .testConnFramer = testConnFramer {
128+ t : t ,
129+ fr : tc .fr ,
130+ dec : hpack .NewDecoder (initialHeaderTableSize , nil ),
131+ }
126132
127- tc .fr .ReadMetaHeaders = hpack .NewDecoder (initialHeaderTableSize , nil )
128133 tc .fr .SetMaxReadFrameSize (10 << 20 )
129134 t .Cleanup (func () {
130135 tc .closeWrite ()
@@ -174,169 +179,15 @@ func (tc *testClientConn) hasFrame() bool {
174179 return len (tc .netconn .Peek ()) > 0
175180}
176181
182+ // isClosed reports whether the peer has closed the connection.
177183func (tc * testClientConn ) isClosed () bool {
178184 return tc .netconn .IsClosedByPeer ()
179185}
180186
181- // readFrame reads the next frame from the conn.
182- func (tc * testClientConn ) readFrame () Frame {
183- tc .t .Helper ()
184- tc .sync ()
185- fr , err := tc .fr .ReadFrame ()
186- if err == io .EOF || err == os .ErrDeadlineExceeded {
187- return nil
188- }
189- if err != nil {
190- tc .t .Fatalf ("ReadFrame: %v" , err )
191- }
192- return fr
193- }
194-
195- // testClientConnReadFrame reads a frame of a specific type from the conn.
196- func testClientConnReadFrame [T any ](tc * testClientConn ) T {
197- tc .t .Helper ()
198- var v T
199- fr := tc .readFrame ()
200- if fr == nil {
201- tc .t .Fatalf ("got no frame, want frame %T" , v )
202- }
203- v , ok := fr .(T )
204- if ! ok {
205- tc .t .Fatalf ("got frame %T, want %T" , fr , v )
206- }
207- return v
208- }
209-
210- // wantFrameType reads the next frame from the conn.
211- // It produces an error if the frame type is not the expected value.
212- func (tc * testClientConn ) wantFrameType (want FrameType ) {
213- tc .t .Helper ()
214- fr := tc .readFrame ()
215- if fr == nil {
216- tc .t .Fatalf ("got no frame, want frame %v" , want )
217- }
218- if got := fr .Header ().Type ; got != want {
219- tc .t .Fatalf ("got frame %v, want %v" , got , want )
220- }
221- }
222-
223- // wantUnorderedFrames reads frames from the conn until every condition in want has been satisfied.
224- //
225- // want is a list of func(*SomeFrame) bool.
226- // wantUnorderedFrames will call each func with frames of the appropriate type
227- // until the func returns true.
228- // It calls t.Fatal if an unexpected frame is received (no func has that frame type,
229- // or all funcs with that type have returned true), or if the conn runs out of frames
230- // with unsatisfied funcs.
231- //
232- // Example:
233- //
234- // // Read a SETTINGS frame, and any number of DATA frames for a stream.
235- // // The SETTINGS frame may appear anywhere in the sequence.
236- // // The last DATA frame must indicate the end of the stream.
237- // tc.wantUnorderedFrames(
238- // func(f *SettingsFrame) bool {
239- // return true
240- // },
241- // func(f *DataFrame) bool {
242- // return f.StreamEnded()
243- // },
244- // )
245- func (tc * testClientConn ) wantUnorderedFrames (want ... any ) {
246- tc .t .Helper ()
247- want = slices .Clone (want )
248- seen := 0
249- frame:
250- for seen < len (want ) && ! tc .t .Failed () {
251- fr := tc .readFrame ()
252- if fr == nil {
253- break
254- }
255- for i , f := range want {
256- if f == nil {
257- continue
258- }
259- typ := reflect .TypeOf (f )
260- if typ .Kind () != reflect .Func ||
261- typ .NumIn () != 1 ||
262- typ .NumOut () != 1 ||
263- typ .Out (0 ) != reflect .TypeOf (true ) {
264- tc .t .Fatalf ("expected func(*SomeFrame) bool, got %T" , f )
265- }
266- if typ .In (0 ) == reflect .TypeOf (fr ) {
267- out := reflect .ValueOf (f ).Call ([]reflect.Value {reflect .ValueOf (fr )})
268- if out [0 ].Bool () {
269- want [i ] = nil
270- seen ++
271- }
272- continue frame
273- }
274- }
275- tc .t .Errorf ("got unexpected frame type %T" , fr )
276- }
277- if seen < len (want ) {
278- for _ , f := range want {
279- if f == nil {
280- continue
281- }
282- tc .t .Errorf ("did not see expected frame: %v" , reflect .TypeOf (f ).In (0 ))
283- }
284- tc .t .Fatalf ("did not see %v expected frame types" , len (want )- seen )
285- }
286- }
287-
288- type wantHeader struct {
289- streamID uint32
290- endStream bool
291- header http.Header
292- }
293-
294- // wantHeaders reads a HEADERS frame and potential CONTINUATION frames,
295- // and asserts that they contain the expected headers.
296- func (tc * testClientConn ) wantHeaders (want wantHeader ) {
297- tc .t .Helper ()
298- got := testClientConnReadFrame [* MetaHeadersFrame ](tc )
299- if got , want := got .StreamID , want .streamID ; got != want {
300- tc .t .Fatalf ("got stream ID %v, want %v" , got , want )
301- }
302- if got , want := got .StreamEnded (), want .endStream ; got != want {
303- tc .t .Fatalf ("got stream ended %v, want %v" , got , want )
304- }
305- gotHeader := make (http.Header )
306- for _ , f := range got .Fields {
307- gotHeader [f .Name ] = append (gotHeader [f .Name ], f .Value )
308- }
309- for k , v := range want .header {
310- if ! reflect .DeepEqual (v , gotHeader [k ]) {
311- tc .t .Fatalf ("got header %q = %q; want %q" , k , v , gotHeader [k ])
312- }
313- }
314- }
315-
316- type wantData struct {
317- streamID uint32
318- endStream bool
319- size int
320- }
321-
322- // wantData reads zero or more DATA frames, and asserts that they match the expectation.
323- func (tc * testClientConn ) wantData (want wantData ) {
324- tc .t .Helper ()
325- gotSize := 0
326- gotEndStream := false
327- for tc .hasFrame () && ! gotEndStream {
328- data := testClientConnReadFrame [* DataFrame ](tc )
329- gotSize += len (data .Data ())
330- if data .StreamEnded () {
331- gotEndStream = true
332- }
333- }
334- if gotSize != want .size {
335- tc .t .Fatalf ("got %v bytes of DATA frames, want %v" , gotSize , want .size )
336- }
337- if gotEndStream != want .endStream {
338- tc .t .Fatalf ("after %v bytes of DATA frames, got END_STREAM=%v; want %v" , gotSize , gotEndStream , want .endStream )
339- }
187+ // closeWrite causes the net.Conn used by the ClientConn to return a error
188+ // from Read calls.
189+ func (tc * testClientConn ) closeWrite () {
190+ tc .netconn .Close ()
340191}
341192
342193// testRequestBody is a Request.Body for use in tests.
@@ -468,38 +319,6 @@ func (tc *testClientConn) greet(settings ...Setting) {
468319 tc .wantFrameType (FrameSettings ) // acknowledgement
469320}
470321
471- func (tc * testClientConn ) writeSettings (settings ... Setting ) {
472- tc .t .Helper ()
473- if err := tc .fr .WriteSettings (settings ... ); err != nil {
474- tc .t .Fatal (err )
475- }
476- tc .sync ()
477- }
478-
479- func (tc * testClientConn ) writeSettingsAck () {
480- tc .t .Helper ()
481- if err := tc .fr .WriteSettingsAck (); err != nil {
482- tc .t .Fatal (err )
483- }
484- tc .sync ()
485- }
486-
487- func (tc * testClientConn ) writeData (streamID uint32 , endStream bool , data []byte ) {
488- tc .t .Helper ()
489- if err := tc .fr .WriteData (streamID , endStream , data ); err != nil {
490- tc .t .Fatal (err )
491- }
492- tc .sync ()
493- }
494-
495- func (tc * testClientConn ) writeDataPadded (streamID uint32 , endStream bool , data , pad []byte ) {
496- tc .t .Helper ()
497- if err := tc .fr .WriteDataPadded (streamID , endStream , data , pad ); err != nil {
498- tc .t .Fatal (err )
499- }
500- tc .sync ()
501- }
502-
503322// makeHeaderBlockFragment encodes headers in a form suitable for inclusion
504323// in a HEADERS or CONTINUATION frame.
505324//
@@ -515,87 +334,6 @@ func (tc *testClientConn) makeHeaderBlockFragment(s ...string) []byte {
515334 return tc .encbuf .Bytes ()
516335}
517336
518- func (tc * testClientConn ) writeHeaders (p HeadersFrameParam ) {
519- tc .t .Helper ()
520- if err := tc .fr .WriteHeaders (p ); err != nil {
521- tc .t .Fatal (err )
522- }
523- tc .sync ()
524- }
525-
526- // writeHeadersMode writes header frames, as modified by mode:
527- //
528- // - noHeader: Don't write the header.
529- // - oneHeader: Write a single HEADERS frame.
530- // - splitHeader: Write a HEADERS frame and CONTINUATION frame.
531- func (tc * testClientConn ) writeHeadersMode (mode headerType , p HeadersFrameParam ) {
532- tc .t .Helper ()
533- switch mode {
534- case noHeader :
535- case oneHeader :
536- tc .writeHeaders (p )
537- case splitHeader :
538- if len (p .BlockFragment ) < 2 {
539- panic ("too small" )
540- }
541- contData := p .BlockFragment [1 :]
542- contEnd := p .EndHeaders
543- p .BlockFragment = p .BlockFragment [:1 ]
544- p .EndHeaders = false
545- tc .writeHeaders (p )
546- tc .writeContinuation (p .StreamID , contEnd , contData )
547- default :
548- panic ("bogus mode" )
549- }
550- }
551-
552- func (tc * testClientConn ) writeContinuation (streamID uint32 , endHeaders bool , headerBlockFragment []byte ) {
553- tc .t .Helper ()
554- if err := tc .fr .WriteContinuation (streamID , endHeaders , headerBlockFragment ); err != nil {
555- tc .t .Fatal (err )
556- }
557- tc .sync ()
558- }
559-
560- func (tc * testClientConn ) writeRSTStream (streamID uint32 , code ErrCode ) {
561- tc .t .Helper ()
562- if err := tc .fr .WriteRSTStream (streamID , code ); err != nil {
563- tc .t .Fatal (err )
564- }
565- tc .sync ()
566- }
567-
568- func (tc * testClientConn ) writePing (ack bool , data [8 ]byte ) {
569- tc .t .Helper ()
570- if err := tc .fr .WritePing (ack , data ); err != nil {
571- tc .t .Fatal (err )
572- }
573- tc .sync ()
574- }
575-
576- func (tc * testClientConn ) writeGoAway (maxStreamID uint32 , code ErrCode , debugData []byte ) {
577- tc .t .Helper ()
578- if err := tc .fr .WriteGoAway (maxStreamID , code , debugData ); err != nil {
579- tc .t .Fatal (err )
580- }
581- tc .sync ()
582- }
583-
584- func (tc * testClientConn ) writeWindowUpdate (streamID , incr uint32 ) {
585- tc .t .Helper ()
586- if err := tc .fr .WriteWindowUpdate (streamID , incr ); err != nil {
587- tc .t .Fatal (err )
588- }
589- tc .sync ()
590- }
591-
592- // closeWrite causes the net.Conn used by the ClientConn to return a error
593- // from Read calls.
594- func (tc * testClientConn ) closeWrite () {
595- tc .netconn .Close ()
596- tc .sync ()
597- }
598-
599337// inflowWindow returns the amount of inbound flow control available for a stream,
600338// or for the connection if streamID is 0.
601339func (tc * testClientConn ) inflowWindow (streamID uint32 ) int32 {
0 commit comments