gitee.com/ks-custle/core-gm@v0.0.0-20230922171213-b83bdd97b62c/grpc/test/gracefulstop_test.go (about) 1 /* 2 * 3 * Copyright 2017 gRPC authors. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 19 package test 20 21 import ( 22 "context" 23 "fmt" 24 "net" 25 "sync" 26 "testing" 27 "time" 28 29 grpc "gitee.com/ks-custle/core-gm/grpc" 30 "gitee.com/ks-custle/core-gm/grpc/codes" 31 "gitee.com/ks-custle/core-gm/grpc/internal/stubserver" 32 "gitee.com/ks-custle/core-gm/grpc/status" 33 testpb "gitee.com/ks-custle/core-gm/grpc/test/grpc_testing" 34 ) 35 36 type delayListener struct { 37 net.Listener 38 closeCalled chan struct{} 39 acceptCalled chan struct{} 40 allowCloseCh chan struct{} 41 dialed bool 42 } 43 44 func (d *delayListener) Accept() (net.Conn, error) { 45 select { 46 case <-d.acceptCalled: 47 // On the second call, block until closed, then return an error. 48 <-d.closeCalled 49 <-d.allowCloseCh 50 return nil, fmt.Errorf("listener is closed") 51 default: 52 close(d.acceptCalled) 53 conn, err := d.Listener.Accept() 54 if err != nil { 55 return nil, err 56 } 57 // Allow closing of listener only after accept. 58 // Note: Dial can return successfully, yet Accept 59 // might now have finished. 60 d.allowClose() 61 return conn, nil 62 } 63 } 64 65 func (d *delayListener) allowClose() { 66 close(d.allowCloseCh) 67 } 68 func (d *delayListener) Close() error { 69 close(d.closeCalled) 70 go func() { 71 <-d.allowCloseCh 72 d.Listener.Close() 73 }() 74 return nil 75 } 76 77 func (d *delayListener) Dial(ctx context.Context) (net.Conn, error) { 78 if d.dialed { 79 // Only hand out one connection (net.Dial can return more even after the 80 // listener is closed). This is not thread-safe, but Dial should never be 81 // called concurrently in this environment. 82 return nil, fmt.Errorf("no more conns") 83 } 84 d.dialed = true 85 return (&net.Dialer{}).DialContext(ctx, "tcp", d.Listener.Addr().String()) 86 } 87 88 func (s) TestGracefulStop(t *testing.T) { 89 // This test ensures GracefulStop causes new connections to fail. 90 // 91 // Steps of this test: 92 // 1. Start Server 93 // 2. GracefulStop() Server after listener's Accept is called, but don't 94 // allow Accept() to exit when Close() is called on it. 95 // 3. Create a new connection to the server after listener.Close() is called. 96 // Server should close this connection immediately, before handshaking. 97 // 4. Send an RPC on the new connection. Should see Unavailable error 98 // because the ClientConn is in transient failure. 99 lis, err := net.Listen("tcp", "localhost:0") 100 if err != nil { 101 t.Fatalf("Error listenening: %v", err) 102 } 103 dlis := &delayListener{ 104 Listener: lis, 105 acceptCalled: make(chan struct{}), 106 closeCalled: make(chan struct{}), 107 allowCloseCh: make(chan struct{}), 108 } 109 d := func(ctx context.Context, _ string) (net.Conn, error) { return dlis.Dial(ctx) } 110 111 ss := &stubserver.StubServer{ 112 FullDuplexCallF: func(stream testpb.TestService_FullDuplexCallServer) error { 113 _, err := stream.Recv() 114 if err != nil { 115 return err 116 } 117 return stream.Send(&testpb.StreamingOutputCallResponse{}) 118 }, 119 } 120 s := grpc.NewServer() 121 testpb.RegisterTestServiceServer(s, ss) 122 123 // 1. Start Server 124 wg := sync.WaitGroup{} 125 wg.Add(1) 126 go func() { 127 s.Serve(dlis) 128 wg.Done() 129 }() 130 131 // 2. GracefulStop() Server after listener's Accept is called, but don't 132 // allow Accept() to exit when Close() is called on it. 133 <-dlis.acceptCalled 134 wg.Add(1) 135 go func() { 136 s.GracefulStop() 137 wg.Done() 138 }() 139 140 // 3. Create a new connection to the server after listener.Close() is called. 141 // Server should close this connection immediately, before handshaking. 142 143 <-dlis.closeCalled // Block until GracefulStop calls dlis.Close() 144 145 // Now dial. The listener's Accept method will return a valid connection, 146 // even though GracefulStop has closed the listener. 147 ctx, dialCancel := context.WithTimeout(context.Background(), 5*time.Second) 148 defer dialCancel() 149 cc, err := grpc.DialContext(ctx, "", grpc.WithInsecure(), grpc.WithContextDialer(d)) 150 if err != nil { 151 t.Fatalf("grpc.DialContext(_, %q, _) = %v", lis.Addr().String(), err) 152 } 153 client := testpb.NewTestServiceClient(cc) 154 defer cc.Close() 155 156 // 4. Send an RPC on the new connection. 157 // The server would send a GOAWAY first, but we are delaying the server's 158 // writes for now until the client writes more than the preface. 159 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) 160 if _, err = client.FullDuplexCall(ctx); err == nil || status.Code(err) != codes.Unavailable { 161 t.Fatalf("FullDuplexCall= _, %v; want _, <status code Unavailable>", err) 162 } 163 cancel() 164 wg.Wait() 165 }