google.golang.org/grpc@v1.62.1/interop/xds/custom_lb_test.go (about) 1 /* 2 * 3 * Copyright 2023 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 xds 20 21 import ( 22 "context" 23 "errors" 24 "fmt" 25 "testing" 26 "time" 27 28 "google.golang.org/grpc" 29 "google.golang.org/grpc/credentials/insecure" 30 "google.golang.org/grpc/internal" 31 "google.golang.org/grpc/internal/grpctest" 32 "google.golang.org/grpc/internal/stubserver" 33 "google.golang.org/grpc/internal/testutils" 34 testgrpc "google.golang.org/grpc/interop/grpc_testing" 35 testpb "google.golang.org/grpc/interop/grpc_testing" 36 "google.golang.org/grpc/metadata" 37 "google.golang.org/grpc/resolver" 38 "google.golang.org/grpc/resolver/manual" 39 "google.golang.org/grpc/serviceconfig" 40 ) 41 42 var defaultTestTimeout = 5 * time.Second 43 44 type s struct { 45 grpctest.Tester 46 } 47 48 func Test(t *testing.T) { 49 grpctest.RunSubTests(t, s{}) 50 } 51 52 // TestCustomLB tests the Custom LB for the interop client. It configures the 53 // custom lb as the top level Load Balancing policy of the channel, then asserts 54 // it can successfully make an RPC and also that the rpc behavior the Custom LB 55 // is configured with makes it's way to the server in metadata. 56 func (s) TestCustomLB(t *testing.T) { 57 errCh := testutils.NewChannel() 58 // Setup a backend which verifies the expected rpc-behavior metadata is 59 // present in the request. 60 backend := &stubserver.StubServer{ 61 UnaryCallF: func(ctx context.Context, in *testpb.SimpleRequest) (*testpb.SimpleResponse, error) { 62 md, ok := metadata.FromIncomingContext(ctx) 63 if !ok { 64 errCh.Send(errors.New("failed to receive metadata")) 65 return &testpb.SimpleResponse{}, nil 66 } 67 rpcBMD := md.Get("rpc-behavior") 68 if len(rpcBMD) != 1 { 69 errCh.Send(fmt.Errorf("received %d values for metadata key \"rpc-behavior\", want 1", len(rpcBMD))) 70 return &testpb.SimpleResponse{}, nil 71 } 72 wantVal := "error-code-0" 73 if rpcBMD[0] != wantVal { 74 errCh.Send(fmt.Errorf("metadata val for key \"rpc-behavior\": got val %v, want val %v", rpcBMD[0], wantVal)) 75 return &testpb.SimpleResponse{}, nil 76 } 77 // Success. 78 errCh.Send(nil) 79 return &testpb.SimpleResponse{}, nil 80 }, 81 } 82 if err := backend.StartServer(); err != nil { 83 t.Fatalf("Failed to start backend: %v", err) 84 } 85 t.Logf("Started good TestService backend at: %q", backend.Address) 86 defer backend.Stop() 87 88 lbCfgJSON := `{ 89 "loadBalancingConfig": [ 90 { 91 "test.RpcBehaviorLoadBalancer": { 92 "rpcBehavior": "error-code-0" 93 } 94 } 95 ] 96 }` 97 98 sc := internal.ParseServiceConfig.(func(string) *serviceconfig.ParseResult)(lbCfgJSON) 99 mr := manual.NewBuilderWithScheme("customlb-e2e") 100 defer mr.Close() 101 mr.InitialState(resolver.State{ 102 Addresses: []resolver.Address{ 103 {Addr: backend.Address}, 104 }, 105 ServiceConfig: sc, 106 }) 107 108 cc, err := grpc.Dial(mr.Scheme()+":///", grpc.WithResolvers(mr), grpc.WithTransportCredentials(insecure.NewCredentials())) 109 if err != nil { 110 t.Fatalf("grpc.Dial() failed: %v", err) 111 } 112 defer cc.Close() 113 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 114 defer cancel() 115 testServiceClient := testgrpc.NewTestServiceClient(cc) 116 117 // Make a Unary RPC. This RPC should be successful due to the round_robin 118 // leaf balancer. Also, the custom load balancer should inject the 119 // "rpc-behavior" string it is configured with into the metadata sent to 120 // server. 121 if _, err := testServiceClient.UnaryCall(ctx, &testpb.SimpleRequest{}); err != nil { 122 t.Fatalf("EmptyCall() failed: %v", err) 123 } 124 125 val, err := errCh.Receive(ctx) 126 if err != nil { 127 t.Fatalf("error receiving from errCh: %v", err) 128 } 129 130 // Should receive nil on the error channel which implies backend verified it 131 // correctly received the correct "rpc-behavior" metadata. 132 if err, ok := val.(error); ok { 133 t.Fatalf("error in backend verifications on metadata received: %v", err) 134 } 135 }