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

     1  /*
     2   *
     3   * Copyright 2019 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  package clusterresolver
    19  
    20  import (
    21  	"context"
    22  	"testing"
    23  	"time"
    24  
    25  	"github.com/google/go-cmp/cmp"
    26  	corepb "github.com/hxx258456/ccgo/go-control-plane/envoy/api/v2/core"
    27  	"github.com/hxx258456/ccgo/grpc/balancer"
    28  	"github.com/hxx258456/ccgo/grpc/connectivity"
    29  	"github.com/hxx258456/ccgo/grpc/internal/testutils"
    30  	"github.com/hxx258456/ccgo/grpc/resolver"
    31  	"github.com/hxx258456/ccgo/grpc/xds/internal/balancer/priority"
    32  	xdstestutils "github.com/hxx258456/ccgo/grpc/xds/internal/testutils"
    33  )
    34  
    35  // When a high priority is ready, adding/removing lower locality doesn't cause
    36  // changes.
    37  //
    38  // Init 0 and 1; 0 is up, use 0; add 2, use 0; remove 2, use 0.
    39  func (s) TestEDSPriority_HighPriorityReady(t *testing.T) {
    40  	edsb, cc, xdsC, cleanup := setupTestEDS(t, nil)
    41  	defer cleanup()
    42  
    43  	// Two localities, with priorities [0, 1], each with one backend.
    44  	clab1 := xdstestutils.NewClusterLoadAssignmentBuilder(testClusterNames[0], nil)
    45  	clab1.AddLocality(testSubZones[0], 1, 0, testEndpointAddrs[:1], nil)
    46  	clab1.AddLocality(testSubZones[1], 1, 1, testEndpointAddrs[1:2], nil)
    47  	xdsC.InvokeWatchEDSCallback("", parseEDSRespProtoForTesting(clab1.Build()), nil)
    48  
    49  	addrs1 := <-cc.NewSubConnAddrsCh
    50  	if got, want := addrs1[0].Addr, testEndpointAddrs[0]; got != want {
    51  		t.Fatalf("sc is created with addr %v, want %v", got, want)
    52  	}
    53  	sc1 := <-cc.NewSubConnCh
    54  
    55  	// p0 is ready.
    56  	edsb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.Connecting})
    57  	edsb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.Ready})
    58  
    59  	// Test roundrobin with only p0 subconns.
    60  	if err := testRoundRobinPickerFromCh(cc.NewPickerCh, []balancer.SubConn{sc1}); err != nil {
    61  		t.Fatal(err)
    62  	}
    63  
    64  	// Add p2, it shouldn't cause any updates.
    65  	clab2 := xdstestutils.NewClusterLoadAssignmentBuilder(testClusterNames[0], nil)
    66  	clab2.AddLocality(testSubZones[0], 1, 0, testEndpointAddrs[:1], nil)
    67  	clab2.AddLocality(testSubZones[1], 1, 1, testEndpointAddrs[1:2], nil)
    68  	clab2.AddLocality(testSubZones[2], 1, 2, testEndpointAddrs[2:3], nil)
    69  	xdsC.InvokeWatchEDSCallback("", parseEDSRespProtoForTesting(clab2.Build()), nil)
    70  
    71  	select {
    72  	case <-cc.NewPickerCh:
    73  		t.Fatalf("got unexpected new picker")
    74  	case <-cc.NewSubConnCh:
    75  		t.Fatalf("got unexpected new SubConn")
    76  	case <-cc.RemoveSubConnCh:
    77  		t.Fatalf("got unexpected remove SubConn")
    78  	case <-time.After(defaultTestShortTimeout):
    79  	}
    80  
    81  	// Remove p2, no updates.
    82  	clab3 := xdstestutils.NewClusterLoadAssignmentBuilder(testClusterNames[0], nil)
    83  	clab3.AddLocality(testSubZones[0], 1, 0, testEndpointAddrs[:1], nil)
    84  	clab3.AddLocality(testSubZones[1], 1, 1, testEndpointAddrs[1:2], nil)
    85  	xdsC.InvokeWatchEDSCallback("", parseEDSRespProtoForTesting(clab3.Build()), nil)
    86  
    87  	select {
    88  	case <-cc.NewPickerCh:
    89  		t.Fatalf("got unexpected new picker")
    90  	case <-cc.NewSubConnCh:
    91  		t.Fatalf("got unexpected new SubConn")
    92  	case <-cc.RemoveSubConnCh:
    93  		t.Fatalf("got unexpected remove SubConn")
    94  	case <-time.After(defaultTestShortTimeout):
    95  	}
    96  }
    97  
    98  // Lower priority is used when higher priority is not ready.
    99  //
   100  // Init 0 and 1; 0 is up, use 0; 0 is down, 1 is up, use 1; add 2, use 1; 1 is
   101  // down, use 2; remove 2, use 1.
   102  func (s) TestEDSPriority_SwitchPriority(t *testing.T) {
   103  	edsb, cc, xdsC, cleanup := setupTestEDS(t, nil)
   104  	defer cleanup()
   105  
   106  	// Two localities, with priorities [0, 1], each with one backend.
   107  	clab1 := xdstestutils.NewClusterLoadAssignmentBuilder(testClusterNames[0], nil)
   108  	clab1.AddLocality(testSubZones[0], 1, 0, testEndpointAddrs[:1], nil)
   109  	clab1.AddLocality(testSubZones[1], 1, 1, testEndpointAddrs[1:2], nil)
   110  	xdsC.InvokeWatchEDSCallback("", parseEDSRespProtoForTesting(clab1.Build()), nil)
   111  
   112  	addrs0 := <-cc.NewSubConnAddrsCh
   113  	if got, want := addrs0[0].Addr, testEndpointAddrs[0]; got != want {
   114  		t.Fatalf("sc is created with addr %v, want %v", got, want)
   115  	}
   116  	sc0 := <-cc.NewSubConnCh
   117  
   118  	// p0 is ready.
   119  	edsb.UpdateSubConnState(sc0, balancer.SubConnState{ConnectivityState: connectivity.Connecting})
   120  	edsb.UpdateSubConnState(sc0, balancer.SubConnState{ConnectivityState: connectivity.Ready})
   121  
   122  	// Test roundrobin with only p0 subconns.
   123  	if err := testRoundRobinPickerFromCh(cc.NewPickerCh, []balancer.SubConn{sc0}); err != nil {
   124  		t.Fatal(err)
   125  	}
   126  
   127  	// Turn down 0, 1 is used.
   128  	edsb.UpdateSubConnState(sc0, balancer.SubConnState{ConnectivityState: connectivity.TransientFailure})
   129  	addrs1 := <-cc.NewSubConnAddrsCh
   130  	if got, want := addrs1[0].Addr, testEndpointAddrs[1]; got != want {
   131  		t.Fatalf("sc is created with addr %v, want %v", got, want)
   132  	}
   133  	sc1 := <-cc.NewSubConnCh
   134  	edsb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.Connecting})
   135  	edsb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.Ready})
   136  
   137  	// Test pick with 1.
   138  	if err := testRoundRobinPickerFromCh(cc.NewPickerCh, []balancer.SubConn{sc1}); err != nil {
   139  		t.Fatal(err)
   140  	}
   141  
   142  	// Add p2, it shouldn't cause any updates.
   143  	clab2 := xdstestutils.NewClusterLoadAssignmentBuilder(testClusterNames[0], nil)
   144  	clab2.AddLocality(testSubZones[0], 1, 0, testEndpointAddrs[:1], nil)
   145  	clab2.AddLocality(testSubZones[1], 1, 1, testEndpointAddrs[1:2], nil)
   146  	clab2.AddLocality(testSubZones[2], 1, 2, testEndpointAddrs[2:3], nil)
   147  	xdsC.InvokeWatchEDSCallback("", parseEDSRespProtoForTesting(clab2.Build()), nil)
   148  
   149  	select {
   150  	case <-cc.NewPickerCh:
   151  		t.Fatalf("got unexpected new picker")
   152  	case <-cc.NewSubConnCh:
   153  		t.Fatalf("got unexpected new SubConn")
   154  	case <-cc.RemoveSubConnCh:
   155  		t.Fatalf("got unexpected remove SubConn")
   156  	case <-time.After(defaultTestShortTimeout):
   157  	}
   158  
   159  	// Turn down 1, use 2
   160  	edsb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.TransientFailure})
   161  	addrs2 := <-cc.NewSubConnAddrsCh
   162  	if got, want := addrs2[0].Addr, testEndpointAddrs[2]; got != want {
   163  		t.Fatalf("sc is created with addr %v, want %v", got, want)
   164  	}
   165  	sc2 := <-cc.NewSubConnCh
   166  	edsb.UpdateSubConnState(sc2, balancer.SubConnState{ConnectivityState: connectivity.Connecting})
   167  	edsb.UpdateSubConnState(sc2, balancer.SubConnState{ConnectivityState: connectivity.Ready})
   168  
   169  	// Test pick with 2.
   170  	if err := testRoundRobinPickerFromCh(cc.NewPickerCh, []balancer.SubConn{sc2}); err != nil {
   171  		t.Fatal(err)
   172  	}
   173  
   174  	// Remove 2, use 1.
   175  	clab3 := xdstestutils.NewClusterLoadAssignmentBuilder(testClusterNames[0], nil)
   176  	clab3.AddLocality(testSubZones[0], 1, 0, testEndpointAddrs[:1], nil)
   177  	clab3.AddLocality(testSubZones[1], 1, 1, testEndpointAddrs[1:2], nil)
   178  	xdsC.InvokeWatchEDSCallback("", parseEDSRespProtoForTesting(clab3.Build()), nil)
   179  
   180  	// p2 SubConns are removed.
   181  	scToRemove := <-cc.RemoveSubConnCh
   182  	if !cmp.Equal(scToRemove, sc2, cmp.AllowUnexported(testutils.TestSubConn{})) {
   183  		t.Fatalf("RemoveSubConn, want %v, got %v", sc2, scToRemove)
   184  	}
   185  
   186  	// Should get an update with 1's old picker, to override 2's old picker.
   187  	if err := testErrPickerFromCh(cc.NewPickerCh, balancer.ErrTransientFailure); err != nil {
   188  		t.Fatal(err)
   189  	}
   190  
   191  }
   192  
   193  // Add a lower priority while the higher priority is down.
   194  //
   195  // Init 0 and 1; 0 and 1 both down; add 2, use 2.
   196  func (s) TestEDSPriority_HigherDownWhileAddingLower(t *testing.T) {
   197  	edsb, cc, xdsC, cleanup := setupTestEDS(t, nil)
   198  	defer cleanup()
   199  	// Two localities, with different priorities, each with one backend.
   200  	clab1 := xdstestutils.NewClusterLoadAssignmentBuilder(testClusterNames[0], nil)
   201  	clab1.AddLocality(testSubZones[0], 1, 0, testEndpointAddrs[:1], nil)
   202  	clab1.AddLocality(testSubZones[1], 1, 1, testEndpointAddrs[1:2], nil)
   203  	xdsC.InvokeWatchEDSCallback("", parseEDSRespProtoForTesting(clab1.Build()), nil)
   204  	addrs0 := <-cc.NewSubConnAddrsCh
   205  	if got, want := addrs0[0].Addr, testEndpointAddrs[0]; got != want {
   206  		t.Fatalf("sc is created with addr %v, want %v", got, want)
   207  	}
   208  	sc0 := <-cc.NewSubConnCh
   209  
   210  	// Turn down 0, 1 is used.
   211  	edsb.UpdateSubConnState(sc0, balancer.SubConnState{ConnectivityState: connectivity.TransientFailure})
   212  	addrs1 := <-cc.NewSubConnAddrsCh
   213  	if got, want := addrs1[0].Addr, testEndpointAddrs[1]; got != want {
   214  		t.Fatalf("sc is created with addr %v, want %v", got, want)
   215  	}
   216  	sc1 := <-cc.NewSubConnCh
   217  	// Turn down 1, pick should error.
   218  	edsb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.TransientFailure})
   219  
   220  	// Test pick failure.
   221  	if err := testErrPickerFromCh(cc.NewPickerCh, balancer.ErrTransientFailure); err != nil {
   222  		t.Fatal(err)
   223  	}
   224  
   225  	// Add p2, it should create a new SubConn.
   226  	clab2 := xdstestutils.NewClusterLoadAssignmentBuilder(testClusterNames[0], nil)
   227  	clab2.AddLocality(testSubZones[0], 1, 0, testEndpointAddrs[:1], nil)
   228  	clab2.AddLocality(testSubZones[1], 1, 1, testEndpointAddrs[1:2], nil)
   229  	clab2.AddLocality(testSubZones[2], 1, 2, testEndpointAddrs[2:3], nil)
   230  	xdsC.InvokeWatchEDSCallback("", parseEDSRespProtoForTesting(clab2.Build()), nil)
   231  	addrs2 := <-cc.NewSubConnAddrsCh
   232  	if got, want := addrs2[0].Addr, testEndpointAddrs[2]; got != want {
   233  		t.Fatalf("sc is created with addr %v, want %v", got, want)
   234  	}
   235  	sc2 := <-cc.NewSubConnCh
   236  	edsb.UpdateSubConnState(sc2, balancer.SubConnState{ConnectivityState: connectivity.Connecting})
   237  	edsb.UpdateSubConnState(sc2, balancer.SubConnState{ConnectivityState: connectivity.Ready})
   238  
   239  	// Test pick with 2.
   240  	if err := testRoundRobinPickerFromCh(cc.NewPickerCh, []balancer.SubConn{sc2}); err != nil {
   241  		t.Fatal(err)
   242  	}
   243  
   244  }
   245  
   246  // When a higher priority becomes available, all lower priorities are closed.
   247  //
   248  // Init 0,1,2; 0 and 1 down, use 2; 0 up, close 1 and 2.
   249  func (s) TestEDSPriority_HigherReadyCloseAllLower(t *testing.T) {
   250  	edsb, cc, xdsC, cleanup := setupTestEDS(t, nil)
   251  	defer cleanup()
   252  	// Two localities, with priorities [0,1,2], each with one backend.
   253  	clab1 := xdstestutils.NewClusterLoadAssignmentBuilder(testClusterNames[0], nil)
   254  	clab1.AddLocality(testSubZones[0], 1, 0, testEndpointAddrs[:1], nil)
   255  	clab1.AddLocality(testSubZones[1], 1, 1, testEndpointAddrs[1:2], nil)
   256  	clab1.AddLocality(testSubZones[2], 1, 2, testEndpointAddrs[2:3], nil)
   257  	xdsC.InvokeWatchEDSCallback("", parseEDSRespProtoForTesting(clab1.Build()), nil)
   258  	addrs0 := <-cc.NewSubConnAddrsCh
   259  	if got, want := addrs0[0].Addr, testEndpointAddrs[0]; got != want {
   260  		t.Fatalf("sc is created with addr %v, want %v", got, want)
   261  	}
   262  	sc0 := <-cc.NewSubConnCh
   263  
   264  	// Turn down 0, 1 is used.
   265  	edsb.UpdateSubConnState(sc0, balancer.SubConnState{ConnectivityState: connectivity.TransientFailure})
   266  	addrs1 := <-cc.NewSubConnAddrsCh
   267  	if got, want := addrs1[0].Addr, testEndpointAddrs[1]; got != want {
   268  		t.Fatalf("sc is created with addr %v, want %v", got, want)
   269  	}
   270  	sc1 := <-cc.NewSubConnCh
   271  	// Turn down 1, 2 is used.
   272  	edsb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.TransientFailure})
   273  	addrs2 := <-cc.NewSubConnAddrsCh
   274  	if got, want := addrs2[0].Addr, testEndpointAddrs[2]; got != want {
   275  		t.Fatalf("sc is created with addr %v, want %v", got, want)
   276  	}
   277  	sc2 := <-cc.NewSubConnCh
   278  	edsb.UpdateSubConnState(sc2, balancer.SubConnState{ConnectivityState: connectivity.Connecting})
   279  	edsb.UpdateSubConnState(sc2, balancer.SubConnState{ConnectivityState: connectivity.Ready})
   280  
   281  	// Test pick with 2.
   282  	if err := testRoundRobinPickerFromCh(cc.NewPickerCh, []balancer.SubConn{sc2}); err != nil {
   283  		t.Fatal(err)
   284  	}
   285  
   286  	// When 0 becomes ready, 0 should be used, 1 and 2 should all be closed.
   287  	edsb.UpdateSubConnState(sc0, balancer.SubConnState{ConnectivityState: connectivity.Ready})
   288  	var (
   289  		scToRemove    []balancer.SubConn
   290  		scToRemoveMap = make(map[balancer.SubConn]struct{})
   291  	)
   292  	// Each subconn is removed twice. This is OK in production, but it makes
   293  	// testing harder.
   294  	//
   295  	// The sub-balancer to be closed is priority's child, clusterimpl, who has
   296  	// weightedtarget as children.
   297  	//
   298  	// - When clusterimpl is removed from priority's balancergroup, all its
   299  	// subconns are removed once.
   300  	// - When clusterimpl is closed, it closes weightedtarget, and this
   301  	// weightedtarget's balancer removes all the same subconns again.
   302  	for i := 0; i < 4; i++ {
   303  		// We expect 2 subconns, so we recv from channel 4 times.
   304  		scToRemoveMap[<-cc.RemoveSubConnCh] = struct{}{}
   305  	}
   306  	for sc := range scToRemoveMap {
   307  		scToRemove = append(scToRemove, sc)
   308  	}
   309  
   310  	// sc1 and sc2 should be removed.
   311  	//
   312  	// With localities caching, the lower priorities are closed after a timeout,
   313  	// in goroutines. The order is no longer guaranteed.
   314  	if !(cmp.Equal(scToRemove[0], sc1, cmp.AllowUnexported(testutils.TestSubConn{})) &&
   315  		cmp.Equal(scToRemove[1], sc2, cmp.AllowUnexported(testutils.TestSubConn{}))) &&
   316  		!(cmp.Equal(scToRemove[0], sc2, cmp.AllowUnexported(testutils.TestSubConn{})) &&
   317  			cmp.Equal(scToRemove[1], sc1, cmp.AllowUnexported(testutils.TestSubConn{}))) {
   318  		t.Errorf("RemoveSubConn, want [%v, %v], got %v", sc1, sc2, scToRemove)
   319  	}
   320  
   321  	// Test pick with 0.
   322  	if err := testRoundRobinPickerFromCh(cc.NewPickerCh, []balancer.SubConn{sc0}); err != nil {
   323  		t.Fatal(err)
   324  	}
   325  }
   326  
   327  // At init, start the next lower priority after timeout if the higher priority
   328  // doesn't get ready.
   329  //
   330  // Init 0,1; 0 is not ready (in connecting), after timeout, use 1.
   331  func (s) TestEDSPriority_InitTimeout(t *testing.T) {
   332  	const testPriorityInitTimeout = time.Second
   333  	defer func() func() {
   334  		old := priority.DefaultPriorityInitTimeout
   335  		priority.DefaultPriorityInitTimeout = testPriorityInitTimeout
   336  		return func() {
   337  			priority.DefaultPriorityInitTimeout = old
   338  		}
   339  	}()()
   340  
   341  	edsb, cc, xdsC, cleanup := setupTestEDS(t, nil)
   342  	defer cleanup()
   343  	// Two localities, with different priorities, each with one backend.
   344  	clab1 := xdstestutils.NewClusterLoadAssignmentBuilder(testClusterNames[0], nil)
   345  	clab1.AddLocality(testSubZones[0], 1, 0, testEndpointAddrs[:1], nil)
   346  	clab1.AddLocality(testSubZones[1], 1, 1, testEndpointAddrs[1:2], nil)
   347  	xdsC.InvokeWatchEDSCallback("", parseEDSRespProtoForTesting(clab1.Build()), nil)
   348  	addrs0 := <-cc.NewSubConnAddrsCh
   349  	if got, want := addrs0[0].Addr, testEndpointAddrs[0]; got != want {
   350  		t.Fatalf("sc is created with addr %v, want %v", got, want)
   351  	}
   352  	sc0 := <-cc.NewSubConnCh
   353  
   354  	// Keep 0 in connecting, 1 will be used after init timeout.
   355  	edsb.UpdateSubConnState(sc0, balancer.SubConnState{ConnectivityState: connectivity.Connecting})
   356  
   357  	// Make sure new SubConn is created before timeout.
   358  	select {
   359  	case <-time.After(testPriorityInitTimeout * 3 / 4):
   360  	case <-cc.NewSubConnAddrsCh:
   361  		t.Fatalf("Got a new SubConn too early (Within timeout). Expect a new SubConn only after timeout")
   362  	}
   363  
   364  	addrs1 := <-cc.NewSubConnAddrsCh
   365  	if got, want := addrs1[0].Addr, testEndpointAddrs[1]; got != want {
   366  		t.Fatalf("sc is created with addr %v, want %v", got, want)
   367  	}
   368  	sc1 := <-cc.NewSubConnCh
   369  
   370  	edsb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.Connecting})
   371  	edsb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.Ready})
   372  
   373  	// Test pick with 1.
   374  	if err := testRoundRobinPickerFromCh(cc.NewPickerCh, []balancer.SubConn{sc1}); err != nil {
   375  		t.Fatal(err)
   376  	}
   377  }
   378  
   379  // Add localities to existing priorities.
   380  //
   381  //  - start with 2 locality with p0 and p1
   382  //  - add localities to existing p0 and p1
   383  func (s) TestEDSPriority_MultipleLocalities(t *testing.T) {
   384  	edsb, cc, xdsC, cleanup := setupTestEDS(t, nil)
   385  	defer cleanup()
   386  	// Two localities, with different priorities, each with one backend.
   387  	clab0 := xdstestutils.NewClusterLoadAssignmentBuilder(testClusterNames[0], nil)
   388  	clab0.AddLocality(testSubZones[0], 1, 0, testEndpointAddrs[:1], nil)
   389  	clab0.AddLocality(testSubZones[1], 1, 1, testEndpointAddrs[1:2], nil)
   390  	xdsC.InvokeWatchEDSCallback("", parseEDSRespProtoForTesting(clab0.Build()), nil)
   391  	addrs0 := <-cc.NewSubConnAddrsCh
   392  	if got, want := addrs0[0].Addr, testEndpointAddrs[0]; got != want {
   393  		t.Fatalf("sc is created with addr %v, want %v", got, want)
   394  	}
   395  	sc0 := <-cc.NewSubConnCh
   396  	edsb.UpdateSubConnState(sc0, balancer.SubConnState{ConnectivityState: connectivity.Connecting})
   397  	edsb.UpdateSubConnState(sc0, balancer.SubConnState{ConnectivityState: connectivity.Ready})
   398  
   399  	// Test roundrobin with only p0 subconns.
   400  	if err := testRoundRobinPickerFromCh(cc.NewPickerCh, []balancer.SubConn{sc0}); err != nil {
   401  		t.Fatal(err)
   402  	}
   403  
   404  	// Turn down p0 subconns, p1 subconns will be created.
   405  	edsb.UpdateSubConnState(sc0, balancer.SubConnState{ConnectivityState: connectivity.TransientFailure})
   406  
   407  	addrs1 := <-cc.NewSubConnAddrsCh
   408  	if got, want := addrs1[0].Addr, testEndpointAddrs[1]; got != want {
   409  		t.Fatalf("sc is created with addr %v, want %v", got, want)
   410  	}
   411  	sc1 := <-cc.NewSubConnCh
   412  	edsb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.Connecting})
   413  	edsb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.Ready})
   414  
   415  	// Test roundrobin with only p1 subconns.
   416  	if err := testRoundRobinPickerFromCh(cc.NewPickerCh, []balancer.SubConn{sc1}); err != nil {
   417  		t.Fatal(err)
   418  	}
   419  
   420  	// Reconnect p0 subconns, p1 subconn will be closed.
   421  	edsb.UpdateSubConnState(sc0, balancer.SubConnState{ConnectivityState: connectivity.Ready})
   422  
   423  	scToRemove := <-cc.RemoveSubConnCh
   424  	if !cmp.Equal(scToRemove, sc1, cmp.AllowUnexported(testutils.TestSubConn{})) {
   425  		t.Fatalf("RemoveSubConn, want %v, got %v", sc1, scToRemove)
   426  	}
   427  
   428  	// Test roundrobin with only p0 subconns.
   429  	if err := testRoundRobinPickerFromCh(cc.NewPickerCh, []balancer.SubConn{sc0}); err != nil {
   430  		t.Fatal(err)
   431  	}
   432  
   433  	// Add two localities, with two priorities, with one backend.
   434  	clab1 := xdstestutils.NewClusterLoadAssignmentBuilder(testClusterNames[0], nil)
   435  	clab1.AddLocality(testSubZones[0], 1, 0, testEndpointAddrs[:1], nil)
   436  	clab1.AddLocality(testSubZones[1], 1, 1, testEndpointAddrs[1:2], nil)
   437  	clab1.AddLocality(testSubZones[2], 1, 0, testEndpointAddrs[2:3], nil)
   438  	clab1.AddLocality(testSubZones[3], 1, 1, testEndpointAddrs[3:4], nil)
   439  	xdsC.InvokeWatchEDSCallback("", parseEDSRespProtoForTesting(clab1.Build()), nil)
   440  	addrs2 := <-cc.NewSubConnAddrsCh
   441  	if got, want := addrs2[0].Addr, testEndpointAddrs[2]; got != want {
   442  		t.Fatalf("sc is created with addr %v, want %v", got, want)
   443  	}
   444  	sc2 := <-cc.NewSubConnCh
   445  	edsb.UpdateSubConnState(sc2, balancer.SubConnState{ConnectivityState: connectivity.Connecting})
   446  	edsb.UpdateSubConnState(sc2, balancer.SubConnState{ConnectivityState: connectivity.Ready})
   447  
   448  	// Test roundrobin with only two p0 subconns.
   449  	if err := testRoundRobinPickerFromCh(cc.NewPickerCh, []balancer.SubConn{sc0, sc2}); err != nil {
   450  		t.Fatal(err)
   451  	}
   452  
   453  	// Turn down p0 subconns, p1 subconns will be created.
   454  	edsb.UpdateSubConnState(sc0, balancer.SubConnState{ConnectivityState: connectivity.TransientFailure})
   455  	edsb.UpdateSubConnState(sc2, balancer.SubConnState{ConnectivityState: connectivity.TransientFailure})
   456  
   457  	sc3 := <-cc.NewSubConnCh
   458  	edsb.UpdateSubConnState(sc3, balancer.SubConnState{ConnectivityState: connectivity.Connecting})
   459  	edsb.UpdateSubConnState(sc3, balancer.SubConnState{ConnectivityState: connectivity.Ready})
   460  	sc4 := <-cc.NewSubConnCh
   461  	edsb.UpdateSubConnState(sc4, balancer.SubConnState{ConnectivityState: connectivity.Connecting})
   462  	edsb.UpdateSubConnState(sc4, balancer.SubConnState{ConnectivityState: connectivity.Ready})
   463  
   464  	// Test roundrobin with only p1 subconns.
   465  	if err := testRoundRobinPickerFromCh(cc.NewPickerCh, []balancer.SubConn{sc3, sc4}); err != nil {
   466  		t.Fatal(err)
   467  	}
   468  }
   469  
   470  // EDS removes all localities, and re-adds them.
   471  func (s) TestEDSPriority_RemovesAllLocalities(t *testing.T) {
   472  	const testPriorityInitTimeout = time.Second
   473  	defer func() func() {
   474  		old := priority.DefaultPriorityInitTimeout
   475  		priority.DefaultPriorityInitTimeout = testPriorityInitTimeout
   476  		return func() {
   477  			priority.DefaultPriorityInitTimeout = old
   478  		}
   479  	}()()
   480  
   481  	edsb, cc, xdsC, cleanup := setupTestEDS(t, nil)
   482  	defer cleanup()
   483  	// Two localities, with different priorities, each with one backend.
   484  	clab0 := xdstestutils.NewClusterLoadAssignmentBuilder(testClusterNames[0], nil)
   485  	clab0.AddLocality(testSubZones[0], 1, 0, testEndpointAddrs[:1], nil)
   486  	clab0.AddLocality(testSubZones[1], 1, 1, testEndpointAddrs[1:2], nil)
   487  	xdsC.InvokeWatchEDSCallback("", parseEDSRespProtoForTesting(clab0.Build()), nil)
   488  	addrs0 := <-cc.NewSubConnAddrsCh
   489  	if got, want := addrs0[0].Addr, testEndpointAddrs[0]; got != want {
   490  		t.Fatalf("sc is created with addr %v, want %v", got, want)
   491  	}
   492  	sc0 := <-cc.NewSubConnCh
   493  	edsb.UpdateSubConnState(sc0, balancer.SubConnState{ConnectivityState: connectivity.Connecting})
   494  	edsb.UpdateSubConnState(sc0, balancer.SubConnState{ConnectivityState: connectivity.Ready})
   495  
   496  	// Test roundrobin with only p0 subconns.
   497  	if err := testRoundRobinPickerFromCh(cc.NewPickerCh, []balancer.SubConn{sc0}); err != nil {
   498  		t.Fatal(err)
   499  	}
   500  
   501  	// Remove all priorities.
   502  	clab1 := xdstestutils.NewClusterLoadAssignmentBuilder(testClusterNames[0], nil)
   503  	xdsC.InvokeWatchEDSCallback("", parseEDSRespProtoForTesting(clab1.Build()), nil)
   504  	// p0 subconn should be removed.
   505  	scToRemove := <-cc.RemoveSubConnCh
   506  	<-cc.RemoveSubConnCh // Drain the duplicate subconn removed.
   507  	if !cmp.Equal(scToRemove, sc0, cmp.AllowUnexported(testutils.TestSubConn{})) {
   508  		t.Fatalf("RemoveSubConn, want %v, got %v", sc0, scToRemove)
   509  	}
   510  
   511  	// time.Sleep(time.Second)
   512  
   513  	// Test pick return TransientFailure.
   514  	if err := testErrPickerFromCh(cc.NewPickerCh, priority.ErrAllPrioritiesRemoved); err != nil {
   515  		t.Fatal(err)
   516  	}
   517  
   518  	// Re-add two localities, with previous priorities, but different backends.
   519  	clab2 := xdstestutils.NewClusterLoadAssignmentBuilder(testClusterNames[0], nil)
   520  	clab2.AddLocality(testSubZones[0], 1, 0, testEndpointAddrs[2:3], nil)
   521  	clab2.AddLocality(testSubZones[1], 1, 1, testEndpointAddrs[3:4], nil)
   522  	xdsC.InvokeWatchEDSCallback("", parseEDSRespProtoForTesting(clab2.Build()), nil)
   523  	addrs01 := <-cc.NewSubConnAddrsCh
   524  	if got, want := addrs01[0].Addr, testEndpointAddrs[2]; got != want {
   525  		t.Fatalf("sc is created with addr %v, want %v", got, want)
   526  	}
   527  	sc01 := <-cc.NewSubConnCh
   528  
   529  	// Don't send any update to p0, so to not override the old state of p0.
   530  	// Later, connect to p1 and then remove p1. This will fallback to p0, and
   531  	// will send p0's old picker if they are not correctly removed.
   532  
   533  	// p1 will be used after priority init timeout.
   534  	addrs11 := <-cc.NewSubConnAddrsCh
   535  	if got, want := addrs11[0].Addr, testEndpointAddrs[3]; got != want {
   536  		t.Fatalf("sc is created with addr %v, want %v", got, want)
   537  	}
   538  	sc11 := <-cc.NewSubConnCh
   539  	edsb.UpdateSubConnState(sc11, balancer.SubConnState{ConnectivityState: connectivity.Connecting})
   540  	edsb.UpdateSubConnState(sc11, balancer.SubConnState{ConnectivityState: connectivity.Ready})
   541  
   542  	// Test roundrobin with only p1 subconns.
   543  	if err := testRoundRobinPickerFromCh(cc.NewPickerCh, []balancer.SubConn{sc11}); err != nil {
   544  		t.Fatal(err)
   545  	}
   546  
   547  	// Remove p1 from EDS, to fallback to p0.
   548  	clab3 := xdstestutils.NewClusterLoadAssignmentBuilder(testClusterNames[0], nil)
   549  	clab3.AddLocality(testSubZones[0], 1, 0, testEndpointAddrs[2:3], nil)
   550  	xdsC.InvokeWatchEDSCallback("", parseEDSRespProtoForTesting(clab3.Build()), nil)
   551  
   552  	// p1 subconn should be removed.
   553  	scToRemove1 := <-cc.RemoveSubConnCh
   554  	<-cc.RemoveSubConnCh // Drain the duplicate subconn removed.
   555  	if !cmp.Equal(scToRemove1, sc11, cmp.AllowUnexported(testutils.TestSubConn{})) {
   556  		t.Fatalf("RemoveSubConn, want %v, got %v", sc11, scToRemove1)
   557  	}
   558  
   559  	// Test pick return TransientFailure.
   560  	if err := testErrPickerFromCh(cc.NewPickerCh, balancer.ErrNoSubConnAvailable); err != nil {
   561  		t.Fatal(err)
   562  	}
   563  
   564  	// Send an ready update for the p0 sc that was received when re-adding
   565  	// localities to EDS.
   566  	edsb.UpdateSubConnState(sc01, balancer.SubConnState{ConnectivityState: connectivity.Connecting})
   567  	edsb.UpdateSubConnState(sc01, balancer.SubConnState{ConnectivityState: connectivity.Ready})
   568  
   569  	// Test roundrobin with only p0 subconns.
   570  	if err := testRoundRobinPickerFromCh(cc.NewPickerCh, []balancer.SubConn{sc01}); err != nil {
   571  		t.Fatal(err)
   572  	}
   573  
   574  	select {
   575  	case <-cc.NewPickerCh:
   576  		t.Fatalf("got unexpected new picker")
   577  	case <-cc.NewSubConnCh:
   578  		t.Fatalf("got unexpected new SubConn")
   579  	case <-cc.RemoveSubConnCh:
   580  		t.Fatalf("got unexpected remove SubConn")
   581  	case <-time.After(defaultTestShortTimeout):
   582  	}
   583  }
   584  
   585  // Test the case where the high priority contains no backends. The low priority
   586  // will be used.
   587  func (s) TestEDSPriority_HighPriorityNoEndpoints(t *testing.T) {
   588  	edsb, cc, xdsC, cleanup := setupTestEDS(t, nil)
   589  	defer cleanup()
   590  	// Two localities, with priorities [0, 1], each with one backend.
   591  	clab1 := xdstestutils.NewClusterLoadAssignmentBuilder(testClusterNames[0], nil)
   592  	clab1.AddLocality(testSubZones[0], 1, 0, testEndpointAddrs[:1], nil)
   593  	clab1.AddLocality(testSubZones[1], 1, 1, testEndpointAddrs[1:2], nil)
   594  	xdsC.InvokeWatchEDSCallback("", parseEDSRespProtoForTesting(clab1.Build()), nil)
   595  	addrs1 := <-cc.NewSubConnAddrsCh
   596  	if got, want := addrs1[0].Addr, testEndpointAddrs[0]; got != want {
   597  		t.Fatalf("sc is created with addr %v, want %v", got, want)
   598  	}
   599  	sc1 := <-cc.NewSubConnCh
   600  
   601  	// p0 is ready.
   602  	edsb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.Connecting})
   603  	edsb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.Ready})
   604  
   605  	// Test roundrobin with only p0 subconns.
   606  	if err := testRoundRobinPickerFromCh(cc.NewPickerCh, []balancer.SubConn{sc1}); err != nil {
   607  		t.Fatal(err)
   608  	}
   609  
   610  	// Remove addresses from priority 0, should use p1.
   611  	clab2 := xdstestutils.NewClusterLoadAssignmentBuilder(testClusterNames[0], nil)
   612  	clab2.AddLocality(testSubZones[0], 1, 0, nil, nil)
   613  	clab2.AddLocality(testSubZones[1], 1, 1, testEndpointAddrs[1:2], nil)
   614  	xdsC.InvokeWatchEDSCallback("", parseEDSRespProtoForTesting(clab2.Build()), nil)
   615  	// p0 will remove the subconn, and ClientConn will send a sc update to
   616  	// shutdown.
   617  	scToRemove := <-cc.RemoveSubConnCh
   618  	edsb.UpdateSubConnState(scToRemove, balancer.SubConnState{ConnectivityState: connectivity.Shutdown})
   619  
   620  	addrs2 := <-cc.NewSubConnAddrsCh
   621  	if got, want := addrs2[0].Addr, testEndpointAddrs[1]; got != want {
   622  		t.Fatalf("sc is created with addr %v, want %v", got, want)
   623  	}
   624  	sc2 := <-cc.NewSubConnCh
   625  
   626  	// p1 is ready.
   627  	edsb.UpdateSubConnState(sc2, balancer.SubConnState{ConnectivityState: connectivity.Connecting})
   628  	edsb.UpdateSubConnState(sc2, balancer.SubConnState{ConnectivityState: connectivity.Ready})
   629  
   630  	// Test roundrobin with only p1 subconns.
   631  	if err := testRoundRobinPickerFromCh(cc.NewPickerCh, []balancer.SubConn{sc2}); err != nil {
   632  		t.Fatal(err)
   633  	}
   634  }
   635  
   636  // Test the case where the high priority contains no healthy backends. The low
   637  // priority will be used.
   638  func (s) TestEDSPriority_HighPriorityAllUnhealthy(t *testing.T) {
   639  	edsb, cc, xdsC, cleanup := setupTestEDS(t, nil)
   640  	defer cleanup()
   641  	// Two localities, with priorities [0, 1], each with one backend.
   642  	clab1 := xdstestutils.NewClusterLoadAssignmentBuilder(testClusterNames[0], nil)
   643  	clab1.AddLocality(testSubZones[0], 1, 0, testEndpointAddrs[:1], nil)
   644  	clab1.AddLocality(testSubZones[1], 1, 1, testEndpointAddrs[1:2], nil)
   645  	xdsC.InvokeWatchEDSCallback("", parseEDSRespProtoForTesting(clab1.Build()), nil)
   646  	addrs1 := <-cc.NewSubConnAddrsCh
   647  	if got, want := addrs1[0].Addr, testEndpointAddrs[0]; got != want {
   648  		t.Fatalf("sc is created with addr %v, want %v", got, want)
   649  	}
   650  	sc1 := <-cc.NewSubConnCh
   651  
   652  	// p0 is ready.
   653  	edsb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.Connecting})
   654  	edsb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.Ready})
   655  
   656  	// Test roundrobin with only p0 subconns.
   657  	if err := testRoundRobinPickerFromCh(cc.NewPickerCh, []balancer.SubConn{sc1}); err != nil {
   658  		t.Fatal(err)
   659  	}
   660  
   661  	// Set priority 0 endpoints to all unhealthy, should use p1.
   662  	clab2 := xdstestutils.NewClusterLoadAssignmentBuilder(testClusterNames[0], nil)
   663  	clab2.AddLocality(testSubZones[0], 1, 0, testEndpointAddrs[:1], &xdstestutils.AddLocalityOptions{
   664  		Health: []corepb.HealthStatus{corepb.HealthStatus_UNHEALTHY},
   665  	})
   666  	clab2.AddLocality(testSubZones[1], 1, 1, testEndpointAddrs[1:2], nil)
   667  	xdsC.InvokeWatchEDSCallback("", parseEDSRespProtoForTesting(clab2.Build()), nil)
   668  	// p0 will remove the subconn, and ClientConn will send a sc update to
   669  	// transient failure.
   670  	scToRemove := <-cc.RemoveSubConnCh
   671  	edsb.UpdateSubConnState(scToRemove, balancer.SubConnState{ConnectivityState: connectivity.Shutdown})
   672  
   673  	addrs2 := <-cc.NewSubConnAddrsCh
   674  	if got, want := addrs2[0].Addr, testEndpointAddrs[1]; got != want {
   675  		t.Fatalf("sc is created with addr %v, want %v", got, want)
   676  	}
   677  	sc2 := <-cc.NewSubConnCh
   678  
   679  	// p1 is ready.
   680  	edsb.UpdateSubConnState(sc2, balancer.SubConnState{ConnectivityState: connectivity.Connecting})
   681  	edsb.UpdateSubConnState(sc2, balancer.SubConnState{ConnectivityState: connectivity.Ready})
   682  
   683  	// Test roundrobin with only p1 subconns.
   684  	if err := testRoundRobinPickerFromCh(cc.NewPickerCh, []balancer.SubConn{sc2}); err != nil {
   685  		t.Fatal(err)
   686  	}
   687  }
   688  
   689  // Test the case where the first and only priority is removed.
   690  func (s) TestEDSPriority_FirstPriorityRemoved(t *testing.T) {
   691  	const testPriorityInitTimeout = time.Second
   692  	defer func() func() {
   693  		old := priority.DefaultPriorityInitTimeout
   694  		priority.DefaultPriorityInitTimeout = testPriorityInitTimeout
   695  		return func() {
   696  			priority.DefaultPriorityInitTimeout = old
   697  		}
   698  	}()()
   699  
   700  	_, cc, xdsC, cleanup := setupTestEDS(t, nil)
   701  	defer cleanup()
   702  	// One localities, with priorities [0], each with one backend.
   703  	clab1 := xdstestutils.NewClusterLoadAssignmentBuilder(testClusterNames[0], nil)
   704  	clab1.AddLocality(testSubZones[0], 1, 0, testEndpointAddrs[:1], nil)
   705  	xdsC.InvokeWatchEDSCallback("", parseEDSRespProtoForTesting(clab1.Build()), nil)
   706  	// Remove the only localities.
   707  	clab2 := xdstestutils.NewClusterLoadAssignmentBuilder(testClusterNames[0], nil)
   708  	xdsC.InvokeWatchEDSCallback("", parseEDSRespProtoForTesting(clab2.Build()), nil)
   709  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   710  	defer cancel()
   711  	if err := cc.WaitForErrPicker(ctx); err != nil {
   712  		t.Fatal(err)
   713  	}
   714  }
   715  
   716  // Watch resources from EDS and DNS, with EDS as the higher priority. Lower
   717  // priority is used when higher priority is not ready.
   718  func (s) TestFallbackToDNS(t *testing.T) {
   719  	const testDNSEndpointAddr = "3.1.4.1:5"
   720  	// dnsTargetCh, dnsCloseCh, resolveNowCh, dnsR, cleanup := setupDNS()
   721  	dnsTargetCh, _, resolveNowCh, dnsR, cleanupDNS := setupDNS()
   722  	defer cleanupDNS()
   723  	edsb, cc, xdsC, cleanup := setupTestEDS(t, nil)
   724  	defer cleanup()
   725  
   726  	if err := edsb.UpdateClientConnState(balancer.ClientConnState{
   727  		BalancerConfig: &LBConfig{
   728  			DiscoveryMechanisms: []DiscoveryMechanism{
   729  				{
   730  					Type:    DiscoveryMechanismTypeEDS,
   731  					Cluster: testClusterName,
   732  				},
   733  				{
   734  					Type:        DiscoveryMechanismTypeLogicalDNS,
   735  					DNSHostname: testDNSTarget,
   736  				},
   737  			},
   738  		},
   739  	}); err != nil {
   740  		t.Fatal(err)
   741  	}
   742  
   743  	ctx, ctxCancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   744  	defer ctxCancel()
   745  	select {
   746  	case target := <-dnsTargetCh:
   747  		if diff := cmp.Diff(target, resolver.Target{Scheme: "dns", Endpoint: testDNSTarget}); diff != "" {
   748  			t.Fatalf("got unexpected DNS target to watch, diff (-got, +want): %v", diff)
   749  		}
   750  	case <-ctx.Done():
   751  		t.Fatal("Timed out waiting for building DNS resolver")
   752  	}
   753  
   754  	// One locality with one backend.
   755  	clab1 := xdstestutils.NewClusterLoadAssignmentBuilder(testClusterNames[0], nil)
   756  	clab1.AddLocality(testSubZones[0], 1, 0, testEndpointAddrs[:1], nil)
   757  	xdsC.InvokeWatchEDSCallback("", parseEDSRespProtoForTesting(clab1.Build()), nil)
   758  
   759  	// Also send a DNS update, because the balancer needs both updates from all
   760  	// resources to move on.
   761  	dnsR.UpdateState(resolver.State{Addresses: []resolver.Address{{Addr: testDNSEndpointAddr}}})
   762  
   763  	addrs0 := <-cc.NewSubConnAddrsCh
   764  	if got, want := addrs0[0].Addr, testEndpointAddrs[0]; got != want {
   765  		t.Fatalf("sc is created with addr %v, want %v", got, want)
   766  	}
   767  	sc0 := <-cc.NewSubConnCh
   768  
   769  	// p0 is ready.
   770  	edsb.UpdateSubConnState(sc0, balancer.SubConnState{ConnectivityState: connectivity.Connecting})
   771  	edsb.UpdateSubConnState(sc0, balancer.SubConnState{ConnectivityState: connectivity.Ready})
   772  
   773  	// Test roundrobin with only p0 subconns.
   774  	if err := testRoundRobinPickerFromCh(cc.NewPickerCh, []balancer.SubConn{sc0}); err != nil {
   775  		t.Fatal(err)
   776  	}
   777  
   778  	// Turn down 0, p1 (DNS) will be used.
   779  	edsb.UpdateSubConnState(sc0, balancer.SubConnState{ConnectivityState: connectivity.TransientFailure})
   780  
   781  	// The transient failure above should not trigger a re-resolve to the DNS
   782  	// resolver. Need to read to clear the channel, to avoid potential deadlock
   783  	// writing to the channel later.
   784  	shortCtx, shortCancel := context.WithTimeout(context.Background(), defaultTestShortTimeout)
   785  	defer shortCancel()
   786  	select {
   787  	case <-resolveNowCh:
   788  		t.Fatal("unexpected re-resolve trigger by transient failure from EDS endpoint")
   789  	case <-shortCtx.Done():
   790  	}
   791  
   792  	// The addresses used to create new SubConn should be the DNS endpoint.
   793  	addrs1 := <-cc.NewSubConnAddrsCh
   794  	if got, want := addrs1[0].Addr, testDNSEndpointAddr; got != want {
   795  		t.Fatalf("sc is created with addr %v, want %v", got, want)
   796  	}
   797  	sc1 := <-cc.NewSubConnCh
   798  	edsb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.Connecting})
   799  	edsb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.Ready})
   800  
   801  	// Test pick with 1.
   802  	if err := testRoundRobinPickerFromCh(cc.NewPickerCh, []balancer.SubConn{sc1}); err != nil {
   803  		t.Fatal(err)
   804  	}
   805  
   806  	// Turn down the DNS endpoint, this should trigger an re-resolve in the DNS
   807  	// resolver.
   808  	edsb.UpdateSubConnState(sc1, balancer.SubConnState{ConnectivityState: connectivity.TransientFailure})
   809  
   810  	// The transient failure above should trigger a re-resolve to the DNS
   811  	// resolver. Need to read to clear the channel, to avoid potential deadlock
   812  	// writing to the channel later.
   813  	select {
   814  	case <-resolveNowCh:
   815  	case <-ctx.Done():
   816  		t.Fatal("Timed out waiting for re-resolve")
   817  	}
   818  }