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 }