google.golang.org/grpc@v1.72.2/test/balancer_switching_test.go (about)

     1  /*
     2   *
     3   * Copyright 2022 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  	"testing"
    25  
    26  	"google.golang.org/grpc"
    27  	"google.golang.org/grpc/balancer"
    28  	grpclbstate "google.golang.org/grpc/balancer/grpclb/state"
    29  	"google.golang.org/grpc/balancer/pickfirst"
    30  	"google.golang.org/grpc/credentials/insecure"
    31  	"google.golang.org/grpc/internal"
    32  	"google.golang.org/grpc/internal/balancer/stub"
    33  	"google.golang.org/grpc/internal/stubserver"
    34  	"google.golang.org/grpc/internal/testutils/fakegrpclb"
    35  	pfutil "google.golang.org/grpc/internal/testutils/pickfirst"
    36  	rrutil "google.golang.org/grpc/internal/testutils/roundrobin"
    37  	"google.golang.org/grpc/resolver"
    38  	"google.golang.org/grpc/resolver/manual"
    39  
    40  	testgrpc "google.golang.org/grpc/interop/grpc_testing"
    41  	testpb "google.golang.org/grpc/interop/grpc_testing"
    42  )
    43  
    44  const (
    45  	loadBalancedServiceName = "foo.bar.service"
    46  	loadBalancedServicePort = 443
    47  	wantGRPCLBTraceDesc     = `Channel switches to new LB policy "grpclb"`
    48  	wantRoundRobinTraceDesc = `Channel switches to new LB policy "round_robin"`
    49  	pickFirstServiceConfig  = `{"loadBalancingConfig": [{"pick_first":{}}]}`
    50  	grpclbServiceConfig     = `{"loadBalancingConfig": [{"grpclb":{}}]}`
    51  
    52  	// This is the number of stub backends set up at the start of each test. The
    53  	// first backend is used for the "grpclb" policy and the rest are used for
    54  	// other LB policies to test balancer switching.
    55  	backendCount = 3
    56  )
    57  
    58  // stubBackendsToResolverAddrs converts from a set of stub server backends to
    59  // resolver addresses. Useful when pushing addresses to the manual resolver.
    60  func stubBackendsToResolverAddrs(backends []*stubserver.StubServer) []resolver.Address {
    61  	addrs := make([]resolver.Address, len(backends))
    62  	for i, backend := range backends {
    63  		addrs[i] = resolver.Address{Addr: backend.Address}
    64  	}
    65  	return addrs
    66  }
    67  
    68  // setupBackendsAndFakeGRPCLB sets up backendCount number of stub server
    69  // backends and a fake grpclb server for tests which exercise balancer switch
    70  // scenarios involving grpclb.
    71  //
    72  // The fake grpclb server always returns the first of the configured stub
    73  // backends as backend addresses. So, the tests are free to use the other
    74  // backends with other LB policies to verify balancer switching scenarios.
    75  //
    76  // Returns a cleanup function to be invoked by the caller.
    77  func setupBackendsAndFakeGRPCLB(t *testing.T) ([]*stubserver.StubServer, *fakegrpclb.Server, func()) {
    78  	backends, backendsCleanup := startBackendsForBalancerSwitch(t)
    79  
    80  	lbServer, err := fakegrpclb.NewServer(fakegrpclb.ServerParams{
    81  		LoadBalancedServiceName: loadBalancedServiceName,
    82  		LoadBalancedServicePort: loadBalancedServicePort,
    83  		BackendAddresses:        []string{backends[0].Address},
    84  	})
    85  	if err != nil {
    86  		t.Fatalf("failed to create fake grpclb server: %v", err)
    87  	}
    88  	go func() {
    89  		if err := lbServer.Serve(); err != nil {
    90  			t.Errorf("fake grpclb Serve() failed: %v", err)
    91  		}
    92  	}()
    93  
    94  	return backends, lbServer, func() {
    95  		backendsCleanup()
    96  		lbServer.Stop()
    97  	}
    98  }
    99  
   100  // startBackendsForBalancerSwitch spins up a bunch of stub server backends
   101  // exposing the TestService. Returns a cleanup function to be invoked by the
   102  // caller.
   103  func startBackendsForBalancerSwitch(t *testing.T) ([]*stubserver.StubServer, func()) {
   104  	t.Helper()
   105  
   106  	backends := make([]*stubserver.StubServer, backendCount)
   107  	for i := 0; i < backendCount; i++ {
   108  		backend := &stubserver.StubServer{
   109  			EmptyCallF: func(context.Context, *testpb.Empty) (*testpb.Empty, error) { return &testpb.Empty{}, nil },
   110  		}
   111  		if err := backend.StartServer(); err != nil {
   112  			t.Fatalf("Failed to start backend: %v", err)
   113  		}
   114  		t.Logf("Started TestService backend at: %q", backend.Address)
   115  		backends[i] = backend
   116  	}
   117  	return backends, func() {
   118  		for _, b := range backends {
   119  			b.Stop()
   120  		}
   121  	}
   122  }
   123  
   124  // TestBalancerSwitch_Basic tests the basic scenario of switching from one LB
   125  // policy to another, as specified in the service config.
   126  func (s) TestBalancerSwitch_Basic(t *testing.T) {
   127  	backends, cleanup := startBackendsForBalancerSwitch(t)
   128  	defer cleanup()
   129  	addrs := stubBackendsToResolverAddrs(backends)
   130  
   131  	r := manual.NewBuilderWithScheme("whatever")
   132  
   133  	r.InitialState(resolver.State{Addresses: addrs})
   134  
   135  	cc, err := grpc.NewClient(r.Scheme()+":///test.server", grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithResolvers(r))
   136  	if err != nil {
   137  		t.Fatalf("grpc.NewClient() failed: %v", err)
   138  	}
   139  	defer cc.Close()
   140  
   141  	// Push a resolver update without an LB policy in the service config. The
   142  	// channel should pick the default LB policy, which is pick_first.
   143  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   144  	defer cancel()
   145  	if err := pfutil.CheckRPCsToBackend(ctx, cc, addrs[0]); err != nil {
   146  		t.Fatal(err)
   147  	}
   148  
   149  	// Push a resolver update with a service config specifying "round_robin".
   150  	r.UpdateState(resolver.State{
   151  		Addresses:     addrs,
   152  		ServiceConfig: parseServiceConfig(t, r, rrServiceConfig),
   153  	})
   154  	client := testgrpc.NewTestServiceClient(cc)
   155  	if err := rrutil.CheckRoundRobinRPCs(ctx, client, addrs); err != nil {
   156  		t.Fatal(err)
   157  	}
   158  
   159  	// Push another resolver update with a service config specifying "pick_first".
   160  	r.UpdateState(resolver.State{
   161  		Addresses:     addrs,
   162  		ServiceConfig: parseServiceConfig(t, r, pickFirstServiceConfig),
   163  	})
   164  	if err := pfutil.CheckRPCsToBackend(ctx, cc, addrs[0]); err != nil {
   165  		t.Fatal(err)
   166  	}
   167  }
   168  
   169  // TestBalancerSwitch_grpclbToPickFirst tests the scenario where the channel
   170  // starts off "grpclb", switches to "pick_first" and back.
   171  func (s) TestBalancerSwitch_grpclbToPickFirst(t *testing.T) {
   172  	backends, lbServer, cleanup := setupBackendsAndFakeGRPCLB(t)
   173  	defer cleanup()
   174  
   175  	addrs := stubBackendsToResolverAddrs(backends)
   176  	r := manual.NewBuilderWithScheme("whatever")
   177  	target := fmt.Sprintf("%s:///%s", r.Scheme(), loadBalancedServiceName)
   178  	cc, err := grpc.NewClient(target, grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithResolvers(r))
   179  	if err != nil {
   180  		t.Fatalf("grpc.NewClient() failed: %v", err)
   181  	}
   182  	defer cc.Close()
   183  	cc.Connect()
   184  
   185  	// Push a resolver update with a GRPCLB service config and a single address
   186  	// pointing to the grpclb server we created above. This will cause the
   187  	// channel to switch to the "grpclb" balancer, which returns a single
   188  	// backend address.
   189  	grpclbConfig := parseServiceConfig(t, r, grpclbServiceConfig)
   190  	state := resolver.State{ServiceConfig: grpclbConfig}
   191  	r.UpdateState(grpclbstate.Set(state, &grpclbstate.State{BalancerAddresses: []resolver.Address{{Addr: lbServer.Address()}}}))
   192  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   193  	defer cancel()
   194  	client := testgrpc.NewTestServiceClient(cc)
   195  	if err := rrutil.CheckRoundRobinRPCs(ctx, client, addrs[0:1]); err != nil {
   196  		t.Fatal(err)
   197  	}
   198  
   199  	// Push a resolver update containing a non-existent grpclb server address.
   200  	// This should not lead to a balancer switch.
   201  	const nonExistentServer = "non-existent-grpclb-server-address"
   202  	r.UpdateState(grpclbstate.Set(state, &grpclbstate.State{BalancerAddresses: []resolver.Address{{Addr: nonExistentServer}}}))
   203  	if err := rrutil.CheckRoundRobinRPCs(ctx, client, addrs[:1]); err != nil {
   204  		t.Fatal(err)
   205  	}
   206  
   207  	// Push a resolver update containing no grpclb server address. This should
   208  	// lead to the channel using the default LB policy which is pick_first. The
   209  	// list of addresses pushed as part of this update is different from the one
   210  	// returned by the "grpclb" balancer. So, we should see RPCs going to the
   211  	// newly configured backends, as part of the balancer switch.
   212  	emptyConfig := parseServiceConfig(t, r, `{}`)
   213  	r.UpdateState(resolver.State{Addresses: addrs[1:], ServiceConfig: emptyConfig})
   214  	if err := pfutil.CheckRPCsToBackend(ctx, cc, addrs[1]); err != nil {
   215  		t.Fatal(err)
   216  	}
   217  }
   218  
   219  // TestBalancerSwitch_pickFirstToGRPCLB tests the scenario where the channel
   220  // starts off with "pick_first", switches to "grpclb" and back.
   221  func (s) TestBalancerSwitch_pickFirstToGRPCLB(t *testing.T) {
   222  	backends, lbServer, cleanup := setupBackendsAndFakeGRPCLB(t)
   223  	defer cleanup()
   224  
   225  	addrs := stubBackendsToResolverAddrs(backends)
   226  	r := manual.NewBuilderWithScheme("whatever")
   227  	target := fmt.Sprintf("%s:///%s", r.Scheme(), loadBalancedServiceName)
   228  	cc, err := grpc.NewClient(target, grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithResolvers(r))
   229  	if err != nil {
   230  		t.Fatalf("grpc.NewClient() failed: %v", err)
   231  	}
   232  	defer cc.Close()
   233  
   234  	// Set an empty initial resolver state. This should lead to the channel
   235  	// using the default LB policy which is pick_first.
   236  	r.InitialState(resolver.State{Addresses: addrs[1:]})
   237  
   238  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   239  	defer cancel()
   240  	if err := pfutil.CheckRPCsToBackend(ctx, cc, addrs[1]); err != nil {
   241  		t.Fatal(err)
   242  	}
   243  
   244  	// Push a resolver update with no service config and a single address pointing
   245  	// to the grpclb server we created above. This will cause the channel to
   246  	// switch to the "grpclb" balancer, which returns a single backend address.
   247  	grpclbConfig := parseServiceConfig(t, r, grpclbServiceConfig)
   248  	state := resolver.State{ServiceConfig: grpclbConfig}
   249  	r.UpdateState(grpclbstate.Set(state, &grpclbstate.State{BalancerAddresses: []resolver.Address{{Addr: lbServer.Address()}}}))
   250  	client := testgrpc.NewTestServiceClient(cc)
   251  	if err := rrutil.CheckRoundRobinRPCs(ctx, client, addrs[:1]); err != nil {
   252  		t.Fatal(err)
   253  	}
   254  
   255  	// Push a resolver update containing a non-existent grpclb server address.
   256  	// This should not lead to a balancer switch.
   257  	r.UpdateState(grpclbstate.Set(state, &grpclbstate.State{BalancerAddresses: []resolver.Address{{Addr: "nonExistentServer"}}}))
   258  	if err := rrutil.CheckRoundRobinRPCs(ctx, client, addrs[:1]); err != nil {
   259  		t.Fatal(err)
   260  	}
   261  
   262  	// Switch to "pick_first" again by sending no grpclb server addresses.
   263  	emptyConfig := parseServiceConfig(t, r, `{}`)
   264  	r.UpdateState(resolver.State{Addresses: addrs[1:], ServiceConfig: emptyConfig})
   265  	if err := pfutil.CheckRPCsToBackend(ctx, cc, addrs[1]); err != nil {
   266  		t.Fatal(err)
   267  	}
   268  }
   269  
   270  // TestBalancerSwitch_RoundRobinToGRPCLB tests the scenario where the channel
   271  // starts off with "round_robin", switches to "grpclb" and back.
   272  //
   273  // Note that this test uses the deprecated `loadBalancingPolicy` field in the
   274  // service config.
   275  func (s) TestBalancerSwitch_RoundRobinToGRPCLB(t *testing.T) {
   276  	backends, lbServer, cleanup := setupBackendsAndFakeGRPCLB(t)
   277  	defer cleanup()
   278  
   279  	addrs := stubBackendsToResolverAddrs(backends)
   280  	r := manual.NewBuilderWithScheme("whatever")
   281  	target := fmt.Sprintf("%s:///%s", r.Scheme(), loadBalancedServiceName)
   282  	cc, err := grpc.NewClient(target, grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithResolvers(r))
   283  	if err != nil {
   284  		t.Fatalf("grpc.NewClient() failed: %v", err)
   285  	}
   286  	defer cc.Close()
   287  	cc.Connect()
   288  	// Note the use of the deprecated `loadBalancingPolicy` field here instead
   289  	// of the now recommended `loadBalancingConfig` field. The logic in the
   290  	// ClientConn which decides which balancer to switch to looks at the
   291  	// following places in the given order of preference:
   292  	// - `loadBalancingConfig` field
   293  	// - addresses of type grpclb
   294  	// - `loadBalancingPolicy` field
   295  	// If we use the `loadBalancingPolicy` field, the switch to "grpclb" later on
   296  	// in the test will not happen as the ClientConn will continue to use the LB
   297  	// policy received in the first update.
   298  	scpr := parseServiceConfig(t, r, rrServiceConfig)
   299  
   300  	// Push a resolver update with the service config specifying "round_robin".
   301  	r.UpdateState(resolver.State{Addresses: addrs[1:], ServiceConfig: scpr})
   302  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   303  	defer cancel()
   304  	client := testgrpc.NewTestServiceClient(cc)
   305  	if err := rrutil.CheckRoundRobinRPCs(ctx, client, addrs[1:]); err != nil {
   306  		t.Fatal(err)
   307  	}
   308  
   309  	// Push a resolver update with grpclb and a single balancer address
   310  	// pointing to the grpclb server we created above. This will cause the
   311  	// channel to switch to the "grpclb" balancer, which returns a single
   312  	// backend address.
   313  	grpclbConfig := parseServiceConfig(t, r, grpclbServiceConfig)
   314  	state := resolver.State{ServiceConfig: grpclbConfig}
   315  	r.UpdateState(grpclbstate.Set(state, &grpclbstate.State{BalancerAddresses: []resolver.Address{{Addr: lbServer.Address()}}}))
   316  	if err := rrutil.CheckRoundRobinRPCs(ctx, client, addrs[:1]); err != nil {
   317  		t.Fatal(err)
   318  	}
   319  
   320  	// Switch back to "round_robin".
   321  	r.UpdateState(resolver.State{Addresses: addrs[1:], ServiceConfig: scpr})
   322  	if err := rrutil.CheckRoundRobinRPCs(ctx, client, addrs[1:]); err != nil {
   323  		t.Fatal(err)
   324  	}
   325  }
   326  
   327  // TestBalancerSwitch_grpclbNotRegistered tests the scenario where the grpclb
   328  // balancer is not registered. Verifies that the ClientConn falls back to the
   329  // default LB policy or the LB policy specified in the service config, and that
   330  // addresses of type "grpclb" are filtered out.
   331  func (s) TestBalancerSwitch_grpclbNotRegistered(t *testing.T) {
   332  	// Unregister the grpclb balancer builder for the duration of this test.
   333  	grpclbBuilder := balancer.Get("grpclb")
   334  	internal.BalancerUnregister(grpclbBuilder.Name())
   335  	defer balancer.Register(grpclbBuilder)
   336  
   337  	backends, cleanup := startBackendsForBalancerSwitch(t)
   338  	defer cleanup()
   339  	addrs := stubBackendsToResolverAddrs(backends)
   340  
   341  	r := manual.NewBuilderWithScheme("whatever")
   342  	cc, err := grpc.NewClient(r.Scheme()+":///test.server", grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithResolvers(r))
   343  	if err != nil {
   344  		t.Fatalf("grpc.NewClient() failed: %v", err)
   345  	}
   346  	defer cc.Close()
   347  	cc.Connect()
   348  
   349  	// Push a resolver update which contains a bunch of stub server backends and a
   350  	// grpclb server address. The latter should get the ClientConn to try and
   351  	// apply the grpclb policy. But since grpclb is not registered, it should
   352  	// fallback to the default LB policy which is pick_first. The ClientConn is
   353  	// also expected to filter out the grpclb address when sending the addresses
   354  	// list for pick_first.
   355  	grpclbAddr := []resolver.Address{{Addr: "non-existent-grpclb-server-address"}}
   356  	grpclbConfig := parseServiceConfig(t, r, `{"loadBalancingPolicy": "grpclb"}`)
   357  	state := resolver.State{ServiceConfig: grpclbConfig, Addresses: addrs}
   358  	r.UpdateState(grpclbstate.Set(state, &grpclbstate.State{BalancerAddresses: grpclbAddr}))
   359  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   360  	defer cancel()
   361  	if err := pfutil.CheckRPCsToBackend(ctx, cc, addrs[0]); err != nil {
   362  		t.Fatalf("Pick_first backend readiness check failed: %v", err)
   363  	}
   364  
   365  	// Push a resolver update with the same addresses, but with a service config
   366  	// specifying "round_robin". The ClientConn is expected to filter out the
   367  	// grpclb address when sending the addresses list to round_robin.
   368  	r.UpdateState(resolver.State{
   369  		Addresses:     addrs,
   370  		ServiceConfig: parseServiceConfig(t, r, rrServiceConfig),
   371  	})
   372  	client := testgrpc.NewTestServiceClient(cc)
   373  	if err := rrutil.CheckRoundRobinRPCs(ctx, client, addrs); err != nil {
   374  		t.Fatalf("Round robin RPCs failed: %v", err)
   375  	}
   376  }
   377  
   378  // TestBalancerSwitch_OldBalancerCallsShutdownInClose tests the scenario where
   379  // the balancer being switched out calls Shutdown() in its Close()
   380  // method. Verifies that this sequence of calls doesn't lead to a deadlock.
   381  func (s) TestBalancerSwitch_OldBalancerCallsShutdownInClose(t *testing.T) {
   382  	// Register a stub balancer which calls Shutdown() from its Close().
   383  	scChan := make(chan balancer.SubConn, 1)
   384  	uccsCalled := make(chan struct{}, 1)
   385  	stub.Register(t.Name(), stub.BalancerFuncs{
   386  		UpdateClientConnState: func(data *stub.BalancerData, ccs balancer.ClientConnState) error {
   387  			sc, err := data.ClientConn.NewSubConn(ccs.ResolverState.Addresses, balancer.NewSubConnOptions{})
   388  			if err != nil {
   389  				t.Errorf("failed to create subConn: %v", err)
   390  			}
   391  			scChan <- sc
   392  			close(uccsCalled)
   393  			return nil
   394  		},
   395  		Close: func(*stub.BalancerData) {
   396  			(<-scChan).Shutdown()
   397  		},
   398  	})
   399  
   400  	r := manual.NewBuilderWithScheme("whatever")
   401  	cc, err := grpc.NewClient(r.Scheme()+":///test.server", grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithResolvers(r))
   402  	if err != nil {
   403  		t.Fatalf("grpc.NewClient() failed: %v", err)
   404  	}
   405  	cc.Connect()
   406  	defer cc.Close()
   407  
   408  	// Push a resolver update specifying our stub balancer as the LB policy.
   409  	scpr := parseServiceConfig(t, r, fmt.Sprintf(`{"loadBalancingPolicy": "%v"}`, t.Name()))
   410  	r.UpdateState(resolver.State{
   411  		Addresses:     []resolver.Address{{Addr: "dummy-address"}},
   412  		ServiceConfig: scpr,
   413  	})
   414  
   415  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   416  	defer cancel()
   417  	select {
   418  	case <-ctx.Done():
   419  		t.Fatalf("timeout waiting for UpdateClientConnState to be called: %v", ctx.Err())
   420  	case <-uccsCalled:
   421  	}
   422  
   423  	// The following service config update will switch balancer from our stub
   424  	// balancer to pick_first. The former will be closed, which will call
   425  	// sc.Shutdown() inline.
   426  	//
   427  	// This is to make sure the sc.Shutdown() from Close() doesn't cause a
   428  	// deadlock (e.g. trying to grab a mutex while it's already locked).
   429  	//
   430  	// Do it in a goroutine so this test will fail with a helpful message
   431  	// (though the goroutine will still leak).
   432  	done := make(chan struct{})
   433  	go func() {
   434  		r.UpdateState(resolver.State{
   435  			Addresses:     []resolver.Address{{Addr: "dummy-address"}},
   436  			ServiceConfig: parseServiceConfig(t, r, pickFirstServiceConfig),
   437  		})
   438  		close(done)
   439  	}()
   440  
   441  	select {
   442  	case <-ctx.Done():
   443  		t.Fatalf("timeout waiting for resolver.UpdateState to finish: %v", ctx.Err())
   444  	case <-done:
   445  	}
   446  }
   447  
   448  // TestBalancerSwitch_Graceful tests the graceful switching of LB policies. It
   449  // starts off by configuring "round_robin" on the channel and ensures that RPCs
   450  // are successful. Then, it switches to a stub balancer which does not report a
   451  // picker until instructed by the test do to so. At this point, the test
   452  // verifies that RPCs are still successful using the old balancer. Then the test
   453  // asks the new balancer to report a healthy picker and the test verifies that
   454  // the RPCs get routed using the picker reported by the new balancer.
   455  func (s) TestBalancerSwitch_Graceful(t *testing.T) {
   456  	backends, cleanup := startBackendsForBalancerSwitch(t)
   457  	defer cleanup()
   458  	addrs := stubBackendsToResolverAddrs(backends)
   459  
   460  	r := manual.NewBuilderWithScheme("whatever")
   461  	cc, err := grpc.NewClient(r.Scheme()+":///test.server", grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithResolvers(r))
   462  	if err != nil {
   463  		t.Fatalf("grpc.NewClient() failed: %v", err)
   464  	}
   465  	defer cc.Close()
   466  	cc.Connect()
   467  	// Push a resolver update with the service config specifying "round_robin".
   468  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   469  	defer cancel()
   470  	r.UpdateState(resolver.State{
   471  		Addresses:     addrs[1:],
   472  		ServiceConfig: parseServiceConfig(t, r, rrServiceConfig),
   473  	})
   474  	client := testgrpc.NewTestServiceClient(cc)
   475  	if err := rrutil.CheckRoundRobinRPCs(ctx, client, addrs[1:]); err != nil {
   476  		t.Fatal(err)
   477  	}
   478  
   479  	// Register a stub balancer which uses a "pick_first" balancer underneath and
   480  	// signals on a channel when it receives ClientConn updates. But it does not
   481  	// forward the ccUpdate to the underlying "pick_first" balancer until the test
   482  	// asks it to do so. This allows us to test the graceful switch functionality.
   483  	// Until the test asks the stub balancer to forward the ccUpdate, RPCs should
   484  	// get routed to the old balancer. And once the test gives the go ahead, RPCs
   485  	// should get routed to the new balancer.
   486  	ccUpdateCh := make(chan struct{})
   487  	waitToProceed := make(chan struct{})
   488  	stub.Register(t.Name(), stub.BalancerFuncs{
   489  		Init: func(bd *stub.BalancerData) {
   490  			pf := balancer.Get(pickfirst.Name)
   491  			bd.Data = pf.Build(bd.ClientConn, bd.BuildOptions)
   492  		},
   493  		Close: func(bd *stub.BalancerData) {
   494  			bd.Data.(balancer.Balancer).Close()
   495  		},
   496  		UpdateClientConnState: func(bd *stub.BalancerData, ccs balancer.ClientConnState) error {
   497  			bal := bd.Data.(balancer.Balancer)
   498  			close(ccUpdateCh)
   499  			go func() {
   500  				<-waitToProceed
   501  				bal.UpdateClientConnState(ccs)
   502  			}()
   503  			return nil
   504  		},
   505  	})
   506  
   507  	// Push a resolver update with the service config specifying our stub
   508  	// balancer. We should see a trace event for this balancer switch. But RPCs
   509  	// should still be routed to the old balancer since our stub balancer does not
   510  	// report a ready picker until we ask it to do so.
   511  	r.UpdateState(resolver.State{
   512  		Addresses:     addrs[:1],
   513  		ServiceConfig: r.CC().ParseServiceConfig(fmt.Sprintf(`{"loadBalancingConfig": [{"%v": {}}]}`, t.Name())),
   514  	})
   515  	select {
   516  	case <-ctx.Done():
   517  		t.Fatal("Timeout when waiting for a ClientConnState update on the new balancer")
   518  	case <-ccUpdateCh:
   519  	}
   520  	if err := rrutil.CheckRoundRobinRPCs(ctx, client, addrs[1:]); err != nil {
   521  		t.Fatalf("RPCs routed to old balancer failed: %v", err)
   522  	}
   523  
   524  	// Ask our stub balancer to forward the earlier received ccUpdate to the
   525  	// underlying "pick_first" balancer which will result in a healthy picker
   526  	// being reported to the channel. RPCs should start using the new balancer.
   527  	close(waitToProceed)
   528  	if err := pfutil.CheckRPCsToBackend(ctx, cc, addrs[0]); err != nil {
   529  		t.Fatalf("RPCs routed to new balancer failed: %v", err)
   530  	}
   531  }