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

     1  /*
     2   * Copyright 2021 gRPC authors.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package cdsbalancer
    18  
    19  import (
    20  	"context"
    21  	"errors"
    22  	"testing"
    23  
    24  	"github.com/google/go-cmp/cmp"
    25  	"github.com/hxx258456/ccgo/grpc/xds/internal/testutils/fakeclient"
    26  	"github.com/hxx258456/ccgo/grpc/xds/internal/xdsclient/xdsresource"
    27  )
    28  
    29  const (
    30  	edsService              = "EDS Service"
    31  	logicalDNSService       = "Logical DNS Service"
    32  	edsService2             = "EDS Service 2"
    33  	logicalDNSService2      = "Logical DNS Service 2"
    34  	aggregateClusterService = "Aggregate Cluster Service"
    35  )
    36  
    37  // setupTests creates a clusterHandler with a fake xds client for control over
    38  // xds client.
    39  func setupTests() (*clusterHandler, *fakeclient.Client) {
    40  	xdsC := fakeclient.NewClient()
    41  	ch := newClusterHandler(&cdsBalancer{xdsClient: xdsC})
    42  	return ch, xdsC
    43  }
    44  
    45  // Simplest case: the cluster handler receives a cluster name, handler starts a
    46  // watch for that cluster, xds client returns that it is a Leaf Node (EDS or
    47  // LogicalDNS), not a tree, so expectation that update is written to buffer
    48  // which will be read by CDS LB.
    49  func (s) TestSuccessCaseLeafNode(t *testing.T) {
    50  	tests := []struct {
    51  		name          string
    52  		clusterName   string
    53  		clusterUpdate xdsresource.ClusterUpdate
    54  		lbPolicy      *xdsresource.ClusterLBPolicyRingHash
    55  	}{
    56  		{
    57  			name:        "test-update-root-cluster-EDS-success",
    58  			clusterName: edsService,
    59  			clusterUpdate: xdsresource.ClusterUpdate{
    60  				ClusterType: xdsresource.ClusterTypeEDS,
    61  				ClusterName: edsService,
    62  			},
    63  		},
    64  		{
    65  			name:        "test-update-root-cluster-EDS-with-ring-hash",
    66  			clusterName: logicalDNSService,
    67  			clusterUpdate: xdsresource.ClusterUpdate{
    68  				ClusterType: xdsresource.ClusterTypeLogicalDNS,
    69  				ClusterName: logicalDNSService,
    70  				LBPolicy:    &xdsresource.ClusterLBPolicyRingHash{MinimumRingSize: 10, MaximumRingSize: 100},
    71  			},
    72  			lbPolicy: &xdsresource.ClusterLBPolicyRingHash{MinimumRingSize: 10, MaximumRingSize: 100},
    73  		},
    74  		{
    75  			name:        "test-update-root-cluster-Logical-DNS-success",
    76  			clusterName: logicalDNSService,
    77  			clusterUpdate: xdsresource.ClusterUpdate{
    78  				ClusterType: xdsresource.ClusterTypeLogicalDNS,
    79  				ClusterName: logicalDNSService,
    80  			},
    81  		},
    82  	}
    83  
    84  	for _, test := range tests {
    85  		t.Run(test.name, func(t *testing.T) {
    86  			ch, fakeClient := setupTests()
    87  			// When you first update the root cluster, it should hit the code
    88  			// path which will start a cluster node for that root. Updating the
    89  			// root cluster logically represents a ping from a ClientConn.
    90  			ch.updateRootCluster(test.clusterName)
    91  			// Starting a cluster node involves communicating with the
    92  			// xdsClient, telling it to watch a cluster.
    93  			ctx, ctxCancel := context.WithTimeout(context.Background(), defaultTestTimeout)
    94  			defer ctxCancel()
    95  			gotCluster, err := fakeClient.WaitForWatchCluster(ctx)
    96  			if err != nil {
    97  				t.Fatalf("xdsClient.WatchCDS failed with error: %v", err)
    98  			}
    99  			if gotCluster != test.clusterName {
   100  				t.Fatalf("xdsClient.WatchCDS called for cluster: %v, want: %v", gotCluster, test.clusterName)
   101  			}
   102  			// Invoke callback with xds client with a certain clusterUpdate. Due
   103  			// to this cluster update filling out the whole cluster tree, as the
   104  			// cluster is of a root type (EDS or Logical DNS) and not an
   105  			// aggregate cluster, this should trigger the ClusterHandler to
   106  			// write to the update buffer to update the CDS policy.
   107  			fakeClient.InvokeWatchClusterCallback(test.clusterUpdate, nil)
   108  			select {
   109  			case chu := <-ch.updateChannel:
   110  				if diff := cmp.Diff(chu.updates, []xdsresource.ClusterUpdate{test.clusterUpdate}); diff != "" {
   111  					t.Fatalf("got unexpected cluster update, diff (-got, +want): %v", diff)
   112  				}
   113  				if diff := cmp.Diff(chu.lbPolicy, test.lbPolicy); diff != "" {
   114  					t.Fatalf("got unexpected lb policy in cluster update, diff (-got, +want): %v", diff)
   115  				}
   116  			case <-ctx.Done():
   117  				t.Fatal("Timed out waiting for update from update channel.")
   118  			}
   119  			// Close the clusterHandler. This is meant to be called when the CDS
   120  			// Balancer is closed, and the call should cancel the watch for this
   121  			// cluster.
   122  			ch.close()
   123  			clusterNameDeleted, err := fakeClient.WaitForCancelClusterWatch(ctx)
   124  			if err != nil {
   125  				t.Fatalf("xdsClient.CancelCDS failed with error: %v", err)
   126  			}
   127  			if clusterNameDeleted != test.clusterName {
   128  				t.Fatalf("xdsClient.CancelCDS called for cluster %v, want: %v", clusterNameDeleted, logicalDNSService)
   129  			}
   130  		})
   131  	}
   132  }
   133  
   134  // The cluster handler receives a cluster name, handler starts a watch for that
   135  // cluster, xds client returns that it is a Leaf Node (EDS or LogicalDNS), not a
   136  // tree, so expectation that first update is written to buffer which will be
   137  // read by CDS LB. Then, send a new cluster update that is different, with the
   138  // expectation that it is also written to the update buffer to send back to CDS.
   139  func (s) TestSuccessCaseLeafNodeThenNewUpdate(t *testing.T) {
   140  	tests := []struct {
   141  		name             string
   142  		clusterName      string
   143  		clusterUpdate    xdsresource.ClusterUpdate
   144  		newClusterUpdate xdsresource.ClusterUpdate
   145  	}{
   146  		{name: "test-update-root-cluster-then-new-update-EDS-success",
   147  			clusterName: edsService,
   148  			clusterUpdate: xdsresource.ClusterUpdate{
   149  				ClusterType: xdsresource.ClusterTypeEDS,
   150  				ClusterName: edsService,
   151  			},
   152  			newClusterUpdate: xdsresource.ClusterUpdate{
   153  				ClusterType: xdsresource.ClusterTypeEDS,
   154  				ClusterName: edsService2,
   155  			},
   156  		},
   157  		{
   158  			name:        "test-update-root-cluster-then-new-update-Logical-DNS-success",
   159  			clusterName: logicalDNSService,
   160  			clusterUpdate: xdsresource.ClusterUpdate{
   161  				ClusterType: xdsresource.ClusterTypeLogicalDNS,
   162  				ClusterName: logicalDNSService,
   163  			},
   164  			newClusterUpdate: xdsresource.ClusterUpdate{
   165  				ClusterType: xdsresource.ClusterTypeLogicalDNS,
   166  				ClusterName: logicalDNSService2,
   167  			},
   168  		},
   169  	}
   170  
   171  	for _, test := range tests {
   172  		t.Run(test.name, func(t *testing.T) {
   173  			ch, fakeClient := setupTests()
   174  			ch.updateRootCluster(test.clusterName)
   175  			ctx, ctxCancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   176  			defer ctxCancel()
   177  			_, err := fakeClient.WaitForWatchCluster(ctx)
   178  			if err != nil {
   179  				t.Fatalf("xdsClient.WatchCDS failed with error: %v", err)
   180  			}
   181  			fakeClient.InvokeWatchClusterCallback(test.clusterUpdate, nil)
   182  			select {
   183  			case <-ch.updateChannel:
   184  			case <-ctx.Done():
   185  				t.Fatal("Timed out waiting for update from updateChannel.")
   186  			}
   187  
   188  			// Check that sending the same cluster update also induces an update
   189  			// to be written to update buffer.
   190  			fakeClient.InvokeWatchClusterCallback(test.clusterUpdate, nil)
   191  			shouldNotHappenCtx, shouldNotHappenCtxCancel := context.WithTimeout(context.Background(), defaultTestShortTimeout)
   192  			defer shouldNotHappenCtxCancel()
   193  			select {
   194  			case <-ch.updateChannel:
   195  			case <-shouldNotHappenCtx.Done():
   196  				t.Fatal("Timed out waiting for update from updateChannel.")
   197  			}
   198  
   199  			// Above represents same thing as the simple
   200  			// TestSuccessCaseLeafNode, extra behavior + validation (clusterNode
   201  			// which is a leaf receives a changed clusterUpdate, which should
   202  			// ping clusterHandler, which should then write to the update
   203  			// buffer).
   204  			fakeClient.InvokeWatchClusterCallback(test.newClusterUpdate, nil)
   205  			select {
   206  			case chu := <-ch.updateChannel:
   207  				if diff := cmp.Diff(chu.updates, []xdsresource.ClusterUpdate{test.newClusterUpdate}); diff != "" {
   208  					t.Fatalf("got unexpected cluster update, diff (-got, +want): %v", diff)
   209  				}
   210  			case <-ctx.Done():
   211  				t.Fatal("Timed out waiting for update from updateChannel.")
   212  			}
   213  		})
   214  	}
   215  }
   216  
   217  // TestUpdateRootClusterAggregateSuccess tests the case where an aggregate
   218  // cluster is a root pointing to two child clusters one of type EDS and the
   219  // other of type LogicalDNS. This test will then send cluster updates for both
   220  // the children, and at the end there should be a successful clusterUpdate
   221  // written to the update buffer to send back to CDS.
   222  func (s) TestUpdateRootClusterAggregateSuccess(t *testing.T) {
   223  	ch, fakeClient := setupTests()
   224  	ch.updateRootCluster(aggregateClusterService)
   225  
   226  	ctx, ctxCancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   227  	defer ctxCancel()
   228  	gotCluster, err := fakeClient.WaitForWatchCluster(ctx)
   229  	if err != nil {
   230  		t.Fatalf("xdsClient.WatchCDS failed with error: %v", err)
   231  	}
   232  	if gotCluster != aggregateClusterService {
   233  		t.Fatalf("xdsClient.WatchCDS called for cluster: %v, want: %v", gotCluster, aggregateClusterService)
   234  	}
   235  
   236  	// The xdsClient telling the clusterNode that the cluster type is an
   237  	// aggregate cluster which will cause a lot of downstream behavior. For a
   238  	// cluster type that isn't an aggregate, the behavior is simple. The
   239  	// clusterNode will simply get a successful update, which will then ping the
   240  	// clusterHandler which will successfully build an update to send to the CDS
   241  	// policy. In the aggregate cluster case, the handleResp callback must also
   242  	// start watches for the aggregate cluster's children. The ping to the
   243  	// clusterHandler at the end of handleResp should be a no-op, as neither the
   244  	// EDS or LogicalDNS child clusters have received an update yet.
   245  	fakeClient.InvokeWatchClusterCallback(xdsresource.ClusterUpdate{
   246  		ClusterType:             xdsresource.ClusterTypeAggregate,
   247  		ClusterName:             aggregateClusterService,
   248  		PrioritizedClusterNames: []string{edsService, logicalDNSService},
   249  	}, nil)
   250  
   251  	// xds client should be called to start a watch for one of the child
   252  	// clusters of the aggregate. The order of the children in the update
   253  	// written to the buffer to send to CDS matters, however there is no
   254  	// guarantee on the order it will start the watches of the children.
   255  	gotCluster, err = fakeClient.WaitForWatchCluster(ctx)
   256  	if err != nil {
   257  		t.Fatalf("xdsClient.WatchCDS failed with error: %v", err)
   258  	}
   259  	if gotCluster != edsService {
   260  		if gotCluster != logicalDNSService {
   261  			t.Fatalf("xdsClient.WatchCDS called for cluster: %v, want: %v", gotCluster, edsService)
   262  		}
   263  	}
   264  
   265  	// xds client should then be called to start a watch for the second child
   266  	// cluster.
   267  	gotCluster, err = fakeClient.WaitForWatchCluster(ctx)
   268  	if err != nil {
   269  		t.Fatalf("xdsClient.WatchCDS failed with error: %v", err)
   270  	}
   271  	if gotCluster != edsService {
   272  		if gotCluster != logicalDNSService {
   273  			t.Fatalf("xdsClient.WatchCDS called for cluster: %v, want: %v", gotCluster, logicalDNSService)
   274  		}
   275  	}
   276  
   277  	// The handleResp() call on the root aggregate cluster should not ping the
   278  	// cluster handler to try and construct an update, as the handleResp()
   279  	// callback knows that when a child is created, it cannot possibly build a
   280  	// successful update yet. Thus, there should be nothing in the update
   281  	// channel.
   282  
   283  	shouldNotHappenCtx, shouldNotHappenCtxCancel := context.WithTimeout(context.Background(), defaultTestShortTimeout)
   284  	defer shouldNotHappenCtxCancel()
   285  
   286  	select {
   287  	case <-ch.updateChannel:
   288  		t.Fatal("Cluster Handler wrote an update to updateChannel when it shouldn't have, as each node in the full cluster tree has not yet received an update")
   289  	case <-shouldNotHappenCtx.Done():
   290  	}
   291  
   292  	// Send callback for the EDS child cluster.
   293  	fakeClient.InvokeWatchClusterCallback(xdsresource.ClusterUpdate{
   294  		ClusterType: xdsresource.ClusterTypeEDS,
   295  		ClusterName: edsService,
   296  	}, nil)
   297  
   298  	// EDS child cluster will ping the Cluster Handler, to try an update, which
   299  	// still won't successfully build as the LogicalDNS child of the root
   300  	// aggregate cluster has not yet received and handled an update.
   301  	select {
   302  	case <-ch.updateChannel:
   303  		t.Fatal("Cluster Handler wrote an update to updateChannel when it shouldn't have, as each node in the full cluster tree has not yet received an update")
   304  	case <-shouldNotHappenCtx.Done():
   305  	}
   306  
   307  	// Invoke callback for Logical DNS child cluster.
   308  
   309  	fakeClient.InvokeWatchClusterCallback(xdsresource.ClusterUpdate{
   310  		ClusterType: xdsresource.ClusterTypeLogicalDNS,
   311  		ClusterName: logicalDNSService,
   312  	}, nil)
   313  
   314  	// Will Ping Cluster Handler, which will finally successfully build an
   315  	// update as all nodes in the tree of clusters have received an update.
   316  	// Since this cluster is an aggregate cluster comprised of two children, the
   317  	// returned update should be length 2, as the xds cluster resolver LB policy
   318  	// only cares about the full list of LogicalDNS and EDS clusters
   319  	// representing the base nodes of the tree of clusters. This list should be
   320  	// ordered as per the cluster update.
   321  	select {
   322  	case chu := <-ch.updateChannel:
   323  		if diff := cmp.Diff(chu.updates, []xdsresource.ClusterUpdate{{
   324  			ClusterType: xdsresource.ClusterTypeEDS,
   325  			ClusterName: edsService,
   326  		}, {
   327  			ClusterType: xdsresource.ClusterTypeLogicalDNS,
   328  			ClusterName: logicalDNSService,
   329  		}}); diff != "" {
   330  			t.Fatalf("got unexpected cluster update, diff (-got, +want): %v", diff)
   331  		}
   332  	case <-ctx.Done():
   333  		t.Fatal("Timed out waiting for the cluster update to be written to the update buffer.")
   334  	}
   335  }
   336  
   337  // TestUpdateRootClusterAggregateThenChangeChild tests the scenario where you
   338  // have an aggregate cluster with an EDS child and a LogicalDNS child, then you
   339  // change one of the children and send an update for the changed child. This
   340  // should write a new update to the update buffer to send back to CDS.
   341  func (s) TestUpdateRootClusterAggregateThenChangeChild(t *testing.T) {
   342  	// This initial code is the same as the test for the aggregate success case,
   343  	// except without validations. This will get this test to the point where it
   344  	// can change one of the children.
   345  	ch, fakeClient := setupTests()
   346  	ch.updateRootCluster(aggregateClusterService)
   347  
   348  	ctx, ctxCancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   349  	defer ctxCancel()
   350  	_, err := fakeClient.WaitForWatchCluster(ctx)
   351  	if err != nil {
   352  		t.Fatalf("xdsClient.WatchCDS failed with error: %v", err)
   353  	}
   354  
   355  	fakeClient.InvokeWatchClusterCallback(xdsresource.ClusterUpdate{
   356  		ClusterType:             xdsresource.ClusterTypeAggregate,
   357  		ClusterName:             aggregateClusterService,
   358  		PrioritizedClusterNames: []string{edsService, logicalDNSService},
   359  	}, nil)
   360  	fakeClient.WaitForWatchCluster(ctx)
   361  	fakeClient.WaitForWatchCluster(ctx)
   362  	fakeClient.InvokeWatchClusterCallback(xdsresource.ClusterUpdate{
   363  		ClusterType: xdsresource.ClusterTypeEDS,
   364  		ClusterName: edsService,
   365  	}, nil)
   366  	fakeClient.InvokeWatchClusterCallback(xdsresource.ClusterUpdate{
   367  		ClusterType: xdsresource.ClusterTypeLogicalDNS,
   368  		ClusterName: logicalDNSService,
   369  	}, nil)
   370  
   371  	select {
   372  	case <-ch.updateChannel:
   373  	case <-ctx.Done():
   374  		t.Fatal("Timed out waiting for the cluster update to be written to the update buffer.")
   375  	}
   376  
   377  	fakeClient.InvokeWatchClusterCallback(xdsresource.ClusterUpdate{
   378  		ClusterType:             xdsresource.ClusterTypeAggregate,
   379  		ClusterName:             aggregateClusterService,
   380  		PrioritizedClusterNames: []string{edsService, logicalDNSService2},
   381  	}, nil)
   382  
   383  	// The cluster update let's the aggregate cluster know that it's children
   384  	// are now edsService and logicalDNSService2, which implies that the
   385  	// aggregateCluster lost it's old logicalDNSService child. Thus, the
   386  	// logicalDNSService child should be deleted.
   387  	clusterNameDeleted, err := fakeClient.WaitForCancelClusterWatch(ctx)
   388  	if err != nil {
   389  		t.Fatalf("xdsClient.CancelCDS failed with error: %v", err)
   390  	}
   391  	if clusterNameDeleted != logicalDNSService {
   392  		t.Fatalf("xdsClient.CancelCDS called for cluster %v, want: %v", clusterNameDeleted, logicalDNSService)
   393  	}
   394  
   395  	// The handleResp() callback should then start a watch for
   396  	// logicalDNSService2.
   397  	clusterNameCreated, err := fakeClient.WaitForWatchCluster(ctx)
   398  	if err != nil {
   399  		t.Fatalf("xdsClient.WatchCDS failed with error: %v", err)
   400  	}
   401  	if clusterNameCreated != logicalDNSService2 {
   402  		t.Fatalf("xdsClient.WatchCDS called for cluster %v, want: %v", clusterNameCreated, logicalDNSService2)
   403  	}
   404  
   405  	// handleResp() should try and send an update here, but it will fail as
   406  	// logicalDNSService2 has not yet received an update.
   407  	shouldNotHappenCtx, shouldNotHappenCtxCancel := context.WithTimeout(context.Background(), defaultTestShortTimeout)
   408  	defer shouldNotHappenCtxCancel()
   409  	select {
   410  	case <-ch.updateChannel:
   411  		t.Fatal("Cluster Handler wrote an update to updateChannel when it shouldn't have, as each node in the full cluster tree has not yet received an update")
   412  	case <-shouldNotHappenCtx.Done():
   413  	}
   414  
   415  	// Invoke a callback for the new logicalDNSService2 - this will fill out the
   416  	// tree with successful updates.
   417  	fakeClient.InvokeWatchClusterCallback(xdsresource.ClusterUpdate{
   418  		ClusterType: xdsresource.ClusterTypeLogicalDNS,
   419  		ClusterName: logicalDNSService2,
   420  	}, nil)
   421  
   422  	// Behavior: This update make every node in the tree of cluster have
   423  	// received an update. Thus, at the end of this callback, when you ping the
   424  	// clusterHandler to try and construct an update, the update should now
   425  	// successfully be written to update buffer to send back to CDS. This new
   426  	// update should contain the new child of LogicalDNS2.
   427  
   428  	select {
   429  	case chu := <-ch.updateChannel:
   430  		if diff := cmp.Diff(chu.updates, []xdsresource.ClusterUpdate{{
   431  			ClusterType: xdsresource.ClusterTypeEDS,
   432  			ClusterName: edsService,
   433  		}, {
   434  			ClusterType: xdsresource.ClusterTypeLogicalDNS,
   435  			ClusterName: logicalDNSService2,
   436  		}}); diff != "" {
   437  			t.Fatalf("got unexpected cluster update, diff (-got, +want): %v", diff)
   438  		}
   439  	case <-ctx.Done():
   440  		t.Fatal("Timed out waiting for the cluster update to be written to the update buffer.")
   441  	}
   442  }
   443  
   444  // TestUpdateRootClusterAggregateThenChangeRootToEDS tests the situation where
   445  // you have a fully updated aggregate cluster (where AggregateCluster success
   446  // test gets you) as the root cluster, then you update that root cluster to a
   447  // cluster of type EDS.
   448  func (s) TestUpdateRootClusterAggregateThenChangeRootToEDS(t *testing.T) {
   449  	// This initial code is the same as the test for the aggregate success case,
   450  	// except without validations. This will get this test to the point where it
   451  	// can update the root cluster to one of type EDS.
   452  	ch, fakeClient := setupTests()
   453  	ch.updateRootCluster(aggregateClusterService)
   454  
   455  	ctx, ctxCancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   456  	defer ctxCancel()
   457  	_, err := fakeClient.WaitForWatchCluster(ctx)
   458  	if err != nil {
   459  		t.Fatalf("xdsClient.WatchCDS failed with error: %v", err)
   460  	}
   461  
   462  	fakeClient.InvokeWatchClusterCallback(xdsresource.ClusterUpdate{
   463  		ClusterType:             xdsresource.ClusterTypeAggregate,
   464  		ClusterName:             aggregateClusterService,
   465  		PrioritizedClusterNames: []string{edsService, logicalDNSService},
   466  	}, nil)
   467  	fakeClient.WaitForWatchCluster(ctx)
   468  	fakeClient.WaitForWatchCluster(ctx)
   469  	fakeClient.InvokeWatchClusterCallback(xdsresource.ClusterUpdate{
   470  		ClusterType: xdsresource.ClusterTypeEDS,
   471  		ClusterName: edsService,
   472  	}, nil)
   473  	fakeClient.InvokeWatchClusterCallback(xdsresource.ClusterUpdate{
   474  		ClusterType: xdsresource.ClusterTypeLogicalDNS,
   475  		ClusterName: logicalDNSService,
   476  	}, nil)
   477  
   478  	select {
   479  	case <-ch.updateChannel:
   480  	case <-ctx.Done():
   481  		t.Fatal("Timed out waiting for the cluster update to be written to the update buffer.")
   482  	}
   483  
   484  	// Changes the root aggregate cluster to a EDS cluster. This should delete
   485  	// the root aggregate cluster and all of it's children by successfully
   486  	// canceling the watches for them.
   487  	ch.updateRootCluster(edsService2)
   488  
   489  	// Reads from the cancel channel, should first be type Aggregate, then EDS
   490  	// then Logical DNS.
   491  	clusterNameDeleted, err := fakeClient.WaitForCancelClusterWatch(ctx)
   492  	if err != nil {
   493  		t.Fatalf("xdsClient.CancelCDS failed with error: %v", err)
   494  	}
   495  	if clusterNameDeleted != aggregateClusterService {
   496  		t.Fatalf("xdsClient.CancelCDS called for cluster %v, want: %v", clusterNameDeleted, logicalDNSService)
   497  	}
   498  
   499  	clusterNameDeleted, err = fakeClient.WaitForCancelClusterWatch(ctx)
   500  	if err != nil {
   501  		t.Fatalf("xdsClient.CancelCDS failed with error: %v", err)
   502  	}
   503  	if clusterNameDeleted != edsService {
   504  		t.Fatalf("xdsClient.CancelCDS called for cluster %v, want: %v", clusterNameDeleted, logicalDNSService)
   505  	}
   506  
   507  	clusterNameDeleted, err = fakeClient.WaitForCancelClusterWatch(ctx)
   508  	if err != nil {
   509  		t.Fatalf("xdsClient.CancelCDS failed with error: %v", err)
   510  	}
   511  	if clusterNameDeleted != logicalDNSService {
   512  		t.Fatalf("xdsClient.CancelCDS called for cluster %v, want: %v", clusterNameDeleted, logicalDNSService)
   513  	}
   514  
   515  	// After deletion, it should start a watch for the EDS Cluster. The behavior
   516  	// for this EDS Cluster receiving an update from xds client and then
   517  	// successfully writing an update to send back to CDS is already tested in
   518  	// the updateEDS success case.
   519  	gotCluster, err := fakeClient.WaitForWatchCluster(ctx)
   520  	if err != nil {
   521  		t.Fatalf("xdsClient.WatchCDS failed with error: %v", err)
   522  	}
   523  	if gotCluster != edsService2 {
   524  		t.Fatalf("xdsClient.WatchCDS called for cluster: %v, want: %v", gotCluster, edsService2)
   525  	}
   526  }
   527  
   528  // TestHandleRespInvokedWithError tests that when handleResp is invoked with an
   529  // error, that the error is successfully written to the update buffer.
   530  func (s) TestHandleRespInvokedWithError(t *testing.T) {
   531  	ch, fakeClient := setupTests()
   532  	ch.updateRootCluster(edsService)
   533  	ctx, ctxCancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   534  	defer ctxCancel()
   535  	_, err := fakeClient.WaitForWatchCluster(ctx)
   536  	if err != nil {
   537  		t.Fatalf("xdsClient.WatchCDS failed with error: %v", err)
   538  	}
   539  	fakeClient.InvokeWatchClusterCallback(xdsresource.ClusterUpdate{}, errors.New("some error"))
   540  	select {
   541  	case chu := <-ch.updateChannel:
   542  		if chu.err.Error() != "some error" {
   543  			t.Fatalf("Did not receive the expected error, instead received: %v", chu.err.Error())
   544  		}
   545  	case <-ctx.Done():
   546  		t.Fatal("Timed out waiting for update from update channel.")
   547  	}
   548  }
   549  
   550  // TestSwitchClusterNodeBetweenLeafAndAggregated tests having an existing
   551  // cluster node switch between a leaf and an aggregated cluster. When the
   552  // cluster switches from a leaf to an aggregated cluster, it should add
   553  // children, and when it switches back to a leaf, it should delete those new
   554  // children and also successfully write a cluster update to the update buffer.
   555  func (s) TestSwitchClusterNodeBetweenLeafAndAggregated(t *testing.T) {
   556  	// Getting the test to the point where there's a root cluster which is a eds
   557  	// leaf.
   558  	ch, fakeClient := setupTests()
   559  	ch.updateRootCluster(edsService2)
   560  	ctx, ctxCancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   561  	defer ctxCancel()
   562  	_, err := fakeClient.WaitForWatchCluster(ctx)
   563  	if err != nil {
   564  		t.Fatalf("xdsClient.WatchCDS failed with error: %v", err)
   565  	}
   566  	fakeClient.InvokeWatchClusterCallback(xdsresource.ClusterUpdate{
   567  		ClusterType: xdsresource.ClusterTypeEDS,
   568  		ClusterName: edsService2,
   569  	}, nil)
   570  	select {
   571  	case <-ch.updateChannel:
   572  	case <-ctx.Done():
   573  		t.Fatal("Timed out waiting for update from update channel.")
   574  	}
   575  	// Switch the cluster to an aggregate cluster, this should cause two new
   576  	// child watches to be created.
   577  	fakeClient.InvokeWatchClusterCallback(xdsresource.ClusterUpdate{
   578  		ClusterType:             xdsresource.ClusterTypeAggregate,
   579  		ClusterName:             edsService2,
   580  		PrioritizedClusterNames: []string{edsService, logicalDNSService},
   581  	}, nil)
   582  
   583  	// xds client should be called to start a watch for one of the child
   584  	// clusters of the aggregate. The order of the children in the update
   585  	// written to the buffer to send to CDS matters, however there is no
   586  	// guarantee on the order it will start the watches of the children.
   587  	gotCluster, err := fakeClient.WaitForWatchCluster(ctx)
   588  	if err != nil {
   589  		t.Fatalf("xdsClient.WatchCDS failed with error: %v", err)
   590  	}
   591  	if gotCluster != edsService {
   592  		if gotCluster != logicalDNSService {
   593  			t.Fatalf("xdsClient.WatchCDS called for cluster: %v, want: %v", gotCluster, edsService)
   594  		}
   595  	}
   596  
   597  	// xds client should then be called to start a watch for the second child
   598  	// cluster.
   599  	gotCluster, err = fakeClient.WaitForWatchCluster(ctx)
   600  	if err != nil {
   601  		t.Fatalf("xdsClient.WatchCDS failed with error: %v", err)
   602  	}
   603  	if gotCluster != edsService {
   604  		if gotCluster != logicalDNSService {
   605  			t.Fatalf("xdsClient.WatchCDS called for cluster: %v, want: %v", gotCluster, logicalDNSService)
   606  		}
   607  	}
   608  
   609  	// After starting a watch for the second child cluster, there should be no
   610  	// more watches started on the xds client.
   611  	shouldNotHappenCtx, shouldNotHappenCtxCancel := context.WithTimeout(context.Background(), defaultTestShortTimeout)
   612  	defer shouldNotHappenCtxCancel()
   613  	gotCluster, err = fakeClient.WaitForWatchCluster(shouldNotHappenCtx)
   614  	if err == nil {
   615  		t.Fatalf("xdsClient.WatchCDS called for cluster: %v, no more watches should be started.", gotCluster)
   616  	}
   617  
   618  	// The handleResp() call on the root aggregate cluster should not ping the
   619  	// cluster handler to try and construct an update, as the handleResp()
   620  	// callback knows that when a child is created, it cannot possibly build a
   621  	// successful update yet. Thus, there should be nothing in the update
   622  	// channel.
   623  
   624  	shouldNotHappenCtx, shouldNotHappenCtxCancel = context.WithTimeout(context.Background(), defaultTestShortTimeout)
   625  	defer shouldNotHappenCtxCancel()
   626  
   627  	select {
   628  	case <-ch.updateChannel:
   629  		t.Fatal("Cluster Handler wrote an update to updateChannel when it shouldn't have, as each node in the full cluster tree has not yet received an update")
   630  	case <-shouldNotHappenCtx.Done():
   631  	}
   632  
   633  	// Switch the cluster back to an EDS Cluster. This should cause the two
   634  	// children to be deleted.
   635  	fakeClient.InvokeWatchClusterCallback(xdsresource.ClusterUpdate{
   636  		ClusterType: xdsresource.ClusterTypeEDS,
   637  		ClusterName: edsService2,
   638  	}, nil)
   639  
   640  	// Should delete the two children (no guarantee of ordering deleted, which
   641  	// is ok), then successfully write an update to the update buffer as the
   642  	// full cluster tree has received updates.
   643  	clusterNameDeleted, err := fakeClient.WaitForCancelClusterWatch(ctx)
   644  	if err != nil {
   645  		t.Fatalf("xdsClient.CancelCDS failed with error: %v", err)
   646  	}
   647  	// No guarantee of ordering, so one of the children should be deleted first.
   648  	if clusterNameDeleted != edsService {
   649  		if clusterNameDeleted != logicalDNSService {
   650  			t.Fatalf("xdsClient.CancelCDS called for cluster %v, want either: %v or: %v", clusterNameDeleted, edsService, logicalDNSService)
   651  		}
   652  	}
   653  	// Then the other child should be deleted.
   654  	clusterNameDeleted, err = fakeClient.WaitForCancelClusterWatch(ctx)
   655  	if err != nil {
   656  		t.Fatalf("xdsClient.CancelCDS failed with error: %v", err)
   657  	}
   658  	if clusterNameDeleted != edsService {
   659  		if clusterNameDeleted != logicalDNSService {
   660  			t.Fatalf("xdsClient.CancelCDS called for cluster %v, want either: %v or: %v", clusterNameDeleted, edsService, logicalDNSService)
   661  		}
   662  	}
   663  
   664  	// After cancelling a watch for the second child cluster, there should be no
   665  	// more watches cancelled on the xds client.
   666  	shouldNotHappenCtx, shouldNotHappenCtxCancel = context.WithTimeout(context.Background(), defaultTestShortTimeout)
   667  	defer shouldNotHappenCtxCancel()
   668  	gotCluster, err = fakeClient.WaitForCancelClusterWatch(shouldNotHappenCtx)
   669  	if err == nil {
   670  		t.Fatalf("xdsClient.WatchCDS called for cluster: %v, no more watches should be cancelled.", gotCluster)
   671  	}
   672  
   673  	// Then an update should successfully be written to the update buffer.
   674  	select {
   675  	case chu := <-ch.updateChannel:
   676  		if diff := cmp.Diff(chu.updates, []xdsresource.ClusterUpdate{{
   677  			ClusterType: xdsresource.ClusterTypeEDS,
   678  			ClusterName: edsService2,
   679  		}}); diff != "" {
   680  			t.Fatalf("got unexpected cluster update, diff (-got, +want): %v", diff)
   681  		}
   682  	case <-ctx.Done():
   683  		t.Fatal("Timed out waiting for update from update channel.")
   684  	}
   685  }