google.golang.org/grpc@v1.62.1/balancer_wrapper_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 grpc 20 21 import ( 22 "fmt" 23 "strings" 24 "sync" 25 "testing" 26 27 "google.golang.org/grpc/balancer" 28 "google.golang.org/grpc/credentials/insecure" 29 "google.golang.org/grpc/internal/balancer/stub" 30 "google.golang.org/grpc/internal/grpcsync" 31 ) 32 33 // TestBalancer_StateListenerBeforeConnect tries to stimulate a race between 34 // NewSubConn and ClientConn.Close. In no cases should the SubConn's 35 // StateListener be invoked, because Connect was never called. 36 func (s) TestBalancer_StateListenerBeforeConnect(t *testing.T) { 37 // started is fired after cc is set so cc can be used in the balancer. 38 started := grpcsync.NewEvent() 39 var cc *ClientConn 40 41 wg := sync.WaitGroup{} 42 wg.Add(2) 43 44 // Create a balancer that calls NewSubConn and cc.Close at approximately the 45 // same time. 46 bf := stub.BalancerFuncs{ 47 UpdateClientConnState: func(bd *stub.BalancerData, ccs balancer.ClientConnState) error { 48 go func() { 49 // Wait for cc to be valid after the channel is created. 50 <-started.Done() 51 // In a goroutine, create the subconn. 52 go func() { 53 _, err := bd.ClientConn.NewSubConn(ccs.ResolverState.Addresses, balancer.NewSubConnOptions{ 54 StateListener: func(scs balancer.SubConnState) { 55 t.Error("Unexpected call to StateListener with:", scs) 56 }, 57 }) 58 if err != nil && !strings.Contains(err.Error(), "connection is closing") && !strings.Contains(err.Error(), "is deleted") && !strings.Contains(err.Error(), "is closed or idle") && !strings.Contains(err.Error(), "balancer is being closed") { 59 t.Error("Unexpected error creating subconn:", err) 60 } 61 wg.Done() 62 }() 63 // At approximately the same time, close the channel. 64 cc.Close() 65 wg.Done() 66 }() 67 return nil 68 }, 69 } 70 stub.Register(t.Name(), bf) 71 svcCfg := fmt.Sprintf(`{ "loadBalancingConfig": [{%q: {}}] }`, t.Name()) 72 73 cc, err := Dial("fake", WithTransportCredentials(insecure.NewCredentials()), WithDefaultServiceConfig(svcCfg)) 74 if err != nil { 75 t.Fatal("Error dialing:", err) 76 } 77 started.Fire() 78 79 // Wait for the LB policy to call NewSubConn and cc.Close. 80 wg.Wait() 81 }