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