github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/grpc/xds/internal/balancer/priority/balancer_test.go (about)

     1  /*
     2   *
     3   * Copyright 2021 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 priority
    20  
    21  import (
    22  	"context"
    23  	"fmt"
    24  	"testing"
    25  	"time"
    26  
    27  	"github.com/google/go-cmp/cmp"
    28  	"github.com/hxx258456/ccgo/grpc/balancer"
    29  	"github.com/hxx258456/ccgo/grpc/balancer/roundrobin"
    30  	"github.com/hxx258456/ccgo/grpc/connectivity"
    31  	"github.com/hxx258456/ccgo/grpc/internal/balancer/stub"
    32  	"github.com/hxx258456/ccgo/grpc/internal/balancergroup"
    33  	"github.com/hxx258456/ccgo/grpc/internal/grpctest"
    34  	"github.com/hxx258456/ccgo/grpc/internal/hierarchy"
    35  	internalserviceconfig "github.com/hxx258456/ccgo/grpc/internal/serviceconfig"
    36  	"github.com/hxx258456/ccgo/grpc/internal/testutils"
    37  	"github.com/hxx258456/ccgo/grpc/resolver"
    38  )
    39  
    40  type s struct {
    41  	grpctest.Tester
    42  }
    43  
    44  func Test(t *testing.T) {
    45  	grpctest.RunSubTests(t, s{})
    46  }
    47  
    48  var testBackendAddrStrs []string
    49  
    50  const (
    51  	testBackendAddrsCount = 12
    52  	testRRBalancerName    = "another-round-robin"
    53  )
    54  
    55  type anotherRR struct {
    56  	balancer.Builder
    57  }
    58  
    59  func (*anotherRR) Name() string {
    60  	return testRRBalancerName
    61  }
    62  
    63  func init() {
    64  	for i := 0; i < testBackendAddrsCount; i++ {
    65  		testBackendAddrStrs = append(testBackendAddrStrs, fmt.Sprintf("%d.%d.%d.%d:%d", i, i, i, i, i))
    66  	}
    67  	balancergroup.DefaultSubBalancerCloseTimeout = time.Millisecond
    68  	balancer.Register(&anotherRR{Builder: balancer.Get(roundrobin.Name)})
    69  }
    70  
    71  func subConnFromPicker(t *testing.T, p balancer.Picker) func() balancer.SubConn {
    72  	return func() balancer.SubConn {
    73  		scst, err := p.Pick(balancer.PickInfo{})
    74  		if err != nil {
    75  			t.Fatalf("unexpected error from picker.Pick: %v", err)
    76  		}
    77  		return scst.SubConn
    78  	}
    79  }
    80  
    81  // When a high priority is ready, adding/removing lower locality doesn't cause
    82  // changes.
    83  //
    84  // Init 0 and 1; 0 is up, use 0; add 2, use 0; remove 2, use 0.
    85  func (s) TestPriority_HighPriorityReady(t *testing.T) {
    86  	cc := testutils.NewTestClientConn(t)
    87  	bb := balancer.Get(Name)
    88  	pb := bb.Build(cc, balancer.BuildOptions{})
    89  	defer pb.Close()
    90  
    91  	// Two children, with priorities [0, 1], each with one backend.
    92  	if err := pb.UpdateClientConnState(balancer.ClientConnState{
    93  		ResolverState: resolver.State{
    94  			Addresses: []resolver.Address{
    95  				hierarchy.Set(resolver.Address{Addr: testBackendAddrStrs[0]}, []string{"child-0"}),
    96  				hierarchy.Set(resolver.Address{Addr: testBackendAddrStrs[1]}, []string{"child-1"}),
    97  			},
    98  		},
    99  		BalancerConfig: &LBConfig{
   100  			Children: map[string]*Child{
   101  				"child-0": {Config: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}},
   102  				"child-1": {Config: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}},
   103  			},
   104  			Priorities: []string{"child-0", "child-1"},
   105  		},
   106  	}); err != nil {
   107  		t.Fatalf("failed to update ClientConn state: %v", err)
   108  	}
   109  
   110  	addrs1 := <-cc.NewSubConnAddrsCh
   111  	if got, want := addrs1[0].Addr, testBackendAddrStrs[0]; got != want {
   112  		t.Fatalf("sc is created with addr %v, want %v", got, want)
   113  	}
   114  	sc1 := <-cc.NewSubConnCh
   115  
   116  	// p0 is ready.
   117  	pb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.Connecting})
   118  	pb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.Ready})
   119  
   120  	// Test roundrobin with only p0 subconns.
   121  	p1 := <-cc.NewPickerCh
   122  	want := []balancer.SubConn{sc1}
   123  	if err := testutils.IsRoundRobin(want, subConnFromPicker(t, p1)); err != nil {
   124  		t.Fatalf("want %v, got %v", want, err)
   125  	}
   126  
   127  	// Add p2, it shouldn't cause any updates.
   128  	if err := pb.UpdateClientConnState(balancer.ClientConnState{
   129  		ResolverState: resolver.State{
   130  			Addresses: []resolver.Address{
   131  				hierarchy.Set(resolver.Address{Addr: testBackendAddrStrs[0]}, []string{"child-0"}),
   132  				hierarchy.Set(resolver.Address{Addr: testBackendAddrStrs[1]}, []string{"child-1"}),
   133  				hierarchy.Set(resolver.Address{Addr: testBackendAddrStrs[2]}, []string{"child-2"}),
   134  			},
   135  		},
   136  		BalancerConfig: &LBConfig{
   137  			Children: map[string]*Child{
   138  				"child-0": {Config: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}},
   139  				"child-1": {Config: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}},
   140  				"child-2": {Config: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}},
   141  			},
   142  			Priorities: []string{"child-0", "child-1", "child-2"},
   143  		},
   144  	}); err != nil {
   145  		t.Fatalf("failed to update ClientConn state: %v", err)
   146  	}
   147  
   148  	select {
   149  	case <-cc.NewPickerCh:
   150  		t.Fatalf("got unexpected new picker")
   151  	case sc := <-cc.NewSubConnCh:
   152  		t.Fatalf("got unexpected new SubConn: %s", sc)
   153  	case sc := <-cc.RemoveSubConnCh:
   154  		t.Fatalf("got unexpected remove SubConn: %v", sc)
   155  	case <-time.After(time.Millisecond * 100):
   156  	}
   157  
   158  	// Remove p2, no updates.
   159  	if err := pb.UpdateClientConnState(balancer.ClientConnState{
   160  		ResolverState: resolver.State{
   161  			Addresses: []resolver.Address{
   162  				hierarchy.Set(resolver.Address{Addr: testBackendAddrStrs[0]}, []string{"child-0"}),
   163  				hierarchy.Set(resolver.Address{Addr: testBackendAddrStrs[1]}, []string{"child-1"}),
   164  			},
   165  		},
   166  		BalancerConfig: &LBConfig{
   167  			Children: map[string]*Child{
   168  				"child-0": {Config: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}},
   169  				"child-1": {Config: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}},
   170  			},
   171  			Priorities: []string{"child-0", "child-1"},
   172  		},
   173  	}); err != nil {
   174  		t.Fatalf("failed to update ClientConn state: %v", err)
   175  	}
   176  
   177  	select {
   178  	case <-cc.NewPickerCh:
   179  		t.Fatalf("got unexpected new picker")
   180  	case <-cc.NewSubConnCh:
   181  		t.Fatalf("got unexpected new SubConn")
   182  	case <-cc.RemoveSubConnCh:
   183  		t.Fatalf("got unexpected remove SubConn")
   184  	case <-time.After(time.Millisecond * 100):
   185  	}
   186  }
   187  
   188  // Lower priority is used when higher priority is not ready.
   189  //
   190  // Init 0 and 1; 0 is up, use 0; 0 is down, 1 is up, use 1; add 2, use 1; 1 is
   191  // down, use 2; remove 2, use 1.
   192  func (s) TestPriority_SwitchPriority(t *testing.T) {
   193  	cc := testutils.NewTestClientConn(t)
   194  	bb := balancer.Get(Name)
   195  	pb := bb.Build(cc, balancer.BuildOptions{})
   196  	defer pb.Close()
   197  
   198  	// Two localities, with priorities [0, 1], each with one backend.
   199  	if err := pb.UpdateClientConnState(balancer.ClientConnState{
   200  		ResolverState: resolver.State{
   201  			Addresses: []resolver.Address{
   202  				hierarchy.Set(resolver.Address{Addr: testBackendAddrStrs[0]}, []string{"child-0"}),
   203  				hierarchy.Set(resolver.Address{Addr: testBackendAddrStrs[1]}, []string{"child-1"}),
   204  			},
   205  		},
   206  		BalancerConfig: &LBConfig{
   207  			Children: map[string]*Child{
   208  				"child-0": {Config: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}},
   209  				"child-1": {Config: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}},
   210  			},
   211  			Priorities: []string{"child-0", "child-1"},
   212  		},
   213  	}); err != nil {
   214  		t.Fatalf("failed to update ClientConn state: %v", err)
   215  	}
   216  
   217  	addrs0 := <-cc.NewSubConnAddrsCh
   218  	if got, want := addrs0[0].Addr, testBackendAddrStrs[0]; got != want {
   219  		t.Fatalf("sc is created with addr %v, want %v", got, want)
   220  	}
   221  	sc0 := <-cc.NewSubConnCh
   222  
   223  	// p0 is ready.
   224  	pb.UpdateSubConnState(sc0, balancer.SubConnState{ConnectivityState: connectivity.Connecting})
   225  	pb.UpdateSubConnState(sc0, balancer.SubConnState{ConnectivityState: connectivity.Ready})
   226  
   227  	// Test roundrobin with only p0 subconns.
   228  	p0 := <-cc.NewPickerCh
   229  	want := []balancer.SubConn{sc0}
   230  	if err := testutils.IsRoundRobin(want, subConnFromPicker(t, p0)); err != nil {
   231  		t.Fatalf("want %v, got %v", want, err)
   232  	}
   233  
   234  	// Turn down 0, will start and use 1.
   235  	pb.UpdateSubConnState(sc0, balancer.SubConnState{ConnectivityState: connectivity.TransientFailure})
   236  
   237  	// Before 1 gets READY, picker should return NoSubConnAvailable, so RPCs
   238  	// will retry.
   239  	p1 := <-cc.NewPickerCh
   240  	for i := 0; i < 5; i++ {
   241  		if _, err := p1.Pick(balancer.PickInfo{}); err != balancer.ErrNoSubConnAvailable {
   242  			t.Fatalf("want pick error %v, got %v", balancer.ErrNoSubConnAvailable, err)
   243  		}
   244  	}
   245  
   246  	// Handle SubConn creation from 1.
   247  	addrs1 := <-cc.NewSubConnAddrsCh
   248  	if got, want := addrs1[0].Addr, testBackendAddrStrs[1]; got != want {
   249  		t.Fatalf("sc is created with addr %v, want %v", got, want)
   250  	}
   251  	sc1 := <-cc.NewSubConnCh
   252  	pb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.Connecting})
   253  	pb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.Ready})
   254  
   255  	// Test pick with 1.
   256  	p2 := <-cc.NewPickerCh
   257  	for i := 0; i < 5; i++ {
   258  		gotSCSt, _ := p2.Pick(balancer.PickInfo{})
   259  		if !cmp.Equal(gotSCSt.SubConn, sc1, cmp.AllowUnexported(testutils.TestSubConn{})) {
   260  			t.Fatalf("picker.Pick, got %v, want SubConn=%v", gotSCSt, sc1)
   261  		}
   262  	}
   263  
   264  	// Add p2, it shouldn't cause any udpates.
   265  	if err := pb.UpdateClientConnState(balancer.ClientConnState{
   266  		ResolverState: resolver.State{
   267  			Addresses: []resolver.Address{
   268  				hierarchy.Set(resolver.Address{Addr: testBackendAddrStrs[0]}, []string{"child-0"}),
   269  				hierarchy.Set(resolver.Address{Addr: testBackendAddrStrs[1]}, []string{"child-1"}),
   270  				hierarchy.Set(resolver.Address{Addr: testBackendAddrStrs[2]}, []string{"child-2"}),
   271  			},
   272  		},
   273  		BalancerConfig: &LBConfig{
   274  			Children: map[string]*Child{
   275  				"child-0": {Config: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}},
   276  				"child-1": {Config: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}},
   277  				"child-2": {Config: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}},
   278  			},
   279  			Priorities: []string{"child-0", "child-1", "child-2"},
   280  		},
   281  	}); err != nil {
   282  		t.Fatalf("failed to update ClientConn state: %v", err)
   283  	}
   284  
   285  	select {
   286  	case <-cc.NewPickerCh:
   287  		t.Fatalf("got unexpected new picker")
   288  	case sc := <-cc.NewSubConnCh:
   289  		t.Fatalf("got unexpected new SubConn, %s", sc)
   290  	case <-cc.RemoveSubConnCh:
   291  		t.Fatalf("got unexpected remove SubConn")
   292  	case <-time.After(time.Millisecond * 100):
   293  	}
   294  
   295  	// Turn down 1, use 2
   296  	pb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.TransientFailure})
   297  
   298  	// Before 2 gets READY, picker should return NoSubConnAvailable, so RPCs
   299  	// will retry.
   300  	p3 := <-cc.NewPickerCh
   301  	for i := 0; i < 5; i++ {
   302  		if _, err := p3.Pick(balancer.PickInfo{}); err != balancer.ErrNoSubConnAvailable {
   303  			t.Fatalf("want pick error %v, got %v", balancer.ErrNoSubConnAvailable, err)
   304  		}
   305  	}
   306  
   307  	addrs2 := <-cc.NewSubConnAddrsCh
   308  	if got, want := addrs2[0].Addr, testBackendAddrStrs[2]; got != want {
   309  		t.Fatalf("sc is created with addr %v, want %v", got, want)
   310  	}
   311  	sc2 := <-cc.NewSubConnCh
   312  	pb.UpdateSubConnState(sc2, balancer.SubConnState{ConnectivityState: connectivity.Connecting})
   313  	pb.UpdateSubConnState(sc2, balancer.SubConnState{ConnectivityState: connectivity.Ready})
   314  
   315  	// Test pick with 2.
   316  	p4 := <-cc.NewPickerCh
   317  	for i := 0; i < 5; i++ {
   318  		gotSCSt, _ := p4.Pick(balancer.PickInfo{})
   319  		if !cmp.Equal(gotSCSt.SubConn, sc2, cmp.AllowUnexported(testutils.TestSubConn{})) {
   320  			t.Fatalf("picker.Pick, got %v, want SubConn=%v", gotSCSt, sc2)
   321  		}
   322  	}
   323  
   324  	// Remove 2, use 1.
   325  	if err := pb.UpdateClientConnState(balancer.ClientConnState{
   326  		ResolverState: resolver.State{
   327  			Addresses: []resolver.Address{
   328  				hierarchy.Set(resolver.Address{Addr: testBackendAddrStrs[0]}, []string{"child-0"}),
   329  				hierarchy.Set(resolver.Address{Addr: testBackendAddrStrs[1]}, []string{"child-1"}),
   330  			},
   331  		},
   332  		BalancerConfig: &LBConfig{
   333  			Children: map[string]*Child{
   334  				"child-0": {Config: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}},
   335  				"child-1": {Config: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}},
   336  			},
   337  			Priorities: []string{"child-0", "child-1"},
   338  		},
   339  	}); err != nil {
   340  		t.Fatalf("failed to update ClientConn state: %v", err)
   341  	}
   342  
   343  	// p2 SubConns are removed.
   344  	scToRemove := <-cc.RemoveSubConnCh
   345  	if !cmp.Equal(scToRemove, sc2, cmp.AllowUnexported(testutils.TestSubConn{})) {
   346  		t.Fatalf("RemoveSubConn, want %v, got %v", sc2, scToRemove)
   347  	}
   348  
   349  	// Should get an update with 1's old transient failure picker, to override
   350  	// 2's old picker.
   351  	p5 := <-cc.NewPickerCh
   352  	for i := 0; i < 5; i++ {
   353  		if _, err := p5.Pick(balancer.PickInfo{}); err == nil {
   354  			t.Fatalf("want pick error non-nil, got nil")
   355  		}
   356  	}
   357  
   358  	pb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.Connecting})
   359  	pb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.Ready})
   360  
   361  	p6 := <-cc.NewPickerCh
   362  	for i := 0; i < 5; i++ {
   363  		gotSCSt, _ := p6.Pick(balancer.PickInfo{})
   364  		if !cmp.Equal(gotSCSt.SubConn, sc1, cmp.AllowUnexported(testutils.TestSubConn{})) {
   365  			t.Fatalf("picker.Pick, got %v, want SubConn=%v", gotSCSt, sc2)
   366  		}
   367  	}
   368  }
   369  
   370  // Lower priority is used when higher priority turns Connecting from Ready.
   371  // Because changing from Ready to Connecting is a failure.
   372  //
   373  // Init 0 and 1; 0 is up, use 0; 0 is connecting, 1 is up, use 1; 0 is ready,
   374  // use 0.
   375  func (s) TestPriority_HighPriorityToConnectingFromReady(t *testing.T) {
   376  	cc := testutils.NewTestClientConn(t)
   377  	bb := balancer.Get(Name)
   378  	pb := bb.Build(cc, balancer.BuildOptions{})
   379  	defer pb.Close()
   380  
   381  	// Two localities, with priorities [0, 1], each with one backend.
   382  	if err := pb.UpdateClientConnState(balancer.ClientConnState{
   383  		ResolverState: resolver.State{
   384  			Addresses: []resolver.Address{
   385  				hierarchy.Set(resolver.Address{Addr: testBackendAddrStrs[0]}, []string{"child-0"}),
   386  				hierarchy.Set(resolver.Address{Addr: testBackendAddrStrs[1]}, []string{"child-1"}),
   387  			},
   388  		},
   389  		BalancerConfig: &LBConfig{
   390  			Children: map[string]*Child{
   391  				"child-0": {Config: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}},
   392  				"child-1": {Config: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}},
   393  			},
   394  			Priorities: []string{"child-0", "child-1"},
   395  		},
   396  	}); err != nil {
   397  		t.Fatalf("failed to update ClientConn state: %v", err)
   398  	}
   399  
   400  	addrs0 := <-cc.NewSubConnAddrsCh
   401  	if got, want := addrs0[0].Addr, testBackendAddrStrs[0]; got != want {
   402  		t.Fatalf("sc is created with addr %v, want %v", got, want)
   403  	}
   404  	sc0 := <-cc.NewSubConnCh
   405  
   406  	// p0 is ready.
   407  	pb.UpdateSubConnState(sc0, balancer.SubConnState{ConnectivityState: connectivity.Connecting})
   408  	pb.UpdateSubConnState(sc0, balancer.SubConnState{ConnectivityState: connectivity.Ready})
   409  
   410  	// Test roundrobin with only p0 subconns.
   411  	p0 := <-cc.NewPickerCh
   412  	want := []balancer.SubConn{sc0}
   413  	if err := testutils.IsRoundRobin(want, subConnFromPicker(t, p0)); err != nil {
   414  		t.Fatalf("want %v, got %v", want, err)
   415  	}
   416  
   417  	// Turn 0 to Connecting, will start and use 1. Because 0 changing from Ready
   418  	// to Connecting is a failure.
   419  	pb.UpdateSubConnState(sc0, balancer.SubConnState{ConnectivityState: connectivity.Connecting})
   420  
   421  	// Before 1 gets READY, picker should return NoSubConnAvailable, so RPCs
   422  	// will retry.
   423  	p1 := <-cc.NewPickerCh
   424  	for i := 0; i < 5; i++ {
   425  		if _, err := p1.Pick(balancer.PickInfo{}); err != balancer.ErrNoSubConnAvailable {
   426  			t.Fatalf("want pick error %v, got %v", balancer.ErrNoSubConnAvailable, err)
   427  		}
   428  	}
   429  
   430  	// Handle SubConn creation from 1.
   431  	addrs1 := <-cc.NewSubConnAddrsCh
   432  	if got, want := addrs1[0].Addr, testBackendAddrStrs[1]; got != want {
   433  		t.Fatalf("sc is created with addr %v, want %v", got, want)
   434  	}
   435  	sc1 := <-cc.NewSubConnCh
   436  	pb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.Connecting})
   437  	pb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.Ready})
   438  
   439  	// Test pick with 1.
   440  	p2 := <-cc.NewPickerCh
   441  	for i := 0; i < 5; i++ {
   442  		gotSCSt, _ := p2.Pick(balancer.PickInfo{})
   443  		if !cmp.Equal(gotSCSt.SubConn, sc1, cmp.AllowUnexported(testutils.TestSubConn{})) {
   444  			t.Fatalf("picker.Pick, got %v, want SubConn=%v", gotSCSt, sc1)
   445  		}
   446  	}
   447  
   448  	// Turn 0 back to Ready.
   449  	pb.UpdateSubConnState(sc0, balancer.SubConnState{ConnectivityState: connectivity.Connecting})
   450  	pb.UpdateSubConnState(sc0, balancer.SubConnState{ConnectivityState: connectivity.Ready})
   451  
   452  	// p1 subconn should be removed.
   453  	scToRemove := <-cc.RemoveSubConnCh
   454  	if !cmp.Equal(scToRemove, sc1, cmp.AllowUnexported(testutils.TestSubConn{})) {
   455  		t.Fatalf("RemoveSubConn, want %v, got %v", sc0, scToRemove)
   456  	}
   457  
   458  	p3 := <-cc.NewPickerCh
   459  	for i := 0; i < 5; i++ {
   460  		gotSCSt, _ := p3.Pick(balancer.PickInfo{})
   461  		if !cmp.Equal(gotSCSt.SubConn, sc0, cmp.AllowUnexported(testutils.TestSubConn{})) {
   462  			t.Fatalf("picker.Pick, got %v, want SubConn=%v", gotSCSt, sc0)
   463  		}
   464  	}
   465  }
   466  
   467  // Add a lower priority while the higher priority is down.
   468  //
   469  // Init 0 and 1; 0 and 1 both down; add 2, use 2.
   470  func (s) TestPriority_HigherDownWhileAddingLower(t *testing.T) {
   471  	cc := testutils.NewTestClientConn(t)
   472  	bb := balancer.Get(Name)
   473  	pb := bb.Build(cc, balancer.BuildOptions{})
   474  	defer pb.Close()
   475  
   476  	// Two localities, with different priorities, each with one backend.
   477  	if err := pb.UpdateClientConnState(balancer.ClientConnState{
   478  		ResolverState: resolver.State{
   479  			Addresses: []resolver.Address{
   480  				hierarchy.Set(resolver.Address{Addr: testBackendAddrStrs[0]}, []string{"child-0"}),
   481  				hierarchy.Set(resolver.Address{Addr: testBackendAddrStrs[1]}, []string{"child-1"}),
   482  			},
   483  		},
   484  		BalancerConfig: &LBConfig{
   485  			Children: map[string]*Child{
   486  				"child-0": {Config: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}},
   487  				"child-1": {Config: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}},
   488  			},
   489  			Priorities: []string{"child-0", "child-1"},
   490  		},
   491  	}); err != nil {
   492  		t.Fatalf("failed to update ClientConn state: %v", err)
   493  	}
   494  
   495  	addrs0 := <-cc.NewSubConnAddrsCh
   496  	if got, want := addrs0[0].Addr, testBackendAddrStrs[0]; got != want {
   497  		t.Fatalf("sc is created with addr %v, want %v", got, want)
   498  	}
   499  	sc0 := <-cc.NewSubConnCh
   500  
   501  	// Turn down 0, 1 is used.
   502  	pb.UpdateSubConnState(sc0, balancer.SubConnState{ConnectivityState: connectivity.TransientFailure})
   503  
   504  	// Before 1 gets READY, picker should return NoSubConnAvailable, so RPCs
   505  	// will retry.
   506  	pFail0 := <-cc.NewPickerCh
   507  	for i := 0; i < 5; i++ {
   508  		if _, err := pFail0.Pick(balancer.PickInfo{}); err != balancer.ErrNoSubConnAvailable {
   509  			t.Fatalf("want pick error %v, got %v", balancer.ErrNoSubConnAvailable, err)
   510  		}
   511  	}
   512  
   513  	addrs1 := <-cc.NewSubConnAddrsCh
   514  	if got, want := addrs1[0].Addr, testBackendAddrStrs[1]; got != want {
   515  		t.Fatalf("sc is created with addr %v, want %v", got, want)
   516  	}
   517  	sc1 := <-cc.NewSubConnCh
   518  	// Turn down 1, pick should error.
   519  	pb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.TransientFailure})
   520  
   521  	// Test pick failure.
   522  	pFail1 := <-cc.NewPickerCh
   523  	for i := 0; i < 5; i++ {
   524  		if _, err := pFail1.Pick(balancer.PickInfo{}); err == nil {
   525  			t.Fatalf("want pick error non-nil, got nil")
   526  		}
   527  	}
   528  
   529  	// Add p2, it should create a new SubConn.
   530  	if err := pb.UpdateClientConnState(balancer.ClientConnState{
   531  		ResolverState: resolver.State{
   532  			Addresses: []resolver.Address{
   533  				hierarchy.Set(resolver.Address{Addr: testBackendAddrStrs[0]}, []string{"child-0"}),
   534  				hierarchy.Set(resolver.Address{Addr: testBackendAddrStrs[1]}, []string{"child-1"}),
   535  				hierarchy.Set(resolver.Address{Addr: testBackendAddrStrs[2]}, []string{"child-2"}),
   536  			},
   537  		},
   538  		BalancerConfig: &LBConfig{
   539  			Children: map[string]*Child{
   540  				"child-0": {Config: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}},
   541  				"child-1": {Config: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}},
   542  				"child-2": {Config: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}},
   543  			},
   544  			Priorities: []string{"child-0", "child-1", "child-2"},
   545  		},
   546  	}); err != nil {
   547  		t.Fatalf("failed to update ClientConn state: %v", err)
   548  	}
   549  
   550  	// A new connecting picker should be updated for the new priority.
   551  	p0 := <-cc.NewPickerCh
   552  	for i := 0; i < 5; i++ {
   553  		if _, err := p0.Pick(balancer.PickInfo{}); err != balancer.ErrNoSubConnAvailable {
   554  			t.Fatalf("want pick error %v, got %v", balancer.ErrNoSubConnAvailable, err)
   555  		}
   556  	}
   557  
   558  	addrs2 := <-cc.NewSubConnAddrsCh
   559  	if got, want := addrs2[0].Addr, testBackendAddrStrs[2]; got != want {
   560  		t.Fatalf("sc is created with addr %v, want %v", got, want)
   561  	}
   562  	sc2 := <-cc.NewSubConnCh
   563  	pb.UpdateSubConnState(sc2, balancer.SubConnState{ConnectivityState: connectivity.Connecting})
   564  	pb.UpdateSubConnState(sc2, balancer.SubConnState{ConnectivityState: connectivity.Ready})
   565  
   566  	// Test pick with 2.
   567  	p1 := <-cc.NewPickerCh
   568  	for i := 0; i < 5; i++ {
   569  		gotSCSt, _ := p1.Pick(balancer.PickInfo{})
   570  		if !cmp.Equal(gotSCSt.SubConn, sc2, cmp.AllowUnexported(testutils.TestSubConn{})) {
   571  			t.Fatalf("picker.Pick, got %v, want SubConn=%v", gotSCSt, sc2)
   572  		}
   573  	}
   574  }
   575  
   576  // When a higher priority becomes available, all lower priorities are closed.
   577  //
   578  // Init 0,1,2; 0 and 1 down, use 2; 0 up, close 1 and 2.
   579  func (s) TestPriority_HigherReadyCloseAllLower(t *testing.T) {
   580  	// defer time.Sleep(10 * time.Millisecond)
   581  
   582  	cc := testutils.NewTestClientConn(t)
   583  	bb := balancer.Get(Name)
   584  	pb := bb.Build(cc, balancer.BuildOptions{})
   585  	defer pb.Close()
   586  
   587  	// Three localities, with priorities [0,1,2], each with one backend.
   588  	if err := pb.UpdateClientConnState(balancer.ClientConnState{
   589  		ResolverState: resolver.State{
   590  			Addresses: []resolver.Address{
   591  				hierarchy.Set(resolver.Address{Addr: testBackendAddrStrs[0]}, []string{"child-0"}),
   592  				hierarchy.Set(resolver.Address{Addr: testBackendAddrStrs[1]}, []string{"child-1"}),
   593  				hierarchy.Set(resolver.Address{Addr: testBackendAddrStrs[2]}, []string{"child-2"}),
   594  			},
   595  		},
   596  		BalancerConfig: &LBConfig{
   597  			Children: map[string]*Child{
   598  				"child-0": {Config: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}},
   599  				"child-1": {Config: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}},
   600  				"child-2": {Config: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}},
   601  			},
   602  			Priorities: []string{"child-0", "child-1", "child-2"},
   603  		},
   604  	}); err != nil {
   605  		t.Fatalf("failed to update ClientConn state: %v", err)
   606  	}
   607  
   608  	addrs0 := <-cc.NewSubConnAddrsCh
   609  	if got, want := addrs0[0].Addr, testBackendAddrStrs[0]; got != want {
   610  		t.Fatalf("sc is created with addr %v, want %v", got, want)
   611  	}
   612  	sc0 := <-cc.NewSubConnCh
   613  
   614  	// Turn down 0, 1 is used.
   615  	pb.UpdateSubConnState(sc0, balancer.SubConnState{ConnectivityState: connectivity.TransientFailure})
   616  	// Before 1 gets READY, picker should return NoSubConnAvailable, so RPCs
   617  	// will retry.
   618  	pFail0 := <-cc.NewPickerCh
   619  	for i := 0; i < 5; i++ {
   620  		if _, err := pFail0.Pick(balancer.PickInfo{}); err != balancer.ErrNoSubConnAvailable {
   621  			t.Fatalf("want pick error %v, got %v", balancer.ErrNoSubConnAvailable, err)
   622  		}
   623  	}
   624  
   625  	addrs1 := <-cc.NewSubConnAddrsCh
   626  	if got, want := addrs1[0].Addr, testBackendAddrStrs[1]; got != want {
   627  		t.Fatalf("sc is created with addr %v, want %v", got, want)
   628  	}
   629  	sc1 := <-cc.NewSubConnCh
   630  
   631  	// Turn down 1, 2 is used.
   632  	pb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.TransientFailure})
   633  	// Before 2 gets READY, picker should return NoSubConnAvailable, so RPCs
   634  	// will retry.
   635  	pFail1 := <-cc.NewPickerCh
   636  	for i := 0; i < 5; i++ {
   637  		if _, err := pFail1.Pick(balancer.PickInfo{}); err != balancer.ErrNoSubConnAvailable {
   638  			t.Fatalf("want pick error %v, got %v", balancer.ErrNoSubConnAvailable, err)
   639  		}
   640  	}
   641  
   642  	addrs2 := <-cc.NewSubConnAddrsCh
   643  	if got, want := addrs2[0].Addr, testBackendAddrStrs[2]; got != want {
   644  		t.Fatalf("sc is created with addr %v, want %v", got, want)
   645  	}
   646  	sc2 := <-cc.NewSubConnCh
   647  	pb.UpdateSubConnState(sc2, balancer.SubConnState{ConnectivityState: connectivity.Connecting})
   648  	pb.UpdateSubConnState(sc2, balancer.SubConnState{ConnectivityState: connectivity.Ready})
   649  
   650  	// Test pick with 2.
   651  	p2 := <-cc.NewPickerCh
   652  	for i := 0; i < 5; i++ {
   653  		gotSCSt, _ := p2.Pick(balancer.PickInfo{})
   654  		if !cmp.Equal(gotSCSt.SubConn, sc2, cmp.AllowUnexported(testutils.TestSubConn{})) {
   655  			t.Fatalf("picker.Pick, got %v, want SubConn=%v", gotSCSt, sc2)
   656  		}
   657  	}
   658  
   659  	// When 0 becomes ready, 0 should be used, 1 and 2 should all be closed.
   660  	pb.UpdateSubConnState(sc0, balancer.SubConnState{ConnectivityState: connectivity.Ready})
   661  
   662  	// sc1 and sc2 should be removed.
   663  	//
   664  	// With localities caching, the lower priorities are closed after a timeout,
   665  	// in goroutines. The order is no longer guaranteed.
   666  	scToRemove := []balancer.SubConn{<-cc.RemoveSubConnCh, <-cc.RemoveSubConnCh}
   667  	if !(cmp.Equal(scToRemove[0], sc1, cmp.AllowUnexported(testutils.TestSubConn{})) &&
   668  		cmp.Equal(scToRemove[1], sc2, cmp.AllowUnexported(testutils.TestSubConn{}))) &&
   669  		!(cmp.Equal(scToRemove[0], sc2, cmp.AllowUnexported(testutils.TestSubConn{})) &&
   670  			cmp.Equal(scToRemove[1], sc1, cmp.AllowUnexported(testutils.TestSubConn{}))) {
   671  		t.Errorf("RemoveSubConn, want [%v, %v], got %v", sc1, sc2, scToRemove)
   672  	}
   673  
   674  	// Test pick with 0.
   675  	p0 := <-cc.NewPickerCh
   676  	for i := 0; i < 5; i++ {
   677  		gotSCSt, _ := p0.Pick(balancer.PickInfo{})
   678  		if !cmp.Equal(gotSCSt.SubConn, sc0, cmp.AllowUnexported(testutils.TestSubConn{})) {
   679  			t.Fatalf("picker.Pick, got %v, want SubConn=%v", gotSCSt, sc0)
   680  		}
   681  	}
   682  }
   683  
   684  // At init, start the next lower priority after timeout if the higher priority
   685  // doesn't get ready.
   686  //
   687  // Init 0,1; 0 is not ready (in connecting), after timeout, use 1.
   688  func (s) TestPriority_InitTimeout(t *testing.T) {
   689  	const testPriorityInitTimeout = time.Second
   690  	defer func() func() {
   691  		old := DefaultPriorityInitTimeout
   692  		DefaultPriorityInitTimeout = testPriorityInitTimeout
   693  		return func() {
   694  			DefaultPriorityInitTimeout = old
   695  		}
   696  	}()()
   697  
   698  	cc := testutils.NewTestClientConn(t)
   699  	bb := balancer.Get(Name)
   700  	pb := bb.Build(cc, balancer.BuildOptions{})
   701  	defer pb.Close()
   702  
   703  	// Two localities, with different priorities, each with one backend.
   704  	if err := pb.UpdateClientConnState(balancer.ClientConnState{
   705  		ResolverState: resolver.State{
   706  			Addresses: []resolver.Address{
   707  				hierarchy.Set(resolver.Address{Addr: testBackendAddrStrs[0]}, []string{"child-0"}),
   708  				hierarchy.Set(resolver.Address{Addr: testBackendAddrStrs[1]}, []string{"child-1"}),
   709  			},
   710  		},
   711  		BalancerConfig: &LBConfig{
   712  			Children: map[string]*Child{
   713  				"child-0": {Config: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}},
   714  				"child-1": {Config: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}},
   715  			},
   716  			Priorities: []string{"child-0", "child-1"},
   717  		},
   718  	}); err != nil {
   719  		t.Fatalf("failed to update ClientConn state: %v", err)
   720  	}
   721  
   722  	addrs0 := <-cc.NewSubConnAddrsCh
   723  	if got, want := addrs0[0].Addr, testBackendAddrStrs[0]; got != want {
   724  		t.Fatalf("sc is created with addr %v, want %v", got, want)
   725  	}
   726  	sc0 := <-cc.NewSubConnCh
   727  
   728  	// Keep 0 in connecting, 1 will be used after init timeout.
   729  	pb.UpdateSubConnState(sc0, balancer.SubConnState{ConnectivityState: connectivity.Connecting})
   730  
   731  	// Make sure new SubConn is created before timeout.
   732  	select {
   733  	case <-time.After(testPriorityInitTimeout * 3 / 4):
   734  	case <-cc.NewSubConnAddrsCh:
   735  		t.Fatalf("Got a new SubConn too early (Within timeout). Expect a new SubConn only after timeout")
   736  	}
   737  
   738  	addrs1 := <-cc.NewSubConnAddrsCh
   739  	if got, want := addrs1[0].Addr, testBackendAddrStrs[1]; got != want {
   740  		t.Fatalf("sc is created with addr %v, want %v", got, want)
   741  	}
   742  	sc1 := <-cc.NewSubConnCh
   743  
   744  	pb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.Connecting})
   745  	pb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.Ready})
   746  
   747  	// Test pick with 1.
   748  	p1 := <-cc.NewPickerCh
   749  	for i := 0; i < 5; i++ {
   750  		gotSCSt, _ := p1.Pick(balancer.PickInfo{})
   751  		if !cmp.Equal(gotSCSt.SubConn, sc1, cmp.AllowUnexported(testutils.TestSubConn{})) {
   752  			t.Fatalf("picker.Pick, got %v, want SubConn=%v", gotSCSt, sc1)
   753  		}
   754  	}
   755  }
   756  
   757  // EDS removes all priorities, and re-adds them.
   758  func (s) TestPriority_RemovesAllPriorities(t *testing.T) {
   759  	const testPriorityInitTimeout = time.Second
   760  	defer func() func() {
   761  		old := DefaultPriorityInitTimeout
   762  		DefaultPriorityInitTimeout = testPriorityInitTimeout
   763  		return func() {
   764  			DefaultPriorityInitTimeout = old
   765  		}
   766  	}()()
   767  
   768  	cc := testutils.NewTestClientConn(t)
   769  	bb := balancer.Get(Name)
   770  	pb := bb.Build(cc, balancer.BuildOptions{})
   771  	defer pb.Close()
   772  
   773  	// Two localities, with different priorities, each with one backend.
   774  	if err := pb.UpdateClientConnState(balancer.ClientConnState{
   775  		ResolverState: resolver.State{
   776  			Addresses: []resolver.Address{
   777  				hierarchy.Set(resolver.Address{Addr: testBackendAddrStrs[0]}, []string{"child-0"}),
   778  				hierarchy.Set(resolver.Address{Addr: testBackendAddrStrs[1]}, []string{"child-1"}),
   779  			},
   780  		},
   781  		BalancerConfig: &LBConfig{
   782  			Children: map[string]*Child{
   783  				"child-0": {Config: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}},
   784  				"child-1": {Config: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}},
   785  			},
   786  			Priorities: []string{"child-0", "child-1"},
   787  		},
   788  	}); err != nil {
   789  		t.Fatalf("failed to update ClientConn state: %v", err)
   790  	}
   791  
   792  	addrs0 := <-cc.NewSubConnAddrsCh
   793  	if got, want := addrs0[0].Addr, testBackendAddrStrs[0]; got != want {
   794  		t.Fatalf("sc is created with addr %v, want %v", got, want)
   795  	}
   796  	sc0 := <-cc.NewSubConnCh
   797  	pb.UpdateSubConnState(sc0, balancer.SubConnState{ConnectivityState: connectivity.Connecting})
   798  	pb.UpdateSubConnState(sc0, balancer.SubConnState{ConnectivityState: connectivity.Ready})
   799  
   800  	// Test roundrobin with only p0 subconns.
   801  	p0 := <-cc.NewPickerCh
   802  	want := []balancer.SubConn{sc0}
   803  	if err := testutils.IsRoundRobin(want, subConnFromPicker(t, p0)); err != nil {
   804  		t.Fatalf("want %v, got %v", want, err)
   805  	}
   806  
   807  	// Remove all priorities.
   808  	if err := pb.UpdateClientConnState(balancer.ClientConnState{
   809  		ResolverState: resolver.State{
   810  			Addresses: nil,
   811  		},
   812  		BalancerConfig: &LBConfig{
   813  			Children:   nil,
   814  			Priorities: nil,
   815  		},
   816  	}); err != nil {
   817  		t.Fatalf("failed to update ClientConn state: %v", err)
   818  	}
   819  
   820  	// p0 subconn should be removed.
   821  	scToRemove := <-cc.RemoveSubConnCh
   822  	if !cmp.Equal(scToRemove, sc0, cmp.AllowUnexported(testutils.TestSubConn{})) {
   823  		t.Fatalf("RemoveSubConn, want %v, got %v", sc0, scToRemove)
   824  	}
   825  
   826  	// Test pick return TransientFailure.
   827  	pFail := <-cc.NewPickerCh
   828  	for i := 0; i < 5; i++ {
   829  		if _, err := pFail.Pick(balancer.PickInfo{}); err != ErrAllPrioritiesRemoved {
   830  			t.Fatalf("want pick error %v, got %v", ErrAllPrioritiesRemoved, err)
   831  		}
   832  	}
   833  
   834  	// Re-add two localities, with previous priorities, but different backends.
   835  	if err := pb.UpdateClientConnState(balancer.ClientConnState{
   836  		ResolverState: resolver.State{
   837  			Addresses: []resolver.Address{
   838  				hierarchy.Set(resolver.Address{Addr: testBackendAddrStrs[2]}, []string{"child-0"}),
   839  				hierarchy.Set(resolver.Address{Addr: testBackendAddrStrs[3]}, []string{"child-1"}),
   840  			},
   841  		},
   842  		BalancerConfig: &LBConfig{
   843  			Children: map[string]*Child{
   844  				"child-0": {Config: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}},
   845  				"child-1": {Config: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}},
   846  			},
   847  			Priorities: []string{"child-0", "child-1"},
   848  		},
   849  	}); err != nil {
   850  		t.Fatalf("failed to update ClientConn state: %v", err)
   851  	}
   852  
   853  	addrs01 := <-cc.NewSubConnAddrsCh
   854  	if got, want := addrs01[0].Addr, testBackendAddrStrs[2]; got != want {
   855  		t.Fatalf("sc is created with addr %v, want %v", got, want)
   856  	}
   857  	sc01 := <-cc.NewSubConnCh
   858  
   859  	// Don't send any update to p0, so to not override the old state of p0.
   860  	// Later, connect to p1 and then remove p1. This will fallback to p0, and
   861  	// will send p0's old picker if they are not correctly removed.
   862  
   863  	// p1 will be used after priority init timeout.
   864  	addrs11 := <-cc.NewSubConnAddrsCh
   865  	if got, want := addrs11[0].Addr, testBackendAddrStrs[3]; got != want {
   866  		t.Fatalf("sc is created with addr %v, want %v", got, want)
   867  	}
   868  	sc11 := <-cc.NewSubConnCh
   869  	pb.UpdateSubConnState(sc11, balancer.SubConnState{ConnectivityState: connectivity.Connecting})
   870  	pb.UpdateSubConnState(sc11, balancer.SubConnState{ConnectivityState: connectivity.Ready})
   871  
   872  	// Test roundrobin with only p1 subconns.
   873  	p1 := <-cc.NewPickerCh
   874  	want = []balancer.SubConn{sc11}
   875  	if err := testutils.IsRoundRobin(want, subConnFromPicker(t, p1)); err != nil {
   876  		t.Fatalf("want %v, got %v", want, err)
   877  	}
   878  
   879  	// Remove p1, to fallback to p0.
   880  	if err := pb.UpdateClientConnState(balancer.ClientConnState{
   881  		ResolverState: resolver.State{
   882  			Addresses: []resolver.Address{
   883  				hierarchy.Set(resolver.Address{Addr: testBackendAddrStrs[2]}, []string{"child-0"}),
   884  			},
   885  		},
   886  		BalancerConfig: &LBConfig{
   887  			Children: map[string]*Child{
   888  				"child-0": {Config: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}},
   889  			},
   890  			Priorities: []string{"child-0"},
   891  		},
   892  	}); err != nil {
   893  		t.Fatalf("failed to update ClientConn state: %v", err)
   894  	}
   895  
   896  	// p1 subconn should be removed.
   897  	scToRemove1 := <-cc.RemoveSubConnCh
   898  	if !cmp.Equal(scToRemove1, sc11, cmp.AllowUnexported(testutils.TestSubConn{})) {
   899  		t.Fatalf("RemoveSubConn, want %v, got %v", sc11, scToRemove1)
   900  	}
   901  
   902  	// Test pick return NoSubConn.
   903  	pFail1 := <-cc.NewPickerCh
   904  	for i := 0; i < 5; i++ {
   905  		if scst, err := pFail1.Pick(balancer.PickInfo{}); err != balancer.ErrNoSubConnAvailable {
   906  			t.Fatalf("want pick error _, %v, got %v, _ ,%v", balancer.ErrNoSubConnAvailable, scst, err)
   907  		}
   908  	}
   909  
   910  	// Send an ready update for the p0 sc that was received when re-adding
   911  	// priorities.
   912  	pb.UpdateSubConnState(sc01, balancer.SubConnState{ConnectivityState: connectivity.Connecting})
   913  	pb.UpdateSubConnState(sc01, balancer.SubConnState{ConnectivityState: connectivity.Ready})
   914  
   915  	// Test roundrobin with only p0 subconns.
   916  	p2 := <-cc.NewPickerCh
   917  	want = []balancer.SubConn{sc01}
   918  	if err := testutils.IsRoundRobin(want, subConnFromPicker(t, p2)); err != nil {
   919  		t.Fatalf("want %v, got %v", want, err)
   920  	}
   921  
   922  	select {
   923  	case <-cc.NewPickerCh:
   924  		t.Fatalf("got unexpected new picker")
   925  	case <-cc.NewSubConnCh:
   926  		t.Fatalf("got unexpected new SubConn")
   927  	case <-cc.RemoveSubConnCh:
   928  		t.Fatalf("got unexpected remove SubConn")
   929  	case <-time.After(time.Millisecond * 100):
   930  	}
   931  }
   932  
   933  // Test the case where the high priority contains no backends. The low priority
   934  // will be used.
   935  func (s) TestPriority_HighPriorityNoEndpoints(t *testing.T) {
   936  	cc := testutils.NewTestClientConn(t)
   937  	bb := balancer.Get(Name)
   938  	pb := bb.Build(cc, balancer.BuildOptions{})
   939  	defer pb.Close()
   940  
   941  	// Two localities, with priorities [0, 1], each with one backend.
   942  	if err := pb.UpdateClientConnState(balancer.ClientConnState{
   943  		ResolverState: resolver.State{
   944  			Addresses: []resolver.Address{
   945  				hierarchy.Set(resolver.Address{Addr: testBackendAddrStrs[0]}, []string{"child-0"}),
   946  				hierarchy.Set(resolver.Address{Addr: testBackendAddrStrs[1]}, []string{"child-1"}),
   947  			},
   948  		},
   949  		BalancerConfig: &LBConfig{
   950  			Children: map[string]*Child{
   951  				"child-0": {Config: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}},
   952  				"child-1": {Config: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}},
   953  			},
   954  			Priorities: []string{"child-0", "child-1"},
   955  		},
   956  	}); err != nil {
   957  		t.Fatalf("failed to update ClientConn state: %v", err)
   958  	}
   959  
   960  	addrs1 := <-cc.NewSubConnAddrsCh
   961  	if got, want := addrs1[0].Addr, testBackendAddrStrs[0]; got != want {
   962  		t.Fatalf("sc is created with addr %v, want %v", got, want)
   963  	}
   964  	sc1 := <-cc.NewSubConnCh
   965  
   966  	// p0 is ready.
   967  	pb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.Connecting})
   968  	pb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.Ready})
   969  
   970  	// Test roundrobin with only p0 subconns.
   971  	p1 := <-cc.NewPickerCh
   972  	want := []balancer.SubConn{sc1}
   973  	if err := testutils.IsRoundRobin(want, subConnFromPicker(t, p1)); err != nil {
   974  		t.Fatalf("want %v, got %v", want, err)
   975  	}
   976  
   977  	// Remove addresses from priority 0, should use p1.
   978  	if err := pb.UpdateClientConnState(balancer.ClientConnState{
   979  		ResolverState: resolver.State{
   980  			Addresses: []resolver.Address{
   981  				hierarchy.Set(resolver.Address{Addr: testBackendAddrStrs[1]}, []string{"child-1"}),
   982  			},
   983  		},
   984  		BalancerConfig: &LBConfig{
   985  			Children: map[string]*Child{
   986  				"child-0": {Config: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}},
   987  				"child-1": {Config: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}},
   988  			},
   989  			Priorities: []string{"child-0", "child-1"},
   990  		},
   991  	}); err != nil {
   992  		t.Fatalf("failed to update ClientConn state: %v", err)
   993  	}
   994  
   995  	// p0 will remove the subconn, and ClientConn will send a sc update to
   996  	// shutdown.
   997  	scToRemove := <-cc.RemoveSubConnCh
   998  	pb.UpdateSubConnState(scToRemove, balancer.SubConnState{ConnectivityState: connectivity.Shutdown})
   999  
  1000  	addrs2 := <-cc.NewSubConnAddrsCh
  1001  	if got, want := addrs2[0].Addr, testBackendAddrStrs[1]; got != want {
  1002  		t.Fatalf("sc is created with addr %v, want %v", got, want)
  1003  	}
  1004  	sc2 := <-cc.NewSubConnCh
  1005  
  1006  	// Before 1 gets READY, picker should return NoSubConnAvailable, so RPCs
  1007  	// will retry.
  1008  	pFail1 := <-cc.NewPickerCh
  1009  	for i := 0; i < 5; i++ {
  1010  		if _, err := pFail1.Pick(balancer.PickInfo{}); err != balancer.ErrNoSubConnAvailable {
  1011  			t.Fatalf("want pick error %v, got %v", balancer.ErrNoSubConnAvailable, err)
  1012  		}
  1013  	}
  1014  
  1015  	// p1 is ready.
  1016  	pb.UpdateSubConnState(sc2, balancer.SubConnState{ConnectivityState: connectivity.Connecting})
  1017  	pb.UpdateSubConnState(sc2, balancer.SubConnState{ConnectivityState: connectivity.Ready})
  1018  
  1019  	// Test roundrobin with only p1 subconns.
  1020  	p2 := <-cc.NewPickerCh
  1021  	want = []balancer.SubConn{sc2}
  1022  	if err := testutils.IsRoundRobin(want, subConnFromPicker(t, p2)); err != nil {
  1023  		t.Fatalf("want %v, got %v", want, err)
  1024  	}
  1025  }
  1026  
  1027  // Test the case where the first and only priority is removed.
  1028  func (s) TestPriority_FirstPriorityUnavailable(t *testing.T) {
  1029  	const testPriorityInitTimeout = time.Second
  1030  	defer func(t time.Duration) {
  1031  		DefaultPriorityInitTimeout = t
  1032  	}(DefaultPriorityInitTimeout)
  1033  	DefaultPriorityInitTimeout = testPriorityInitTimeout
  1034  
  1035  	cc := testutils.NewTestClientConn(t)
  1036  	bb := balancer.Get(Name)
  1037  	pb := bb.Build(cc, balancer.BuildOptions{})
  1038  	defer pb.Close()
  1039  
  1040  	// One localities, with priorities [0], each with one backend.
  1041  	if err := pb.UpdateClientConnState(balancer.ClientConnState{
  1042  		ResolverState: resolver.State{
  1043  			Addresses: []resolver.Address{
  1044  				hierarchy.Set(resolver.Address{Addr: testBackendAddrStrs[0]}, []string{"child-0"}),
  1045  			},
  1046  		},
  1047  		BalancerConfig: &LBConfig{
  1048  			Children: map[string]*Child{
  1049  				"child-0": {Config: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}},
  1050  			},
  1051  			Priorities: []string{"child-0"},
  1052  		},
  1053  	}); err != nil {
  1054  		t.Fatalf("failed to update ClientConn state: %v", err)
  1055  	}
  1056  
  1057  	// Remove the only localities.
  1058  	if err := pb.UpdateClientConnState(balancer.ClientConnState{
  1059  		ResolverState: resolver.State{
  1060  			Addresses: nil,
  1061  		},
  1062  		BalancerConfig: &LBConfig{
  1063  			Children:   nil,
  1064  			Priorities: nil,
  1065  		},
  1066  	}); err != nil {
  1067  		t.Fatalf("failed to update ClientConn state: %v", err)
  1068  	}
  1069  
  1070  	// Wait after double the init timer timeout, to ensure it doesn't panic.
  1071  	time.Sleep(testPriorityInitTimeout * 2)
  1072  }
  1073  
  1074  // When a child is moved from low priority to high.
  1075  //
  1076  // Init a(p0) and b(p1); a(p0) is up, use a; move b to p0, a to p1, use b.
  1077  func (s) TestPriority_MoveChildToHigherPriority(t *testing.T) {
  1078  	cc := testutils.NewTestClientConn(t)
  1079  	bb := balancer.Get(Name)
  1080  	pb := bb.Build(cc, balancer.BuildOptions{})
  1081  	defer pb.Close()
  1082  
  1083  	// Two children, with priorities [0, 1], each with one backend.
  1084  	if err := pb.UpdateClientConnState(balancer.ClientConnState{
  1085  		ResolverState: resolver.State{
  1086  			Addresses: []resolver.Address{
  1087  				hierarchy.Set(resolver.Address{Addr: testBackendAddrStrs[0]}, []string{"child-0"}),
  1088  				hierarchy.Set(resolver.Address{Addr: testBackendAddrStrs[1]}, []string{"child-1"}),
  1089  			},
  1090  		},
  1091  		BalancerConfig: &LBConfig{
  1092  			Children: map[string]*Child{
  1093  				"child-0": {Config: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}},
  1094  				"child-1": {Config: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}},
  1095  			},
  1096  			Priorities: []string{"child-0", "child-1"},
  1097  		},
  1098  	}); err != nil {
  1099  		t.Fatalf("failed to update ClientConn state: %v", err)
  1100  	}
  1101  
  1102  	addrs1 := <-cc.NewSubConnAddrsCh
  1103  	if got, want := addrs1[0].Addr, testBackendAddrStrs[0]; got != want {
  1104  		t.Fatalf("sc is created with addr %v, want %v", got, want)
  1105  	}
  1106  	sc1 := <-cc.NewSubConnCh
  1107  
  1108  	// p0 is ready.
  1109  	pb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.Connecting})
  1110  	pb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.Ready})
  1111  
  1112  	// Test roundrobin with only p0 subconns.
  1113  	p1 := <-cc.NewPickerCh
  1114  	want := []balancer.SubConn{sc1}
  1115  	if err := testutils.IsRoundRobin(want, subConnFromPicker(t, p1)); err != nil {
  1116  		t.Fatalf("want %v, got %v", want, err)
  1117  	}
  1118  
  1119  	// Swap child with p0 and p1, the child at lower priority should now be the
  1120  	// higher priority, and be used. The old SubConn should be closed.
  1121  	if err := pb.UpdateClientConnState(balancer.ClientConnState{
  1122  		ResolverState: resolver.State{
  1123  			Addresses: []resolver.Address{
  1124  				hierarchy.Set(resolver.Address{Addr: testBackendAddrStrs[0]}, []string{"child-0"}),
  1125  				hierarchy.Set(resolver.Address{Addr: testBackendAddrStrs[1]}, []string{"child-1"}),
  1126  			},
  1127  		},
  1128  		BalancerConfig: &LBConfig{
  1129  			Children: map[string]*Child{
  1130  				"child-0": {Config: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}},
  1131  				"child-1": {Config: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}},
  1132  			},
  1133  			Priorities: []string{"child-1", "child-0"},
  1134  		},
  1135  	}); err != nil {
  1136  		t.Fatalf("failed to update ClientConn state: %v", err)
  1137  	}
  1138  
  1139  	// When the new child for p0 is changed from the previous child, the
  1140  	// balancer should immediately update the picker so the picker from old
  1141  	// child is not used. In this case, the picker becomes a
  1142  	// no-subconn-available picker because this child is just started.
  1143  	pFail := <-cc.NewPickerCh
  1144  	for i := 0; i < 5; i++ {
  1145  		if _, err := pFail.Pick(balancer.PickInfo{}); err != balancer.ErrNoSubConnAvailable {
  1146  			t.Fatalf("want pick error %v, got %v", balancer.ErrNoSubConnAvailable, err)
  1147  		}
  1148  	}
  1149  
  1150  	// Old subconn should be removed.
  1151  	scToRemove := <-cc.RemoveSubConnCh
  1152  	if !cmp.Equal(scToRemove, sc1, cmp.AllowUnexported(testutils.TestSubConn{})) {
  1153  		t.Fatalf("RemoveSubConn, want %v, got %v", sc1, scToRemove)
  1154  	}
  1155  
  1156  	addrs2 := <-cc.NewSubConnAddrsCh
  1157  	if got, want := addrs2[0].Addr, testBackendAddrStrs[1]; got != want {
  1158  		t.Fatalf("sc is created with addr %v, want %v", got, want)
  1159  	}
  1160  	sc2 := <-cc.NewSubConnCh
  1161  
  1162  	// New p0 child is ready.
  1163  	pb.UpdateSubConnState(sc2, balancer.SubConnState{ConnectivityState: connectivity.Connecting})
  1164  	pb.UpdateSubConnState(sc2, balancer.SubConnState{ConnectivityState: connectivity.Ready})
  1165  
  1166  	// Test roundrobin with only new subconns.
  1167  	p2 := <-cc.NewPickerCh
  1168  	want2 := []balancer.SubConn{sc2}
  1169  	if err := testutils.IsRoundRobin(want2, subConnFromPicker(t, p2)); err != nil {
  1170  		t.Fatalf("want %v, got %v", want2, err)
  1171  	}
  1172  }
  1173  
  1174  // When a child is in lower priority, and in use (because higher is down),
  1175  // move it from low priority to high.
  1176  //
  1177  // Init a(p0) and b(p1); a(p0) is down, use b; move b to p0, a to p1, use b.
  1178  func (s) TestPriority_MoveReadyChildToHigherPriority(t *testing.T) {
  1179  	cc := testutils.NewTestClientConn(t)
  1180  	bb := balancer.Get(Name)
  1181  	pb := bb.Build(cc, balancer.BuildOptions{})
  1182  	defer pb.Close()
  1183  
  1184  	// Two children, with priorities [0, 1], each with one backend.
  1185  	if err := pb.UpdateClientConnState(balancer.ClientConnState{
  1186  		ResolverState: resolver.State{
  1187  			Addresses: []resolver.Address{
  1188  				hierarchy.Set(resolver.Address{Addr: testBackendAddrStrs[0]}, []string{"child-0"}),
  1189  				hierarchy.Set(resolver.Address{Addr: testBackendAddrStrs[1]}, []string{"child-1"}),
  1190  			},
  1191  		},
  1192  		BalancerConfig: &LBConfig{
  1193  			Children: map[string]*Child{
  1194  				"child-0": {Config: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}},
  1195  				"child-1": {Config: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}},
  1196  			},
  1197  			Priorities: []string{"child-0", "child-1"},
  1198  		},
  1199  	}); err != nil {
  1200  		t.Fatalf("failed to update ClientConn state: %v", err)
  1201  	}
  1202  
  1203  	addrs0 := <-cc.NewSubConnAddrsCh
  1204  	if got, want := addrs0[0].Addr, testBackendAddrStrs[0]; got != want {
  1205  		t.Fatalf("sc is created with addr %v, want %v", got, want)
  1206  	}
  1207  	sc0 := <-cc.NewSubConnCh
  1208  
  1209  	// p0 is down.
  1210  	pb.UpdateSubConnState(sc0, balancer.SubConnState{ConnectivityState: connectivity.TransientFailure})
  1211  	// Before 1 gets READY, picker should return NoSubConnAvailable, so RPCs
  1212  	// will retry.
  1213  	pFail0 := <-cc.NewPickerCh
  1214  	for i := 0; i < 5; i++ {
  1215  		if _, err := pFail0.Pick(balancer.PickInfo{}); err != balancer.ErrNoSubConnAvailable {
  1216  			t.Fatalf("want pick error %v, got %v", balancer.ErrNoSubConnAvailable, err)
  1217  		}
  1218  	}
  1219  
  1220  	addrs1 := <-cc.NewSubConnAddrsCh
  1221  	if got, want := addrs1[0].Addr, testBackendAddrStrs[1]; got != want {
  1222  		t.Fatalf("sc is created with addr %v, want %v", got, want)
  1223  	}
  1224  	sc1 := <-cc.NewSubConnCh
  1225  	pb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.Connecting})
  1226  	pb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.Ready})
  1227  
  1228  	// Test roundrobin with only p1 subconns.
  1229  	p0 := <-cc.NewPickerCh
  1230  	want := []balancer.SubConn{sc1}
  1231  	if err := testutils.IsRoundRobin(want, subConnFromPicker(t, p0)); err != nil {
  1232  		t.Fatalf("want %v, got %v", want, err)
  1233  	}
  1234  
  1235  	// Swap child with p0 and p1, the child at lower priority should now be the
  1236  	// higher priority, and be used. The old SubConn should be closed.
  1237  	if err := pb.UpdateClientConnState(balancer.ClientConnState{
  1238  		ResolverState: resolver.State{
  1239  			Addresses: []resolver.Address{
  1240  				hierarchy.Set(resolver.Address{Addr: testBackendAddrStrs[0]}, []string{"child-0"}),
  1241  				hierarchy.Set(resolver.Address{Addr: testBackendAddrStrs[1]}, []string{"child-1"}),
  1242  			},
  1243  		},
  1244  		BalancerConfig: &LBConfig{
  1245  			Children: map[string]*Child{
  1246  				"child-0": {Config: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}},
  1247  				"child-1": {Config: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}},
  1248  			},
  1249  			Priorities: []string{"child-1", "child-0"},
  1250  		},
  1251  	}); err != nil {
  1252  		t.Fatalf("failed to update ClientConn state: %v", err)
  1253  	}
  1254  
  1255  	// Old subconn from child-0 should be removed.
  1256  	scToRemove := <-cc.RemoveSubConnCh
  1257  	if !cmp.Equal(scToRemove, sc0, cmp.AllowUnexported(testutils.TestSubConn{})) {
  1258  		t.Fatalf("RemoveSubConn, want %v, got %v", sc0, scToRemove)
  1259  	}
  1260  
  1261  	// Because this was a ready child moved to a higher priority, no new subconn
  1262  	// or picker should be updated.
  1263  	select {
  1264  	case <-cc.NewPickerCh:
  1265  		t.Fatalf("got unexpected new picker")
  1266  	case <-cc.NewSubConnCh:
  1267  		t.Fatalf("got unexpected new SubConn")
  1268  	case <-cc.RemoveSubConnCh:
  1269  		t.Fatalf("got unexpected remove SubConn")
  1270  	case <-time.After(time.Millisecond * 100):
  1271  	}
  1272  }
  1273  
  1274  // When the lowest child is in use, and is removed, should use the higher
  1275  // priority child even though it's not ready.
  1276  //
  1277  // Init a(p0) and b(p1); a(p0) is down, use b; move b to p0, a to p1, use b.
  1278  func (s) TestPriority_RemoveReadyLowestChild(t *testing.T) {
  1279  	cc := testutils.NewTestClientConn(t)
  1280  	bb := balancer.Get(Name)
  1281  	pb := bb.Build(cc, balancer.BuildOptions{})
  1282  	defer pb.Close()
  1283  
  1284  	// Two children, with priorities [0, 1], each with one backend.
  1285  	if err := pb.UpdateClientConnState(balancer.ClientConnState{
  1286  		ResolverState: resolver.State{
  1287  			Addresses: []resolver.Address{
  1288  				hierarchy.Set(resolver.Address{Addr: testBackendAddrStrs[0]}, []string{"child-0"}),
  1289  				hierarchy.Set(resolver.Address{Addr: testBackendAddrStrs[1]}, []string{"child-1"}),
  1290  			},
  1291  		},
  1292  		BalancerConfig: &LBConfig{
  1293  			Children: map[string]*Child{
  1294  				"child-0": {Config: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}},
  1295  				"child-1": {Config: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}},
  1296  			},
  1297  			Priorities: []string{"child-0", "child-1"},
  1298  		},
  1299  	}); err != nil {
  1300  		t.Fatalf("failed to update ClientConn state: %v", err)
  1301  	}
  1302  
  1303  	addrs0 := <-cc.NewSubConnAddrsCh
  1304  	if got, want := addrs0[0].Addr, testBackendAddrStrs[0]; got != want {
  1305  		t.Fatalf("sc is created with addr %v, want %v", got, want)
  1306  	}
  1307  	sc0 := <-cc.NewSubConnCh
  1308  
  1309  	// p0 is down.
  1310  	pb.UpdateSubConnState(sc0, balancer.SubConnState{ConnectivityState: connectivity.TransientFailure})
  1311  	// Before 1 gets READY, picker should return NoSubConnAvailable, so RPCs
  1312  	// will retry.
  1313  	pFail0 := <-cc.NewPickerCh
  1314  	for i := 0; i < 5; i++ {
  1315  		if _, err := pFail0.Pick(balancer.PickInfo{}); err != balancer.ErrNoSubConnAvailable {
  1316  			t.Fatalf("want pick error %v, got %v", balancer.ErrNoSubConnAvailable, err)
  1317  		}
  1318  	}
  1319  
  1320  	addrs1 := <-cc.NewSubConnAddrsCh
  1321  	if got, want := addrs1[0].Addr, testBackendAddrStrs[1]; got != want {
  1322  		t.Fatalf("sc is created with addr %v, want %v", got, want)
  1323  	}
  1324  	sc1 := <-cc.NewSubConnCh
  1325  	pb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.Connecting})
  1326  	pb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.Ready})
  1327  
  1328  	// Test roundrobin with only p1 subconns.
  1329  	p0 := <-cc.NewPickerCh
  1330  	want := []balancer.SubConn{sc1}
  1331  	if err := testutils.IsRoundRobin(want, subConnFromPicker(t, p0)); err != nil {
  1332  		t.Fatalf("want %v, got %v", want, err)
  1333  	}
  1334  
  1335  	// Remove child with p1, the child at higher priority should now be used.
  1336  	if err := pb.UpdateClientConnState(balancer.ClientConnState{
  1337  		ResolverState: resolver.State{
  1338  			Addresses: []resolver.Address{
  1339  				hierarchy.Set(resolver.Address{Addr: testBackendAddrStrs[0]}, []string{"child-0"}),
  1340  			},
  1341  		},
  1342  		BalancerConfig: &LBConfig{
  1343  			Children: map[string]*Child{
  1344  				"child-0": {Config: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}},
  1345  			},
  1346  			Priorities: []string{"child-0"},
  1347  		},
  1348  	}); err != nil {
  1349  		t.Fatalf("failed to update ClientConn state: %v", err)
  1350  	}
  1351  
  1352  	// Old subconn from child-1 should be removed.
  1353  	scToRemove := <-cc.RemoveSubConnCh
  1354  	if !cmp.Equal(scToRemove, sc1, cmp.AllowUnexported(testutils.TestSubConn{})) {
  1355  		t.Fatalf("RemoveSubConn, want %v, got %v", sc1, scToRemove)
  1356  	}
  1357  
  1358  	pFail := <-cc.NewPickerCh
  1359  	for i := 0; i < 5; i++ {
  1360  		if _, err := pFail.Pick(balancer.PickInfo{}); err == nil {
  1361  			t.Fatalf("want pick error <non-nil>, got %v", err)
  1362  		}
  1363  	}
  1364  
  1365  	// Because there was no new child, no new subconn should be created.
  1366  	select {
  1367  	case <-cc.NewSubConnCh:
  1368  		t.Fatalf("got unexpected new SubConn")
  1369  	case <-time.After(time.Millisecond * 100):
  1370  	}
  1371  }
  1372  
  1373  // When a ready child is removed, it's kept in cache. Re-adding doesn't create subconns.
  1374  //
  1375  // Init 0; 0 is up, use 0; remove 0, only picker is updated, no subconn is
  1376  // removed; re-add 0, picker is updated.
  1377  func (s) TestPriority_ReadyChildRemovedButInCache(t *testing.T) {
  1378  	const testChildCacheTimeout = time.Second
  1379  	defer func() func() {
  1380  		old := balancergroup.DefaultSubBalancerCloseTimeout
  1381  		balancergroup.DefaultSubBalancerCloseTimeout = testChildCacheTimeout
  1382  		return func() {
  1383  			balancergroup.DefaultSubBalancerCloseTimeout = old
  1384  		}
  1385  	}()()
  1386  
  1387  	cc := testutils.NewTestClientConn(t)
  1388  	bb := balancer.Get(Name)
  1389  	pb := bb.Build(cc, balancer.BuildOptions{})
  1390  	defer pb.Close()
  1391  
  1392  	// One children, with priorities [0], with one backend.
  1393  	if err := pb.UpdateClientConnState(balancer.ClientConnState{
  1394  		ResolverState: resolver.State{
  1395  			Addresses: []resolver.Address{
  1396  				hierarchy.Set(resolver.Address{Addr: testBackendAddrStrs[0]}, []string{"child-0"}),
  1397  			},
  1398  		},
  1399  		BalancerConfig: &LBConfig{
  1400  			Children: map[string]*Child{
  1401  				"child-0": {Config: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}},
  1402  			},
  1403  			Priorities: []string{"child-0"},
  1404  		},
  1405  	}); err != nil {
  1406  		t.Fatalf("failed to update ClientConn state: %v", err)
  1407  	}
  1408  
  1409  	addrs1 := <-cc.NewSubConnAddrsCh
  1410  	if got, want := addrs1[0].Addr, testBackendAddrStrs[0]; got != want {
  1411  		t.Fatalf("sc is created with addr %v, want %v", got, want)
  1412  	}
  1413  	sc1 := <-cc.NewSubConnCh
  1414  
  1415  	// p0 is ready.
  1416  	pb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.Connecting})
  1417  	pb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.Ready})
  1418  
  1419  	// Test roundrobin with only p0 subconns.
  1420  	p1 := <-cc.NewPickerCh
  1421  	want := []balancer.SubConn{sc1}
  1422  	if err := testutils.IsRoundRobin(want, subConnFromPicker(t, p1)); err != nil {
  1423  		t.Fatalf("want %v, got %v", want, err)
  1424  	}
  1425  
  1426  	// Remove the child, it shouldn't cause any conn changed, but picker should
  1427  	// be different.
  1428  	if err := pb.UpdateClientConnState(balancer.ClientConnState{
  1429  		ResolverState:  resolver.State{},
  1430  		BalancerConfig: &LBConfig{},
  1431  	}); err != nil {
  1432  		t.Fatalf("failed to update ClientConn state: %v", err)
  1433  	}
  1434  
  1435  	pFail := <-cc.NewPickerCh
  1436  	for i := 0; i < 5; i++ {
  1437  		if _, err := pFail.Pick(balancer.PickInfo{}); err != ErrAllPrioritiesRemoved {
  1438  			t.Fatalf("want pick error %v, got %v", ErrAllPrioritiesRemoved, err)
  1439  		}
  1440  	}
  1441  
  1442  	// But no conn changes should happen. Child balancer is in cache.
  1443  	select {
  1444  	case sc := <-cc.NewSubConnCh:
  1445  		t.Fatalf("got unexpected new SubConn: %s", sc)
  1446  	case sc := <-cc.RemoveSubConnCh:
  1447  		t.Fatalf("got unexpected remove SubConn: %v", sc)
  1448  	case <-time.After(time.Millisecond * 100):
  1449  	}
  1450  
  1451  	// Re-add the child, shouldn't create new connections.
  1452  	if err := pb.UpdateClientConnState(balancer.ClientConnState{
  1453  		ResolverState: resolver.State{
  1454  			Addresses: []resolver.Address{
  1455  				hierarchy.Set(resolver.Address{Addr: testBackendAddrStrs[0]}, []string{"child-0"}),
  1456  			},
  1457  		},
  1458  		BalancerConfig: &LBConfig{
  1459  			Children: map[string]*Child{
  1460  				"child-0": {Config: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}},
  1461  			},
  1462  			Priorities: []string{"child-0"},
  1463  		},
  1464  	}); err != nil {
  1465  		t.Fatalf("failed to update ClientConn state: %v", err)
  1466  	}
  1467  
  1468  	// Test roundrobin with only p0 subconns.
  1469  	p2 := <-cc.NewPickerCh
  1470  	want2 := []balancer.SubConn{sc1}
  1471  	if err := testutils.IsRoundRobin(want2, subConnFromPicker(t, p2)); err != nil {
  1472  		t.Fatalf("want %v, got %v", want2, err)
  1473  	}
  1474  
  1475  	// But no conn changes should happen. Child balancer is just taken out from
  1476  	// the cache.
  1477  	select {
  1478  	case sc := <-cc.NewSubConnCh:
  1479  		t.Fatalf("got unexpected new SubConn: %s", sc)
  1480  	case sc := <-cc.RemoveSubConnCh:
  1481  		t.Fatalf("got unexpected remove SubConn: %v", sc)
  1482  	case <-time.After(time.Millisecond * 100):
  1483  	}
  1484  }
  1485  
  1486  // When the policy of a child is changed.
  1487  //
  1488  // Init 0; 0 is up, use 0; change 0's policy, 0 is used.
  1489  func (s) TestPriority_ChildPolicyChange(t *testing.T) {
  1490  	cc := testutils.NewTestClientConn(t)
  1491  	bb := balancer.Get(Name)
  1492  	pb := bb.Build(cc, balancer.BuildOptions{})
  1493  	defer pb.Close()
  1494  
  1495  	// One children, with priorities [0], with one backend.
  1496  	if err := pb.UpdateClientConnState(balancer.ClientConnState{
  1497  		ResolverState: resolver.State{
  1498  			Addresses: []resolver.Address{
  1499  				hierarchy.Set(resolver.Address{Addr: testBackendAddrStrs[0]}, []string{"child-0"}),
  1500  			},
  1501  		},
  1502  		BalancerConfig: &LBConfig{
  1503  			Children: map[string]*Child{
  1504  				"child-0": {Config: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}},
  1505  			},
  1506  			Priorities: []string{"child-0"},
  1507  		},
  1508  	}); err != nil {
  1509  		t.Fatalf("failed to update ClientConn state: %v", err)
  1510  	}
  1511  
  1512  	addrs1 := <-cc.NewSubConnAddrsCh
  1513  	if got, want := addrs1[0].Addr, testBackendAddrStrs[0]; got != want {
  1514  		t.Fatalf("sc is created with addr %v, want %v", got, want)
  1515  	}
  1516  	sc1 := <-cc.NewSubConnCh
  1517  
  1518  	// p0 is ready.
  1519  	pb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.Connecting})
  1520  	pb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.Ready})
  1521  
  1522  	// Test roundrobin with only p0 subconns.
  1523  	p1 := <-cc.NewPickerCh
  1524  	want := []balancer.SubConn{sc1}
  1525  	if err := testutils.IsRoundRobin(want, subConnFromPicker(t, p1)); err != nil {
  1526  		t.Fatalf("want %v, got %v", want, err)
  1527  	}
  1528  
  1529  	// Change the policy for the child (still roundrobin, but with a different
  1530  	// name).
  1531  	if err := pb.UpdateClientConnState(balancer.ClientConnState{
  1532  		ResolverState: resolver.State{
  1533  			Addresses: []resolver.Address{
  1534  				hierarchy.Set(resolver.Address{Addr: testBackendAddrStrs[0]}, []string{"child-0"}),
  1535  			},
  1536  		},
  1537  		BalancerConfig: &LBConfig{
  1538  			Children: map[string]*Child{
  1539  				"child-0": {Config: &internalserviceconfig.BalancerConfig{Name: testRRBalancerName}},
  1540  			},
  1541  			Priorities: []string{"child-0"},
  1542  		},
  1543  	}); err != nil {
  1544  		t.Fatalf("failed to update ClientConn state: %v", err)
  1545  	}
  1546  
  1547  	// Old subconn should be removed.
  1548  	scToRemove := <-cc.RemoveSubConnCh
  1549  	if !cmp.Equal(scToRemove, sc1, cmp.AllowUnexported(testutils.TestSubConn{})) {
  1550  		t.Fatalf("RemoveSubConn, want %v, got %v", sc1, scToRemove)
  1551  	}
  1552  
  1553  	// A new subconn should be created.
  1554  	addrs2 := <-cc.NewSubConnAddrsCh
  1555  	if got, want := addrs2[0].Addr, testBackendAddrStrs[0]; got != want {
  1556  		t.Fatalf("sc is created with addr %v, want %v", got, want)
  1557  	}
  1558  	sc2 := <-cc.NewSubConnCh
  1559  	pb.UpdateSubConnState(sc2, balancer.SubConnState{ConnectivityState: connectivity.Connecting})
  1560  	pb.UpdateSubConnState(sc2, balancer.SubConnState{ConnectivityState: connectivity.Ready})
  1561  
  1562  	// Test pickfirst with the new subconns.
  1563  	p2 := <-cc.NewPickerCh
  1564  	want2 := []balancer.SubConn{sc2}
  1565  	if err := testutils.IsRoundRobin(want2, subConnFromPicker(t, p2)); err != nil {
  1566  		t.Fatalf("want %v, got %v", want2, err)
  1567  	}
  1568  }
  1569  
  1570  const inlineUpdateBalancerName = "test-inline-update-balancer"
  1571  
  1572  var errTestInlineStateUpdate = fmt.Errorf("don't like addresses, empty or not")
  1573  
  1574  func init() {
  1575  	stub.Register(inlineUpdateBalancerName, stub.BalancerFuncs{
  1576  		UpdateClientConnState: func(bd *stub.BalancerData, opts balancer.ClientConnState) error {
  1577  			bd.ClientConn.UpdateState(balancer.State{
  1578  				ConnectivityState: connectivity.Ready,
  1579  				Picker:            &testutils.TestConstPicker{Err: errTestInlineStateUpdate},
  1580  			})
  1581  			return nil
  1582  		},
  1583  	})
  1584  }
  1585  
  1586  // When the child policy update picker inline in a handleClientUpdate call
  1587  // (e.g., roundrobin handling empty addresses). There could be deadlock caused
  1588  // by acquiring a locked mutex.
  1589  func (s) TestPriority_ChildPolicyUpdatePickerInline(t *testing.T) {
  1590  	cc := testutils.NewTestClientConn(t)
  1591  	bb := balancer.Get(Name)
  1592  	pb := bb.Build(cc, balancer.BuildOptions{})
  1593  	defer pb.Close()
  1594  
  1595  	// One children, with priorities [0], with one backend.
  1596  	if err := pb.UpdateClientConnState(balancer.ClientConnState{
  1597  		ResolverState: resolver.State{
  1598  			Addresses: []resolver.Address{
  1599  				hierarchy.Set(resolver.Address{Addr: testBackendAddrStrs[0]}, []string{"child-0"}),
  1600  			},
  1601  		},
  1602  		BalancerConfig: &LBConfig{
  1603  			Children: map[string]*Child{
  1604  				"child-0": {Config: &internalserviceconfig.BalancerConfig{Name: inlineUpdateBalancerName}},
  1605  			},
  1606  			Priorities: []string{"child-0"},
  1607  		},
  1608  	}); err != nil {
  1609  		t.Fatalf("failed to update ClientConn state: %v", err)
  1610  	}
  1611  
  1612  	p0 := <-cc.NewPickerCh
  1613  	for i := 0; i < 5; i++ {
  1614  		_, err := p0.Pick(balancer.PickInfo{})
  1615  		if err != errTestInlineStateUpdate {
  1616  			t.Fatalf("picker.Pick, got err %q, want err %q", err, errTestInlineStateUpdate)
  1617  		}
  1618  	}
  1619  }
  1620  
  1621  // When the child policy's configured to ignore reresolution requests, the
  1622  // ResolveNow() calls from this child should be all ignored.
  1623  func (s) TestPriority_IgnoreReresolutionRequest(t *testing.T) {
  1624  	cc := testutils.NewTestClientConn(t)
  1625  	bb := balancer.Get(Name)
  1626  	pb := bb.Build(cc, balancer.BuildOptions{})
  1627  	defer pb.Close()
  1628  
  1629  	// One children, with priorities [0], with one backend, reresolution is
  1630  	// ignored.
  1631  	if err := pb.UpdateClientConnState(balancer.ClientConnState{
  1632  		ResolverState: resolver.State{
  1633  			Addresses: []resolver.Address{
  1634  				hierarchy.Set(resolver.Address{Addr: testBackendAddrStrs[0]}, []string{"child-0"}),
  1635  			},
  1636  		},
  1637  		BalancerConfig: &LBConfig{
  1638  			Children: map[string]*Child{
  1639  				"child-0": {
  1640  					Config:                     &internalserviceconfig.BalancerConfig{Name: resolveNowBalancerName},
  1641  					IgnoreReresolutionRequests: true,
  1642  				},
  1643  			},
  1644  			Priorities: []string{"child-0"},
  1645  		},
  1646  	}); err != nil {
  1647  		t.Fatalf("failed to update ClientConn state: %v", err)
  1648  	}
  1649  
  1650  	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
  1651  	defer cancel()
  1652  	// This is the balancer.ClientConn that the inner resolverNowBalancer is
  1653  	// built with.
  1654  	balancerCCI, err := resolveNowBalancerCCCh.Receive(ctx)
  1655  	if err != nil {
  1656  		t.Fatalf("timeout waiting for ClientConn from balancer builder")
  1657  	}
  1658  	balancerCC := balancerCCI.(balancer.ClientConn)
  1659  
  1660  	// Since IgnoreReresolutionRequests was set to true, all ResolveNow() calls
  1661  	// should be ignored.
  1662  	for i := 0; i < 5; i++ {
  1663  		balancerCC.ResolveNow(resolver.ResolveNowOptions{})
  1664  	}
  1665  	select {
  1666  	case <-cc.ResolveNowCh:
  1667  		t.Fatalf("got unexpected ResolveNow() call")
  1668  	case <-time.After(time.Millisecond * 100):
  1669  	}
  1670  
  1671  	// Send another update to set IgnoreReresolutionRequests to false.
  1672  	if err := pb.UpdateClientConnState(balancer.ClientConnState{
  1673  		ResolverState: resolver.State{
  1674  			Addresses: []resolver.Address{
  1675  				hierarchy.Set(resolver.Address{Addr: testBackendAddrStrs[0]}, []string{"child-0"}),
  1676  			},
  1677  		},
  1678  		BalancerConfig: &LBConfig{
  1679  			Children: map[string]*Child{
  1680  				"child-0": {
  1681  					Config:                     &internalserviceconfig.BalancerConfig{Name: resolveNowBalancerName},
  1682  					IgnoreReresolutionRequests: false,
  1683  				},
  1684  			},
  1685  			Priorities: []string{"child-0"},
  1686  		},
  1687  	}); err != nil {
  1688  		t.Fatalf("failed to update ClientConn state: %v", err)
  1689  	}
  1690  
  1691  	// Call ResolveNow() on the CC, it should be forwarded.
  1692  	balancerCC.ResolveNow(resolver.ResolveNowOptions{})
  1693  	select {
  1694  	case <-cc.ResolveNowCh:
  1695  	case <-time.After(time.Second):
  1696  		t.Fatalf("timeout waiting for ResolveNow()")
  1697  	}
  1698  
  1699  }
  1700  
  1701  // When the child policy's configured to ignore reresolution requests, the
  1702  // ResolveNow() calls from this child should be all ignored, from the other
  1703  // children are forwarded.
  1704  func (s) TestPriority_IgnoreReresolutionRequestTwoChildren(t *testing.T) {
  1705  	cc := testutils.NewTestClientConn(t)
  1706  	bb := balancer.Get(Name)
  1707  	pb := bb.Build(cc, balancer.BuildOptions{})
  1708  	defer pb.Close()
  1709  
  1710  	// One children, with priorities [0, 1], each with one backend.
  1711  	// Reresolution is ignored for p0.
  1712  	if err := pb.UpdateClientConnState(balancer.ClientConnState{
  1713  		ResolverState: resolver.State{
  1714  			Addresses: []resolver.Address{
  1715  				hierarchy.Set(resolver.Address{Addr: testBackendAddrStrs[0]}, []string{"child-0"}),
  1716  				hierarchy.Set(resolver.Address{Addr: testBackendAddrStrs[1]}, []string{"child-1"}),
  1717  			},
  1718  		},
  1719  		BalancerConfig: &LBConfig{
  1720  			Children: map[string]*Child{
  1721  				"child-0": {
  1722  					Config:                     &internalserviceconfig.BalancerConfig{Name: resolveNowBalancerName},
  1723  					IgnoreReresolutionRequests: true,
  1724  				},
  1725  				"child-1": {
  1726  					Config: &internalserviceconfig.BalancerConfig{Name: resolveNowBalancerName},
  1727  				},
  1728  			},
  1729  			Priorities: []string{"child-0", "child-1"},
  1730  		},
  1731  	}); err != nil {
  1732  		t.Fatalf("failed to update ClientConn state: %v", err)
  1733  	}
  1734  
  1735  	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
  1736  	defer cancel()
  1737  	// This is the balancer.ClientConn from p0.
  1738  	balancerCCI0, err := resolveNowBalancerCCCh.Receive(ctx)
  1739  	if err != nil {
  1740  		t.Fatalf("timeout waiting for ClientConn from balancer builder 0")
  1741  	}
  1742  	balancerCC0 := balancerCCI0.(balancer.ClientConn)
  1743  
  1744  	// Set p0 to transient failure, p1 will be started.
  1745  	addrs0 := <-cc.NewSubConnAddrsCh
  1746  	if got, want := addrs0[0].Addr, testBackendAddrStrs[0]; got != want {
  1747  		t.Fatalf("sc is created with addr %v, want %v", got, want)
  1748  	}
  1749  	sc0 := <-cc.NewSubConnCh
  1750  	pb.UpdateSubConnState(sc0, balancer.SubConnState{ConnectivityState: connectivity.TransientFailure})
  1751  
  1752  	// This is the balancer.ClientConn from p1.
  1753  	ctx1, cancel1 := context.WithTimeout(context.Background(), time.Second)
  1754  	defer cancel1()
  1755  	balancerCCI1, err := resolveNowBalancerCCCh.Receive(ctx1)
  1756  	if err != nil {
  1757  		t.Fatalf("timeout waiting for ClientConn from balancer builder 1")
  1758  	}
  1759  	balancerCC1 := balancerCCI1.(balancer.ClientConn)
  1760  
  1761  	// Since IgnoreReresolutionRequests was set to true for p0, ResolveNow()
  1762  	// from p0 should all be ignored.
  1763  	for i := 0; i < 5; i++ {
  1764  		balancerCC0.ResolveNow(resolver.ResolveNowOptions{})
  1765  	}
  1766  	select {
  1767  	case <-cc.ResolveNowCh:
  1768  		t.Fatalf("got unexpected ResolveNow() call")
  1769  	case <-time.After(time.Millisecond * 100):
  1770  	}
  1771  
  1772  	// But IgnoreReresolutionRequests was false for p1, ResolveNow() from p1
  1773  	// should be forwarded.
  1774  	balancerCC1.ResolveNow(resolver.ResolveNowOptions{})
  1775  	select {
  1776  	case <-cc.ResolveNowCh:
  1777  	case <-time.After(time.Second):
  1778  		t.Fatalf("timeout waiting for ResolveNow()")
  1779  	}
  1780  }
  1781  
  1782  const initIdleBalancerName = "test-init-Idle-balancer"
  1783  
  1784  var errsTestInitIdle = []error{
  1785  	fmt.Errorf("init Idle balancer error 0"),
  1786  	fmt.Errorf("init Idle balancer error 1"),
  1787  }
  1788  
  1789  func init() {
  1790  	for i := 0; i < 2; i++ {
  1791  		ii := i
  1792  		stub.Register(fmt.Sprintf("%s-%d", initIdleBalancerName, ii), stub.BalancerFuncs{
  1793  			UpdateClientConnState: func(bd *stub.BalancerData, opts balancer.ClientConnState) error {
  1794  				bd.ClientConn.NewSubConn(opts.ResolverState.Addresses, balancer.NewSubConnOptions{})
  1795  				return nil
  1796  			},
  1797  			UpdateSubConnState: func(bd *stub.BalancerData, sc balancer.SubConn, state balancer.SubConnState) {
  1798  				err := fmt.Errorf("wrong picker error")
  1799  				if state.ConnectivityState == connectivity.Idle {
  1800  					err = errsTestInitIdle[ii]
  1801  				}
  1802  				bd.ClientConn.UpdateState(balancer.State{
  1803  					ConnectivityState: state.ConnectivityState,
  1804  					Picker:            &testutils.TestConstPicker{Err: err},
  1805  				})
  1806  			},
  1807  		})
  1808  	}
  1809  }
  1810  
  1811  // If the high priorities send initial pickers with Idle state, their pickers
  1812  // should get picks, because policies like ringhash starts in Idle, and doesn't
  1813  // connect.
  1814  //
  1815  // Init 0, 1; 0 is Idle, use 0; 0 is down, start 1; 1 is Idle, use 1.
  1816  func (s) TestPriority_HighPriorityInitIdle(t *testing.T) {
  1817  	cc := testutils.NewTestClientConn(t)
  1818  	bb := balancer.Get(Name)
  1819  	pb := bb.Build(cc, balancer.BuildOptions{})
  1820  	defer pb.Close()
  1821  
  1822  	// Two children, with priorities [0, 1], each with one backend.
  1823  	if err := pb.UpdateClientConnState(balancer.ClientConnState{
  1824  		ResolverState: resolver.State{
  1825  			Addresses: []resolver.Address{
  1826  				hierarchy.Set(resolver.Address{Addr: testBackendAddrStrs[0]}, []string{"child-0"}),
  1827  				hierarchy.Set(resolver.Address{Addr: testBackendAddrStrs[1]}, []string{"child-1"}),
  1828  			},
  1829  		},
  1830  		BalancerConfig: &LBConfig{
  1831  			Children: map[string]*Child{
  1832  				"child-0": {Config: &internalserviceconfig.BalancerConfig{Name: fmt.Sprintf("%s-%d", initIdleBalancerName, 0)}},
  1833  				"child-1": {Config: &internalserviceconfig.BalancerConfig{Name: fmt.Sprintf("%s-%d", initIdleBalancerName, 1)}},
  1834  			},
  1835  			Priorities: []string{"child-0", "child-1"},
  1836  		},
  1837  	}); err != nil {
  1838  		t.Fatalf("failed to update ClientConn state: %v", err)
  1839  	}
  1840  
  1841  	addrs0 := <-cc.NewSubConnAddrsCh
  1842  	if got, want := addrs0[0].Addr, testBackendAddrStrs[0]; got != want {
  1843  		t.Fatalf("sc is created with addr %v, want %v", got, want)
  1844  	}
  1845  	sc0 := <-cc.NewSubConnCh
  1846  
  1847  	// Send an Idle state update to trigger an Idle picker update.
  1848  	pb.UpdateSubConnState(sc0, balancer.SubConnState{ConnectivityState: connectivity.Idle})
  1849  	p0 := <-cc.NewPickerCh
  1850  	if pr, err := p0.Pick(balancer.PickInfo{}); err != errsTestInitIdle[0] {
  1851  		t.Fatalf("pick returned %v, %v, want _, %v", pr, err, errsTestInitIdle[0])
  1852  	}
  1853  
  1854  	// Turn p0 down, to start p1.
  1855  	pb.UpdateSubConnState(sc0, balancer.SubConnState{ConnectivityState: connectivity.TransientFailure})
  1856  	// Before 1 gets READY, picker should return NoSubConnAvailable, so RPCs
  1857  	// will retry.
  1858  	p1 := <-cc.NewPickerCh
  1859  	for i := 0; i < 5; i++ {
  1860  		if _, err := p1.Pick(balancer.PickInfo{}); err != balancer.ErrNoSubConnAvailable {
  1861  			t.Fatalf("want pick error %v, got %v", balancer.ErrNoSubConnAvailable, err)
  1862  		}
  1863  	}
  1864  
  1865  	addrs1 := <-cc.NewSubConnAddrsCh
  1866  	if got, want := addrs1[0].Addr, testBackendAddrStrs[1]; got != want {
  1867  		t.Fatalf("sc is created with addr %v, want %v", got, want)
  1868  	}
  1869  	sc1 := <-cc.NewSubConnCh
  1870  	// Idle picker from p1 should also be forwarded.
  1871  	pb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.Idle})
  1872  	p2 := <-cc.NewPickerCh
  1873  	if pr, err := p2.Pick(balancer.PickInfo{}); err != errsTestInitIdle[1] {
  1874  		t.Fatalf("pick returned %v, %v, want _, %v", pr, err, errsTestInitIdle[1])
  1875  	}
  1876  }
  1877  
  1878  // If the high priorities send initial pickers with Idle state, their pickers
  1879  // should get picks, because policies like ringhash starts in Idle, and doesn't
  1880  // connect. In this case, if a lower priority is added, it shouldn't switch to
  1881  // the lower priority.
  1882  //
  1883  // Init 0; 0 is Idle, use 0; add 1, use 0.
  1884  func (s) TestPriority_AddLowPriorityWhenHighIsInIdle(t *testing.T) {
  1885  	cc := testutils.NewTestClientConn(t)
  1886  	bb := balancer.Get(Name)
  1887  	pb := bb.Build(cc, balancer.BuildOptions{})
  1888  	defer pb.Close()
  1889  
  1890  	// One child, with priorities [0], one backend.
  1891  	if err := pb.UpdateClientConnState(balancer.ClientConnState{
  1892  		ResolverState: resolver.State{
  1893  			Addresses: []resolver.Address{
  1894  				hierarchy.Set(resolver.Address{Addr: testBackendAddrStrs[0]}, []string{"child-0"}),
  1895  			},
  1896  		},
  1897  		BalancerConfig: &LBConfig{
  1898  			Children: map[string]*Child{
  1899  				"child-0": {Config: &internalserviceconfig.BalancerConfig{Name: fmt.Sprintf("%s-%d", initIdleBalancerName, 0)}},
  1900  			},
  1901  			Priorities: []string{"child-0"},
  1902  		},
  1903  	}); err != nil {
  1904  		t.Fatalf("failed to update ClientConn state: %v", err)
  1905  	}
  1906  
  1907  	addrs0 := <-cc.NewSubConnAddrsCh
  1908  	if got, want := addrs0[0].Addr, testBackendAddrStrs[0]; got != want {
  1909  		t.Fatalf("sc is created with addr %v, want %v", got, want)
  1910  	}
  1911  	sc0 := <-cc.NewSubConnCh
  1912  
  1913  	// Send an Idle state update to trigger an Idle picker update.
  1914  	pb.UpdateSubConnState(sc0, balancer.SubConnState{ConnectivityState: connectivity.Idle})
  1915  	p0 := <-cc.NewPickerCh
  1916  	if pr, err := p0.Pick(balancer.PickInfo{}); err != errsTestInitIdle[0] {
  1917  		t.Fatalf("pick returned %v, %v, want _, %v", pr, err, errsTestInitIdle[0])
  1918  	}
  1919  
  1920  	// Add 1, should keep using 0.
  1921  	if err := pb.UpdateClientConnState(balancer.ClientConnState{
  1922  		ResolverState: resolver.State{
  1923  			Addresses: []resolver.Address{
  1924  				hierarchy.Set(resolver.Address{Addr: testBackendAddrStrs[0]}, []string{"child-0"}),
  1925  				hierarchy.Set(resolver.Address{Addr: testBackendAddrStrs[1]}, []string{"child-1"}),
  1926  			},
  1927  		},
  1928  		BalancerConfig: &LBConfig{
  1929  			Children: map[string]*Child{
  1930  				"child-0": {Config: &internalserviceconfig.BalancerConfig{Name: fmt.Sprintf("%s-%d", initIdleBalancerName, 0)}},
  1931  				"child-1": {Config: &internalserviceconfig.BalancerConfig{Name: fmt.Sprintf("%s-%d", initIdleBalancerName, 1)}},
  1932  			},
  1933  			Priorities: []string{"child-0", "child-1"},
  1934  		},
  1935  	}); err != nil {
  1936  		t.Fatalf("failed to update ClientConn state: %v", err)
  1937  	}
  1938  
  1939  	// The ClientConn state update triggers a priority switch, from p0 -> p0
  1940  	// (since p0 is still in use). Along with this the update, p0 also gets a
  1941  	// ClientConn state update, with the addresses, which didn't change in this
  1942  	// test (this update to the child is necessary in case the addresses are
  1943  	// different).
  1944  	//
  1945  	// The test child policy, initIdleBalancer, blindly calls NewSubConn with
  1946  	// all the addresses it receives, so this will trigger a NewSubConn with the
  1947  	// old p0 addresses. (Note that in a real balancer, like roundrobin, no new
  1948  	// SubConn will be created because the addresses didn't change).
  1949  	//
  1950  	// The check below makes sure that the addresses are still from p0, and not
  1951  	// from p1. This is good enough for the purpose of this test.
  1952  	addrsNew := <-cc.NewSubConnAddrsCh
  1953  	if got, want := addrsNew[0].Addr, testBackendAddrStrs[0]; got != want {
  1954  		// Fail if p1 is started and creates a SubConn.
  1955  		t.Fatalf("got unexpected call to NewSubConn with addr: %v, want %v", addrsNew, want)
  1956  	}
  1957  }