@@ -90,9 +90,10 @@ const (
9090 invalidHeaderField
9191 delayRead
9292 pingpong
93- goAwayFrameSize = 42
9493)
9594
95+ const goAwayFrameSize = 42
96+
9697func (h * testStreamHandler ) handleStreamAndNotify (s * Stream ) {
9798 if h .notify == nil {
9899 return
@@ -2661,94 +2662,14 @@ func TestConnectionError_Unwrap(t *testing.T) {
26612662// clientTransport.Close(), client sends a goaway to the server with the correct
26622663// error code and debug data.
26632664func (s ) TestClientSendsAGoAwayFrame (t * testing.T ) {
2664- // Create a server.
2665- lis , err := net .Listen ("tcp" , "localhost:0" )
2666- if err != nil {
2667- t .Fatalf ("Error while listening: %v" , err )
2668- }
2669- defer lis .Close ()
2670- // greetDone is used to notify when server is done greeting the client.
2671- greetDone := make (chan struct {})
2672- // errorCh verifies that desired GOAWAY not received by server
2673- errorCh := make (chan error )
2674- ctx , cancel := context .WithTimeout (context .Background (), defaultTestTimeout )
2675- defer cancel ()
2676- // Launch the server.
2677- go func () {
2678- sconn , err := lis .Accept ()
2679- if err != nil {
2680- t .Errorf ("Error while accepting: %v" , err )
2681- }
2682- defer sconn .Close ()
2683- if _ , err := io .ReadFull (sconn , make ([]byte , len (clientPreface ))); err != nil {
2684- t .Errorf ("Error while writing settings ack: %v" , err )
2685- return
2686- }
2687- sfr := http2 .NewFramer (sconn , sconn )
2688- if err := sfr .WriteSettings (); err != nil {
2689- t .Errorf ("Error while writing settings %v" , err )
2690- return
2691- }
2692- fr , _ := sfr .ReadFrame ()
2693- if _ , ok := fr .(* http2.SettingsFrame ); ! ok {
2694- t .Errorf ("Expected settings frame, got %v" , fr )
2695- }
2696- fr , _ = sfr .ReadFrame ()
2697- if fr , ok := fr .(* http2.SettingsFrame ); ! ok || ! fr .IsAck () {
2698- t .Errorf ("Expected settings ACK frame, got %v" , fr )
2699- }
2700- fr , _ = sfr .ReadFrame ()
2701- if fr , ok := fr .(* http2.HeadersFrame ); ! ok || ! fr .Flags .Has (http2 .FlagHeadersEndHeaders ) {
2702- t .Errorf ("Expected Headers frame with END_HEADERS frame, got %v" , fr )
2703- }
2704- close (greetDone )
2705-
2706- frame , err := sfr .ReadFrame ()
2707- if err != nil {
2708- return
2709- }
2710- switch fr := frame .(type ) {
2711- case * http2.GoAwayFrame :
2712- // Records that the server successfully received a GOAWAY frame.
2713- goAwayFrame := fr
2714- if goAwayFrame .ErrCode == http2 .ErrCodeNo {
2715- t .Logf ("Received goAway frame from client" )
2716- close (errorCh )
2717- } else {
2718- errorCh <- fmt .Errorf ("received unexpected goAway frame: %v" , err )
2719- close (errorCh )
2720- }
2721- return
2722- default :
2723- errorCh <- fmt .Errorf ("server received a frame other than GOAWAY: %v" , err )
2724- close (errorCh )
2725- return
2726- }
2727- }()
2728-
2729- ct , err := NewClientTransport (ctx , context .Background (), resolver.Address {Addr : lis .Addr ().String ()}, ConnectOptions {}, func (GoAwayReason ) {})
2730- if err != nil {
2731- t .Fatalf ("Error while creating client transport: %v" , err )
2732- }
2733- _ , err = ct .NewStream (ctx , & CallHdr {})
2734- if err != nil {
2735- t .Fatalf ("failed to open stream: %v" , err )
2736- }
2737- // Wait until server receives the headers and settings frame as part of greet.
2738- <- greetDone
2739- ct .Close (errors .New ("manually closed by client" ))
2740- select {
2741- case err := <- errorCh :
2742- if err != nil {
2743- t .Errorf ("Error receiving the GOAWAY frame: %v" , err )
2744- }
2745- case <- ctx .Done ():
2746- t .Errorf ("Context timed out" )
2747- }
2665+ createClientServerConn (t , ConnectOptions {})
27482666}
27492667
27502668var writeHangSignal chan struct {}
27512669
2670+ // hangingConn is a net.Conn wrapper for testing, simulating hanging connections
2671+ // after a GOAWAY frame is sent, of which Write operations pause until explicitly signaled
2672+ // or a timeout occurs.
27522673type hangingConn struct {
27532674 net.Conn
27542675}
@@ -2761,8 +2682,11 @@ func (hc *hangingConn) Read(b []byte) (n int, err error) {
27612682func (hc * hangingConn ) Write (b []byte ) (n int , err error ) {
27622683 n , err = hc .Conn .Write (b )
27632684 if n == goAwayFrameSize { // GOAWAY frame
2764- writeHangSignal = make (chan struct {})
2765- time .Sleep (15 * time .Second )
2685+ timer := time .NewTimer (GoAwayLoopyWriterTimeout )
2686+ select {
2687+ case <- writeHangSignal :
2688+ case <- timer .C :
2689+ }
27662690 }
27672691 return n , err
27682692}
@@ -2801,8 +2725,20 @@ func hangingDialer(_ context.Context, addr string) (net.Conn, error) {
28012725
28022726// TestClientCloseTimeoutOnHang verifies that in the event of a graceful
28032727// client transport shutdown, i.e., clientTransport.Close(), if the conn hung
2804- // forever, client should still be close itself and do not wait for long.
2728+ // for LoopyWriterTimeout, client should still be close itself and should
2729+ // not wait for long.
28052730func (s ) TestClientCloseTimeoutOnHang (t * testing.T ) {
2731+ writeHangSignal = make (chan struct {})
2732+ ctx , _ , _ := createClientServerConn (t , ConnectOptions {Dialer : hangingDialer })
2733+ defer close (writeHangSignal )
2734+ select {
2735+ case <- writeHangSignal :
2736+ t .Errorf ("error: channel closed too early." )
2737+ case <- ctx .Done ():
2738+ }
2739+ }
2740+
2741+ func createClientServerConn (t * testing.T , connectOptions ConnectOptions ) (context.Context , chan error , ClientTransport ) {
28062742 // Create a server.
28072743 lis , err := net .Listen ("tcp" , "localhost:0" )
28082744 if err != nil {
@@ -2868,7 +2804,7 @@ func (s) TestClientCloseTimeoutOnHang(t *testing.T) {
28682804 }
28692805 }()
28702806
2871- ct , err := NewClientTransport (ctx , context .Background (), resolver.Address {Addr : lis .Addr ().String ()}, ConnectOptions { Dialer : hangingDialer } , func (GoAwayReason ) {})
2807+ ct , err := NewClientTransport (ctx , context .Background (), resolver.Address {Addr : lis .Addr ().String ()}, connectOptions , func (GoAwayReason ) {})
28722808 if err != nil {
28732809 t .Fatalf ("Error while creating client transport: %v" , err )
28742810 }
@@ -2879,11 +2815,13 @@ func (s) TestClientCloseTimeoutOnHang(t *testing.T) {
28792815 // Wait until server receives the headers and settings frame as part of greet.
28802816 <- greetDone
28812817 ct .Close (errors .New ("manually closed by client" ))
2882- defer close (writeHangSignal )
28832818 select {
2884- case <- writeHangSignal :
2885- t .Errorf ("error: channel closed too early." )
2819+ case err := <- errorCh :
2820+ if err != nil {
2821+ t .Errorf ("Error receiving the GOAWAY frame: %v" , err )
2822+ }
28862823 case <- ctx .Done ():
2824+ t .Errorf ("Context timed out" )
28872825 }
2888-
2826+ return ctx , errorCh , ct
28892827}
0 commit comments