...

Source file src/google.golang.org/grpc/balancer_wrapper_test.go

Documentation: google.golang.org/grpc

     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  }
    82  

View as plain text