google.golang.org/grpc@v1.72.2/internal/balancergroup/balancergroup_test.go (about)

     1  /*
     2   * Copyright 2019 gRPC authors.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package balancergroup
    18  
    19  import (
    20  	"context"
    21  	"encoding/json"
    22  	"errors"
    23  	"fmt"
    24  	"testing"
    25  	"time"
    26  
    27  	"google.golang.org/grpc/balancer"
    28  	"google.golang.org/grpc/balancer/pickfirst"
    29  	"google.golang.org/grpc/balancer/roundrobin"
    30  	"google.golang.org/grpc/balancer/weightedtarget/weightedaggregator"
    31  	"google.golang.org/grpc/connectivity"
    32  	"google.golang.org/grpc/credentials/insecure"
    33  	"google.golang.org/grpc/internal/balancer/stub"
    34  	"google.golang.org/grpc/internal/channelz"
    35  	"google.golang.org/grpc/internal/grpctest"
    36  	"google.golang.org/grpc/internal/testutils"
    37  	"google.golang.org/grpc/resolver"
    38  )
    39  
    40  const (
    41  	defaultTestTimeout      = 5 * time.Second
    42  	defaultTestShortTimeout = 10 * time.Millisecond
    43  )
    44  
    45  var (
    46  	rrBuilder            = balancer.Get(roundrobin.Name)
    47  	testBalancerIDs      = []string{"b1", "b2", "b3"}
    48  	testBackendAddrs     []resolver.Address
    49  	testBackendEndpoints []resolver.Endpoint
    50  )
    51  
    52  const testBackendAddrsCount = 12
    53  
    54  func init() {
    55  	for i := 0; i < testBackendAddrsCount; i++ {
    56  		addr := resolver.Address{Addr: fmt.Sprintf("%d.%d.%d.%d:%d", i, i, i, i, i)}
    57  		testBackendAddrs = append(testBackendAddrs, addr)
    58  		testBackendEndpoints = append(testBackendEndpoints, resolver.Endpoint{Addresses: []resolver.Address{addr}})
    59  	}
    60  }
    61  
    62  type s struct {
    63  	grpctest.Tester
    64  }
    65  
    66  func Test(t *testing.T) {
    67  	grpctest.RunSubTests(t, s{})
    68  }
    69  
    70  // Create a new balancer group, add balancer and backends.
    71  // - b1, weight 2, backends [0,1]
    72  // - b2, weight 1, backends [2,3]
    73  // Start the balancer group and check behavior.
    74  //
    75  // Close the balancer group.
    76  func (s) TestBalancerGroup_start_close(t *testing.T) {
    77  	cc := testutils.NewBalancerClientConn(t)
    78  	gator := weightedaggregator.New(cc, nil, testutils.NewTestWRR)
    79  	gator.Start()
    80  	bg := New(Options{
    81  		CC:                      cc,
    82  		BuildOpts:               balancer.BuildOptions{},
    83  		StateAggregator:         gator,
    84  		Logger:                  nil,
    85  		SubBalancerCloseTimeout: time.Duration(0),
    86  	})
    87  
    88  	// Add two balancers to group and send two resolved addresses to both
    89  	// balancers.
    90  	gator.Add(testBalancerIDs[0], 2)
    91  	bg.Add(testBalancerIDs[0], rrBuilder)
    92  	bg.UpdateClientConnState(testBalancerIDs[0], balancer.ClientConnState{ResolverState: resolver.State{Endpoints: testBackendEndpoints[0:2]}})
    93  	gator.Add(testBalancerIDs[1], 1)
    94  	bg.Add(testBalancerIDs[1], rrBuilder)
    95  	bg.UpdateClientConnState(testBalancerIDs[1], balancer.ClientConnState{ResolverState: resolver.State{Endpoints: testBackendEndpoints[2:4]}})
    96  
    97  	m1 := make(map[string]balancer.SubConn)
    98  	for i := 0; i < 4; i++ {
    99  		addrs := <-cc.NewSubConnAddrsCh
   100  		sc := <-cc.NewSubConnCh
   101  		m1[addrs[0].Addr] = sc
   102  		sc.UpdateState(balancer.SubConnState{ConnectivityState: connectivity.Connecting})
   103  		sc.UpdateState(balancer.SubConnState{ConnectivityState: connectivity.Ready})
   104  	}
   105  
   106  	// Test roundrobin on the last picker.
   107  	p1 := <-cc.NewPickerCh
   108  	want := []balancer.SubConn{
   109  		m1[testBackendAddrs[0].Addr], m1[testBackendAddrs[0].Addr],
   110  		m1[testBackendAddrs[1].Addr], m1[testBackendAddrs[1].Addr],
   111  		m1[testBackendAddrs[2].Addr], m1[testBackendAddrs[3].Addr],
   112  	}
   113  	if err := testutils.IsRoundRobin(want, testutils.SubConnFromPicker(p1)); err != nil {
   114  		t.Fatalf("want %v, got %v", want, err)
   115  	}
   116  
   117  	gator.Stop()
   118  	bg.Close()
   119  	for i := 0; i < 4; i++ {
   120  		(<-cc.ShutdownSubConnCh).UpdateState(balancer.SubConnState{ConnectivityState: connectivity.Shutdown})
   121  	}
   122  }
   123  
   124  // Test that balancer group start() doesn't deadlock if the balancer calls back
   125  // into balancer group inline when it gets an update.
   126  //
   127  // The potential deadlock can happen if we
   128  //   - hold a lock and send updates to balancer (e.g. update resolved addresses)
   129  //   - the balancer calls back (NewSubConn or update picker) in line
   130  //
   131  // The callback will try to hold the same lock again, which will cause a
   132  // deadlock.
   133  //
   134  // This test starts the balancer group with a test balancer, will update picker
   135  // whenever it gets an address update. It's expected that start() doesn't block
   136  // because of deadlock.
   137  func (s) TestBalancerGroup_start_close_deadlock(t *testing.T) {
   138  	const balancerName = "stub-TestBalancerGroup_start_close_deadlock"
   139  	stub.Register(balancerName, stub.BalancerFuncs{})
   140  	builder := balancer.Get(balancerName)
   141  
   142  	cc := testutils.NewBalancerClientConn(t)
   143  	gator := weightedaggregator.New(cc, nil, testutils.NewTestWRR)
   144  	gator.Start()
   145  	bg := New(Options{
   146  		CC:                      cc,
   147  		BuildOpts:               balancer.BuildOptions{},
   148  		StateAggregator:         gator,
   149  		Logger:                  nil,
   150  		SubBalancerCloseTimeout: time.Duration(0),
   151  	})
   152  
   153  	gator.Add(testBalancerIDs[0], 2)
   154  	bg.Add(testBalancerIDs[0], builder)
   155  	bg.UpdateClientConnState(testBalancerIDs[0], balancer.ClientConnState{ResolverState: resolver.State{Addresses: testBackendAddrs[0:2]}})
   156  	gator.Add(testBalancerIDs[1], 1)
   157  	bg.Add(testBalancerIDs[1], builder)
   158  	bg.UpdateClientConnState(testBalancerIDs[1], balancer.ClientConnState{ResolverState: resolver.State{Addresses: testBackendAddrs[2:4]}})
   159  }
   160  
   161  // initBalancerGroupForCachingTest creates a balancer group, and initialize it
   162  // to be ready for caching tests.
   163  //
   164  // Two rr balancers are added to bg, each with 2 ready subConns. A sub-balancer
   165  // is removed later, so the balancer group returned has one sub-balancer in its
   166  // own map, and one sub-balancer in cache.
   167  func initBalancerGroupForCachingTest(t *testing.T, idleCacheTimeout time.Duration) (*weightedaggregator.Aggregator, *BalancerGroup, *testutils.BalancerClientConn, map[string]*testutils.TestSubConn) {
   168  	cc := testutils.NewBalancerClientConn(t)
   169  	gator := weightedaggregator.New(cc, nil, testutils.NewTestWRR)
   170  	gator.Start()
   171  	bg := New(Options{
   172  		CC:                      cc,
   173  		BuildOpts:               balancer.BuildOptions{},
   174  		StateAggregator:         gator,
   175  		Logger:                  nil,
   176  		SubBalancerCloseTimeout: idleCacheTimeout,
   177  	})
   178  
   179  	// Add two balancers to group and send two resolved addresses to both
   180  	// balancers.
   181  	gator.Add(testBalancerIDs[0], 2)
   182  	bg.Add(testBalancerIDs[0], rrBuilder)
   183  	bg.UpdateClientConnState(testBalancerIDs[0], balancer.ClientConnState{ResolverState: resolver.State{Endpoints: testBackendEndpoints[0:2]}})
   184  	gator.Add(testBalancerIDs[1], 1)
   185  	bg.Add(testBalancerIDs[1], rrBuilder)
   186  	bg.UpdateClientConnState(testBalancerIDs[1], balancer.ClientConnState{ResolverState: resolver.State{Endpoints: testBackendEndpoints[2:4]}})
   187  
   188  	m1 := make(map[string]*testutils.TestSubConn)
   189  	for i := 0; i < 4; i++ {
   190  		addrs := <-cc.NewSubConnAddrsCh
   191  		sc := <-cc.NewSubConnCh
   192  		m1[addrs[0].Addr] = sc
   193  		sc.UpdateState(balancer.SubConnState{ConnectivityState: connectivity.Connecting})
   194  		sc.UpdateState(balancer.SubConnState{ConnectivityState: connectivity.Ready})
   195  	}
   196  
   197  	// Test roundrobin on the last picker.
   198  	p1 := <-cc.NewPickerCh
   199  	want := []balancer.SubConn{
   200  		m1[testBackendAddrs[0].Addr], m1[testBackendAddrs[0].Addr],
   201  		m1[testBackendAddrs[1].Addr], m1[testBackendAddrs[1].Addr],
   202  		m1[testBackendAddrs[2].Addr], m1[testBackendAddrs[3].Addr],
   203  	}
   204  	if err := testutils.IsRoundRobin(want, testutils.SubConnFromPicker(p1)); err != nil {
   205  		t.Fatalf("want %v, got %v", want, err)
   206  	}
   207  
   208  	gator.Remove(testBalancerIDs[1])
   209  	bg.Remove(testBalancerIDs[1])
   210  	// Don't wait for SubConns to be removed after close, because they are only
   211  	// removed after close timeout.
   212  	for i := 0; i < 10; i++ {
   213  		select {
   214  		case sc := <-cc.ShutdownSubConnCh:
   215  			t.Fatalf("Got request to shut down subconn %v, want no shut down subconn (because subconns were still in cache)", sc)
   216  		default:
   217  		}
   218  		time.Sleep(time.Millisecond)
   219  	}
   220  	// Test roundrobin on the with only sub-balancer0.
   221  	p2 := <-cc.NewPickerCh
   222  	want = []balancer.SubConn{
   223  		m1[testBackendAddrs[0].Addr], m1[testBackendAddrs[1].Addr],
   224  	}
   225  	if err := testutils.IsRoundRobin(want, testutils.SubConnFromPicker(p2)); err != nil {
   226  		t.Fatalf("want %v, got %v", want, err)
   227  	}
   228  
   229  	return gator, bg, cc, m1
   230  }
   231  
   232  // Test that if a sub-balancer is removed, and re-added within close timeout,
   233  // the subConns won't be re-created.
   234  func (s) TestBalancerGroup_locality_caching(t *testing.T) {
   235  	gator, bg, cc, addrToSC := initBalancerGroupForCachingTest(t, defaultTestTimeout)
   236  
   237  	// Turn down subconn for addr2, shouldn't get picker update because
   238  	// sub-balancer1 was removed.
   239  	addrToSC[testBackendAddrs[2].Addr].UpdateState(balancer.SubConnState{
   240  		ConnectivityState: connectivity.TransientFailure,
   241  		ConnectionError:   errors.New("test error"),
   242  	})
   243  	for i := 0; i < 10; i++ {
   244  		select {
   245  		case <-cc.NewPickerCh:
   246  			t.Fatalf("Got new picker, want no new picker (because the sub-balancer was removed)")
   247  		default:
   248  		}
   249  		time.Sleep(defaultTestShortTimeout)
   250  	}
   251  
   252  	// Re-add sub-balancer-1, because subconns were in cache, no new subconns
   253  	// should be created. But a new picker will still be generated, with subconn
   254  	// states update to date.
   255  	gator.Add(testBalancerIDs[1], 1)
   256  	bg.Add(testBalancerIDs[1], rrBuilder)
   257  
   258  	p3 := <-cc.NewPickerCh
   259  	want := []balancer.SubConn{
   260  		addrToSC[testBackendAddrs[0].Addr], addrToSC[testBackendAddrs[0].Addr],
   261  		addrToSC[testBackendAddrs[1].Addr], addrToSC[testBackendAddrs[1].Addr],
   262  		// addr2 is down, b2 only has addr3 in READY state.
   263  		addrToSC[testBackendAddrs[3].Addr], addrToSC[testBackendAddrs[3].Addr],
   264  	}
   265  	if err := testutils.IsRoundRobin(want, testutils.SubConnFromPicker(p3)); err != nil {
   266  		t.Fatalf("want %v, got %v", want, err)
   267  	}
   268  
   269  	for i := 0; i < 10; i++ {
   270  		select {
   271  		case <-cc.NewSubConnAddrsCh:
   272  			t.Fatalf("Got new subconn, want no new subconn (because subconns were still in cache)")
   273  		default:
   274  		}
   275  		time.Sleep(defaultTestShortTimeout)
   276  	}
   277  }
   278  
   279  // Sub-balancers are put in cache when they are shut down. If balancer group is
   280  // closed within close timeout, all subconns should still be removed
   281  // immediately.
   282  func (s) TestBalancerGroup_locality_caching_close_group(t *testing.T) {
   283  	_, bg, cc, addrToSC := initBalancerGroupForCachingTest(t, defaultTestTimeout)
   284  
   285  	bg.Close()
   286  	// The balancer group is closed. The subconns should be shutdown immediately.
   287  	shutdownTimeout := time.After(time.Millisecond * 500)
   288  	scToShutdown := map[balancer.SubConn]int{
   289  		addrToSC[testBackendAddrs[0].Addr]: 1,
   290  		addrToSC[testBackendAddrs[1].Addr]: 1,
   291  		addrToSC[testBackendAddrs[2].Addr]: 1,
   292  		addrToSC[testBackendAddrs[3].Addr]: 1,
   293  	}
   294  	for i := 0; i < len(scToShutdown); i++ {
   295  		select {
   296  		case sc := <-cc.ShutdownSubConnCh:
   297  			c := scToShutdown[sc]
   298  			if c == 0 {
   299  				t.Fatalf("Got Shutdown for %v when there's %d shutdown expected", sc, c)
   300  			}
   301  			scToShutdown[sc] = c - 1
   302  		case <-shutdownTimeout:
   303  			t.Fatalf("timeout waiting for subConns (from balancer in cache) to be shut down")
   304  		}
   305  	}
   306  }
   307  
   308  // Sub-balancers in cache will be closed if not re-added within timeout, and
   309  // subConns will be shut down.
   310  func (s) TestBalancerGroup_locality_caching_not_read_within_timeout(t *testing.T) {
   311  	_, _, cc, addrToSC := initBalancerGroupForCachingTest(t, time.Second)
   312  
   313  	// The sub-balancer is not re-added within timeout. The subconns should be
   314  	// shut down.
   315  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   316  	defer cancel()
   317  	scToShutdown := map[balancer.SubConn]int{
   318  		addrToSC[testBackendAddrs[2].Addr]: 1,
   319  		addrToSC[testBackendAddrs[3].Addr]: 1,
   320  	}
   321  	for i := 0; i < len(scToShutdown); i++ {
   322  		select {
   323  		case sc := <-cc.ShutdownSubConnCh:
   324  			c := scToShutdown[sc]
   325  			if c == 0 {
   326  				t.Fatalf("Got Shutdown for %v when there's %d shutdown expected", sc, c)
   327  			}
   328  			scToShutdown[sc] = c - 1
   329  		case <-ctx.Done():
   330  			t.Fatalf("timeout waiting for subConns (from balancer in cache) to be shut down")
   331  		}
   332  	}
   333  }
   334  
   335  // Wrap the rr builder, so it behaves the same, but has a different name.
   336  type noopBalancerBuilderWrapper struct {
   337  	balancer.Builder
   338  }
   339  
   340  func init() {
   341  	balancer.Register(&noopBalancerBuilderWrapper{Builder: rrBuilder})
   342  }
   343  
   344  func (*noopBalancerBuilderWrapper) Name() string {
   345  	return "noopBalancerBuilderWrapper"
   346  }
   347  
   348  // After removing a sub-balancer, re-add with same ID, but different balancer
   349  // builder. Old subconns should be shut down, and new subconns should be created.
   350  func (s) TestBalancerGroup_locality_caching_read_with_different_builder(t *testing.T) {
   351  	gator, bg, cc, addrToSC := initBalancerGroupForCachingTest(t, defaultTestTimeout)
   352  
   353  	// Re-add sub-balancer-1, but with a different balancer builder. The
   354  	// sub-balancer was still in cache, but can't be reused. This should cause
   355  	// old sub-balancer's subconns to be shut down immediately, and new
   356  	// subconns to be created.
   357  	gator.Add(testBalancerIDs[1], 1)
   358  	bg.Add(testBalancerIDs[1], &noopBalancerBuilderWrapper{rrBuilder})
   359  
   360  	// The cached sub-balancer should be closed, and the subconns should be
   361  	// shut down immediately.
   362  	shutdownTimeout := time.After(time.Millisecond * 500)
   363  	scToShutdown := map[balancer.SubConn]int{
   364  		addrToSC[testBackendAddrs[2].Addr]: 1,
   365  		addrToSC[testBackendAddrs[3].Addr]: 1,
   366  	}
   367  	for i := 0; i < len(scToShutdown); i++ {
   368  		select {
   369  		case sc := <-cc.ShutdownSubConnCh:
   370  			c := scToShutdown[sc]
   371  			if c == 0 {
   372  				t.Fatalf("Got Shutdown for %v when there's %d shutdown expected", sc, c)
   373  			}
   374  			scToShutdown[sc] = c - 1
   375  		case <-shutdownTimeout:
   376  			t.Fatalf("timeout waiting for subConns (from balancer in cache) to be shut down")
   377  		}
   378  	}
   379  
   380  	bg.UpdateClientConnState(testBalancerIDs[1], balancer.ClientConnState{ResolverState: resolver.State{Endpoints: testBackendEndpoints[4:6]}})
   381  
   382  	newSCTimeout := time.After(time.Millisecond * 500)
   383  	scToAdd := map[string]int{
   384  		testBackendAddrs[4].Addr: 1,
   385  		testBackendAddrs[5].Addr: 1,
   386  	}
   387  	for i := 0; i < len(scToAdd); i++ {
   388  		select {
   389  		case addr := <-cc.NewSubConnAddrsCh:
   390  			c := scToAdd[addr[0].Addr]
   391  			if c == 0 {
   392  				t.Fatalf("Got newSubConn for %v when there's %d new expected", addr, c)
   393  			}
   394  			scToAdd[addr[0].Addr] = c - 1
   395  			sc := <-cc.NewSubConnCh
   396  			addrToSC[addr[0].Addr] = sc
   397  			sc.UpdateState(balancer.SubConnState{ConnectivityState: connectivity.Connecting})
   398  			sc.UpdateState(balancer.SubConnState{ConnectivityState: connectivity.Ready})
   399  		case <-newSCTimeout:
   400  			t.Fatalf("timeout waiting for subConns (from new sub-balancer) to be newed")
   401  		}
   402  	}
   403  
   404  	// Test roundrobin on the new picker.
   405  	p3 := <-cc.NewPickerCh
   406  	want := []balancer.SubConn{
   407  		addrToSC[testBackendAddrs[0].Addr], addrToSC[testBackendAddrs[0].Addr],
   408  		addrToSC[testBackendAddrs[1].Addr], addrToSC[testBackendAddrs[1].Addr],
   409  		addrToSC[testBackendAddrs[4].Addr], addrToSC[testBackendAddrs[5].Addr],
   410  	}
   411  	if err := testutils.IsRoundRobin(want, testutils.SubConnFromPicker(p3)); err != nil {
   412  		t.Fatalf("want %v, got %v", want, err)
   413  	}
   414  }
   415  
   416  // After removing a sub-balancer, it will be kept in cache. Make sure that this
   417  // sub-balancer's Close is called when the balancer group is closed.
   418  func (s) TestBalancerGroup_CloseStopsBalancerInCache(t *testing.T) {
   419  	const balancerName = "stub-TestBalancerGroup_check_close"
   420  	closed := make(chan struct{})
   421  	stub.Register(balancerName, stub.BalancerFuncs{Close: func(_ *stub.BalancerData) {
   422  		close(closed)
   423  	}})
   424  	builder := balancer.Get(balancerName)
   425  
   426  	gator, bg, _, _ := initBalancerGroupForCachingTest(t, time.Second)
   427  
   428  	// Add balancer, and remove
   429  	gator.Add(testBalancerIDs[2], 1)
   430  	bg.Add(testBalancerIDs[2], builder)
   431  	gator.Remove(testBalancerIDs[2])
   432  	bg.Remove(testBalancerIDs[2])
   433  
   434  	// Immediately close balancergroup, before the cache timeout.
   435  	bg.Close()
   436  
   437  	// Make sure the removed child balancer is closed eventually.
   438  	select {
   439  	case <-closed:
   440  	case <-time.After(time.Second * 2):
   441  		t.Fatalf("timeout waiting for the child balancer in cache to be closed")
   442  	}
   443  }
   444  
   445  // TestBalancerGroupBuildOptions verifies that the balancer.BuildOptions passed
   446  // to the balancergroup at creation time is passed to child policies.
   447  func (s) TestBalancerGroupBuildOptions(t *testing.T) {
   448  	const (
   449  		balancerName = "stubBalancer-TestBalancerGroupBuildOptions"
   450  		userAgent    = "ua"
   451  	)
   452  
   453  	// Setup the stub balancer such that we can read the build options passed to
   454  	// it in the UpdateClientConnState method.
   455  	bOpts := balancer.BuildOptions{
   456  		DialCreds:       insecure.NewCredentials(),
   457  		ChannelzParent:  channelz.RegisterChannel(nil, "test channel"),
   458  		CustomUserAgent: userAgent,
   459  	}
   460  	stub.Register(balancerName, stub.BalancerFuncs{
   461  		UpdateClientConnState: func(bd *stub.BalancerData, _ balancer.ClientConnState) error {
   462  			if bd.BuildOptions.DialCreds != bOpts.DialCreds || bd.BuildOptions.ChannelzParent != bOpts.ChannelzParent || bd.BuildOptions.CustomUserAgent != bOpts.CustomUserAgent {
   463  				return fmt.Errorf("buildOptions in child balancer: %v, want %v", bd, bOpts)
   464  			}
   465  			return nil
   466  		},
   467  	})
   468  	cc := testutils.NewBalancerClientConn(t)
   469  	bg := New(Options{
   470  		CC:              cc,
   471  		BuildOpts:       bOpts,
   472  		StateAggregator: nil,
   473  		Logger:          nil,
   474  	})
   475  
   476  	// Add the stub balancer build above as a child policy.
   477  	balancerBuilder := balancer.Get(balancerName)
   478  	bg.Add(testBalancerIDs[0], balancerBuilder)
   479  
   480  	// Send an empty clientConn state change. This should trigger the
   481  	// verification of the buildOptions being passed to the child policy.
   482  	if err := bg.UpdateClientConnState(testBalancerIDs[0], balancer.ClientConnState{}); err != nil {
   483  		t.Fatal(err)
   484  	}
   485  }
   486  
   487  func (s) TestBalancerExitIdleOne(t *testing.T) {
   488  	const balancerName = "stub-balancer-test-balancergroup-exit-idle-one"
   489  	exitIdleCh := make(chan struct{}, 1)
   490  	stub.Register(balancerName, stub.BalancerFuncs{
   491  		ExitIdle: func(*stub.BalancerData) {
   492  			exitIdleCh <- struct{}{}
   493  		},
   494  	})
   495  	cc := testutils.NewBalancerClientConn(t)
   496  	bg := New(Options{
   497  		CC:              cc,
   498  		BuildOpts:       balancer.BuildOptions{},
   499  		StateAggregator: nil,
   500  		Logger:          nil,
   501  	})
   502  	defer bg.Close()
   503  
   504  	// Add the stub balancer build above as a child policy.
   505  	builder := balancer.Get(balancerName)
   506  	bg.Add(testBalancerIDs[0], builder)
   507  
   508  	// Call ExitIdle on the child policy.
   509  	bg.ExitIdleOne(testBalancerIDs[0])
   510  	select {
   511  	case <-time.After(time.Second):
   512  		t.Fatal("Timeout when waiting for ExitIdle to be invoked on child policy")
   513  	case <-exitIdleCh:
   514  	}
   515  }
   516  
   517  // TestBalancerGracefulSwitch tests the graceful switch functionality for a
   518  // child of the balancer group. At first, the child is configured as a round
   519  // robin load balancer, and thus should behave accordingly. The test then
   520  // gracefully switches this child to a custom type which only creates a SubConn
   521  // for the second passed in address and also only picks that created SubConn.
   522  // The new aggregated picker should reflect this change for the child.
   523  func (s) TestBalancerGracefulSwitch(t *testing.T) {
   524  	cc := testutils.NewBalancerClientConn(t)
   525  	gator := weightedaggregator.New(cc, nil, testutils.NewTestWRR)
   526  	gator.Start()
   527  	bg := New(Options{
   528  		CC:              cc,
   529  		BuildOpts:       balancer.BuildOptions{},
   530  		StateAggregator: gator,
   531  		Logger:          nil,
   532  	})
   533  	gator.Add(testBalancerIDs[0], 1)
   534  	bg.Add(testBalancerIDs[0], rrBuilder)
   535  	bg.UpdateClientConnState(testBalancerIDs[0], balancer.ClientConnState{ResolverState: resolver.State{Endpoints: testBackendEndpoints[0:2]}})
   536  
   537  	defer bg.Close()
   538  
   539  	m1 := make(map[string]balancer.SubConn)
   540  	scs := make(map[balancer.SubConn]bool)
   541  	for i := 0; i < 2; i++ {
   542  		addrs := <-cc.NewSubConnAddrsCh
   543  		sc := <-cc.NewSubConnCh
   544  		m1[addrs[0].Addr] = sc
   545  		scs[sc] = true
   546  		sc.UpdateState(balancer.SubConnState{ConnectivityState: connectivity.Connecting})
   547  		sc.UpdateState(balancer.SubConnState{ConnectivityState: connectivity.Ready})
   548  	}
   549  
   550  	p1 := <-cc.NewPickerCh
   551  	want := []balancer.SubConn{
   552  		m1[testBackendAddrs[0].Addr], m1[testBackendAddrs[1].Addr],
   553  	}
   554  	if err := testutils.IsRoundRobin(want, testutils.SubConnFromPicker(p1)); err != nil {
   555  		t.Fatal(err)
   556  	}
   557  
   558  	// The balancer type for testBalancersIDs[0] is currently Round Robin. Now,
   559  	// change it to a balancer that has separate behavior logically (creating
   560  	// SubConn for second address in address list and always picking that
   561  	// SubConn), and see if the downstream behavior reflects that change.
   562  	childPolicyName := t.Name()
   563  	stub.Register(childPolicyName, stub.BalancerFuncs{
   564  		Init: func(bd *stub.BalancerData) {
   565  			bd.Data = balancer.Get(pickfirst.Name).Build(bd.ClientConn, bd.BuildOptions)
   566  		},
   567  		Close: func(bd *stub.BalancerData) {
   568  			bd.Data.(balancer.Balancer).Close()
   569  		},
   570  		UpdateClientConnState: func(bd *stub.BalancerData, ccs balancer.ClientConnState) error {
   571  			ccs.ResolverState.Endpoints = ccs.ResolverState.Endpoints[1:]
   572  			bal := bd.Data.(balancer.Balancer)
   573  			return bal.UpdateClientConnState(ccs)
   574  		},
   575  	})
   576  	cfgJSON := json.RawMessage(fmt.Sprintf(`[{%q: {}}]`, t.Name()))
   577  	lbCfg, err := ParseConfig(cfgJSON)
   578  	if err != nil {
   579  		t.Fatalf("ParseConfig(%s) failed: %v", string(cfgJSON), err)
   580  	}
   581  	if err := bg.UpdateClientConnState(testBalancerIDs[0], balancer.ClientConnState{
   582  		ResolverState:  resolver.State{Endpoints: testBackendEndpoints[2:4]},
   583  		BalancerConfig: lbCfg,
   584  	}); err != nil {
   585  		t.Fatalf("error updating ClientConn state: %v", err)
   586  	}
   587  
   588  	addrs := <-cc.NewSubConnAddrsCh
   589  	if addrs[0].Addr != testBackendAddrs[3].Addr {
   590  		// Verifies forwarded to new created balancer, as the wrapped pick first
   591  		// balancer will delete first address.
   592  		t.Fatalf("newSubConn called with wrong address, want: %v, got : %v", testBackendAddrs[3].Addr, addrs[0].Addr)
   593  	}
   594  	sc := <-cc.NewSubConnCh
   595  
   596  	// Update the pick first balancers SubConn as CONNECTING. This will cause
   597  	// the pick first balancer to UpdateState() with CONNECTING, which shouldn't send
   598  	// a Picker update back, as the Graceful Switch process is not complete.
   599  	sc.UpdateState(balancer.SubConnState{ConnectivityState: connectivity.Connecting})
   600  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestShortTimeout)
   601  	defer cancel()
   602  	select {
   603  	case <-cc.NewPickerCh:
   604  		t.Fatalf("No new picker should have been sent due to the Graceful Switch process not completing")
   605  	case <-ctx.Done():
   606  	}
   607  
   608  	// Update the pick first balancers SubConn as READY. This will cause
   609  	// the pick first balancer to UpdateState() with READY, which should send a
   610  	// Picker update back, as the Graceful Switch process is complete. This
   611  	// Picker should always pick the pick first's created SubConn which
   612  	// corresponds to address 3.
   613  	sc.UpdateState(balancer.SubConnState{ConnectivityState: connectivity.Ready})
   614  	p2 := <-cc.NewPickerCh
   615  	pr, err := p2.Pick(balancer.PickInfo{})
   616  	if err != nil {
   617  		t.Fatalf("error picking: %v", err)
   618  	}
   619  	if pr.SubConn != sc {
   620  		t.Fatalf("picker.Pick(), want %v, got %v", sc, pr.SubConn)
   621  	}
   622  
   623  	// The Graceful Switch process completing for the child should cause the
   624  	// SubConns for the balancer being gracefully switched from to get deleted.
   625  	ctx, cancel = context.WithTimeout(context.Background(), defaultTestTimeout)
   626  	defer cancel()
   627  	for i := 0; i < 2; i++ {
   628  		select {
   629  		case <-ctx.Done():
   630  			t.Fatalf("error waiting for Shutdown()")
   631  		case sc := <-cc.ShutdownSubConnCh:
   632  			// The SubConn shut down should have been one of the two created
   633  			// SubConns, and both should be deleted.
   634  			if ok := scs[sc]; ok {
   635  				delete(scs, sc)
   636  				continue
   637  			} else {
   638  				t.Fatalf("Shutdown called for wrong SubConn %v, want in %v", sc, scs)
   639  			}
   640  		}
   641  	}
   642  }