github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/grpc/xds/internal/xdsclient/authority_test.go (about)

     1  /*
     2   *
     3   * Copyright 2021 gRPC authors.
     4   *
     5   * Licensed under the Apache License, Version 2.0 (the "License");
     6   * you may not use this file except in compliance with the License.
     7   * You may obtain a copy of the License at
     8   *
     9   *     http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   */
    17  
    18  package xdsclient
    19  
    20  import (
    21  	"testing"
    22  	"time"
    23  
    24  	"github.com/google/go-cmp/cmp"
    25  	"github.com/google/go-cmp/cmp/cmpopts"
    26  	grpc "github.com/hxx258456/ccgo/grpc"
    27  	"github.com/hxx258456/ccgo/grpc/credentials/insecure"
    28  	"github.com/hxx258456/ccgo/grpc/internal/testutils"
    29  	xdstestutils "github.com/hxx258456/ccgo/grpc/xds/internal/testutils"
    30  	"github.com/hxx258456/ccgo/grpc/xds/internal/xdsclient/bootstrap"
    31  	"github.com/hxx258456/ccgo/grpc/xds/internal/xdsclient/xdsresource"
    32  	"github.com/hxx258456/ccgo/grpc/xds/internal/xdsclient/xdsresource/version"
    33  	"google.golang.org/protobuf/testing/protocmp"
    34  )
    35  
    36  var (
    37  	serverConfigs = []*bootstrap.ServerConfig{
    38  		{
    39  			ServerURI:    testXDSServer + "0",
    40  			Creds:        grpc.WithTransportCredentials(insecure.NewCredentials()),
    41  			CredsType:    "creds-0",
    42  			TransportAPI: version.TransportV2,
    43  			NodeProto:    xdstestutils.EmptyNodeProtoV2,
    44  		},
    45  		{
    46  			ServerURI:    testXDSServer + "1",
    47  			Creds:        grpc.WithTransportCredentials(insecure.NewCredentials()),
    48  			CredsType:    "creds-1",
    49  			TransportAPI: version.TransportV3,
    50  			NodeProto:    xdstestutils.EmptyNodeProtoV3,
    51  		},
    52  		{
    53  			ServerURI:    testXDSServer + "2",
    54  			Creds:        grpc.WithTransportCredentials(insecure.NewCredentials()),
    55  			CredsType:    "creds-2",
    56  			TransportAPI: version.TransportV2,
    57  			NodeProto:    xdstestutils.EmptyNodeProtoV2,
    58  		},
    59  	}
    60  
    61  	serverConfigCmpOptions = cmp.Options{
    62  		cmpopts.IgnoreFields(bootstrap.ServerConfig{}, "Creds"),
    63  		protocmp.Transform(),
    64  	}
    65  )
    66  
    67  // watchAndFetchNewController starts a CDS watch on the client for the given
    68  // resourceName, and tries to receive a new controller from the ctrlCh.
    69  //
    70  // It returns false if there's no controller in the ctrlCh.
    71  func watchAndFetchNewController(t *testing.T, client *clientImpl, resourceName string, ctrlCh *testutils.Channel) (*testController, bool, func()) {
    72  	updateCh := testutils.NewChannel()
    73  	cancelWatch := client.WatchCluster(resourceName, func(update xdsresource.ClusterUpdate, err error) {
    74  		updateCh.Send(xdsresource.ClusterUpdateErrTuple{Update: update, Err: err})
    75  	})
    76  
    77  	// Clear the item in the watch channel, otherwise the next watch will block.
    78  	authority := xdsresource.ParseName(resourceName).Authority
    79  	var config *bootstrap.ServerConfig
    80  	if authority == "" {
    81  		config = client.config.XDSServer
    82  	} else {
    83  		authConfig, ok := client.config.Authorities[authority]
    84  		if !ok {
    85  			t.Fatalf("failed to find authority %q", authority)
    86  		}
    87  		config = authConfig.XDSServer
    88  	}
    89  	a := client.authorities[config.String()]
    90  	if a == nil {
    91  		t.Fatalf("authority for %q is not created", authority)
    92  	}
    93  	ctrlTemp := a.controller.(*testController)
    94  	// Clear the channel so the next watch on this controller can proceed.
    95  	ctrlTemp.addWatches[xdsresource.ClusterResource].ReceiveOrFail()
    96  
    97  	cancelWatchRet := func() {
    98  		cancelWatch()
    99  		ctrlTemp.removeWatches[xdsresource.ClusterResource].ReceiveOrFail()
   100  	}
   101  
   102  	// Try to receive a new controller.
   103  	c, ok := ctrlCh.ReceiveOrFail()
   104  	if !ok {
   105  		return nil, false, cancelWatchRet
   106  	}
   107  	ctrl := c.(*testController)
   108  	return ctrl, true, cancelWatchRet
   109  }
   110  
   111  // TestAuthorityDefaultAuthority covers that a watch for an old style resource
   112  // name (one without authority) builds a controller using the top level server
   113  // config.
   114  func (s) TestAuthorityDefaultAuthority(t *testing.T) {
   115  	overrideFedEnvVar(t)
   116  	ctrlCh := overrideNewController(t)
   117  
   118  	client, err := newWithConfig(&bootstrap.Config{
   119  		XDSServer:   serverConfigs[0],
   120  		Authorities: map[string]*bootstrap.Authority{testAuthority: {XDSServer: serverConfigs[1]}},
   121  	}, defaultWatchExpiryTimeout, defaultIdleAuthorityDeleteTimeout)
   122  	if err != nil {
   123  		t.Fatalf("failed to create client: %v", err)
   124  	}
   125  	t.Cleanup(client.Close)
   126  
   127  	ctrl, ok, _ := watchAndFetchNewController(t, client, testCDSName, ctrlCh)
   128  	if !ok {
   129  		t.Fatalf("want a new controller to be built, got none")
   130  	}
   131  	// Want the default server config.
   132  	wantConfig := serverConfigs[0]
   133  	if diff := cmp.Diff(ctrl.config, wantConfig, serverConfigCmpOptions); diff != "" {
   134  		t.Fatalf("controller is built with unexpected config, diff (-got +want): %v", diff)
   135  	}
   136  }
   137  
   138  // TestAuthorityNoneDefaultAuthority covers that a watch with a new style
   139  // resource name creates a controller with the corresponding server config.
   140  func (s) TestAuthorityNoneDefaultAuthority(t *testing.T) {
   141  	overrideFedEnvVar(t)
   142  	ctrlCh := overrideNewController(t)
   143  
   144  	client, err := newWithConfig(&bootstrap.Config{
   145  		XDSServer:   serverConfigs[0],
   146  		Authorities: map[string]*bootstrap.Authority{testAuthority: {XDSServer: serverConfigs[1]}},
   147  	}, defaultWatchExpiryTimeout, defaultIdleAuthorityDeleteTimeout)
   148  	if err != nil {
   149  		t.Fatalf("failed to create client: %v", err)
   150  	}
   151  	t.Cleanup(client.Close)
   152  
   153  	resourceName := xdstestutils.BuildResourceName(xdsresource.ClusterResource, testAuthority, testCDSName, nil)
   154  	ctrl, ok, _ := watchAndFetchNewController(t, client, resourceName, ctrlCh)
   155  	if !ok {
   156  		t.Fatalf("want a new controller to be built, got none")
   157  	}
   158  	// Want the server config for this authority.
   159  	wantConfig := serverConfigs[1]
   160  	if diff := cmp.Diff(ctrl.config, wantConfig, serverConfigCmpOptions); diff != "" {
   161  		t.Fatalf("controller is built with unexpected config, diff (-got +want): %v", diff)
   162  	}
   163  }
   164  
   165  // TestAuthorityShare covers that
   166  // - watch with the same authority name doesn't create new authority
   167  // - watch with different authority name but same authority config doesn't
   168  //   create new authority
   169  func (s) TestAuthorityShare(t *testing.T) {
   170  	overrideFedEnvVar(t)
   171  	ctrlCh := overrideNewController(t)
   172  
   173  	client, err := newWithConfig(&bootstrap.Config{
   174  		XDSServer: serverConfigs[0],
   175  		Authorities: map[string]*bootstrap.Authority{
   176  			testAuthority:  {XDSServer: serverConfigs[1]},
   177  			testAuthority2: {XDSServer: serverConfigs[1]}, // Another authority name, but with the same config.
   178  		},
   179  	}, defaultWatchExpiryTimeout, defaultIdleAuthorityDeleteTimeout)
   180  	if err != nil {
   181  		t.Fatalf("failed to create client: %v", err)
   182  	}
   183  	t.Cleanup(client.Close)
   184  
   185  	resourceName := xdstestutils.BuildResourceName(xdsresource.ClusterResource, testAuthority, testCDSName, nil)
   186  	ctrl1, ok1, _ := watchAndFetchNewController(t, client, resourceName, ctrlCh)
   187  	if !ok1 {
   188  		t.Fatalf("want a new controller to be built, got none")
   189  	}
   190  	// Want the server config for this authority.
   191  	wantConfig := serverConfigs[1]
   192  	if diff := cmp.Diff(ctrl1.config, wantConfig, serverConfigCmpOptions); diff != "" {
   193  		t.Fatalf("controller is built with unexpected config, diff (-got +want): %v", diff)
   194  	}
   195  
   196  	// Call the watch with the same authority name. This shouldn't create a new
   197  	// controller.
   198  	resourceNameSameAuthority := xdstestutils.BuildResourceName(xdsresource.ClusterResource, testAuthority, testCDSName+"1", nil)
   199  	ctrl2, ok2, _ := watchAndFetchNewController(t, client, resourceNameSameAuthority, ctrlCh)
   200  	if ok2 {
   201  		t.Fatalf("an unexpected controller is built with config: %v", ctrl2.config)
   202  	}
   203  
   204  	// Call the watch with a different authority name, but the same server
   205  	// config. This shouldn't create a new controller.
   206  	resourceNameSameConfig := xdstestutils.BuildResourceName(xdsresource.ClusterResource, testAuthority2, testCDSName+"1", nil)
   207  	if ctrl, ok, _ := watchAndFetchNewController(t, client, resourceNameSameConfig, ctrlCh); ok {
   208  		t.Fatalf("an unexpected controller is built with config: %v", ctrl.config)
   209  	}
   210  }
   211  
   212  // TestAuthorityIdle covers that
   213  // - authorities are put in a timeout cache when the last watch is canceled
   214  // - idle authorities are not immediately closed. They will be closed after a
   215  //   timeout.
   216  func (s) TestAuthorityIdleTimeout(t *testing.T) {
   217  	overrideFedEnvVar(t)
   218  	ctrlCh := overrideNewController(t)
   219  
   220  	const idleTimeout = 50 * time.Millisecond
   221  
   222  	client, err := newWithConfig(&bootstrap.Config{
   223  		XDSServer: serverConfigs[0],
   224  		Authorities: map[string]*bootstrap.Authority{
   225  			testAuthority: {XDSServer: serverConfigs[1]},
   226  		},
   227  	}, defaultWatchExpiryTimeout, idleTimeout)
   228  	if err != nil {
   229  		t.Fatalf("failed to create client: %v", err)
   230  	}
   231  	t.Cleanup(client.Close)
   232  
   233  	resourceName := xdstestutils.BuildResourceName(xdsresource.ClusterResource, testAuthority, testCDSName, nil)
   234  	ctrl1, ok1, cancelWatch1 := watchAndFetchNewController(t, client, resourceName, ctrlCh)
   235  	if !ok1 {
   236  		t.Fatalf("want a new controller to be built, got none")
   237  	}
   238  
   239  	var cancelWatch2 func()
   240  	// Call the watch with the same authority name. This shouldn't create a new
   241  	// controller.
   242  	resourceNameSameAuthority := xdstestutils.BuildResourceName(xdsresource.ClusterResource, testAuthority, testCDSName+"1", nil)
   243  	ctrl2, ok2, cancelWatch2 := watchAndFetchNewController(t, client, resourceNameSameAuthority, ctrlCh)
   244  	if ok2 {
   245  		t.Fatalf("an unexpected controller is built with config: %v", ctrl2.config)
   246  	}
   247  
   248  	cancelWatch1()
   249  	if ctrl1.done.HasFired() {
   250  		t.Fatalf("controller is closed immediately when the watch is canceled, wanted to be put in the idle cache")
   251  	}
   252  
   253  	// Cancel the second watch, should put controller in the idle cache.
   254  	cancelWatch2()
   255  	if ctrl1.done.HasFired() {
   256  		t.Fatalf("controller is closed when the second watch is closed")
   257  	}
   258  
   259  	time.Sleep(idleTimeout * 2)
   260  	if !ctrl1.done.HasFired() {
   261  		t.Fatalf("controller is not closed after idle timeout")
   262  	}
   263  }
   264  
   265  // TestAuthorityClientClose covers that the authorities in use and in idle cache
   266  // are all closed when the client is closed.
   267  func (s) TestAuthorityClientClose(t *testing.T) {
   268  	overrideFedEnvVar(t)
   269  	ctrlCh := overrideNewController(t)
   270  
   271  	client, err := newWithConfig(&bootstrap.Config{
   272  		XDSServer: serverConfigs[0],
   273  		Authorities: map[string]*bootstrap.Authority{
   274  			testAuthority: {XDSServer: serverConfigs[1]},
   275  		},
   276  	}, defaultWatchExpiryTimeout, defaultIdleAuthorityDeleteTimeout)
   277  	if err != nil {
   278  		t.Fatalf("failed to create client: %v", err)
   279  	}
   280  	t.Cleanup(client.Close)
   281  
   282  	resourceName := testCDSName
   283  	ctrl1, ok1, cancelWatch1 := watchAndFetchNewController(t, client, resourceName, ctrlCh)
   284  	if !ok1 {
   285  		t.Fatalf("want a new controller to be built, got none")
   286  	}
   287  
   288  	resourceNameWithAuthority := xdstestutils.BuildResourceName(xdsresource.ClusterResource, testAuthority, testCDSName, nil)
   289  	ctrl2, ok2, _ := watchAndFetchNewController(t, client, resourceNameWithAuthority, ctrlCh)
   290  	if !ok2 {
   291  		t.Fatalf("want a new controller to be built, got none")
   292  	}
   293  
   294  	cancelWatch1()
   295  	if ctrl1.done.HasFired() {
   296  		t.Fatalf("controller is closed immediately when the watch is canceled, wanted to be put in the idle cache")
   297  	}
   298  
   299  	// Close the client while watch2 is not canceled. ctrl1 is in the idle
   300  	// cache, ctrl2 is in use. Both should be closed.
   301  	client.Close()
   302  
   303  	if !ctrl1.done.HasFired() {
   304  		t.Fatalf("controller in idle cache is not closed after client is closed")
   305  	}
   306  	if !ctrl2.done.HasFired() {
   307  		t.Fatalf("controller in use is not closed after client is closed")
   308  	}
   309  }
   310  
   311  // TestAuthorityRevive covers that the authorities in the idle cache is revived
   312  // when a new watch is started on this authority.
   313  func (s) TestAuthorityRevive(t *testing.T) {
   314  	overrideFedEnvVar(t)
   315  	ctrlCh := overrideNewController(t)
   316  
   317  	const idleTimeout = 50 * time.Millisecond
   318  
   319  	client, err := newWithConfig(&bootstrap.Config{
   320  		XDSServer: serverConfigs[0],
   321  		Authorities: map[string]*bootstrap.Authority{
   322  			testAuthority: {XDSServer: serverConfigs[1]},
   323  		},
   324  	}, defaultWatchExpiryTimeout, idleTimeout)
   325  	if err != nil {
   326  		t.Fatalf("failed to create client: %v", err)
   327  	}
   328  	t.Cleanup(client.Close)
   329  
   330  	// Start a watch on the authority, and cancel it. This puts the authority in
   331  	// the idle cache.
   332  	resourceName := xdstestutils.BuildResourceName(xdsresource.ClusterResource, testAuthority, testCDSName, nil)
   333  	ctrl1, ok1, cancelWatch1 := watchAndFetchNewController(t, client, resourceName, ctrlCh)
   334  	if !ok1 {
   335  		t.Fatalf("want a new controller to be built, got none")
   336  	}
   337  	cancelWatch1()
   338  
   339  	// Start another watch on this authority, it should retrieve the authority
   340  	// from the cache, instead of creating a new one.
   341  	resourceNameWithAuthority := xdstestutils.BuildResourceName(xdsresource.ClusterResource, testAuthority, testCDSName+"1", nil)
   342  	ctrl2, ok2, _ := watchAndFetchNewController(t, client, resourceNameWithAuthority, ctrlCh)
   343  	if ok2 {
   344  		t.Fatalf("an unexpected controller is built with config: %v", ctrl2.config)
   345  	}
   346  
   347  	// Wait for double the idle timeout, the controller shouldn't be closed,
   348  	// since it was revived.
   349  	time.Sleep(idleTimeout * 2)
   350  	if ctrl1.done.HasFired() {
   351  		t.Fatalf("controller that was revived is closed after timeout, want not closed")
   352  	}
   353  }