@@ -32,6 +32,7 @@ import (
32
32
"strconv"
33
33
"strings"
34
34
"sync"
35
+ "sync/atomic"
35
36
"testing"
36
37
"time"
37
38
@@ -58,8 +59,6 @@ func Test(t *testing.T) {
58
59
grpctest .RunSubTests (t , s {})
59
60
}
60
61
61
- const goAwayFrameSize = 42
62
-
63
62
var (
64
63
expectedRequest = []byte ("ping" )
65
64
expectedResponse = []byte ("pong" )
@@ -2754,25 +2753,18 @@ func (s) TestClientSendsAGoAwayFrame(t *testing.T) {
2754
2753
// signaled or a timeout occurs.
2755
2754
type hangingConn struct {
2756
2755
net.Conn
2757
- hangConn chan struct {}
2756
+ hangConn chan struct {}
2757
+ startHanging * atomic.Bool
2758
2758
}
2759
2759
2760
2760
func (hc * hangingConn ) Write (b []byte ) (n int , err error ) {
2761
2761
n , err = hc .Conn .Write (b )
2762
- if n == goAwayFrameSize { // hang the conn after the goAway is received
2762
+ if hc . startHanging . Load () == true {
2763
2763
<- hc .hangConn
2764
2764
}
2765
2765
return n , err
2766
2766
}
2767
2767
2768
- func hangingDialer (_ context.Context , addr string ) (net.Conn , error ) {
2769
- conn , err := net .Dial ("tcp" , addr )
2770
- if err != nil {
2771
- return nil , err
2772
- }
2773
- return & hangingConn {Conn : conn , hangConn : make (chan struct {})}, nil
2774
- }
2775
-
2776
2768
// Tests the scenario where a client transport is closed and writing of the
2777
2769
// GOAWAY frame as part of the close does not complete because of a network
2778
2770
// hang. The test verifies that the client transport is closed without waiting
@@ -2788,7 +2780,27 @@ func (s) TestClientCloseReturnsEarlyWhenGoAwayWriteHangs(t *testing.T) {
2788
2780
}()
2789
2781
2790
2782
// Create the server set up.
2791
- server , ct , cancel := setUpWithOptions (t , 0 , & ServerConfig {}, normal , ConnectOptions {Dialer : hangingDialer })
2783
+ connectCtx , cancel := context .WithDeadline (context .Background (), time .Now ().Add (2 * time .Second ))
2784
+ server := setUpServerOnly (t , 0 , & ServerConfig {}, normal )
2785
+ addr := resolver.Address {Addr : "localhost:" + server .port }
2786
+ isGreetingDone := & atomic.Bool {}
2787
+ hangConn := make (chan struct {})
2788
+ dialer := func (_ context.Context , addr string ) (net.Conn , error ) {
2789
+ conn , err := net .Dial ("tcp" , addr )
2790
+ if err != nil {
2791
+ return nil , err
2792
+ }
2793
+ isGreetingDone .Store (false )
2794
+ return & hangingConn {Conn : conn , hangConn : hangConn , startHanging : isGreetingDone }, nil
2795
+ }
2796
+ copts := ConnectOptions {Dialer : dialer }
2797
+ copts .ChannelzParent = channelzSubChannel (t )
2798
+ // Create client transport with custom dialer
2799
+ ct , connErr := NewClientTransport (connectCtx , context .Background (), addr , copts , func (GoAwayReason ) {})
2800
+ if connErr != nil {
2801
+ cancel () // Do not cancel in success path.
2802
+ t .Fatalf ("failed to create transport: %v" , connErr )
2803
+ }
2792
2804
defer cancel ()
2793
2805
defer server .stop ()
2794
2806
@@ -2797,5 +2809,8 @@ func (s) TestClientCloseReturnsEarlyWhenGoAwayWriteHangs(t *testing.T) {
2797
2809
if _ , err := ct .NewStream (ctx , & CallHdr {}); err != nil {
2798
2810
t .Fatalf ("Failed to open stream: %v" , err )
2799
2811
}
2812
+
2813
+ isGreetingDone .Store (true )
2800
2814
ct .Close (errors .New ("manually closed by client" ))
2815
+ close (hangConn )
2801
2816
}
0 commit comments