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