github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/grpc/xds/internal/test/xds_client_integration_test.go (about) 1 //go:build !386 2 // +build !386 3 4 /* 5 * 6 * Copyright 2021 gRPC authors. 7 * 8 * Licensed under the Apache License, Version 2.0 (the "License"); 9 * you may not use this file except in compliance with the License. 10 * You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, software 15 * distributed under the License is distributed on an "AS IS" BASIS, 16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 * See the License for the specific language governing permissions and 18 * limitations under the License. 19 * 20 */ 21 22 package xds_test 23 24 import ( 25 "context" 26 "fmt" 27 "net" 28 "testing" 29 30 grpc "github.com/hxx258456/ccgo/grpc" 31 "github.com/hxx258456/ccgo/grpc/codes" 32 "github.com/hxx258456/ccgo/grpc/credentials/insecure" 33 "github.com/hxx258456/ccgo/grpc/internal/stubserver" 34 "github.com/hxx258456/ccgo/grpc/internal/testutils" 35 "github.com/hxx258456/ccgo/grpc/status" 36 "github.com/hxx258456/ccgo/grpc/xds/internal/testutils/e2e" 37 38 wrapperspb "github.com/golang/protobuf/ptypes/wrappers" 39 v3routepb "github.com/hxx258456/ccgo/go-control-plane/envoy/config/route/v3" 40 testpb "github.com/hxx258456/ccgo/grpc/test/grpc_testing" 41 ) 42 43 // clientSetup performs a bunch of steps common to all xDS client tests here: 44 // - spin up a gRPC server and register the test service on it 45 // - create a local TCP listener and start serving on it 46 // 47 // Returns the following: 48 // - the port the server is listening on 49 // - cleanup function to be invoked by the tests when done 50 func clientSetup(t *testing.T, tss testpb.TestServiceServer) (uint32, func()) { 51 // Initialize a gRPC server and register the stubServer on it. 52 server := grpc.NewServer() 53 testpb.RegisterTestServiceServer(server, tss) 54 55 // Create a local listener and pass it to Serve(). 56 lis, err := testutils.LocalTCPListener() 57 if err != nil { 58 t.Fatalf("testutils.LocalTCPListener() failed: %v", err) 59 } 60 61 go func() { 62 if err := server.Serve(lis); err != nil { 63 t.Errorf("Serve() failed: %v", err) 64 } 65 }() 66 67 return uint32(lis.Addr().(*net.TCPAddr).Port), func() { 68 server.Stop() 69 } 70 } 71 72 func (s) TestClientSideXDS(t *testing.T) { 73 managementServer, nodeID, _, resolver, cleanup1 := setupManagementServer(t) 74 defer cleanup1() 75 76 port, cleanup2 := clientSetup(t, &testService{}) 77 defer cleanup2() 78 79 const serviceName = "my-service-client-side-xds" 80 resources := e2e.DefaultClientResources(e2e.ResourceParams{ 81 DialTarget: serviceName, 82 NodeID: nodeID, 83 Host: "localhost", 84 Port: port, 85 SecLevel: e2e.SecurityLevelNone, 86 }) 87 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 88 defer cancel() 89 if err := managementServer.Update(ctx, resources); err != nil { 90 t.Fatal(err) 91 } 92 93 // Create a ClientConn and make a successful RPC. 94 cc, err := grpc.Dial(fmt.Sprintf("xds:///%s", serviceName), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithResolvers(resolver)) 95 if err != nil { 96 t.Fatalf("failed to dial local test server: %v", err) 97 } 98 defer cc.Close() 99 100 client := testpb.NewTestServiceClient(cc) 101 if _, err := client.EmptyCall(ctx, &testpb.Empty{}, grpc.WaitForReady(true)); err != nil { 102 t.Fatalf("rpc EmptyCall() failed: %v", err) 103 } 104 } 105 106 func (s) TestClientSideRetry(t *testing.T) { 107 ctr := 0 108 errs := []codes.Code{codes.ResourceExhausted} 109 ss := &stubserver.StubServer{ 110 EmptyCallF: func(ctx context.Context, in *testpb.Empty) (*testpb.Empty, error) { 111 defer func() { ctr++ }() 112 if ctr < len(errs) { 113 return nil, status.Errorf(errs[ctr], "this should be retried") 114 } 115 return &testpb.Empty{}, nil 116 }, 117 } 118 119 managementServer, nodeID, _, resolver, cleanup1 := setupManagementServer(t) 120 defer cleanup1() 121 122 port, cleanup2 := clientSetup(t, ss) 123 defer cleanup2() 124 125 const serviceName = "my-service-client-side-xds" 126 resources := e2e.DefaultClientResources(e2e.ResourceParams{ 127 DialTarget: serviceName, 128 NodeID: nodeID, 129 Host: "localhost", 130 Port: port, 131 SecLevel: e2e.SecurityLevelNone, 132 }) 133 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 134 if err := managementServer.Update(ctx, resources); err != nil { 135 t.Fatal(err) 136 } 137 138 // Create a ClientConn and make a successful RPC. 139 cc, err := grpc.Dial(fmt.Sprintf("xds:///%s", serviceName), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithResolvers(resolver)) 140 if err != nil { 141 t.Fatalf("failed to dial local test server: %v", err) 142 } 143 defer cc.Close() 144 145 client := testpb.NewTestServiceClient(cc) 146 defer cancel() 147 if _, err := client.EmptyCall(ctx, &testpb.Empty{}, grpc.WaitForReady(true)); status.Code(err) != codes.ResourceExhausted { 148 t.Fatalf("rpc EmptyCall() = _, %v; want _, ResourceExhausted", err) 149 } 150 151 testCases := []struct { 152 name string 153 vhPolicy *v3routepb.RetryPolicy 154 routePolicy *v3routepb.RetryPolicy 155 errs []codes.Code // the errors returned by the server for each RPC 156 tryAgainErr codes.Code // the error that would be returned if we are still using the old retry policies. 157 errWant codes.Code 158 }{{ 159 name: "virtualHost only, fail", 160 vhPolicy: &v3routepb.RetryPolicy{ 161 RetryOn: "resource-exhausted,unavailable", 162 NumRetries: &wrapperspb.UInt32Value{Value: 1}, 163 }, 164 errs: []codes.Code{codes.ResourceExhausted, codes.Unavailable}, 165 routePolicy: nil, 166 tryAgainErr: codes.ResourceExhausted, 167 errWant: codes.Unavailable, 168 }, { 169 name: "virtualHost only", 170 vhPolicy: &v3routepb.RetryPolicy{ 171 RetryOn: "resource-exhausted, unavailable", 172 NumRetries: &wrapperspb.UInt32Value{Value: 2}, 173 }, 174 errs: []codes.Code{codes.ResourceExhausted, codes.Unavailable}, 175 routePolicy: nil, 176 tryAgainErr: codes.Unavailable, 177 errWant: codes.OK, 178 }, { 179 name: "virtualHost+route, fail", 180 vhPolicy: &v3routepb.RetryPolicy{ 181 RetryOn: "resource-exhausted,unavailable", 182 NumRetries: &wrapperspb.UInt32Value{Value: 2}, 183 }, 184 routePolicy: &v3routepb.RetryPolicy{ 185 RetryOn: "resource-exhausted", 186 NumRetries: &wrapperspb.UInt32Value{Value: 2}, 187 }, 188 errs: []codes.Code{codes.ResourceExhausted, codes.Unavailable}, 189 tryAgainErr: codes.OK, 190 errWant: codes.Unavailable, 191 }, { 192 name: "virtualHost+route", 193 vhPolicy: &v3routepb.RetryPolicy{ 194 RetryOn: "resource-exhausted", 195 NumRetries: &wrapperspb.UInt32Value{Value: 2}, 196 }, 197 routePolicy: &v3routepb.RetryPolicy{ 198 RetryOn: "unavailable", 199 NumRetries: &wrapperspb.UInt32Value{Value: 2}, 200 }, 201 errs: []codes.Code{codes.Unavailable}, 202 tryAgainErr: codes.Unavailable, 203 errWant: codes.OK, 204 }, { 205 name: "virtualHost+route, not enough attempts", 206 vhPolicy: &v3routepb.RetryPolicy{ 207 RetryOn: "unavailable", 208 NumRetries: &wrapperspb.UInt32Value{Value: 2}, 209 }, 210 routePolicy: &v3routepb.RetryPolicy{ 211 RetryOn: "unavailable", 212 NumRetries: &wrapperspb.UInt32Value{Value: 1}, 213 }, 214 errs: []codes.Code{codes.Unavailable, codes.Unavailable}, 215 tryAgainErr: codes.OK, 216 errWant: codes.Unavailable, 217 }} 218 219 for _, tc := range testCases { 220 t.Run(tc.name, func(t *testing.T) { 221 errs = tc.errs 222 223 // Confirm tryAgainErr is correct before updating resources. 224 ctr = 0 225 _, err := client.EmptyCall(ctx, &testpb.Empty{}) 226 if code := status.Code(err); code != tc.tryAgainErr { 227 t.Fatalf("with old retry policy: EmptyCall() = _, %v; want _, %v", err, tc.tryAgainErr) 228 } 229 230 resources.Routes[0].VirtualHosts[0].RetryPolicy = tc.vhPolicy 231 resources.Routes[0].VirtualHosts[0].Routes[0].GetRoute().RetryPolicy = tc.routePolicy 232 if err := managementServer.Update(ctx, resources); err != nil { 233 t.Fatal(err) 234 } 235 236 for { 237 ctr = 0 238 _, err := client.EmptyCall(ctx, &testpb.Empty{}) 239 if code := status.Code(err); code == tc.tryAgainErr { 240 continue 241 } else if code != tc.errWant { 242 t.Fatalf("rpc EmptyCall() = _, %v; want _, %v", err, tc.errWant) 243 } 244 break 245 } 246 }) 247 } 248 }