gitee.com/ks-custle/core-gm@v0.0.0-20230922171213-b83bdd97b62c/grpc/xds/internal/balancer/clusterresolver/resource_resolver_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 clusterresolver
    20  
    21  import (
    22  	"context"
    23  	"fmt"
    24  	"net/url"
    25  	"testing"
    26  
    27  	"gitee.com/ks-custle/core-gm/grpc/resolver"
    28  	"gitee.com/ks-custle/core-gm/grpc/resolver/manual"
    29  	"gitee.com/ks-custle/core-gm/grpc/xds/internal/testutils"
    30  	"gitee.com/ks-custle/core-gm/grpc/xds/internal/testutils/fakeclient"
    31  	"gitee.com/ks-custle/core-gm/grpc/xds/internal/xdsclient/xdsresource"
    32  	"github.com/google/go-cmp/cmp"
    33  )
    34  
    35  const (
    36  	testDNSTarget = "dns.com"
    37  )
    38  
    39  var (
    40  	testEDSUpdates []xdsresource.EndpointsUpdate
    41  )
    42  
    43  func init() {
    44  	clab1 := testutils.NewClusterLoadAssignmentBuilder(testClusterNames[0], nil)
    45  	clab1.AddLocality(testSubZones[0], 1, 0, testEndpointAddrs[:1], nil)
    46  	testEDSUpdates = append(testEDSUpdates, parseEDSRespProtoForTesting(clab1.Build()))
    47  	clab2 := testutils.NewClusterLoadAssignmentBuilder(testClusterNames[0], nil)
    48  	clab2.AddLocality(testSubZones[1], 1, 0, testEndpointAddrs[1:2], nil)
    49  	testEDSUpdates = append(testEDSUpdates, parseEDSRespProtoForTesting(clab2.Build()))
    50  }
    51  
    52  // Test the simple case with one EDS resource to watch.
    53  func (s) TestResourceResolverOneEDSResource(t *testing.T) {
    54  	for _, test := range []struct {
    55  		name                 string
    56  		clusterName, edsName string
    57  		wantName             string
    58  		edsUpdate            xdsresource.EndpointsUpdate
    59  		want                 []priorityConfig
    60  	}{
    61  		{name: "watch EDS",
    62  			clusterName: testClusterName,
    63  			edsName:     testEDSServcie,
    64  			wantName:    testEDSServcie,
    65  			edsUpdate:   testEDSUpdates[0],
    66  			want: []priorityConfig{{
    67  				mechanism: DiscoveryMechanism{
    68  					Type:           DiscoveryMechanismTypeEDS,
    69  					Cluster:        testClusterName,
    70  					EDSServiceName: testEDSServcie,
    71  				},
    72  				edsResp: testEDSUpdates[0],
    73  			}},
    74  		},
    75  		{
    76  			name:        "watch EDS no EDS name", // Will watch for cluster name.
    77  			clusterName: testClusterName,
    78  			wantName:    testClusterName,
    79  			edsUpdate:   testEDSUpdates[1],
    80  			want: []priorityConfig{{
    81  				mechanism: DiscoveryMechanism{
    82  					Type:    DiscoveryMechanismTypeEDS,
    83  					Cluster: testClusterName,
    84  				},
    85  				edsResp: testEDSUpdates[1],
    86  			}},
    87  		},
    88  	} {
    89  		t.Run(test.name, func(t *testing.T) {
    90  			fakeClient := fakeclient.NewClient()
    91  			rr := newResourceResolver(&clusterResolverBalancer{xdsClient: fakeClient})
    92  			rr.updateMechanisms([]DiscoveryMechanism{{
    93  				Type:           DiscoveryMechanismTypeEDS,
    94  				Cluster:        test.clusterName,
    95  				EDSServiceName: test.edsName,
    96  			}})
    97  			ctx, ctxCancel := context.WithTimeout(context.Background(), defaultTestTimeout)
    98  			defer ctxCancel()
    99  			gotEDSName, err := fakeClient.WaitForWatchEDS(ctx)
   100  			if err != nil {
   101  				t.Fatalf("xdsClient.WatchCDS failed with error: %v", err)
   102  			}
   103  			if gotEDSName != test.wantName {
   104  				t.Fatalf("xdsClient.WatchEDS called for cluster: %v, want: %v", gotEDSName, test.wantName)
   105  			}
   106  
   107  			// Invoke callback, should get an update.
   108  			fakeClient.InvokeWatchEDSCallback("", test.edsUpdate, nil)
   109  			select {
   110  			case u := <-rr.updateChannel:
   111  				if diff := cmp.Diff(u.priorities, test.want, cmp.AllowUnexported(priorityConfig{})); diff != "" {
   112  					t.Fatalf("got unexpected resource update, diff (-got, +want): %v", diff)
   113  				}
   114  			case <-ctx.Done():
   115  				t.Fatal("Timed out waiting for update from update channel.")
   116  			}
   117  			// Close the resource resolver. Should stop EDS watch.
   118  			rr.stop()
   119  			edsNameCanceled, err := fakeClient.WaitForCancelEDSWatch(ctx)
   120  			if err != nil {
   121  				t.Fatalf("xdsClient.CancelCDS failed with error: %v", err)
   122  			}
   123  			if edsNameCanceled != test.wantName {
   124  				t.Fatalf("xdsClient.CancelEDS called for %v, want: %v", edsNameCanceled, testEDSServcie)
   125  			}
   126  		})
   127  	}
   128  }
   129  
   130  func setupDNS() (chan resolver.Target, chan struct{}, chan resolver.ResolveNowOptions, *manual.Resolver, func()) {
   131  	dnsTargetCh := make(chan resolver.Target, 1)
   132  	dnsCloseCh := make(chan struct{}, 1)
   133  	resolveNowCh := make(chan resolver.ResolveNowOptions, 1)
   134  
   135  	mr := manual.NewBuilderWithScheme("dns")
   136  	mr.BuildCallback = func(target resolver.Target, _ resolver.ClientConn, _ resolver.BuildOptions) { dnsTargetCh <- target }
   137  	mr.CloseCallback = func() { dnsCloseCh <- struct{}{} }
   138  	mr.ResolveNowCallback = func(opts resolver.ResolveNowOptions) { resolveNowCh <- opts }
   139  	oldNewDNS := newDNS
   140  	newDNS = func(target resolver.Target, cc resolver.ClientConn, opts resolver.BuildOptions) (resolver.Resolver, error) {
   141  		return mr.Build(target, cc, opts)
   142  	}
   143  	return dnsTargetCh, dnsCloseCh, resolveNowCh, mr, func() { newDNS = oldNewDNS }
   144  }
   145  
   146  // Test the simple case of one DNS resolver.
   147  func (s) TestResourceResolverOneDNSResource(t *testing.T) {
   148  	for _, test := range []struct {
   149  		name       string
   150  		target     string
   151  		wantTarget resolver.Target
   152  		addrs      []resolver.Address
   153  		want       []priorityConfig
   154  	}{
   155  		{
   156  			name:   "watch DNS",
   157  			target: testDNSTarget,
   158  			// Target.Scheme、Target.Endpoint are deprecated, use URL.Scheme、URL.Path instead.
   159  			//wantTarget: resolver.Target{Scheme: "dns", Endpoint: testDNSTarget},
   160  			wantTarget: resolver.Target{URL: url.URL{Scheme: "dns", Path: testDNSTarget}},
   161  			addrs:      []resolver.Address{{Addr: "1.1.1.1"}, {Addr: "2.2.2.2"}},
   162  			want: []priorityConfig{{
   163  				mechanism: DiscoveryMechanism{
   164  					Type:        DiscoveryMechanismTypeLogicalDNS,
   165  					DNSHostname: testDNSTarget,
   166  				},
   167  				addresses: []string{"1.1.1.1", "2.2.2.2"},
   168  			}},
   169  		},
   170  	} {
   171  		t.Run(test.name, func(t *testing.T) {
   172  			dnsTargetCh, dnsCloseCh, _, dnsR, cleanup := setupDNS()
   173  			defer cleanup()
   174  			fakeClient := fakeclient.NewClient()
   175  			rr := newResourceResolver(&clusterResolverBalancer{xdsClient: fakeClient})
   176  			rr.updateMechanisms([]DiscoveryMechanism{{
   177  				Type:        DiscoveryMechanismTypeLogicalDNS,
   178  				DNSHostname: test.target,
   179  			}})
   180  			ctx, ctxCancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   181  			defer ctxCancel()
   182  			select {
   183  			case target := <-dnsTargetCh:
   184  				if diff := cmp.Diff(target, test.wantTarget); diff != "" {
   185  					t.Fatalf("got unexpected DNS target to watch, diff (-got, +want): %v", diff)
   186  				}
   187  			case <-ctx.Done():
   188  				t.Fatal("Timed out waiting for building DNS resolver")
   189  			}
   190  
   191  			// Invoke callback, should get an update.
   192  			dnsR.UpdateState(resolver.State{Addresses: test.addrs})
   193  			select {
   194  			case u := <-rr.updateChannel:
   195  				if diff := cmp.Diff(u.priorities, test.want, cmp.AllowUnexported(priorityConfig{})); diff != "" {
   196  					t.Fatalf("got unexpected resource update, diff (-got, +want): %v", diff)
   197  				}
   198  			case <-ctx.Done():
   199  				t.Fatal("Timed out waiting for update from update channel.")
   200  			}
   201  			// Close the resource resolver. Should close the underlying resolver.
   202  			rr.stop()
   203  			select {
   204  			case <-dnsCloseCh:
   205  			case <-ctx.Done():
   206  				t.Fatal("Timed out waiting for closing DNS resolver")
   207  			}
   208  		})
   209  	}
   210  }
   211  
   212  // Test that changing EDS name would cause a cancel and a new watch.
   213  //
   214  // Also, changes that don't actually change EDS names (e.g. changing cluster
   215  // name but not service name, or change circuit breaking count) doesn't do
   216  // anything.
   217  //
   218  // - update DiscoveryMechanism
   219  // - same EDS name to watch, but different MaxCurrentCount: no new watch
   220  // - different cluster name, but same EDS name: no new watch
   221  func (s) TestResourceResolverChangeEDSName(t *testing.T) {
   222  	fakeClient := fakeclient.NewClient()
   223  	rr := newResourceResolver(&clusterResolverBalancer{xdsClient: fakeClient})
   224  	rr.updateMechanisms([]DiscoveryMechanism{{
   225  		Type:           DiscoveryMechanismTypeEDS,
   226  		Cluster:        testClusterName,
   227  		EDSServiceName: testEDSServcie,
   228  	}})
   229  	ctx, ctxCancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   230  	defer ctxCancel()
   231  	gotEDSName1, err := fakeClient.WaitForWatchEDS(ctx)
   232  	if err != nil {
   233  		t.Fatalf("xdsClient.WatchCDS failed with error: %v", err)
   234  	}
   235  	if gotEDSName1 != testEDSServcie {
   236  		t.Fatalf("xdsClient.WatchEDS called for cluster: %v, want: %v", gotEDSName1, testEDSServcie)
   237  	}
   238  
   239  	// Invoke callback, should get an update.
   240  	fakeClient.InvokeWatchEDSCallback(gotEDSName1, testEDSUpdates[0], nil)
   241  	select {
   242  	case u := <-rr.updateChannel:
   243  		if diff := cmp.Diff(u.priorities, []priorityConfig{{
   244  			mechanism: DiscoveryMechanism{
   245  				Type:           DiscoveryMechanismTypeEDS,
   246  				Cluster:        testClusterName,
   247  				EDSServiceName: testEDSServcie,
   248  			},
   249  			edsResp: testEDSUpdates[0],
   250  		}}, cmp.AllowUnexported(priorityConfig{})); diff != "" {
   251  			t.Fatalf("got unexpected resource update, diff (-got, +want): %v", diff)
   252  		}
   253  	case <-ctx.Done():
   254  		t.Fatal("Timed out waiting for update from update channel.")
   255  	}
   256  
   257  	// Change name to watch.
   258  	rr.updateMechanisms([]DiscoveryMechanism{{
   259  		Type:    DiscoveryMechanismTypeEDS,
   260  		Cluster: testClusterName,
   261  	}})
   262  	edsNameCanceled1, err := fakeClient.WaitForCancelEDSWatch(ctx)
   263  	if err != nil {
   264  		t.Fatalf("xdsClient.CancelCDS failed with error: %v", err)
   265  	}
   266  	if edsNameCanceled1 != gotEDSName1 {
   267  		t.Fatalf("xdsClient.CancelEDS called for %v, want: %v", edsNameCanceled1, testEDSServcie)
   268  	}
   269  	gotEDSName2, err := fakeClient.WaitForWatchEDS(ctx)
   270  	if err != nil {
   271  		t.Fatalf("xdsClient.WatchCDS failed with error: %v", err)
   272  	}
   273  	if gotEDSName2 != testClusterName {
   274  		t.Fatalf("xdsClient.WatchEDS called for cluster: %v, want: %v", gotEDSName2, testClusterName)
   275  	}
   276  	// Shouldn't get any update, because the new resource hasn't received any
   277  	// update.
   278  	shortCtx, shortCancel := context.WithTimeout(context.Background(), defaultTestShortTimeout)
   279  	defer shortCancel()
   280  	select {
   281  	case u := <-rr.updateChannel:
   282  		t.Fatalf("get unexpected update %+v", u)
   283  	case <-shortCtx.Done():
   284  	}
   285  
   286  	// Invoke callback, should get an update.
   287  	fakeClient.InvokeWatchEDSCallback(gotEDSName2, testEDSUpdates[1], nil)
   288  	select {
   289  	case u := <-rr.updateChannel:
   290  		if diff := cmp.Diff(u.priorities, []priorityConfig{{
   291  			mechanism: DiscoveryMechanism{
   292  				Type:    DiscoveryMechanismTypeEDS,
   293  				Cluster: testClusterName,
   294  			},
   295  			edsResp: testEDSUpdates[1],
   296  		}}, cmp.AllowUnexported(priorityConfig{})); diff != "" {
   297  			t.Fatalf("got unexpected resource update, diff (-got, +want): %v", diff)
   298  		}
   299  	case <-ctx.Done():
   300  		t.Fatal("Timed out waiting for update from update channel.")
   301  	}
   302  
   303  	// Change circuit breaking count, should get an update with new circuit
   304  	// breaking count, but shouldn't trigger new watch.
   305  	rr.updateMechanisms([]DiscoveryMechanism{{
   306  		Type:                  DiscoveryMechanismTypeEDS,
   307  		Cluster:               testClusterName,
   308  		MaxConcurrentRequests: newUint32(123),
   309  	}})
   310  	shortCtx, shortCancel = context.WithTimeout(context.Background(), defaultTestShortTimeout)
   311  	defer shortCancel()
   312  	if n, err := fakeClient.WaitForWatchEDS(shortCtx); err == nil {
   313  		t.Fatalf("unexpected watch started for EDS: %v", n)
   314  	}
   315  	select {
   316  	case u := <-rr.updateChannel:
   317  		if diff := cmp.Diff(u.priorities, []priorityConfig{{
   318  			mechanism: DiscoveryMechanism{
   319  				Type:                  DiscoveryMechanismTypeEDS,
   320  				Cluster:               testClusterName,
   321  				MaxConcurrentRequests: newUint32(123),
   322  			},
   323  			edsResp: testEDSUpdates[1],
   324  		}}, cmp.AllowUnexported(priorityConfig{})); diff != "" {
   325  			t.Fatalf("got unexpected resource update, diff (-got, +want): %v", diff)
   326  		}
   327  	case <-ctx.Done():
   328  		t.Fatal("Timed out waiting for update from update channel.")
   329  	}
   330  
   331  	// Close the resource resolver. Should stop EDS watch.
   332  	rr.stop()
   333  	edsNameCanceled, err := fakeClient.WaitForCancelEDSWatch(ctx)
   334  	if err != nil {
   335  		t.Fatalf("xdsClient.CancelCDS failed with error: %v", err)
   336  	}
   337  	if edsNameCanceled != gotEDSName2 {
   338  		t.Fatalf("xdsClient.CancelEDS called for %v, want: %v", edsNameCanceled, gotEDSName2)
   339  	}
   340  }
   341  
   342  // Test the case that same resources with the same priority should not add new
   343  // EDS watch, and also should not trigger an update.
   344  func (s) TestResourceResolverNoChangeNoUpdate(t *testing.T) {
   345  	fakeClient := fakeclient.NewClient()
   346  	rr := newResourceResolver(&clusterResolverBalancer{xdsClient: fakeClient})
   347  	rr.updateMechanisms([]DiscoveryMechanism{
   348  		{
   349  			Type:    DiscoveryMechanismTypeEDS,
   350  			Cluster: testClusterNames[0],
   351  		},
   352  		{
   353  			Type:                  DiscoveryMechanismTypeEDS,
   354  			Cluster:               testClusterNames[1],
   355  			MaxConcurrentRequests: newUint32(100),
   356  		},
   357  	})
   358  	ctx, ctxCancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   359  	defer ctxCancel()
   360  	gotEDSName1, err := fakeClient.WaitForWatchEDS(ctx)
   361  	if err != nil {
   362  		t.Fatalf("xdsClient.WatchCDS failed with error: %v", err)
   363  	}
   364  	if gotEDSName1 != testClusterNames[0] {
   365  		t.Fatalf("xdsClient.WatchEDS called for cluster: %v, want: %v", gotEDSName1, testClusterNames[0])
   366  	}
   367  	gotEDSName2, err := fakeClient.WaitForWatchEDS(ctx)
   368  	if err != nil {
   369  		t.Fatalf("xdsClient.WatchCDS failed with error: %v", err)
   370  	}
   371  	if gotEDSName2 != testClusterNames[1] {
   372  		t.Fatalf("xdsClient.WatchEDS called for cluster: %v, want: %v", gotEDSName2, testClusterNames[1])
   373  	}
   374  
   375  	// Invoke callback, should get an update.
   376  	fakeClient.InvokeWatchEDSCallback(gotEDSName1, testEDSUpdates[0], nil)
   377  	// Shouldn't send update, because only one resource received an update.
   378  	shortCtx, shortCancel := context.WithTimeout(context.Background(), defaultTestShortTimeout)
   379  	defer shortCancel()
   380  	select {
   381  	case u := <-rr.updateChannel:
   382  		t.Fatalf("get unexpected update %+v", u)
   383  	case <-shortCtx.Done():
   384  	}
   385  	fakeClient.InvokeWatchEDSCallback(gotEDSName2, testEDSUpdates[1], nil)
   386  	select {
   387  	case u := <-rr.updateChannel:
   388  		if diff := cmp.Diff(u.priorities, []priorityConfig{
   389  			{
   390  				mechanism: DiscoveryMechanism{
   391  					Type:    DiscoveryMechanismTypeEDS,
   392  					Cluster: testClusterNames[0],
   393  				},
   394  				edsResp: testEDSUpdates[0],
   395  			},
   396  			{
   397  				mechanism: DiscoveryMechanism{
   398  					Type:                  DiscoveryMechanismTypeEDS,
   399  					Cluster:               testClusterNames[1],
   400  					MaxConcurrentRequests: newUint32(100),
   401  				},
   402  				edsResp: testEDSUpdates[1],
   403  			},
   404  		}, cmp.AllowUnexported(priorityConfig{})); diff != "" {
   405  			t.Fatalf("got unexpected resource update, diff (-got, +want): %v", diff)
   406  		}
   407  	case <-ctx.Done():
   408  		t.Fatal("Timed out waiting for update from update channel.")
   409  	}
   410  
   411  	// Send the same resources with the same priorities, shouldn't any change.
   412  	rr.updateMechanisms([]DiscoveryMechanism{
   413  		{
   414  			Type:    DiscoveryMechanismTypeEDS,
   415  			Cluster: testClusterNames[0],
   416  		},
   417  		{
   418  			Type:                  DiscoveryMechanismTypeEDS,
   419  			Cluster:               testClusterNames[1],
   420  			MaxConcurrentRequests: newUint32(100),
   421  		},
   422  	})
   423  	shortCtx, shortCancel = context.WithTimeout(context.Background(), defaultTestShortTimeout)
   424  	defer shortCancel()
   425  	if n, err := fakeClient.WaitForWatchEDS(shortCtx); err == nil {
   426  		t.Fatalf("unexpected watch started for EDS: %v", n)
   427  	}
   428  	shortCtx, shortCancel = context.WithTimeout(context.Background(), defaultTestShortTimeout)
   429  	defer shortCancel()
   430  	select {
   431  	case u := <-rr.updateChannel:
   432  		t.Fatalf("unexpected update: %+v", u)
   433  	case <-shortCtx.Done():
   434  	}
   435  
   436  	// Close the resource resolver. Should stop EDS watch.
   437  	rr.stop()
   438  	edsNameCanceled1, err := fakeClient.WaitForCancelEDSWatch(ctx)
   439  	if err != nil {
   440  		t.Fatalf("xdsClient.CancelCDS failed with error: %v", err)
   441  	}
   442  	if edsNameCanceled1 != gotEDSName1 && edsNameCanceled1 != gotEDSName2 {
   443  		t.Fatalf("xdsClient.CancelEDS called for %v, want: %v or %v", edsNameCanceled1, gotEDSName1, gotEDSName2)
   444  	}
   445  	edsNameCanceled2, err := fakeClient.WaitForCancelEDSWatch(ctx)
   446  	if err != nil {
   447  		t.Fatalf("xdsClient.CancelCDS failed with error: %v", err)
   448  	}
   449  	if edsNameCanceled2 != gotEDSName2 && edsNameCanceled2 != gotEDSName1 {
   450  		t.Fatalf("xdsClient.CancelEDS called for %v, want: %v or %v", edsNameCanceled2, gotEDSName1, gotEDSName2)
   451  	}
   452  }
   453  
   454  // Test the case that same resources are watched, but with different priority.
   455  // Should not add new EDS watch, but should trigger an update with the new
   456  // priorities.
   457  func (s) TestResourceResolverChangePriority(t *testing.T) {
   458  	fakeClient := fakeclient.NewClient()
   459  	rr := newResourceResolver(&clusterResolverBalancer{xdsClient: fakeClient})
   460  	rr.updateMechanisms([]DiscoveryMechanism{
   461  		{
   462  			Type:    DiscoveryMechanismTypeEDS,
   463  			Cluster: testClusterNames[0],
   464  		},
   465  		{
   466  			Type:    DiscoveryMechanismTypeEDS,
   467  			Cluster: testClusterNames[1],
   468  		},
   469  	})
   470  	ctx, ctxCancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   471  	defer ctxCancel()
   472  	gotEDSName1, err := fakeClient.WaitForWatchEDS(ctx)
   473  	if err != nil {
   474  		t.Fatalf("xdsClient.WatchCDS failed with error: %v", err)
   475  	}
   476  	if gotEDSName1 != testClusterNames[0] {
   477  		t.Fatalf("xdsClient.WatchEDS called for cluster: %v, want: %v", gotEDSName1, testClusterNames[0])
   478  	}
   479  	gotEDSName2, err := fakeClient.WaitForWatchEDS(ctx)
   480  	if err != nil {
   481  		t.Fatalf("xdsClient.WatchCDS failed with error: %v", err)
   482  	}
   483  	if gotEDSName2 != testClusterNames[1] {
   484  		t.Fatalf("xdsClient.WatchEDS called for cluster: %v, want: %v", gotEDSName2, testClusterNames[1])
   485  	}
   486  
   487  	// Invoke callback, should get an update.
   488  	fakeClient.InvokeWatchEDSCallback(gotEDSName1, testEDSUpdates[0], nil)
   489  	// Shouldn't send update, because only one resource received an update.
   490  	shortCtx, shortCancel := context.WithTimeout(context.Background(), defaultTestShortTimeout)
   491  	defer shortCancel()
   492  	select {
   493  	case u := <-rr.updateChannel:
   494  		t.Fatalf("get unexpected update %+v", u)
   495  	case <-shortCtx.Done():
   496  	}
   497  	fakeClient.InvokeWatchEDSCallback(gotEDSName2, testEDSUpdates[1], nil)
   498  	select {
   499  	case u := <-rr.updateChannel:
   500  		if diff := cmp.Diff(u.priorities, []priorityConfig{
   501  			{
   502  				mechanism: DiscoveryMechanism{
   503  					Type:    DiscoveryMechanismTypeEDS,
   504  					Cluster: testClusterNames[0],
   505  				},
   506  				edsResp: testEDSUpdates[0],
   507  			},
   508  			{
   509  				mechanism: DiscoveryMechanism{
   510  					Type:    DiscoveryMechanismTypeEDS,
   511  					Cluster: testClusterNames[1],
   512  				},
   513  				edsResp: testEDSUpdates[1],
   514  			},
   515  		}, cmp.AllowUnexported(priorityConfig{})); diff != "" {
   516  			t.Fatalf("got unexpected resource update, diff (-got, +want): %v", diff)
   517  		}
   518  	case <-ctx.Done():
   519  		t.Fatal("Timed out waiting for update from update channel.")
   520  	}
   521  
   522  	// Send the same resources with different priorities, shouldn't trigger
   523  	// watch, but should trigger an update with the new priorities.
   524  	rr.updateMechanisms([]DiscoveryMechanism{
   525  		{
   526  			Type:    DiscoveryMechanismTypeEDS,
   527  			Cluster: testClusterNames[1],
   528  		},
   529  		{
   530  			Type:    DiscoveryMechanismTypeEDS,
   531  			Cluster: testClusterNames[0],
   532  		},
   533  	})
   534  	shortCtx, shortCancel = context.WithTimeout(context.Background(), defaultTestShortTimeout)
   535  	defer shortCancel()
   536  	if n, err := fakeClient.WaitForWatchEDS(shortCtx); err == nil {
   537  		t.Fatalf("unexpected watch started for EDS: %v", n)
   538  	}
   539  	select {
   540  	case u := <-rr.updateChannel:
   541  		if diff := cmp.Diff(u.priorities, []priorityConfig{
   542  			{
   543  				mechanism: DiscoveryMechanism{
   544  					Type:    DiscoveryMechanismTypeEDS,
   545  					Cluster: testClusterNames[1],
   546  				},
   547  				edsResp: testEDSUpdates[1],
   548  			},
   549  			{
   550  				mechanism: DiscoveryMechanism{
   551  					Type:    DiscoveryMechanismTypeEDS,
   552  					Cluster: testClusterNames[0],
   553  				},
   554  				edsResp: testEDSUpdates[0],
   555  			},
   556  		}, cmp.AllowUnexported(priorityConfig{})); diff != "" {
   557  			t.Fatalf("got unexpected resource update, diff (-got, +want): %v", diff)
   558  		}
   559  	case <-ctx.Done():
   560  		t.Fatal("Timed out waiting for update from update channel.")
   561  	}
   562  
   563  	// Close the resource resolver. Should stop EDS watch.
   564  	rr.stop()
   565  	edsNameCanceled1, err := fakeClient.WaitForCancelEDSWatch(ctx)
   566  	if err != nil {
   567  		t.Fatalf("xdsClient.CancelCDS failed with error: %v", err)
   568  	}
   569  	if edsNameCanceled1 != gotEDSName1 && edsNameCanceled1 != gotEDSName2 {
   570  		t.Fatalf("xdsClient.CancelEDS called for %v, want: %v or %v", edsNameCanceled1, gotEDSName1, gotEDSName2)
   571  	}
   572  	edsNameCanceled2, err := fakeClient.WaitForCancelEDSWatch(ctx)
   573  	if err != nil {
   574  		t.Fatalf("xdsClient.CancelCDS failed with error: %v", err)
   575  	}
   576  	if edsNameCanceled2 != gotEDSName2 && edsNameCanceled2 != gotEDSName1 {
   577  		t.Fatalf("xdsClient.CancelEDS called for %v, want: %v or %v", edsNameCanceled2, gotEDSName1, gotEDSName2)
   578  	}
   579  }
   580  
   581  // Test the case that covers resource for both EDS and DNS.
   582  func (s) TestResourceResolverEDSAndDNS(t *testing.T) {
   583  	dnsTargetCh, dnsCloseCh, _, dnsR, cleanup := setupDNS()
   584  	defer cleanup()
   585  	fakeClient := fakeclient.NewClient()
   586  	rr := newResourceResolver(&clusterResolverBalancer{xdsClient: fakeClient})
   587  	rr.updateMechanisms([]DiscoveryMechanism{
   588  		{
   589  			Type:    DiscoveryMechanismTypeEDS,
   590  			Cluster: testClusterName,
   591  		},
   592  		{
   593  			Type:        DiscoveryMechanismTypeLogicalDNS,
   594  			DNSHostname: testDNSTarget,
   595  		},
   596  	})
   597  	ctx, ctxCancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   598  	defer ctxCancel()
   599  	gotEDSName1, err := fakeClient.WaitForWatchEDS(ctx)
   600  	if err != nil {
   601  		t.Fatalf("xdsClient.WatchCDS failed with error: %v", err)
   602  	}
   603  	if gotEDSName1 != testClusterName {
   604  		t.Fatalf("xdsClient.WatchEDS called for cluster: %v, want: %v", gotEDSName1, testClusterName)
   605  	}
   606  	select {
   607  	case target := <-dnsTargetCh:
   608  		// Target.Scheme、Target.Endpoint are deprecated, use URL.Scheme、URL.Path instead.
   609  		//if diff := cmp.Diff(target, resolver.Target{Scheme: "dns", Endpoint: testDNSTarget}); diff != "" {
   610  		if diff := cmp.Diff(target, resolver.Target{URL: url.URL{Scheme: "dns", Path: testDNSTarget}}); diff != "" {
   611  			t.Fatalf("got unexpected DNS target to watch, diff (-got, +want): %v", diff)
   612  		}
   613  	case <-ctx.Done():
   614  		t.Fatal("Timed out waiting for building DNS resolver")
   615  	}
   616  
   617  	fakeClient.InvokeWatchEDSCallback(gotEDSName1, testEDSUpdates[0], nil)
   618  	// Shouldn't send update, because only one resource received an update.
   619  	shortCtx, shortCancel := context.WithTimeout(context.Background(), defaultTestShortTimeout)
   620  	defer shortCancel()
   621  	select {
   622  	case u := <-rr.updateChannel:
   623  		t.Fatalf("get unexpected update %+v", u)
   624  	case <-shortCtx.Done():
   625  	}
   626  	// Invoke DNS, should get an update.
   627  	dnsR.UpdateState(resolver.State{Addresses: []resolver.Address{{Addr: "1.1.1.1"}, {Addr: "2.2.2.2"}}})
   628  	select {
   629  	case u := <-rr.updateChannel:
   630  		if diff := cmp.Diff(u.priorities, []priorityConfig{
   631  			{
   632  				mechanism: DiscoveryMechanism{
   633  					Type:    DiscoveryMechanismTypeEDS,
   634  					Cluster: testClusterName,
   635  				},
   636  				edsResp: testEDSUpdates[0],
   637  			},
   638  			{
   639  				mechanism: DiscoveryMechanism{
   640  					Type:        DiscoveryMechanismTypeLogicalDNS,
   641  					DNSHostname: testDNSTarget,
   642  				},
   643  				addresses: []string{"1.1.1.1", "2.2.2.2"},
   644  			},
   645  		}, cmp.AllowUnexported(priorityConfig{})); diff != "" {
   646  			t.Fatalf("got unexpected resource update, diff (-got, +want): %v", diff)
   647  		}
   648  	case <-ctx.Done():
   649  		t.Fatal("Timed out waiting for update from update channel.")
   650  	}
   651  
   652  	// Close the resource resolver. Should stop EDS watch.
   653  	rr.stop()
   654  	edsNameCanceled1, err := fakeClient.WaitForCancelEDSWatch(ctx)
   655  	if err != nil {
   656  		t.Fatalf("xdsClient.CancelCDS failed with error: %v", err)
   657  	}
   658  	if edsNameCanceled1 != gotEDSName1 {
   659  		t.Fatalf("xdsClient.CancelEDS called for %v, want: %v", edsNameCanceled1, gotEDSName1)
   660  	}
   661  	select {
   662  	case <-dnsCloseCh:
   663  	case <-ctx.Done():
   664  		t.Fatal("Timed out waiting for closing DNS resolver")
   665  	}
   666  }
   667  
   668  // Test the case that covers resource changing between EDS and DNS.
   669  func (s) TestResourceResolverChangeFromEDSToDNS(t *testing.T) {
   670  	dnsTargetCh, dnsCloseCh, _, dnsR, cleanup := setupDNS()
   671  	defer cleanup()
   672  	fakeClient := fakeclient.NewClient()
   673  	rr := newResourceResolver(&clusterResolverBalancer{xdsClient: fakeClient})
   674  	rr.updateMechanisms([]DiscoveryMechanism{{
   675  		Type:    DiscoveryMechanismTypeEDS,
   676  		Cluster: testClusterName,
   677  	}})
   678  	ctx, ctxCancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   679  	defer ctxCancel()
   680  	gotEDSName1, err := fakeClient.WaitForWatchEDS(ctx)
   681  	if err != nil {
   682  		t.Fatalf("xdsClient.WatchCDS failed with error: %v", err)
   683  	}
   684  	if gotEDSName1 != testClusterName {
   685  		t.Fatalf("xdsClient.WatchEDS called for cluster: %v, want: %v", gotEDSName1, testClusterName)
   686  	}
   687  
   688  	// Invoke callback, should get an update.
   689  	fakeClient.InvokeWatchEDSCallback(gotEDSName1, testEDSUpdates[0], nil)
   690  	select {
   691  	case u := <-rr.updateChannel:
   692  		if diff := cmp.Diff(u.priorities, []priorityConfig{{
   693  			mechanism: DiscoveryMechanism{
   694  				Type:    DiscoveryMechanismTypeEDS,
   695  				Cluster: testClusterName,
   696  			},
   697  			edsResp: testEDSUpdates[0],
   698  		}}, cmp.AllowUnexported(priorityConfig{})); diff != "" {
   699  			t.Fatalf("got unexpected resource update, diff (-got, +want): %v", diff)
   700  		}
   701  	case <-ctx.Done():
   702  		t.Fatal("Timed out waiting for update from update channel.")
   703  	}
   704  
   705  	// Update to watch DNS instead. Should cancel EDS, and start DNS.
   706  	rr.updateMechanisms([]DiscoveryMechanism{{
   707  		Type:        DiscoveryMechanismTypeLogicalDNS,
   708  		DNSHostname: testDNSTarget,
   709  	}})
   710  	select {
   711  	case target := <-dnsTargetCh:
   712  		// Target.Scheme、Target.Endpoint are deprecated, use URL.Scheme、URL.Path instead.
   713  		//if diff := cmp.Diff(target, resolver.Target{Scheme: "dns", Endpoint: testDNSTarget}); diff != "" {
   714  		if diff := cmp.Diff(target, resolver.Target{URL: url.URL{Scheme: "dns", Path: testDNSTarget}}); diff != "" {
   715  			t.Fatalf("got unexpected DNS target to watch, diff (-got, +want): %v", diff)
   716  		}
   717  	case <-ctx.Done():
   718  		t.Fatal("Timed out waiting for building DNS resolver")
   719  	}
   720  	edsNameCanceled1, err := fakeClient.WaitForCancelEDSWatch(ctx)
   721  	if err != nil {
   722  		t.Fatalf("xdsClient.CancelCDS failed with error: %v", err)
   723  	}
   724  	if edsNameCanceled1 != gotEDSName1 {
   725  		t.Fatalf("xdsClient.CancelEDS called for %v, want: %v", edsNameCanceled1, gotEDSName1)
   726  	}
   727  
   728  	dnsR.UpdateState(resolver.State{Addresses: []resolver.Address{{Addr: "1.1.1.1"}, {Addr: "2.2.2.2"}}})
   729  	select {
   730  	case u := <-rr.updateChannel:
   731  		if diff := cmp.Diff(u.priorities, []priorityConfig{{
   732  			mechanism: DiscoveryMechanism{
   733  				Type:        DiscoveryMechanismTypeLogicalDNS,
   734  				DNSHostname: testDNSTarget,
   735  			},
   736  			addresses: []string{"1.1.1.1", "2.2.2.2"},
   737  		}}, cmp.AllowUnexported(priorityConfig{})); diff != "" {
   738  			t.Fatalf("got unexpected resource update, diff (-got, +want): %v", diff)
   739  		}
   740  	case <-ctx.Done():
   741  		t.Fatal("Timed out waiting for update from update channel.")
   742  	}
   743  
   744  	// Close the resource resolver. Should stop DNS.
   745  	rr.stop()
   746  	select {
   747  	case <-dnsCloseCh:
   748  	case <-ctx.Done():
   749  		t.Fatal("Timed out waiting for closing DNS resolver")
   750  	}
   751  }
   752  
   753  // Test the case that covers errors for both EDS and DNS.
   754  func (s) TestResourceResolverError(t *testing.T) {
   755  	dnsTargetCh, dnsCloseCh, _, dnsR, cleanup := setupDNS()
   756  	defer cleanup()
   757  	fakeClient := fakeclient.NewClient()
   758  	rr := newResourceResolver(&clusterResolverBalancer{xdsClient: fakeClient})
   759  	rr.updateMechanisms([]DiscoveryMechanism{
   760  		{
   761  			Type:    DiscoveryMechanismTypeEDS,
   762  			Cluster: testClusterName,
   763  		},
   764  		{
   765  			Type:        DiscoveryMechanismTypeLogicalDNS,
   766  			DNSHostname: testDNSTarget,
   767  		},
   768  	})
   769  	ctx, ctxCancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   770  	defer ctxCancel()
   771  	gotEDSName1, err := fakeClient.WaitForWatchEDS(ctx)
   772  	if err != nil {
   773  		t.Fatalf("xdsClient.WatchCDS failed with error: %v", err)
   774  	}
   775  	if gotEDSName1 != testClusterName {
   776  		t.Fatalf("xdsClient.WatchEDS called for cluster: %v, want: %v", gotEDSName1, testClusterName)
   777  	}
   778  	select {
   779  	case target := <-dnsTargetCh:
   780  		// Target.Scheme、Target.Endpoint are deprecated, use URL.Scheme、URL.Path instead.
   781  		//if diff := cmp.Diff(target, resolver.Target{Scheme: "dns", Endpoint: testDNSTarget}); diff != "" {
   782  		if diff := cmp.Diff(target, resolver.Target{URL: url.URL{Scheme: "dns", Path: testDNSTarget}}); diff != "" {
   783  			t.Fatalf("got unexpected DNS target to watch, diff (-got, +want): %v", diff)
   784  		}
   785  	case <-ctx.Done():
   786  		t.Fatal("Timed out waiting for building DNS resolver")
   787  	}
   788  
   789  	// Invoke callback with an error, should get an update.
   790  	edsErr := fmt.Errorf("EDS error")
   791  	fakeClient.InvokeWatchEDSCallback(gotEDSName1, xdsresource.EndpointsUpdate{}, edsErr)
   792  	select {
   793  	case u := <-rr.updateChannel:
   794  		if u.err != edsErr {
   795  			t.Fatalf("got unexpected error from update, want %v, got %v", edsErr, u.err)
   796  		}
   797  	case <-ctx.Done():
   798  		t.Fatal("Timed out waiting for update from update channel.")
   799  	}
   800  
   801  	// Invoke DNS with an error, should get an update.
   802  	dnsErr := fmt.Errorf("DNS error")
   803  	dnsR.ReportError(dnsErr)
   804  	select {
   805  	case u := <-rr.updateChannel:
   806  		if u.err != dnsErr {
   807  			t.Fatalf("got unexpected error from update, want %v, got %v", dnsErr, u.err)
   808  		}
   809  	case <-ctx.Done():
   810  		t.Fatal("Timed out waiting for update from update channel.")
   811  	}
   812  
   813  	// Close the resource resolver. Should stop EDS watch.
   814  	rr.stop()
   815  	edsNameCanceled1, err := fakeClient.WaitForCancelEDSWatch(ctx)
   816  	if err != nil {
   817  		t.Fatalf("xdsClient.CancelCDS failed with error: %v", err)
   818  	}
   819  	if edsNameCanceled1 != gotEDSName1 {
   820  		t.Fatalf("xdsClient.CancelEDS called for %v, want: %v", edsNameCanceled1, gotEDSName1)
   821  	}
   822  	select {
   823  	case <-dnsCloseCh:
   824  	case <-ctx.Done():
   825  		t.Fatal("Timed out waiting for closing DNS resolver")
   826  	}
   827  }
   828  
   829  // Test re-resolve of the DNS resolver.
   830  func (s) TestResourceResolverDNSResolveNow(t *testing.T) {
   831  	dnsTargetCh, dnsCloseCh, resolveNowCh, dnsR, cleanup := setupDNS()
   832  	defer cleanup()
   833  	fakeClient := fakeclient.NewClient()
   834  	rr := newResourceResolver(&clusterResolverBalancer{xdsClient: fakeClient})
   835  	rr.updateMechanisms([]DiscoveryMechanism{{
   836  		Type:        DiscoveryMechanismTypeLogicalDNS,
   837  		DNSHostname: testDNSTarget,
   838  	}})
   839  	ctx, ctxCancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   840  	defer ctxCancel()
   841  	select {
   842  	case target := <-dnsTargetCh:
   843  		// Target.Scheme、Target.Endpoint are deprecated, use URL.Scheme、URL.Path instead.
   844  		//if diff := cmp.Diff(target, resolver.Target{Scheme: "dns", Endpoint: testDNSTarget}); diff != "" {
   845  		if diff := cmp.Diff(target, resolver.Target{URL: url.URL{Scheme: "dns", Path: testDNSTarget}}); diff != "" {
   846  			t.Fatalf("got unexpected DNS target to watch, diff (-got, +want): %v", diff)
   847  		}
   848  	case <-ctx.Done():
   849  		t.Fatal("Timed out waiting for building DNS resolver")
   850  	}
   851  
   852  	// Invoke callback, should get an update.
   853  	dnsR.UpdateState(resolver.State{Addresses: []resolver.Address{{Addr: "1.1.1.1"}, {Addr: "2.2.2.2"}}})
   854  	select {
   855  	case u := <-rr.updateChannel:
   856  		if diff := cmp.Diff(u.priorities, []priorityConfig{{
   857  			mechanism: DiscoveryMechanism{
   858  				Type:        DiscoveryMechanismTypeLogicalDNS,
   859  				DNSHostname: testDNSTarget,
   860  			},
   861  			addresses: []string{"1.1.1.1", "2.2.2.2"},
   862  		}}, cmp.AllowUnexported(priorityConfig{})); diff != "" {
   863  			t.Fatalf("got unexpected resource update, diff (-got, +want): %v", diff)
   864  		}
   865  	case <-ctx.Done():
   866  		t.Fatal("Timed out waiting for update from update channel.")
   867  	}
   868  	rr.resolveNow()
   869  	select {
   870  	case <-resolveNowCh:
   871  	case <-ctx.Done():
   872  		t.Fatal("Timed out waiting for re-resolve")
   873  	}
   874  	// Close the resource resolver. Should close the underlying resolver.
   875  	rr.stop()
   876  	select {
   877  	case <-dnsCloseCh:
   878  	case <-ctx.Done():
   879  		t.Fatal("Timed out waiting for closing DNS resolver")
   880  	}
   881  }