github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/grpc/xds/internal/xdsclient/dump_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 xdsclient
    20  
    21  import (
    22  	"fmt"
    23  	"testing"
    24  	"time"
    25  
    26  	"github.com/google/go-cmp/cmp"
    27  	"github.com/google/go-cmp/cmp/cmpopts"
    28  	v3clusterpb "github.com/hxx258456/ccgo/go-control-plane/envoy/config/cluster/v3"
    29  	v3corepb "github.com/hxx258456/ccgo/go-control-plane/envoy/config/core/v3"
    30  	v3listenerpb "github.com/hxx258456/ccgo/go-control-plane/envoy/config/listener/v3"
    31  	v3routepb "github.com/hxx258456/ccgo/go-control-plane/envoy/config/route/v3"
    32  	v3httppb "github.com/hxx258456/ccgo/go-control-plane/envoy/extensions/filters/network/http_connection_manager/v3"
    33  	grpc "github.com/hxx258456/ccgo/grpc"
    34  	"github.com/hxx258456/ccgo/grpc/xds/internal/xdsclient/xdsresource"
    35  	"google.golang.org/protobuf/testing/protocmp"
    36  	"google.golang.org/protobuf/types/known/anypb"
    37  	"google.golang.org/protobuf/types/known/durationpb"
    38  
    39  	"github.com/hxx258456/ccgo/grpc/credentials/insecure"
    40  	"github.com/hxx258456/ccgo/grpc/internal/testutils"
    41  	xdstestutils "github.com/hxx258456/ccgo/grpc/xds/internal/testutils"
    42  	"github.com/hxx258456/ccgo/grpc/xds/internal/xdsclient/bootstrap"
    43  )
    44  
    45  func (s) TestLDSConfigDump(t *testing.T) {
    46  	const testVersion = "test-version-lds"
    47  	var (
    48  		ldsTargets       = []string{"lds.target.good:0000", "lds.target.good:1111"}
    49  		routeConfigNames = []string{"route-config-0", "route-config-1"}
    50  		listenerRaws     = make(map[string]*anypb.Any, len(ldsTargets))
    51  	)
    52  
    53  	for i := range ldsTargets {
    54  		listenersT := &v3listenerpb.Listener{
    55  			Name: ldsTargets[i],
    56  			ApiListener: &v3listenerpb.ApiListener{
    57  				ApiListener: testutils.MarshalAny(&v3httppb.HttpConnectionManager{
    58  					RouteSpecifier: &v3httppb.HttpConnectionManager_Rds{
    59  						Rds: &v3httppb.Rds{
    60  							ConfigSource: &v3corepb.ConfigSource{
    61  								ConfigSourceSpecifier: &v3corepb.ConfigSource_Ads{Ads: &v3corepb.AggregatedConfigSource{}},
    62  							},
    63  							RouteConfigName: routeConfigNames[i],
    64  						},
    65  					},
    66  					CommonHttpProtocolOptions: &v3corepb.HttpProtocolOptions{
    67  						MaxStreamDuration: durationpb.New(time.Second),
    68  					},
    69  				}),
    70  			},
    71  		}
    72  		listenerRaws[ldsTargets[i]] = testutils.MarshalAny(listenersT)
    73  	}
    74  
    75  	client, err := NewWithConfigForTesting(&bootstrap.Config{
    76  		XDSServer: &bootstrap.ServerConfig{
    77  			ServerURI: testXDSServer,
    78  			Creds:     grpc.WithTransportCredentials(insecure.NewCredentials()),
    79  			NodeProto: xdstestutils.EmptyNodeProtoV2,
    80  		},
    81  	}, defaultTestWatchExpiryTimeout)
    82  	if err != nil {
    83  		t.Fatalf("failed to create client: %v", err)
    84  	}
    85  	defer client.Close()
    86  
    87  	// Expected unknown.
    88  	if err := compareDump(client.DumpLDS, map[string]xdsresource.UpdateWithMD{}); err != nil {
    89  		t.Fatalf(err.Error())
    90  	}
    91  
    92  	wantRequested := make(map[string]xdsresource.UpdateWithMD)
    93  	for _, n := range ldsTargets {
    94  		cancel := client.WatchListener(n, func(update xdsresource.ListenerUpdate, err error) {})
    95  		defer cancel()
    96  		wantRequested[n] = xdsresource.UpdateWithMD{MD: xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusRequested}}
    97  	}
    98  	// Expected requested.
    99  	if err := compareDump(client.DumpLDS, wantRequested); err != nil {
   100  		t.Fatalf(err.Error())
   101  	}
   102  
   103  	update0 := make(map[string]xdsresource.ListenerUpdateErrTuple)
   104  	want0 := make(map[string]xdsresource.UpdateWithMD)
   105  	for n, r := range listenerRaws {
   106  		update0[n] = xdsresource.ListenerUpdateErrTuple{Update: xdsresource.ListenerUpdate{Raw: r}}
   107  		want0[n] = xdsresource.UpdateWithMD{
   108  			MD:  xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusACKed, Version: testVersion},
   109  			Raw: r,
   110  		}
   111  	}
   112  	updateHandler := findPubsubForTest(t, client.(*clientRefCounted).clientImpl, "")
   113  	updateHandler.NewListeners(update0, xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusACKed, Version: testVersion})
   114  
   115  	// Expect ACK.
   116  	if err := compareDump(client.DumpLDS, want0); err != nil {
   117  		t.Fatalf(err.Error())
   118  	}
   119  
   120  	const nackVersion = "lds-version-nack"
   121  	var nackErr = fmt.Errorf("lds nack error")
   122  	updateHandler.NewListeners(
   123  		map[string]xdsresource.ListenerUpdateErrTuple{
   124  			ldsTargets[0]: {Err: nackErr},
   125  			ldsTargets[1]: {Update: xdsresource.ListenerUpdate{Raw: listenerRaws[ldsTargets[1]]}},
   126  		},
   127  		xdsresource.UpdateMetadata{
   128  			Status: xdsresource.ServiceStatusNACKed,
   129  			ErrState: &xdsresource.UpdateErrorMetadata{
   130  				Version: nackVersion,
   131  				Err:     nackErr,
   132  			},
   133  		},
   134  	)
   135  
   136  	// Expect NACK for [0], but old ACK for [1].
   137  	wantDump := make(map[string]xdsresource.UpdateWithMD)
   138  	// Though resource 0 was NACKed, the dump should show the previous ACKed raw
   139  	// message, as well as the NACK error.
   140  	wantDump[ldsTargets[0]] = xdsresource.UpdateWithMD{
   141  		MD: xdsresource.UpdateMetadata{
   142  			Status:  xdsresource.ServiceStatusNACKed,
   143  			Version: testVersion,
   144  			ErrState: &xdsresource.UpdateErrorMetadata{
   145  				Version: nackVersion,
   146  				Err:     nackErr,
   147  			},
   148  		},
   149  		Raw: listenerRaws[ldsTargets[0]],
   150  	}
   151  
   152  	wantDump[ldsTargets[1]] = xdsresource.UpdateWithMD{
   153  		MD:  xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusACKed, Version: nackVersion},
   154  		Raw: listenerRaws[ldsTargets[1]],
   155  	}
   156  	if err := compareDump(client.DumpLDS, wantDump); err != nil {
   157  		t.Fatalf(err.Error())
   158  	}
   159  }
   160  
   161  func (s) TestRDSConfigDump(t *testing.T) {
   162  	const testVersion = "test-version-rds"
   163  	var (
   164  		listenerNames = []string{"lds.target.good:0000", "lds.target.good:1111"}
   165  		rdsTargets    = []string{"route-config-0", "route-config-1"}
   166  		clusterNames  = []string{"cluster-0", "cluster-1"}
   167  		routeRaws     = make(map[string]*anypb.Any, len(rdsTargets))
   168  	)
   169  
   170  	for i := range rdsTargets {
   171  		routeConfigT := &v3routepb.RouteConfiguration{
   172  			Name: rdsTargets[i],
   173  			VirtualHosts: []*v3routepb.VirtualHost{
   174  				{
   175  					Domains: []string{listenerNames[i]},
   176  					Routes: []*v3routepb.Route{{
   177  						Match: &v3routepb.RouteMatch{PathSpecifier: &v3routepb.RouteMatch_Prefix{Prefix: ""}},
   178  						Action: &v3routepb.Route_Route{
   179  							Route: &v3routepb.RouteAction{
   180  								ClusterSpecifier: &v3routepb.RouteAction_Cluster{Cluster: clusterNames[i]},
   181  							},
   182  						},
   183  					}},
   184  				},
   185  			},
   186  		}
   187  
   188  		routeRaws[rdsTargets[i]] = testutils.MarshalAny(routeConfigT)
   189  	}
   190  
   191  	client, err := NewWithConfigForTesting(&bootstrap.Config{
   192  		XDSServer: &bootstrap.ServerConfig{
   193  			ServerURI: testXDSServer,
   194  			Creds:     grpc.WithTransportCredentials(insecure.NewCredentials()),
   195  			NodeProto: xdstestutils.EmptyNodeProtoV2,
   196  		},
   197  	}, defaultTestWatchExpiryTimeout)
   198  	if err != nil {
   199  		t.Fatalf("failed to create client: %v", err)
   200  	}
   201  	defer client.Close()
   202  
   203  	// Expected unknown.
   204  	if err := compareDump(client.DumpRDS, map[string]xdsresource.UpdateWithMD{}); err != nil {
   205  		t.Fatalf(err.Error())
   206  	}
   207  
   208  	wantRequested := make(map[string]xdsresource.UpdateWithMD)
   209  	for _, n := range rdsTargets {
   210  		cancel := client.WatchRouteConfig(n, func(update xdsresource.RouteConfigUpdate, err error) {})
   211  		defer cancel()
   212  		wantRequested[n] = xdsresource.UpdateWithMD{MD: xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusRequested}}
   213  	}
   214  	// Expected requested.
   215  	if err := compareDump(client.DumpRDS, wantRequested); err != nil {
   216  		t.Fatalf(err.Error())
   217  	}
   218  
   219  	update0 := make(map[string]xdsresource.RouteConfigUpdateErrTuple)
   220  	want0 := make(map[string]xdsresource.UpdateWithMD)
   221  	for n, r := range routeRaws {
   222  		update0[n] = xdsresource.RouteConfigUpdateErrTuple{Update: xdsresource.RouteConfigUpdate{Raw: r}}
   223  		want0[n] = xdsresource.UpdateWithMD{
   224  			MD:  xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusACKed, Version: testVersion},
   225  			Raw: r,
   226  		}
   227  	}
   228  	updateHandler := findPubsubForTest(t, client.(*clientRefCounted).clientImpl, "")
   229  	updateHandler.NewRouteConfigs(update0, xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusACKed, Version: testVersion})
   230  
   231  	// Expect ACK.
   232  	if err := compareDump(client.DumpRDS, want0); err != nil {
   233  		t.Fatalf(err.Error())
   234  	}
   235  
   236  	const nackVersion = "rds-version-nack"
   237  	var nackErr = fmt.Errorf("rds nack error")
   238  	updateHandler.NewRouteConfigs(
   239  		map[string]xdsresource.RouteConfigUpdateErrTuple{
   240  			rdsTargets[0]: {Err: nackErr},
   241  			rdsTargets[1]: {Update: xdsresource.RouteConfigUpdate{Raw: routeRaws[rdsTargets[1]]}},
   242  		},
   243  		xdsresource.UpdateMetadata{
   244  			Status: xdsresource.ServiceStatusNACKed,
   245  			ErrState: &xdsresource.UpdateErrorMetadata{
   246  				Version: nackVersion,
   247  				Err:     nackErr,
   248  			},
   249  		},
   250  	)
   251  
   252  	// Expect NACK for [0], but old ACK for [1].
   253  	wantDump := make(map[string]xdsresource.UpdateWithMD)
   254  	// Though resource 0 was NACKed, the dump should show the previous ACKed raw
   255  	// message, as well as the NACK error.
   256  	wantDump[rdsTargets[0]] = xdsresource.UpdateWithMD{
   257  		MD: xdsresource.UpdateMetadata{
   258  			Status:  xdsresource.ServiceStatusNACKed,
   259  			Version: testVersion,
   260  			ErrState: &xdsresource.UpdateErrorMetadata{
   261  				Version: nackVersion,
   262  				Err:     nackErr,
   263  			},
   264  		},
   265  		Raw: routeRaws[rdsTargets[0]],
   266  	}
   267  	wantDump[rdsTargets[1]] = xdsresource.UpdateWithMD{
   268  		MD:  xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusACKed, Version: nackVersion},
   269  		Raw: routeRaws[rdsTargets[1]],
   270  	}
   271  	if err := compareDump(client.DumpRDS, wantDump); err != nil {
   272  		t.Fatalf(err.Error())
   273  	}
   274  }
   275  
   276  func (s) TestCDSConfigDump(t *testing.T) {
   277  	const testVersion = "test-version-cds"
   278  	var (
   279  		cdsTargets   = []string{"cluster-0", "cluster-1"}
   280  		serviceNames = []string{"service-0", "service-1"}
   281  		clusterRaws  = make(map[string]*anypb.Any, len(cdsTargets))
   282  	)
   283  
   284  	for i := range cdsTargets {
   285  		clusterT := &v3clusterpb.Cluster{
   286  			Name:                 cdsTargets[i],
   287  			ClusterDiscoveryType: &v3clusterpb.Cluster_Type{Type: v3clusterpb.Cluster_EDS},
   288  			EdsClusterConfig: &v3clusterpb.Cluster_EdsClusterConfig{
   289  				EdsConfig: &v3corepb.ConfigSource{
   290  					ConfigSourceSpecifier: &v3corepb.ConfigSource_Ads{
   291  						Ads: &v3corepb.AggregatedConfigSource{},
   292  					},
   293  				},
   294  				ServiceName: serviceNames[i],
   295  			},
   296  			LbPolicy: v3clusterpb.Cluster_ROUND_ROBIN,
   297  			LrsServer: &v3corepb.ConfigSource{
   298  				ConfigSourceSpecifier: &v3corepb.ConfigSource_Self{
   299  					Self: &v3corepb.SelfConfigSource{},
   300  				},
   301  			},
   302  		}
   303  
   304  		clusterRaws[cdsTargets[i]] = testutils.MarshalAny(clusterT)
   305  	}
   306  
   307  	client, err := NewWithConfigForTesting(&bootstrap.Config{
   308  		XDSServer: &bootstrap.ServerConfig{
   309  			ServerURI: testXDSServer,
   310  			Creds:     grpc.WithTransportCredentials(insecure.NewCredentials()),
   311  			NodeProto: xdstestutils.EmptyNodeProtoV2,
   312  		},
   313  	}, defaultTestWatchExpiryTimeout)
   314  	if err != nil {
   315  		t.Fatalf("failed to create client: %v", err)
   316  	}
   317  	defer client.Close()
   318  
   319  	// Expected unknown.
   320  	if err := compareDump(client.DumpCDS, map[string]xdsresource.UpdateWithMD{}); err != nil {
   321  		t.Fatalf(err.Error())
   322  	}
   323  
   324  	wantRequested := make(map[string]xdsresource.UpdateWithMD)
   325  	for _, n := range cdsTargets {
   326  		cancel := client.WatchCluster(n, func(update xdsresource.ClusterUpdate, err error) {})
   327  		defer cancel()
   328  		wantRequested[n] = xdsresource.UpdateWithMD{MD: xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusRequested}}
   329  	}
   330  	// Expected requested.
   331  	if err := compareDump(client.DumpCDS, wantRequested); err != nil {
   332  		t.Fatalf(err.Error())
   333  	}
   334  
   335  	update0 := make(map[string]xdsresource.ClusterUpdateErrTuple)
   336  	want0 := make(map[string]xdsresource.UpdateWithMD)
   337  	for n, r := range clusterRaws {
   338  		update0[n] = xdsresource.ClusterUpdateErrTuple{Update: xdsresource.ClusterUpdate{Raw: r}}
   339  		want0[n] = xdsresource.UpdateWithMD{
   340  			MD:  xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusACKed, Version: testVersion},
   341  			Raw: r,
   342  		}
   343  	}
   344  	updateHandler := findPubsubForTest(t, client.(*clientRefCounted).clientImpl, "")
   345  	updateHandler.NewClusters(update0, xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusACKed, Version: testVersion})
   346  
   347  	// Expect ACK.
   348  	if err := compareDump(client.DumpCDS, want0); err != nil {
   349  		t.Fatalf(err.Error())
   350  	}
   351  
   352  	const nackVersion = "cds-version-nack"
   353  	var nackErr = fmt.Errorf("cds nack error")
   354  	updateHandler.NewClusters(
   355  		map[string]xdsresource.ClusterUpdateErrTuple{
   356  			cdsTargets[0]: {Err: nackErr},
   357  			cdsTargets[1]: {Update: xdsresource.ClusterUpdate{Raw: clusterRaws[cdsTargets[1]]}},
   358  		},
   359  		xdsresource.UpdateMetadata{
   360  			Status: xdsresource.ServiceStatusNACKed,
   361  			ErrState: &xdsresource.UpdateErrorMetadata{
   362  				Version: nackVersion,
   363  				Err:     nackErr,
   364  			},
   365  		},
   366  	)
   367  
   368  	// Expect NACK for [0], but old ACK for [1].
   369  	wantDump := make(map[string]xdsresource.UpdateWithMD)
   370  	// Though resource 0 was NACKed, the dump should show the previous ACKed raw
   371  	// message, as well as the NACK error.
   372  	wantDump[cdsTargets[0]] = xdsresource.UpdateWithMD{
   373  		MD: xdsresource.UpdateMetadata{
   374  			Status:  xdsresource.ServiceStatusNACKed,
   375  			Version: testVersion,
   376  			ErrState: &xdsresource.UpdateErrorMetadata{
   377  				Version: nackVersion,
   378  				Err:     nackErr,
   379  			},
   380  		},
   381  		Raw: clusterRaws[cdsTargets[0]],
   382  	}
   383  	wantDump[cdsTargets[1]] = xdsresource.UpdateWithMD{
   384  		MD:  xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusACKed, Version: nackVersion},
   385  		Raw: clusterRaws[cdsTargets[1]],
   386  	}
   387  	if err := compareDump(client.DumpCDS, wantDump); err != nil {
   388  		t.Fatalf(err.Error())
   389  	}
   390  }
   391  
   392  func (s) TestEDSConfigDump(t *testing.T) {
   393  	const testVersion = "test-version-cds"
   394  	var (
   395  		edsTargets    = []string{"cluster-0", "cluster-1"}
   396  		localityNames = []string{"locality-0", "locality-1"}
   397  		addrs         = []string{"addr0:123", "addr1:456"}
   398  		endpointRaws  = make(map[string]*anypb.Any, len(edsTargets))
   399  	)
   400  
   401  	for i := range edsTargets {
   402  		clab0 := xdstestutils.NewClusterLoadAssignmentBuilder(edsTargets[i], nil)
   403  		clab0.AddLocality(localityNames[i], 1, 1, []string{addrs[i]}, nil)
   404  		claT := clab0.Build()
   405  
   406  		endpointRaws[edsTargets[i]] = testutils.MarshalAny(claT)
   407  	}
   408  
   409  	client, err := NewWithConfigForTesting(&bootstrap.Config{
   410  		XDSServer: &bootstrap.ServerConfig{
   411  			ServerURI: testXDSServer,
   412  			Creds:     grpc.WithTransportCredentials(insecure.NewCredentials()),
   413  			NodeProto: xdstestutils.EmptyNodeProtoV2,
   414  		},
   415  	}, defaultTestWatchExpiryTimeout)
   416  	if err != nil {
   417  		t.Fatalf("failed to create client: %v", err)
   418  	}
   419  	defer client.Close()
   420  
   421  	// Expected unknown.
   422  	if err := compareDump(client.DumpEDS, map[string]xdsresource.UpdateWithMD{}); err != nil {
   423  		t.Fatalf(err.Error())
   424  	}
   425  
   426  	wantRequested := make(map[string]xdsresource.UpdateWithMD)
   427  	for _, n := range edsTargets {
   428  		cancel := client.WatchEndpoints(n, func(update xdsresource.EndpointsUpdate, err error) {})
   429  		defer cancel()
   430  		wantRequested[n] = xdsresource.UpdateWithMD{MD: xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusRequested}}
   431  	}
   432  	// Expected requested.
   433  	if err := compareDump(client.DumpEDS, wantRequested); err != nil {
   434  		t.Fatalf(err.Error())
   435  	}
   436  
   437  	update0 := make(map[string]xdsresource.EndpointsUpdateErrTuple)
   438  	want0 := make(map[string]xdsresource.UpdateWithMD)
   439  	for n, r := range endpointRaws {
   440  		update0[n] = xdsresource.EndpointsUpdateErrTuple{Update: xdsresource.EndpointsUpdate{Raw: r}}
   441  		want0[n] = xdsresource.UpdateWithMD{
   442  			MD:  xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusACKed, Version: testVersion},
   443  			Raw: r,
   444  		}
   445  	}
   446  	updateHandler := findPubsubForTest(t, client.(*clientRefCounted).clientImpl, "")
   447  	updateHandler.NewEndpoints(update0, xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusACKed, Version: testVersion})
   448  
   449  	// Expect ACK.
   450  	if err := compareDump(client.DumpEDS, want0); err != nil {
   451  		t.Fatalf(err.Error())
   452  	}
   453  
   454  	const nackVersion = "eds-version-nack"
   455  	var nackErr = fmt.Errorf("eds nack error")
   456  	updateHandler.NewEndpoints(
   457  		map[string]xdsresource.EndpointsUpdateErrTuple{
   458  			edsTargets[0]: {Err: nackErr},
   459  			edsTargets[1]: {Update: xdsresource.EndpointsUpdate{Raw: endpointRaws[edsTargets[1]]}},
   460  		},
   461  		xdsresource.UpdateMetadata{
   462  			Status: xdsresource.ServiceStatusNACKed,
   463  			ErrState: &xdsresource.UpdateErrorMetadata{
   464  				Version: nackVersion,
   465  				Err:     nackErr,
   466  			},
   467  		},
   468  	)
   469  
   470  	// Expect NACK for [0], but old ACK for [1].
   471  	wantDump := make(map[string]xdsresource.UpdateWithMD)
   472  	// Though resource 0 was NACKed, the dump should show the previous ACKed raw
   473  	// message, as well as the NACK error.
   474  	wantDump[edsTargets[0]] = xdsresource.UpdateWithMD{
   475  		MD: xdsresource.UpdateMetadata{
   476  			Status:  xdsresource.ServiceStatusNACKed,
   477  			Version: testVersion,
   478  			ErrState: &xdsresource.UpdateErrorMetadata{
   479  				Version: nackVersion,
   480  				Err:     nackErr,
   481  			},
   482  		},
   483  		Raw: endpointRaws[edsTargets[0]],
   484  	}
   485  	wantDump[edsTargets[1]] = xdsresource.UpdateWithMD{
   486  		MD:  xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusACKed, Version: nackVersion},
   487  		Raw: endpointRaws[edsTargets[1]],
   488  	}
   489  	if err := compareDump(client.DumpEDS, wantDump); err != nil {
   490  		t.Fatalf(err.Error())
   491  	}
   492  }
   493  
   494  func compareDump(dumpFunc func() map[string]xdsresource.UpdateWithMD, wantDump interface{}) error {
   495  	dump := dumpFunc()
   496  	cmpOpts := cmp.Options{
   497  		cmpopts.EquateEmpty(),
   498  		cmp.Comparer(func(a, b time.Time) bool { return true }),
   499  		cmp.Comparer(func(x, y error) bool {
   500  			if x == nil || y == nil {
   501  				return x == nil && y == nil
   502  			}
   503  			return x.Error() == y.Error()
   504  		}),
   505  		protocmp.Transform(),
   506  	}
   507  	if diff := cmp.Diff(dump, wantDump, cmpOpts); diff != "" {
   508  		return fmt.Errorf("Dump() returned unexpected dump, diff (-got +want): %s", diff)
   509  	}
   510  	return nil
   511  }