google.golang.org/grpc@v1.74.2/xds/internal/clients/xdsclient/test/lds_watchers_test.go (about)

     1  /*
     2   *
     3   * Copyright 2022 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_test
    20  
    21  import (
    22  	"context"
    23  	"fmt"
    24  	"strings"
    25  	"testing"
    26  	"time"
    27  
    28  	"github.com/google/go-cmp/cmp"
    29  	"github.com/google/go-cmp/cmp/cmpopts"
    30  	"github.com/google/uuid"
    31  	"google.golang.org/grpc/credentials/insecure"
    32  	"google.golang.org/grpc/xds/internal/clients"
    33  	"google.golang.org/grpc/xds/internal/clients/grpctransport"
    34  	"google.golang.org/grpc/xds/internal/clients/internal/syncutil"
    35  	"google.golang.org/grpc/xds/internal/clients/internal/testutils"
    36  	"google.golang.org/grpc/xds/internal/clients/internal/testutils/e2e"
    37  	"google.golang.org/grpc/xds/internal/clients/xdsclient"
    38  	xdsclientinternal "google.golang.org/grpc/xds/internal/clients/xdsclient/internal"
    39  	"google.golang.org/grpc/xds/internal/clients/xdsclient/internal/xdsresource"
    40  
    41  	v3listenerpb "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3"
    42  	v3httppb "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/http_connection_manager/v3"
    43  	v3discoverypb "github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3"
    44  )
    45  
    46  type noopListenerWatcher struct{}
    47  
    48  func (noopListenerWatcher) ResourceChanged(_ xdsclient.ResourceData, onDone func()) {
    49  	onDone()
    50  }
    51  func (noopListenerWatcher) ResourceError(_ error, onDone func()) {
    52  	onDone()
    53  }
    54  func (noopListenerWatcher) AmbientError(_ error, onDone func()) {
    55  	onDone()
    56  }
    57  
    58  type listenerUpdateErrTuple struct {
    59  	update      listenerUpdate
    60  	resourceErr error
    61  	ambientErr  error
    62  }
    63  
    64  type listenerWatcher struct {
    65  	updateCh      *testutils.Channel // Messages of type listenerUpdate
    66  	resourceErrCh *testutils.Channel // Messages of type resource error
    67  	ambientErrCh  *testutils.Channel // Messages of type ambient error
    68  }
    69  
    70  func newListenerWatcher() *listenerWatcher {
    71  	return &listenerWatcher{
    72  		updateCh:      testutils.NewChannelWithSize(1),
    73  		resourceErrCh: testutils.NewChannelWithSize(1),
    74  		ambientErrCh:  testutils.NewChannelWithSize(1),
    75  	}
    76  }
    77  
    78  func (lw *listenerWatcher) ResourceChanged(update xdsclient.ResourceData, onDone func()) {
    79  	lisData, ok := update.(*listenerResourceData)
    80  	if !ok {
    81  		lw.resourceErrCh.Send(listenerUpdateErrTuple{resourceErr: fmt.Errorf("unexpected resource type: %T", update)})
    82  		onDone()
    83  		return
    84  	}
    85  	select {
    86  	case <-lw.updateCh.C:
    87  	default:
    88  	}
    89  	lw.updateCh.Send(listenerUpdateErrTuple{update: lisData.Resource})
    90  	onDone()
    91  }
    92  
    93  func (lw *listenerWatcher) AmbientError(err error, onDone func()) {
    94  	// When used with a go-control-plane management server that continuously
    95  	// resends resources which are NACKed by the xDS client, using a `Replace()`
    96  	// here and in OnResourceDoesNotExist() simplifies tests which will have
    97  	// access to the most recently received error.
    98  	lw.ambientErrCh.Replace(listenerUpdateErrTuple{ambientErr: err})
    99  	onDone()
   100  }
   101  
   102  func (lw *listenerWatcher) ResourceError(err error, onDone func()) {
   103  	lw.resourceErrCh.Replace(listenerUpdateErrTuple{resourceErr: err})
   104  	onDone()
   105  }
   106  
   107  // badListenerResource returns a listener resource for the given name which does
   108  // not contain the `RouteSpecifier` field in the HTTPConnectionManager, and
   109  // hence is expected to be NACKed by the client.
   110  func badListenerResource(t *testing.T, name string) *v3listenerpb.Listener {
   111  	hcm := testutils.MarshalAny(t, &v3httppb.HttpConnectionManager{})
   112  	return &v3listenerpb.Listener{
   113  		Name:        name,
   114  		ApiListener: &v3listenerpb.ApiListener{ApiListener: hcm},
   115  	}
   116  }
   117  
   118  func overrideWatchExpiryTimeout(t *testing.T, watchExpiryTimeout time.Duration) {
   119  	originalWatchExpiryTimeout := xdsclientinternal.WatchExpiryTimeout
   120  	xdsclientinternal.WatchExpiryTimeout = watchExpiryTimeout
   121  	t.Cleanup(func() { xdsclientinternal.WatchExpiryTimeout = originalWatchExpiryTimeout })
   122  }
   123  
   124  // verifyNoListenerUpdate verifies that no listener update is received on the
   125  // provided update channel, and returns an error if an update is received.
   126  //
   127  // A very short deadline is used while waiting for the update, as this function
   128  // is intended to be used when an update is not expected.
   129  func verifyNoListenerUpdate(ctx context.Context, updateCh *testutils.Channel) error {
   130  	sCtx, sCancel := context.WithTimeout(ctx, defaultTestShortTimeout)
   131  	defer sCancel()
   132  	if u, err := updateCh.Receive(sCtx); err != context.DeadlineExceeded {
   133  		return fmt.Errorf("unexpected ListenerUpdate: %v", u)
   134  	}
   135  	return nil
   136  }
   137  
   138  // verifyListenerUpdate waits for a listenerUpdateErrTuple from the provided
   139  // updateCh (typically the updateCh, resourceErrCh, or ambientErrCh of
   140  // listenerWatcher) and verifies that it matches the expected wantUpdate tuple.
   141  //
   142  // It performs the following checks:
   143  //   - Waits for an item on updateCh until the context deadline.
   144  //   - If wantUpdate contains a resourceErr or ambientErr, it compares the
   145  //     xdsresource.ErrorType of the received error with the expected error
   146  //     type.
   147  //   - If wantUpdate contains an update, it compares the received update with
   148  //     the expected update, ignoring the Raw field.
   149  //
   150  // Returns an error if the context expires, or if the received tuple does not
   151  // match the expected tuple according to the comparison logic.
   152  func verifyListenerUpdate(ctx context.Context, updateCh *testutils.Channel, wantUpdate listenerUpdateErrTuple) error {
   153  	u, err := updateCh.Receive(ctx)
   154  	if err != nil {
   155  		return fmt.Errorf("timeout when waiting for a listener resource from the management server: %v", err)
   156  	}
   157  	got := u.(listenerUpdateErrTuple)
   158  	if wantUpdate.resourceErr != nil {
   159  		if gotType, wantType := xdsresource.ErrType(got.resourceErr), xdsresource.ErrType(wantUpdate.resourceErr); gotType != wantType {
   160  			return fmt.Errorf("received update with resource error type %v, want %v", gotType, wantType)
   161  		}
   162  	}
   163  	if wantUpdate.ambientErr != nil {
   164  		if gotType, wantType := xdsresource.ErrType(got.ambientErr), xdsresource.ErrType(wantUpdate.ambientErr); gotType != wantType {
   165  			return fmt.Errorf("received update with ambient error type %v, want %v", gotType, wantType)
   166  		}
   167  	}
   168  	cmpOpts := []cmp.Option{
   169  		cmpopts.EquateEmpty(),
   170  		cmpopts.IgnoreFields(listenerUpdate{}, "Raw"),
   171  	}
   172  	if diff := cmp.Diff(wantUpdate.update, got.update, cmpOpts...); diff != "" {
   173  		return fmt.Errorf("received unexpected diff in the listener resource update: (-want, got):\n%s", diff)
   174  	}
   175  	return nil
   176  }
   177  
   178  func verifyListenerResourceError(ctx context.Context, updateCh *testutils.Channel, wantErr, wantNodeID string) error {
   179  	u, err := updateCh.Receive(ctx)
   180  	if err != nil {
   181  		return fmt.Errorf("timeout when waiting for a listener error from the management server: %v", err)
   182  	}
   183  	gotErr := u.(listenerUpdateErrTuple).resourceErr
   184  	return verifyListenerError(ctx, gotErr, wantErr, wantNodeID)
   185  }
   186  
   187  func verifyListenerError(_ context.Context, gotErr error, wantErr, wantNodeID string) error {
   188  	if gotErr == nil || !strings.Contains(gotErr.Error(), wantErr) {
   189  		return fmt.Errorf("update received with error: %v, want %q", gotErr, wantErr)
   190  	}
   191  	if !strings.Contains(gotErr.Error(), wantNodeID) {
   192  		return fmt.Errorf("update received with error: %v, want error with node ID: %q", gotErr, wantNodeID)
   193  	}
   194  	return nil
   195  }
   196  
   197  func verifyAmbientErrorType(ctx context.Context, updateCh *testutils.Channel, wantErrType xdsresource.ErrorType, wantNodeID string) error {
   198  	u, err := updateCh.Receive(ctx)
   199  	if err != nil {
   200  		return fmt.Errorf("timeout when waiting for a listener error from the management server: %v", err)
   201  	}
   202  	gotErr := u.(listenerUpdateErrTuple).ambientErr
   203  	return verifyErrorType(gotErr, wantErrType, wantNodeID)
   204  }
   205  
   206  func verifyResourceErrorType(ctx context.Context, updateCh *testutils.Channel, wantErrType xdsresource.ErrorType, wantNodeID string) error {
   207  	u, err := updateCh.Receive(ctx)
   208  	if err != nil {
   209  		return fmt.Errorf("timeout when waiting for a listener error from the management server: %v", err)
   210  	}
   211  	gotErr := u.(listenerUpdateErrTuple).resourceErr
   212  	return verifyErrorType(gotErr, wantErrType, wantNodeID)
   213  }
   214  
   215  func verifyErrorType(gotErr error, wantErrType xdsresource.ErrorType, wantNodeID string) error {
   216  	if got, want := xdsresource.ErrType(gotErr), wantErrType; got != want {
   217  		return fmt.Errorf("update received with error %v of type: %v, want %v", gotErr, got, want)
   218  	}
   219  	if !strings.Contains(gotErr.Error(), wantNodeID) {
   220  		return fmt.Errorf("update received with error: %v, want error with node ID: %q", gotErr, wantNodeID)
   221  	}
   222  	return nil
   223  }
   224  
   225  // TestLDSWatch covers the case where a single watcher exists for a single
   226  // listener resource. The test verifies the following scenarios:
   227  //  1. An update from the management server containing the resource being
   228  //     watched should result in the invocation of the watch callback.
   229  //  2. An update from the management server containing a resource *not* being
   230  //     watched should not result in the invocation of the watch callback.
   231  //  3. After the watch is cancelled, an update from the management server
   232  //     containing the resource that was being watched should not result in the
   233  //     invocation of the watch callback.
   234  //
   235  // The test is run for old and new style names.
   236  func (s) TestLDSWatch(t *testing.T) {
   237  	tests := []struct {
   238  		desc                   string
   239  		resourceName           string
   240  		watchedResource        *v3listenerpb.Listener // The resource being watched.
   241  		updatedWatchedResource *v3listenerpb.Listener // The watched resource after an update.
   242  		notWatchedResource     *v3listenerpb.Listener // A resource which is not being watched.
   243  		wantUpdate             listenerUpdateErrTuple
   244  	}{
   245  		{
   246  			desc:                   "old style resource",
   247  			resourceName:           ldsName,
   248  			watchedResource:        e2e.DefaultClientListener(ldsName, rdsName),
   249  			updatedWatchedResource: e2e.DefaultClientListener(ldsName, "new-rds-resource"),
   250  			notWatchedResource:     e2e.DefaultClientListener("unsubscribed-lds-resource", rdsName),
   251  			wantUpdate: listenerUpdateErrTuple{
   252  				update: listenerUpdate{
   253  					RouteConfigName: rdsName,
   254  				},
   255  			},
   256  		},
   257  		{
   258  			desc:                   "new style resource",
   259  			resourceName:           ldsNameNewStyle,
   260  			watchedResource:        e2e.DefaultClientListener(ldsNameNewStyle, rdsNameNewStyle),
   261  			updatedWatchedResource: e2e.DefaultClientListener(ldsNameNewStyle, "new-rds-resource"),
   262  			notWatchedResource:     e2e.DefaultClientListener("unsubscribed-lds-resource", rdsNameNewStyle),
   263  			wantUpdate: listenerUpdateErrTuple{
   264  				update: listenerUpdate{
   265  					RouteConfigName: rdsNameNewStyle,
   266  				},
   267  			},
   268  		},
   269  	}
   270  
   271  	for _, test := range tests {
   272  		t.Run(test.desc, func(t *testing.T) {
   273  			mgmtServer := e2e.StartManagementServer(t, e2e.ManagementServerOptions{})
   274  
   275  			nodeID := uuid.New().String()
   276  
   277  			resourceTypes := map[string]xdsclient.ResourceType{xdsresource.V3ListenerURL: listenerType}
   278  			si := clients.ServerIdentifier{
   279  				ServerURI:  mgmtServer.Address,
   280  				Extensions: grpctransport.ServerIdentifierExtension{ConfigName: "insecure"},
   281  			}
   282  
   283  			configs := map[string]grpctransport.Config{"insecure": {Credentials: insecure.NewBundle()}}
   284  			xdsClientConfig := xdsclient.Config{
   285  				Servers:          []xdsclient.ServerConfig{{ServerIdentifier: si}},
   286  				Node:             clients.Node{ID: nodeID},
   287  				TransportBuilder: grpctransport.NewBuilder(configs),
   288  				ResourceTypes:    resourceTypes,
   289  				// Xdstp resource names used in this test do not specify an
   290  				// authority. These will end up looking up an entry with the
   291  				// empty key in the authorities map. Having an entry with an
   292  				// empty key and empty configuration, results in these
   293  				// resources also using the top-level configuration.
   294  				Authorities: map[string]xdsclient.Authority{
   295  					"": {XDSServers: []xdsclient.ServerConfig{}},
   296  				},
   297  			}
   298  
   299  			// Create an xDS client with the above config.
   300  			client, err := xdsclient.New(xdsClientConfig)
   301  			if err != nil {
   302  				t.Fatalf("Failed to create xDS client: %v", err)
   303  			}
   304  			defer client.Close()
   305  
   306  			// Register a watch for a listener resource and have the watch
   307  			// callback push the received update on to a channel.
   308  			lw := newListenerWatcher()
   309  			ldsCancel := client.WatchResource(xdsresource.V3ListenerURL, test.resourceName, lw)
   310  
   311  			// Configure the management server to return a single listener
   312  			// resource, corresponding to the one we registered a watch for.
   313  			resources := e2e.UpdateOptions{
   314  				NodeID:         nodeID,
   315  				Listeners:      []*v3listenerpb.Listener{test.watchedResource},
   316  				SkipValidation: true,
   317  			}
   318  			ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   319  			defer cancel()
   320  			if err := mgmtServer.Update(ctx, resources); err != nil {
   321  				t.Fatalf("Failed to update management server with resources: %v, err: %v", resources, err)
   322  			}
   323  
   324  			// Verify the contents of the received update.
   325  			if err := verifyListenerUpdate(ctx, lw.updateCh, test.wantUpdate); err != nil {
   326  				t.Fatal(err)
   327  			}
   328  
   329  			// Configure the management server to return an additional listener
   330  			// resource, one that we are not interested in.
   331  			resources = e2e.UpdateOptions{
   332  				NodeID:         nodeID,
   333  				Listeners:      []*v3listenerpb.Listener{test.watchedResource, test.notWatchedResource},
   334  				SkipValidation: true,
   335  			}
   336  			if err := mgmtServer.Update(ctx, resources); err != nil {
   337  				t.Fatalf("Failed to update management server with resources: %v, err: %v", resources, err)
   338  			}
   339  			if err := verifyNoListenerUpdate(ctx, lw.updateCh); err != nil {
   340  				t.Fatal(err)
   341  			}
   342  
   343  			// Cancel the watch and update the resource corresponding to the original
   344  			// watch.  Ensure that the cancelled watch callback is not invoked.
   345  			ldsCancel()
   346  			resources = e2e.UpdateOptions{
   347  				NodeID:         nodeID,
   348  				Listeners:      []*v3listenerpb.Listener{test.updatedWatchedResource, test.notWatchedResource},
   349  				SkipValidation: true,
   350  			}
   351  			if err := mgmtServer.Update(ctx, resources); err != nil {
   352  				t.Fatalf("Failed to update management server with resources: %v, err: %v", resources, err)
   353  			}
   354  			if err := verifyNoListenerUpdate(ctx, lw.updateCh); err != nil {
   355  				t.Fatal(err)
   356  			}
   357  		})
   358  	}
   359  }
   360  
   361  // TestLDSWatch_TwoWatchesForSameResourceName covers the case where two watchers
   362  // exist for a single listener resource.  The test verifies the following
   363  // scenarios:
   364  //  1. An update from the management server containing the resource being
   365  //     watched should result in the invocation of both watch callbacks.
   366  //  2. After one of the watches is cancelled, a redundant update from the
   367  //     management server should not result in the invocation of either of the
   368  //     watch callbacks.
   369  //  3. An update from the management server containing the resource being
   370  //     watched should result in the invocation of the un-cancelled watch
   371  //     callback.
   372  //
   373  // The test is run for old and new style names.
   374  func (s) TestLDSWatch_TwoWatchesForSameResourceName(t *testing.T) {
   375  	tests := []struct {
   376  		desc                   string
   377  		resourceName           string
   378  		watchedResource        *v3listenerpb.Listener // The resource being watched.
   379  		updatedWatchedResource *v3listenerpb.Listener // The watched resource after an update.
   380  		wantUpdateV1           listenerUpdateErrTuple
   381  		wantUpdateV2           listenerUpdateErrTuple
   382  	}{
   383  		{
   384  			desc:                   "old style resource",
   385  			resourceName:           ldsName,
   386  			watchedResource:        e2e.DefaultClientListener(ldsName, rdsName),
   387  			updatedWatchedResource: e2e.DefaultClientListener(ldsName, "new-rds-resource"),
   388  			wantUpdateV1: listenerUpdateErrTuple{
   389  				update: listenerUpdate{
   390  					RouteConfigName: rdsName,
   391  				},
   392  			},
   393  			wantUpdateV2: listenerUpdateErrTuple{
   394  				update: listenerUpdate{
   395  					RouteConfigName: "new-rds-resource",
   396  				},
   397  			},
   398  		},
   399  		{
   400  			desc:                   "new style resource",
   401  			resourceName:           ldsNameNewStyle,
   402  			watchedResource:        e2e.DefaultClientListener(ldsNameNewStyle, rdsNameNewStyle),
   403  			updatedWatchedResource: e2e.DefaultClientListener(ldsNameNewStyle, "new-rds-resource"),
   404  			wantUpdateV1: listenerUpdateErrTuple{
   405  				update: listenerUpdate{
   406  					RouteConfigName: rdsNameNewStyle,
   407  				},
   408  			},
   409  			wantUpdateV2: listenerUpdateErrTuple{
   410  				update: listenerUpdate{
   411  					RouteConfigName: "new-rds-resource",
   412  				},
   413  			},
   414  		},
   415  	}
   416  
   417  	for _, test := range tests {
   418  		t.Run(test.desc, func(t *testing.T) {
   419  			mgmtServer := e2e.StartManagementServer(t, e2e.ManagementServerOptions{})
   420  
   421  			nodeID := uuid.New().String()
   422  
   423  			resourceTypes := map[string]xdsclient.ResourceType{xdsresource.V3ListenerURL: listenerType}
   424  			si := clients.ServerIdentifier{
   425  				ServerURI:  mgmtServer.Address,
   426  				Extensions: grpctransport.ServerIdentifierExtension{ConfigName: "insecure"},
   427  			}
   428  
   429  			configs := map[string]grpctransport.Config{"insecure": {Credentials: insecure.NewBundle()}}
   430  			xdsClientConfig := xdsclient.Config{
   431  				Servers:          []xdsclient.ServerConfig{{ServerIdentifier: si}},
   432  				Node:             clients.Node{ID: nodeID},
   433  				TransportBuilder: grpctransport.NewBuilder(configs),
   434  				ResourceTypes:    resourceTypes,
   435  				// Xdstp resource names used in this test do not specify an
   436  				// authority. These will end up looking up an entry with the
   437  				// empty key in the authorities map. Having an entry with an
   438  				// empty key and empty configuration, results in these
   439  				// resources also using the top-level configuration.
   440  				Authorities: map[string]xdsclient.Authority{
   441  					"": {XDSServers: []xdsclient.ServerConfig{}},
   442  				},
   443  			}
   444  
   445  			// Create an xDS client with the above config.
   446  			client, err := xdsclient.New(xdsClientConfig)
   447  			if err != nil {
   448  				t.Fatalf("Failed to create xDS client: %v", err)
   449  			}
   450  			defer client.Close()
   451  
   452  			// Register two watches for the same listener resource and have the
   453  			// callbacks push the received updates on to a channel.
   454  			lw1 := newListenerWatcher()
   455  			ldsCancel1 := client.WatchResource(xdsresource.V3ListenerURL, test.resourceName, lw1)
   456  			defer ldsCancel1()
   457  			lw2 := newListenerWatcher()
   458  			ldsCancel2 := client.WatchResource(xdsresource.V3ListenerURL, test.resourceName, lw2)
   459  
   460  			// Configure the management server to return a single listener
   461  			// resource, corresponding to the one we registered watches for.
   462  			resources := e2e.UpdateOptions{
   463  				NodeID:         nodeID,
   464  				Listeners:      []*v3listenerpb.Listener{test.watchedResource},
   465  				SkipValidation: true,
   466  			}
   467  			ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   468  			defer cancel()
   469  			if err := mgmtServer.Update(ctx, resources); err != nil {
   470  				t.Fatalf("Failed to update management server with resources: %v, err: %v", resources, err)
   471  			}
   472  
   473  			// Verify the contents of the received update.
   474  			if err := verifyListenerUpdate(ctx, lw1.updateCh, test.wantUpdateV1); err != nil {
   475  				t.Fatal(err)
   476  			}
   477  			if err := verifyListenerUpdate(ctx, lw2.updateCh, test.wantUpdateV1); err != nil {
   478  				t.Fatal(err)
   479  			}
   480  
   481  			// Cancel the second watch and force the management server to push a
   482  			// redundant update for the resource being watched. Neither of the
   483  			// two watch callbacks should be invoked.
   484  			ldsCancel2()
   485  			if err := mgmtServer.Update(ctx, resources); err != nil {
   486  				t.Fatalf("Failed to update management server with resources: %v, err: %v", resources, err)
   487  			}
   488  			if err := verifyNoListenerUpdate(ctx, lw1.updateCh); err != nil {
   489  				t.Fatal(err)
   490  			}
   491  			if err := verifyNoListenerUpdate(ctx, lw2.updateCh); err != nil {
   492  				t.Fatal(err)
   493  			}
   494  
   495  			// Update to the resource being watched. The un-cancelled callback
   496  			// should be invoked while the cancelled one should not be.
   497  			resources = e2e.UpdateOptions{
   498  				NodeID:         nodeID,
   499  				Listeners:      []*v3listenerpb.Listener{test.updatedWatchedResource},
   500  				SkipValidation: true,
   501  			}
   502  			if err := mgmtServer.Update(ctx, resources); err != nil {
   503  				t.Fatalf("Failed to update management server with resources: %v, err: %v", resources, err)
   504  			}
   505  			if err := verifyListenerUpdate(ctx, lw1.updateCh, test.wantUpdateV2); err != nil {
   506  				t.Fatal(err)
   507  			}
   508  			if err := verifyNoListenerUpdate(ctx, lw2.updateCh); err != nil {
   509  				t.Fatal(err)
   510  			}
   511  		})
   512  	}
   513  }
   514  
   515  // TestLDSWatch_ThreeWatchesForDifferentResourceNames covers the case with three
   516  // watchers (two watchers for one resource, and the third watcher for another
   517  // resource), exist across two listener resources.  The test verifies that an
   518  // update from the management server containing both resources results in the
   519  // invocation of all watch callbacks.
   520  //
   521  // The test is run with both old and new style names.
   522  func (s) TestLDSWatch_ThreeWatchesForDifferentResourceNames(t *testing.T) {
   523  	mgmtServer := e2e.StartManagementServer(t, e2e.ManagementServerOptions{})
   524  
   525  	nodeID := uuid.New().String()
   526  	authority := makeAuthorityName(t.Name())
   527  
   528  	resourceTypes := map[string]xdsclient.ResourceType{xdsresource.V3ListenerURL: listenerType}
   529  	si := clients.ServerIdentifier{
   530  		ServerURI:  mgmtServer.Address,
   531  		Extensions: grpctransport.ServerIdentifierExtension{ConfigName: "insecure"},
   532  	}
   533  
   534  	configs := map[string]grpctransport.Config{"insecure": {Credentials: insecure.NewBundle()}}
   535  	xdsClientConfig := xdsclient.Config{
   536  		Servers:          []xdsclient.ServerConfig{{ServerIdentifier: si}},
   537  		Node:             clients.Node{ID: nodeID},
   538  		TransportBuilder: grpctransport.NewBuilder(configs),
   539  		ResourceTypes:    resourceTypes,
   540  		// Xdstp style resource names used in this test use a slash removed
   541  		// version of t.Name as their authority, and the empty config
   542  		// results in the top-level xds server configuration being used for
   543  		// this authority.
   544  		Authorities: map[string]xdsclient.Authority{
   545  			authority: {XDSServers: []xdsclient.ServerConfig{}},
   546  		},
   547  	}
   548  
   549  	// Create an xDS client with the above config.
   550  	client, err := xdsclient.New(xdsClientConfig)
   551  	if err != nil {
   552  		t.Fatalf("Failed to create xDS client: %v", err)
   553  	}
   554  	defer client.Close()
   555  
   556  	// Register two watches for the same listener resource and have the
   557  	// callbacks push the received updates on to a channel.
   558  	lw1 := newListenerWatcher()
   559  	ldsCancel1 := client.WatchResource(xdsresource.V3ListenerURL, ldsName, lw1)
   560  	defer ldsCancel1()
   561  	lw2 := newListenerWatcher()
   562  	ldsCancel2 := client.WatchResource(xdsresource.V3ListenerURL, ldsName, lw2)
   563  	defer ldsCancel2()
   564  
   565  	// Register the third watch for a different listener resource.
   566  	ldsNameNewStyle := makeNewStyleLDSName(authority)
   567  	lw3 := newListenerWatcher()
   568  	ldsCancel3 := client.WatchResource(xdsresource.V3ListenerURL, ldsNameNewStyle, lw3)
   569  	defer ldsCancel3()
   570  
   571  	// Configure the management server to return two listener resources,
   572  	// corresponding to the registered watches.
   573  	resources := e2e.UpdateOptions{
   574  		NodeID: nodeID,
   575  		Listeners: []*v3listenerpb.Listener{
   576  			e2e.DefaultClientListener(ldsName, rdsName),
   577  			e2e.DefaultClientListener(ldsNameNewStyle, rdsName),
   578  		},
   579  		SkipValidation: true,
   580  	}
   581  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   582  	defer cancel()
   583  	if err := mgmtServer.Update(ctx, resources); err != nil {
   584  		t.Fatalf("Failed to update management server with resources: %v, err: %v", resources, err)
   585  	}
   586  
   587  	// Verify the contents of the received update for the all watchers. The two
   588  	// resources returned differ only in the resource name. Therefore the
   589  	// expected update is the same for all the watchers.
   590  	wantUpdate := listenerUpdateErrTuple{
   591  		update: listenerUpdate{
   592  			RouteConfigName: rdsName,
   593  		},
   594  	}
   595  	if err := verifyListenerUpdate(ctx, lw1.updateCh, wantUpdate); err != nil {
   596  		t.Fatal(err)
   597  	}
   598  	if err := verifyListenerUpdate(ctx, lw2.updateCh, wantUpdate); err != nil {
   599  		t.Fatal(err)
   600  	}
   601  	if err := verifyListenerUpdate(ctx, lw3.updateCh, wantUpdate); err != nil {
   602  		t.Fatal(err)
   603  	}
   604  }
   605  
   606  // TestLDSWatch_ResourceCaching covers the case where a watch is registered for
   607  // a resource which is already present in the cache.  The test verifies that the
   608  // watch callback is invoked with the contents from the cache, instead of a
   609  // request being sent to the management server.
   610  func (s) TestLDSWatch_ResourceCaching(t *testing.T) {
   611  	firstRequestReceived := false
   612  	firstAckReceived := syncutil.NewEvent()
   613  	secondRequestReceived := syncutil.NewEvent()
   614  
   615  	mgmtServer := e2e.StartManagementServer(t, e2e.ManagementServerOptions{
   616  		OnStreamRequest: func(_ int64, req *v3discoverypb.DiscoveryRequest) error {
   617  			// The first request has an empty version string.
   618  			if !firstRequestReceived && req.GetVersionInfo() == "" {
   619  				firstRequestReceived = true
   620  				return nil
   621  			}
   622  			// The first ack has a non-empty version string.
   623  			if !firstAckReceived.HasFired() && req.GetVersionInfo() != "" {
   624  				firstAckReceived.Fire()
   625  				return nil
   626  			}
   627  			// Any requests after the first request and ack, are not expected.
   628  			secondRequestReceived.Fire()
   629  			return nil
   630  		},
   631  	})
   632  
   633  	nodeID := uuid.New().String()
   634  
   635  	resourceTypes := map[string]xdsclient.ResourceType{xdsresource.V3ListenerURL: listenerType}
   636  	si := clients.ServerIdentifier{
   637  		ServerURI:  mgmtServer.Address,
   638  		Extensions: grpctransport.ServerIdentifierExtension{ConfigName: "insecure"},
   639  	}
   640  
   641  	configs := map[string]grpctransport.Config{"insecure": {Credentials: insecure.NewBundle()}}
   642  	xdsClientConfig := xdsclient.Config{
   643  		Servers:          []xdsclient.ServerConfig{{ServerIdentifier: si}},
   644  		Node:             clients.Node{ID: nodeID},
   645  		TransportBuilder: grpctransport.NewBuilder(configs),
   646  		ResourceTypes:    resourceTypes,
   647  	}
   648  
   649  	// Create an xDS client with the above config.
   650  	client, err := xdsclient.New(xdsClientConfig)
   651  	if err != nil {
   652  		t.Fatalf("Failed to create xDS client: %v", err)
   653  	}
   654  	defer client.Close()
   655  
   656  	// Register a watch for a listener resource and have the watch
   657  	// callback push the received update on to a channel.
   658  	lw1 := newListenerWatcher()
   659  	ldsCancel1 := client.WatchResource(xdsresource.V3ListenerURL, ldsName, lw1)
   660  	defer ldsCancel1()
   661  
   662  	// Configure the management server to return a single listener
   663  	// resource, corresponding to the one we registered a watch for.
   664  	resources := e2e.UpdateOptions{
   665  		NodeID:         nodeID,
   666  		Listeners:      []*v3listenerpb.Listener{e2e.DefaultClientListener(ldsName, rdsName)},
   667  		SkipValidation: true,
   668  	}
   669  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   670  	defer cancel()
   671  	if err := mgmtServer.Update(ctx, resources); err != nil {
   672  		t.Fatalf("Failed to update management server with resources: %v, err: %v", resources, err)
   673  	}
   674  
   675  	// Verify the contents of the received update.
   676  	wantUpdate := listenerUpdateErrTuple{
   677  		update: listenerUpdate{
   678  			RouteConfigName: rdsName,
   679  		},
   680  	}
   681  	if err := verifyListenerUpdate(ctx, lw1.updateCh, wantUpdate); err != nil {
   682  		t.Fatal(err)
   683  	}
   684  	select {
   685  	case <-ctx.Done():
   686  		t.Fatal("timeout when waiting for receipt of ACK at the management server")
   687  	case <-firstAckReceived.Done():
   688  	}
   689  
   690  	// Register another watch for the same resource. This should get the update
   691  	// from the cache.
   692  	lw2 := newListenerWatcher()
   693  	ldsCancel2 := client.WatchResource(xdsresource.V3ListenerURL, ldsName, lw2)
   694  	defer ldsCancel2()
   695  	if err := verifyListenerUpdate(ctx, lw2.updateCh, wantUpdate); err != nil {
   696  		t.Fatal(err)
   697  	}
   698  	// No request should get sent out as part of this watch.
   699  	sCtx, sCancel := context.WithTimeout(ctx, defaultTestShortTimeout)
   700  	defer sCancel()
   701  	select {
   702  	case <-sCtx.Done():
   703  	case <-secondRequestReceived.Done():
   704  		t.Fatal("xdsClient sent out request instead of using update from cache")
   705  	}
   706  }
   707  
   708  // TestLDSWatch_ExpiryTimerFiresBeforeResponse tests the case where the client
   709  // does not receive an LDS response for the request that it sends. The test
   710  // verifies that the watch callback is invoked with an error once the
   711  // watchExpiryTimer fires.
   712  func (s) TestLDSWatch_ExpiryTimerFiresBeforeResponse(t *testing.T) {
   713  	mgmtServer := e2e.StartManagementServer(t, e2e.ManagementServerOptions{})
   714  
   715  	nodeID := uuid.New().String()
   716  
   717  	resourceTypes := map[string]xdsclient.ResourceType{xdsresource.V3ListenerURL: listenerType}
   718  	si := clients.ServerIdentifier{
   719  		ServerURI:  mgmtServer.Address,
   720  		Extensions: grpctransport.ServerIdentifierExtension{ConfigName: "insecure"},
   721  	}
   722  
   723  	configs := map[string]grpctransport.Config{"insecure": {Credentials: insecure.NewBundle()}}
   724  	xdsClientConfig := xdsclient.Config{
   725  		Servers:          []xdsclient.ServerConfig{{ServerIdentifier: si}},
   726  		Node:             clients.Node{ID: nodeID},
   727  		TransportBuilder: grpctransport.NewBuilder(configs),
   728  		ResourceTypes:    resourceTypes,
   729  	}
   730  
   731  	// Create an xDS client with the above config and override the default
   732  	// watch expiry timeout.
   733  	overrideWatchExpiryTimeout(t, defaultTestWatchExpiryTimeout)
   734  	client, err := xdsclient.New(xdsClientConfig)
   735  	if err != nil {
   736  		t.Fatalf("Failed to create xDS client: %v", err)
   737  	}
   738  	defer client.Close()
   739  
   740  	// Register a watch for a resource which is expected to fail with an error
   741  	// after the watch expiry timer fires.
   742  	lw := newListenerWatcher()
   743  	ldsCancel := client.WatchResource(xdsresource.V3ListenerURL, ldsName, lw)
   744  	defer ldsCancel()
   745  
   746  	// Wait for the watch expiry timer to fire.
   747  	<-time.After(defaultTestWatchExpiryTimeout)
   748  
   749  	// Verify that an empty update with the expected resource error is
   750  	// received.
   751  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   752  	defer cancel()
   753  	wantErr := xdsresource.NewError(xdsresource.ErrorTypeResourceNotFound, "")
   754  	if err := verifyListenerUpdate(ctx, lw.resourceErrCh, listenerUpdateErrTuple{resourceErr: wantErr}); err != nil {
   755  		t.Fatal(err)
   756  	}
   757  }
   758  
   759  // TestLDSWatch_ValidResponseCancelsExpiryTimerBehavior tests the case where the
   760  // client receives a valid LDS response for the request that it sends. The test
   761  // verifies that the behavior associated with the expiry timer (i.e, callback
   762  // invocation with error) does not take place.
   763  func (s) TestLDSWatch_ValidResponseCancelsExpiryTimerBehavior(t *testing.T) {
   764  	mgmtServer := e2e.StartManagementServer(t, e2e.ManagementServerOptions{})
   765  
   766  	nodeID := uuid.New().String()
   767  
   768  	resourceTypes := map[string]xdsclient.ResourceType{xdsresource.V3ListenerURL: listenerType}
   769  	si := clients.ServerIdentifier{
   770  		ServerURI:  mgmtServer.Address,
   771  		Extensions: grpctransport.ServerIdentifierExtension{ConfigName: "insecure"},
   772  	}
   773  
   774  	configs := map[string]grpctransport.Config{"insecure": {Credentials: insecure.NewBundle()}}
   775  	xdsClientConfig := xdsclient.Config{
   776  		Servers:          []xdsclient.ServerConfig{{ServerIdentifier: si}},
   777  		Node:             clients.Node{ID: nodeID},
   778  		TransportBuilder: grpctransport.NewBuilder(configs),
   779  		ResourceTypes:    resourceTypes,
   780  	}
   781  
   782  	// Create an xDS client with the above config and override the default
   783  	// watch expiry timeout.
   784  	overrideWatchExpiryTimeout(t, defaultTestWatchExpiryTimeout)
   785  	client, err := xdsclient.New(xdsClientConfig)
   786  	if err != nil {
   787  		t.Fatalf("Failed to create xDS client: %v", err)
   788  	}
   789  	defer client.Close()
   790  
   791  	// Register a watch for a listener resource and have the watch
   792  	// callback push the received update on to a channel.
   793  	lw := newListenerWatcher()
   794  	ldsCancel := client.WatchResource(xdsresource.V3ListenerURL, ldsName, lw)
   795  	defer ldsCancel()
   796  
   797  	// Configure the management server to return a single listener
   798  	// resource, corresponding to the one we registered a watch for.
   799  	resources := e2e.UpdateOptions{
   800  		NodeID:         nodeID,
   801  		Listeners:      []*v3listenerpb.Listener{e2e.DefaultClientListener(ldsName, rdsName)},
   802  		SkipValidation: true,
   803  	}
   804  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   805  	defer cancel()
   806  	if err := mgmtServer.Update(ctx, resources); err != nil {
   807  		t.Fatalf("Failed to update management server with resources: %v, err: %v", resources, err)
   808  	}
   809  
   810  	// Verify the contents of the received update.
   811  	wantUpdate := listenerUpdateErrTuple{
   812  		update: listenerUpdate{
   813  			RouteConfigName: rdsName,
   814  		},
   815  	}
   816  	if err := verifyListenerUpdate(ctx, lw.updateCh, wantUpdate); err != nil {
   817  		t.Fatal(err)
   818  	}
   819  
   820  	// Wait for the watch expiry timer to fire, and verify that the callback is
   821  	// not invoked.
   822  	<-time.After(defaultTestWatchExpiryTimeout)
   823  	if err := verifyNoListenerUpdate(ctx, lw.updateCh); err != nil {
   824  		t.Fatal(err)
   825  	}
   826  }
   827  
   828  // TestLDSWatch_ResourceRemoved covers the cases where a resource being watched
   829  // is removed from the management server. The test verifies the following
   830  // scenarios:
   831  //  1. Removing a resource should trigger the watch callback with a resource
   832  //     removed error. It should not trigger the watch callback for an unrelated
   833  //     resource.
   834  //  2. An update to another resource should result in the invocation of the watch
   835  //     callback associated with that resource.  It should not result in the
   836  //     invocation of the watch callback associated with the deleted resource.
   837  //
   838  // The test is run with both old and new style names.
   839  func (s) TestLDSWatch_ResourceRemoved(t *testing.T) {
   840  	mgmtServer := e2e.StartManagementServer(t, e2e.ManagementServerOptions{})
   841  
   842  	nodeID := uuid.New().String()
   843  	authority := makeAuthorityName(t.Name())
   844  
   845  	resourceTypes := map[string]xdsclient.ResourceType{xdsresource.V3ListenerURL: listenerType}
   846  	si := clients.ServerIdentifier{
   847  		ServerURI:  mgmtServer.Address,
   848  		Extensions: grpctransport.ServerIdentifierExtension{ConfigName: "insecure"},
   849  	}
   850  
   851  	configs := map[string]grpctransport.Config{"insecure": {Credentials: insecure.NewBundle()}}
   852  	xdsClientConfig := xdsclient.Config{
   853  		Servers:          []xdsclient.ServerConfig{{ServerIdentifier: si}},
   854  		Node:             clients.Node{ID: nodeID},
   855  		TransportBuilder: grpctransport.NewBuilder(configs),
   856  		ResourceTypes:    resourceTypes,
   857  		// Xdstp style resource names used in this test use a slash removed
   858  		// version of t.Name as their authority, and the empty config
   859  		// results in the top-level xds server configuration being used for
   860  		// this authority.
   861  		Authorities: map[string]xdsclient.Authority{
   862  			authority: {XDSServers: []xdsclient.ServerConfig{}},
   863  		},
   864  	}
   865  
   866  	// Create an xDS client with the above config.
   867  	client, err := xdsclient.New(xdsClientConfig)
   868  	if err != nil {
   869  		t.Fatalf("Failed to create xDS client: %v", err)
   870  	}
   871  	defer client.Close()
   872  
   873  	// Register two watches for two listener resources and have the
   874  	// callbacks push the received updates on to a channel.
   875  	resourceName1 := ldsName
   876  	lw1 := newListenerWatcher()
   877  	ldsCancel1 := client.WatchResource(xdsresource.V3ListenerURL, resourceName1, lw1)
   878  	defer ldsCancel1()
   879  
   880  	resourceName2 := makeNewStyleLDSName(authority)
   881  	lw2 := newListenerWatcher()
   882  	ldsCancel2 := client.WatchResource(xdsresource.V3ListenerURL, resourceName2, lw2)
   883  	defer ldsCancel2()
   884  
   885  	// Configure the management server to return two listener resources,
   886  	// corresponding to the registered watches.
   887  	resources := e2e.UpdateOptions{
   888  		NodeID: nodeID,
   889  		Listeners: []*v3listenerpb.Listener{
   890  			e2e.DefaultClientListener(resourceName1, rdsName),
   891  			e2e.DefaultClientListener(resourceName2, rdsName),
   892  		},
   893  		SkipValidation: true,
   894  	}
   895  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   896  	defer cancel()
   897  	if err := mgmtServer.Update(ctx, resources); err != nil {
   898  		t.Fatalf("Failed to update management server with resources: %v, err: %v", resources, err)
   899  	}
   900  
   901  	// Verify the contents of the received update for both watchers. The two
   902  	// resources returned differ only in the resource name. Therefore the
   903  	// expected update is the same for both watchers.
   904  	wantUpdate := listenerUpdateErrTuple{
   905  		update: listenerUpdate{
   906  			RouteConfigName: rdsName,
   907  		},
   908  	}
   909  	if err := verifyListenerUpdate(ctx, lw1.updateCh, wantUpdate); err != nil {
   910  		t.Fatal(err)
   911  	}
   912  	if err := verifyListenerUpdate(ctx, lw2.updateCh, wantUpdate); err != nil {
   913  		t.Fatal(err)
   914  	}
   915  
   916  	// Remove the first listener resource on the management server.
   917  	resources = e2e.UpdateOptions{
   918  		NodeID:         nodeID,
   919  		Listeners:      []*v3listenerpb.Listener{e2e.DefaultClientListener(resourceName2, rdsName)},
   920  		SkipValidation: true,
   921  	}
   922  	if err := mgmtServer.Update(ctx, resources); err != nil {
   923  		t.Fatalf("Failed to update management server with resources: %v, err: %v", resources, err)
   924  	}
   925  
   926  	// The first watcher should receive a resource error for resource removal,
   927  	// while the second watcher should not see an update.
   928  	if err := verifyListenerUpdate(ctx, lw1.resourceErrCh, listenerUpdateErrTuple{
   929  		resourceErr: xdsresource.NewError(xdsresource.ErrorTypeResourceNotFound, ""),
   930  	}); err != nil {
   931  		t.Fatal(err)
   932  	}
   933  	if err := verifyNoListenerUpdate(ctx, lw2.updateCh); err != nil {
   934  		t.Fatal(err)
   935  	}
   936  
   937  	// Update the second listener resource on the management server. The first
   938  	// watcher should not see an update, while the second watcher should.
   939  	resources = e2e.UpdateOptions{
   940  		NodeID:         nodeID,
   941  		Listeners:      []*v3listenerpb.Listener{e2e.DefaultClientListener(resourceName2, "new-rds-resource")},
   942  		SkipValidation: true,
   943  	}
   944  	if err := mgmtServer.Update(ctx, resources); err != nil {
   945  		t.Fatalf("Failed to update management server with resources: %v, err: %v", resources, err)
   946  	}
   947  	if err := verifyNoListenerUpdate(ctx, lw1.updateCh); err != nil {
   948  		t.Fatal(err)
   949  	}
   950  	wantUpdate = listenerUpdateErrTuple{
   951  		update: listenerUpdate{
   952  			RouteConfigName: "new-rds-resource",
   953  		},
   954  	}
   955  	if err := verifyListenerUpdate(ctx, lw2.updateCh, wantUpdate); err != nil {
   956  		t.Fatal(err)
   957  	}
   958  }
   959  
   960  // TestLDSWatch_NewWatcherForRemovedResource covers the case where a new
   961  // watcher registers for a resource that has been removed. The test verifies
   962  // the following scenarios:
   963  //  1. When a resource is deleted by the management server, any active
   964  //     watchers of that resource should be notified with a "resource removed"
   965  //     error through their watch callback.
   966  //  2. If a new watcher attempts to register for a resource that has already
   967  //     been deleted, its watch callback should be immediately invoked with a
   968  //     "resource removed" error.
   969  func (s) TestLDSWatch_NewWatcherForRemovedResource(t *testing.T) {
   970  	mgmtServer := e2e.StartManagementServer(t, e2e.ManagementServerOptions{})
   971  
   972  	nodeID := uuid.New().String()
   973  
   974  	resourceTypes := map[string]xdsclient.ResourceType{xdsresource.V3ListenerURL: listenerType}
   975  	si := clients.ServerIdentifier{
   976  		ServerURI:  mgmtServer.Address,
   977  		Extensions: grpctransport.ServerIdentifierExtension{ConfigName: "insecure"},
   978  	}
   979  
   980  	configs := map[string]grpctransport.Config{"insecure": {Credentials: insecure.NewBundle()}}
   981  	xdsClientConfig := xdsclient.Config{
   982  		Servers:          []xdsclient.ServerConfig{{ServerIdentifier: si}},
   983  		Node:             clients.Node{ID: nodeID},
   984  		TransportBuilder: grpctransport.NewBuilder(configs),
   985  		ResourceTypes:    resourceTypes,
   986  	}
   987  
   988  	// Create an xDS client with the above config.
   989  	client, err := xdsclient.New(xdsClientConfig)
   990  	if err != nil {
   991  		t.Fatalf("Failed to create xDS client: %v", err)
   992  	}
   993  	defer client.Close()
   994  
   995  	// Register watch for the listener resource and have the
   996  	// callbacks push the received updates on to a channel.
   997  	lw1 := newListenerWatcher()
   998  	ldsCancel1 := client.WatchResource(xdsresource.V3ListenerURL, ldsName, lw1)
   999  	defer ldsCancel1()
  1000  
  1001  	// Configure the management server to return listener resource,
  1002  	// corresponding to the registered watch.
  1003  	resource := e2e.UpdateOptions{
  1004  		NodeID:         nodeID,
  1005  		Listeners:      []*v3listenerpb.Listener{e2e.DefaultClientListener(ldsName, rdsName)},
  1006  		SkipValidation: true,
  1007  	}
  1008  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
  1009  	defer cancel()
  1010  	if err := mgmtServer.Update(ctx, resource); err != nil {
  1011  		t.Fatalf("Failed to update management server with resource: %v, err: %v", resource, err)
  1012  	}
  1013  
  1014  	// Verify the contents of the received update for existing watch.
  1015  	wantUpdate := listenerUpdateErrTuple{
  1016  		update: listenerUpdate{
  1017  			RouteConfigName: rdsName,
  1018  		},
  1019  	}
  1020  	if err := verifyListenerUpdate(ctx, lw1.updateCh, wantUpdate); err != nil {
  1021  		t.Fatal(err)
  1022  	}
  1023  
  1024  	// Remove the listener resource on the management server.
  1025  	resource = e2e.UpdateOptions{
  1026  		NodeID:         nodeID,
  1027  		Listeners:      []*v3listenerpb.Listener{},
  1028  		SkipValidation: true,
  1029  	}
  1030  	if err := mgmtServer.Update(ctx, resource); err != nil {
  1031  		t.Fatalf("Failed to update management server with resource: %v, err: %v", resource, err)
  1032  	}
  1033  
  1034  	// The existing watcher should receive a resource error for resource
  1035  	// removal.
  1036  	updateError := listenerUpdateErrTuple{resourceErr: xdsresource.NewError(xdsresource.ErrorTypeResourceNotFound, "")}
  1037  	if err := verifyListenerUpdate(ctx, lw1.resourceErrCh, updateError); err != nil {
  1038  		t.Fatal(err)
  1039  	}
  1040  
  1041  	// New watchers attempting to register for a deleted resource should also
  1042  	// receive a "resource removed" error.
  1043  	lw2 := newListenerWatcher()
  1044  	ldsCancel2 := client.WatchResource(xdsresource.V3ListenerURL, ldsName, lw2)
  1045  	defer ldsCancel2()
  1046  	if err := verifyListenerUpdate(ctx, lw2.resourceErrCh, updateError); err != nil {
  1047  		t.Fatal(err)
  1048  	}
  1049  }
  1050  
  1051  // TestLDSWatch_NACKError covers the case where an update from the management
  1052  // server is NACKed by the xdsclient. The test verifies that the error is
  1053  // propagated to the existing watcher. After NACK, if a new watcher registers
  1054  // for the resource, error is propagated to the new watcher as well.
  1055  func (s) TestLDSWatch_NACKError(t *testing.T) {
  1056  	mgmtServer := e2e.StartManagementServer(t, e2e.ManagementServerOptions{})
  1057  
  1058  	nodeID := uuid.New().String()
  1059  
  1060  	resourceTypes := map[string]xdsclient.ResourceType{xdsresource.V3ListenerURL: listenerType}
  1061  	si := clients.ServerIdentifier{
  1062  		ServerURI:  mgmtServer.Address,
  1063  		Extensions: grpctransport.ServerIdentifierExtension{ConfigName: "insecure"},
  1064  	}
  1065  
  1066  	configs := map[string]grpctransport.Config{"insecure": {Credentials: insecure.NewBundle()}}
  1067  	xdsClientConfig := xdsclient.Config{
  1068  		Servers:          []xdsclient.ServerConfig{{ServerIdentifier: si}},
  1069  		Node:             clients.Node{ID: nodeID},
  1070  		TransportBuilder: grpctransport.NewBuilder(configs),
  1071  		ResourceTypes:    resourceTypes,
  1072  	}
  1073  
  1074  	// Create an xDS client with the above config.
  1075  	client, err := xdsclient.New(xdsClientConfig)
  1076  	if err != nil {
  1077  		t.Fatalf("Failed to create xDS client: %v", err)
  1078  	}
  1079  	defer client.Close()
  1080  
  1081  	// Register a watch for a listener resource and have the watch
  1082  	// callback push the received update on to a channel.
  1083  	lw := newListenerWatcher()
  1084  	ldsCancel := client.WatchResource(xdsresource.V3ListenerURL, ldsName, lw)
  1085  	defer ldsCancel()
  1086  
  1087  	// Configure the management server to return a single listener resource
  1088  	// which is expected to be NACKed by the client.
  1089  	resources := e2e.UpdateOptions{
  1090  		NodeID:         nodeID,
  1091  		Listeners:      []*v3listenerpb.Listener{badListenerResource(t, ldsName)},
  1092  		SkipValidation: true,
  1093  	}
  1094  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
  1095  	defer cancel()
  1096  	if err := mgmtServer.Update(ctx, resources); err != nil {
  1097  		t.Fatalf("Failed to update management server with resources: %v, err: %v", resources, err)
  1098  	}
  1099  
  1100  	// Verify that the expected error is propagated to the existing watcher.
  1101  	// Since the resource is not cached, it should be received as resource
  1102  	// error.
  1103  	if err := verifyResourceErrorType(ctx, lw.resourceErrCh, xdsresource.ErrorTypeNACKed, nodeID); err != nil {
  1104  		t.Fatal(err)
  1105  	}
  1106  
  1107  	// Verify that the expected error is propagated to the new watcher as well.
  1108  	// Since the resource is not cached, it should be received as resource
  1109  	// error.
  1110  	lw2 := newListenerWatcher()
  1111  	ldsCancel2 := client.WatchResource(xdsresource.V3ListenerURL, ldsName, lw2)
  1112  	defer ldsCancel2()
  1113  	if err := verifyResourceErrorType(ctx, lw2.resourceErrCh, xdsresource.ErrorTypeNACKed, nodeID); err != nil {
  1114  		t.Fatal(err)
  1115  	}
  1116  }
  1117  
  1118  // Tests the scenario where a watch registered for a resource results in a good
  1119  // update followed by a bad update. This results in the resource cache
  1120  // containing both the old good update and the latest NACK error. The test
  1121  // verifies that a when a new watch is registered for the same resource, the new
  1122  // watcher receives the good update followed by the NACK error.
  1123  func (s) TestLDSWatch_ResourceCaching_NACKError(t *testing.T) {
  1124  	mgmtServer := e2e.StartManagementServer(t, e2e.ManagementServerOptions{})
  1125  
  1126  	nodeID := uuid.New().String()
  1127  
  1128  	resourceTypes := map[string]xdsclient.ResourceType{xdsresource.V3ListenerURL: listenerType}
  1129  	si := clients.ServerIdentifier{
  1130  		ServerURI:  mgmtServer.Address,
  1131  		Extensions: grpctransport.ServerIdentifierExtension{ConfigName: "insecure"},
  1132  	}
  1133  
  1134  	configs := map[string]grpctransport.Config{"insecure": {Credentials: insecure.NewBundle()}}
  1135  	xdsClientConfig := xdsclient.Config{
  1136  		Servers:          []xdsclient.ServerConfig{{ServerIdentifier: si}},
  1137  		Node:             clients.Node{ID: nodeID},
  1138  		TransportBuilder: grpctransport.NewBuilder(configs),
  1139  		ResourceTypes:    resourceTypes,
  1140  	}
  1141  
  1142  	// Create an xDS client with the above config.
  1143  	client, err := xdsclient.New(xdsClientConfig)
  1144  	if err != nil {
  1145  		t.Fatalf("Failed to create xDS client: %v", err)
  1146  	}
  1147  	defer client.Close()
  1148  
  1149  	// Register a watch for a listener resource and have the watch
  1150  	// callback push the received update on to a channel.
  1151  	lw1 := newListenerWatcher()
  1152  	ldsCancel1 := client.WatchResource(xdsresource.V3ListenerURL, ldsName, lw1)
  1153  	defer ldsCancel1()
  1154  
  1155  	// Configure the management server to return a single listener
  1156  	// resource, corresponding to the one we registered a watch for.
  1157  	resources := e2e.UpdateOptions{
  1158  		NodeID:         nodeID,
  1159  		Listeners:      []*v3listenerpb.Listener{e2e.DefaultClientListener(ldsName, rdsName)},
  1160  		SkipValidation: true,
  1161  	}
  1162  	ctx, cancel := context.WithTimeout(context.Background(), 1000*defaultTestTimeout)
  1163  	defer cancel()
  1164  	if err := mgmtServer.Update(ctx, resources); err != nil {
  1165  		t.Fatalf("Failed to update management server with resources: %v, err: %v", resources, err)
  1166  	}
  1167  
  1168  	// Verify the contents of the received update.
  1169  	wantUpdate := listenerUpdateErrTuple{
  1170  		update: listenerUpdate{
  1171  			RouteConfigName: rdsName,
  1172  		},
  1173  	}
  1174  	if err := verifyListenerUpdate(ctx, lw1.updateCh, wantUpdate); err != nil {
  1175  		t.Fatal(err)
  1176  	}
  1177  
  1178  	// Configure the management server to return a single listener resource
  1179  	// which is expected to be NACKed by the client.
  1180  	resources = e2e.UpdateOptions{
  1181  		NodeID:         nodeID,
  1182  		Listeners:      []*v3listenerpb.Listener{badListenerResource(t, ldsName)},
  1183  		SkipValidation: true,
  1184  	}
  1185  	if err := mgmtServer.Update(ctx, resources); err != nil {
  1186  		t.Fatalf("Failed to update management server with resources: %v, err: %v", resources, err)
  1187  	}
  1188  
  1189  	// Verify that the expected error is propagated to the existing watcher.
  1190  	// Since the resource is cached, it should be received as ambient error.
  1191  	if err := verifyAmbientErrorType(ctx, lw1.ambientErrCh, xdsresource.ErrorTypeNACKed, nodeID); err != nil {
  1192  		t.Fatal(err)
  1193  	}
  1194  
  1195  	// Register another watch for the same resource. This should get the update
  1196  	// and error from the cache.
  1197  	lw2 := newListenerWatcher()
  1198  	ldsCancel2 := client.WatchResource(xdsresource.V3ListenerURL, ldsName, lw2)
  1199  	defer ldsCancel2()
  1200  	if err := verifyListenerUpdate(ctx, lw2.updateCh, wantUpdate); err != nil {
  1201  		t.Fatal(err)
  1202  	}
  1203  	// Verify that the expected error is propagated to the existing watcher.
  1204  	// Since the resource is cached, it should be received as ambient error.
  1205  	if err := verifyAmbientErrorType(ctx, lw2.ambientErrCh, xdsresource.ErrorTypeNACKed, nodeID); err != nil {
  1206  		t.Fatal(err)
  1207  	}
  1208  }
  1209  
  1210  // TestLDSWatch_PartialValid covers the case where a response from the
  1211  // management server contains both valid and invalid resources and is expected
  1212  // to be NACKed by the xdsclient. The test verifies that watchers corresponding
  1213  // to the valid resource receive the update, while watchers corresponding to the
  1214  // invalid resource receive an error.
  1215  func (s) TestLDSWatch_PartialValid(t *testing.T) {
  1216  	mgmtServer := e2e.StartManagementServer(t, e2e.ManagementServerOptions{})
  1217  
  1218  	nodeID := uuid.New().String()
  1219  	authority := makeAuthorityName(t.Name())
  1220  
  1221  	resourceTypes := map[string]xdsclient.ResourceType{xdsresource.V3ListenerURL: listenerType}
  1222  	si := clients.ServerIdentifier{
  1223  		ServerURI:  mgmtServer.Address,
  1224  		Extensions: grpctransport.ServerIdentifierExtension{ConfigName: "insecure"},
  1225  	}
  1226  
  1227  	configs := map[string]grpctransport.Config{"insecure": {Credentials: insecure.NewBundle()}}
  1228  	xdsClientConfig := xdsclient.Config{
  1229  		Servers:          []xdsclient.ServerConfig{{ServerIdentifier: si}},
  1230  		Node:             clients.Node{ID: nodeID},
  1231  		TransportBuilder: grpctransport.NewBuilder(configs),
  1232  		ResourceTypes:    resourceTypes,
  1233  		// Xdstp style resource names used in this test use a slash removed
  1234  		// version of t.Name as their authority, and the empty config
  1235  		// results in the top-level xds server configuration being used for
  1236  		// this authority.
  1237  		Authorities: map[string]xdsclient.Authority{
  1238  			authority: {XDSServers: []xdsclient.ServerConfig{}},
  1239  		},
  1240  	}
  1241  
  1242  	// Create an xDS client with the above config.
  1243  	client, err := xdsclient.New(xdsClientConfig)
  1244  	if err != nil {
  1245  		t.Fatalf("Failed to create xDS client: %v", err)
  1246  	}
  1247  	defer client.Close()
  1248  
  1249  	// Register two watches for listener resources. The first watch is expected
  1250  	// to receive an error because the received resource is NACKed. The second
  1251  	// watch is expected to get a good update.
  1252  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
  1253  	defer cancel()
  1254  	badResourceName := ldsName
  1255  	lw1 := newListenerWatcher()
  1256  	ldsCancel1 := client.WatchResource(xdsresource.V3ListenerURL, badResourceName, lw1)
  1257  	defer ldsCancel1()
  1258  	goodResourceName := makeNewStyleLDSName(authority)
  1259  	lw2 := newListenerWatcher()
  1260  	ldsCancel2 := client.WatchResource(xdsresource.V3ListenerURL, goodResourceName, lw2)
  1261  	defer ldsCancel2()
  1262  
  1263  	// Configure the management server with two listener resources. One of these
  1264  	// is a bad resource causing the update to be NACKed.
  1265  	resources := e2e.UpdateOptions{
  1266  		NodeID: nodeID,
  1267  		Listeners: []*v3listenerpb.Listener{
  1268  			badListenerResource(t, badResourceName),
  1269  			e2e.DefaultClientListener(goodResourceName, rdsName),
  1270  		},
  1271  		SkipValidation: true,
  1272  	}
  1273  	if err := mgmtServer.Update(ctx, resources); err != nil {
  1274  		t.Fatalf("Failed to update management server with resources: %v, err: %v", resources, err)
  1275  	}
  1276  
  1277  	// Verify that the expected error is propagated to the watcher which
  1278  	// requested for the bad resource.
  1279  	// Verify that the expected error is propagated to the existing watcher.
  1280  	// Since the resource is not cached, it should be received as resource
  1281  	// error.
  1282  	if err := verifyResourceErrorType(ctx, lw1.resourceErrCh, xdsresource.ErrorTypeNACKed, nodeID); err != nil {
  1283  		t.Fatal(err)
  1284  	}
  1285  
  1286  	// Verify that the watcher watching the good resource receives a good
  1287  	// update.
  1288  	wantUpdate := listenerUpdateErrTuple{
  1289  		update: listenerUpdate{
  1290  			RouteConfigName: rdsName,
  1291  		},
  1292  	}
  1293  	if err := verifyListenerUpdate(ctx, lw2.updateCh, wantUpdate); err != nil {
  1294  		t.Fatal(err)
  1295  	}
  1296  }
  1297  
  1298  // TestLDSWatch_PartialResponse covers the case where a response from the
  1299  // management server does not contain all requested resources. LDS responses are
  1300  // supposed to contain all requested resources, and the absence of one usually
  1301  // indicates that the management server does not know about it. In cases where
  1302  // the server has never responded with this resource before, the xDS client is
  1303  // expected to wait for the watch timeout to expire before concluding that the
  1304  // resource does not exist on the server
  1305  func (s) TestLDSWatch_PartialResponse(t *testing.T) {
  1306  	mgmtServer := e2e.StartManagementServer(t, e2e.ManagementServerOptions{})
  1307  
  1308  	nodeID := uuid.New().String()
  1309  	authority := makeAuthorityName(t.Name())
  1310  
  1311  	resourceTypes := map[string]xdsclient.ResourceType{xdsresource.V3ListenerURL: listenerType}
  1312  	si := clients.ServerIdentifier{
  1313  		ServerURI:  mgmtServer.Address,
  1314  		Extensions: grpctransport.ServerIdentifierExtension{ConfigName: "insecure"},
  1315  	}
  1316  
  1317  	configs := map[string]grpctransport.Config{"insecure": {Credentials: insecure.NewBundle()}}
  1318  	xdsClientConfig := xdsclient.Config{
  1319  		Servers:          []xdsclient.ServerConfig{{ServerIdentifier: si}},
  1320  		Node:             clients.Node{ID: nodeID},
  1321  		TransportBuilder: grpctransport.NewBuilder(configs),
  1322  		ResourceTypes:    resourceTypes,
  1323  		// Xdstp style resource names used in this test use a slash removed
  1324  		// version of t.Name as their authority, and the empty config
  1325  		// results in the top-level xds server configuration being used for
  1326  		// this authority.
  1327  		Authorities: map[string]xdsclient.Authority{
  1328  			authority: {XDSServers: []xdsclient.ServerConfig{}},
  1329  		},
  1330  	}
  1331  
  1332  	// Create an xDS client with the above config.
  1333  	client, err := xdsclient.New(xdsClientConfig)
  1334  	if err != nil {
  1335  		t.Fatalf("Failed to create xDS client: %v", err)
  1336  	}
  1337  	defer client.Close()
  1338  
  1339  	// Register two watches for two listener resources and have the
  1340  	// callbacks push the received updates on to a channel.
  1341  	resourceName1 := ldsName
  1342  	lw1 := newListenerWatcher()
  1343  	ldsCancel1 := client.WatchResource(xdsresource.V3ListenerURL, resourceName1, lw1)
  1344  	defer ldsCancel1()
  1345  
  1346  	resourceName2 := makeNewStyleLDSName(authority)
  1347  	lw2 := newListenerWatcher()
  1348  	ldsCancel2 := client.WatchResource(xdsresource.V3ListenerURL, resourceName2, lw2)
  1349  	defer ldsCancel2()
  1350  
  1351  	// Configure the management server to return only one of the two listener
  1352  	// resources, corresponding to the registered watches.
  1353  	resources := e2e.UpdateOptions{
  1354  		NodeID: nodeID,
  1355  		Listeners: []*v3listenerpb.Listener{
  1356  			e2e.DefaultClientListener(resourceName1, rdsName),
  1357  		},
  1358  		SkipValidation: true,
  1359  	}
  1360  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
  1361  	defer cancel()
  1362  	if err := mgmtServer.Update(ctx, resources); err != nil {
  1363  		t.Fatalf("Failed to update management server with resources: %v, err: %v", resources, err)
  1364  	}
  1365  
  1366  	// Verify the contents of the received update for first watcher.
  1367  	wantUpdate1 := listenerUpdateErrTuple{
  1368  		update: listenerUpdate{
  1369  			RouteConfigName: rdsName,
  1370  		},
  1371  	}
  1372  	if err := verifyListenerUpdate(ctx, lw1.updateCh, wantUpdate1); err != nil {
  1373  		t.Fatal(err)
  1374  	}
  1375  
  1376  	// Verify that the second watcher does not get an update with an error.
  1377  	if err := verifyNoListenerUpdate(ctx, lw2.updateCh); err != nil {
  1378  		t.Fatal(err)
  1379  	}
  1380  
  1381  	// Configure the management server to return two listener resources,
  1382  	// corresponding to the registered watches.
  1383  	resources = e2e.UpdateOptions{
  1384  		NodeID: nodeID,
  1385  		Listeners: []*v3listenerpb.Listener{
  1386  			e2e.DefaultClientListener(resourceName1, rdsName),
  1387  			e2e.DefaultClientListener(resourceName2, rdsName),
  1388  		},
  1389  		SkipValidation: true,
  1390  	}
  1391  	if err := mgmtServer.Update(ctx, resources); err != nil {
  1392  		t.Fatalf("Failed to update management server with resources: %v, err: %v", resources, err)
  1393  	}
  1394  
  1395  	// Verify the contents of the received update for the second watcher.
  1396  	wantUpdate2 := listenerUpdateErrTuple{
  1397  		update: listenerUpdate{
  1398  			RouteConfigName: rdsName,
  1399  		},
  1400  	}
  1401  	if err := verifyListenerUpdate(ctx, lw2.updateCh, wantUpdate2); err != nil {
  1402  		t.Fatal(err)
  1403  	}
  1404  
  1405  	// Verify that the first watcher gets no update, as the first resource did
  1406  	// not change.
  1407  	if err := verifyNoListenerUpdate(ctx, lw1.updateCh); err != nil {
  1408  		t.Fatal(err)
  1409  	}
  1410  }