gitee.com/ks-custle/core-gm@v0.0.0-20230922171213-b83bdd97b62c/grpc/xds/internal/xdsclient/watchers_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 "context" 22 "fmt" 23 "testing" 24 25 "gitee.com/ks-custle/core-gm/grpc/internal/testutils" 26 xdstestutils "gitee.com/ks-custle/core-gm/grpc/xds/internal/testutils" 27 "gitee.com/ks-custle/core-gm/grpc/xds/internal/xdsclient/bootstrap" 28 "gitee.com/ks-custle/core-gm/grpc/xds/internal/xdsclient/pubsub" 29 "gitee.com/ks-custle/core-gm/grpc/xds/internal/xdsclient/xdsresource" 30 "google.golang.org/protobuf/types/known/anypb" 31 ) 32 33 // testClientSetup sets up the client and controller for the test. It returns a 34 // newly created client, and a channel where new controllers will be sent to. 35 func testClientSetup(t *testing.T, overrideWatchExpiryTimeout bool) (*clientImpl, *testutils.Channel) { 36 t.Helper() 37 ctrlCh := overrideNewController(t) 38 39 watchExpiryTimeout := defaultWatchExpiryTimeout 40 if overrideWatchExpiryTimeout { 41 watchExpiryTimeout = defaultTestWatchExpiryTimeout 42 } 43 44 client, err := newWithConfig(clientOpts(), watchExpiryTimeout, defaultIdleAuthorityDeleteTimeout) 45 if err != nil { 46 t.Fatalf("failed to create client: %v", err) 47 } 48 t.Cleanup(client.Close) 49 return client, ctrlCh 50 } 51 52 // newWatch starts a new watch on the client. 53 func newWatch(t *testing.T, client *clientImpl, typ xdsresource.ResourceType, resourceName string) (updateCh *testutils.Channel, cancelWatch func()) { 54 newWatchF, _, _ := typeToTestFuncs(typ) 55 updateCh, cancelWatch = newWatchF(client, resourceName) 56 t.Cleanup(cancelWatch) 57 58 if u, ok := updateCh.ReceiveOrFail(); ok { 59 t.Fatalf("received unexpected update immediately after watch: %+v", u) 60 } 61 return 62 } 63 64 // getControllerAndPubsub returns the controller and pubsub for the given 65 // type+resourceName from the client. 66 func getControllerAndPubsub(ctx context.Context, t *testing.T, client *clientImpl, ctrlCh *testutils.Channel, typ xdsresource.ResourceType, resourceName string) (*testController, pubsub.UpdateHandler) { 67 c, err := ctrlCh.Receive(ctx) 68 if err != nil { 69 t.Fatalf("timeout when waiting for API client to be created: %v", err) 70 } 71 ctrl := c.(*testController) 72 73 if _, err := ctrl.addWatches[typ].Receive(ctx); err != nil { 74 t.Fatalf("want new watch to start, got error %v", err) 75 } 76 77 updateHandler := findPubsubForTest(t, client, xdsresource.ParseName(resourceName).Authority) 78 79 return ctrl, updateHandler 80 } 81 82 // findPubsubForTest returns the pubsub for the given authority, to send updates 83 // to. If authority is "", the default is returned. If the authority is not 84 // found, the test will fail. 85 func findPubsubForTest(t *testing.T, c *clientImpl, authority string) pubsub.UpdateHandler { 86 t.Helper() 87 var config *bootstrap.ServerConfig 88 if authority == "" { 89 config = c.config.XDSServer 90 } else { 91 authConfig, ok := c.config.Authorities[authority] 92 if !ok { 93 t.Fatalf("failed to find authority %q", authority) 94 } 95 config = authConfig.XDSServer 96 } 97 a := c.authorities[config.String()] 98 if a == nil { 99 t.Fatalf("authority for %q is not created", authority) 100 } 101 return a.pubsub 102 } 103 104 var ( 105 newLDSWatchF = func(client *clientImpl, resourceName string) (*testutils.Channel, func()) { 106 updateCh := testutils.NewChannel() 107 cancelLastWatch := client.WatchListener(resourceName, func(update xdsresource.ListenerUpdate, err error) { 108 updateCh.Send(xdsresource.ListenerUpdateErrTuple{Update: update, Err: err}) 109 }) 110 return updateCh, cancelLastWatch 111 } 112 newLDSUpdateF = func(updateHandler pubsub.UpdateHandler, updates map[string]interface{}) { 113 wantUpdates := map[string]xdsresource.ListenerUpdateErrTuple{} 114 for n, u := range updates { 115 wantUpdate := u.(xdsresource.ListenerUpdate) 116 wantUpdates[n] = xdsresource.ListenerUpdateErrTuple{Update: wantUpdate} 117 } 118 updateHandler.NewListeners(wantUpdates, xdsresource.UpdateMetadata{}) 119 } 120 verifyLDSUpdateF = func(ctx context.Context, t *testing.T, updateCh *testutils.Channel, update interface{}, err error) { 121 t.Helper() 122 wantUpdate := update.(xdsresource.ListenerUpdate) 123 if err := verifyListenerUpdate(ctx, updateCh, wantUpdate, err); err != nil { 124 t.Fatal(err) 125 } 126 } 127 128 newRDSWatchF = func(client *clientImpl, resourceName string) (*testutils.Channel, func()) { 129 updateCh := testutils.NewChannel() 130 cancelLastWatch := client.WatchRouteConfig(resourceName, func(update xdsresource.RouteConfigUpdate, err error) { 131 updateCh.Send(xdsresource.RouteConfigUpdateErrTuple{Update: update, Err: err}) 132 }) 133 return updateCh, cancelLastWatch 134 } 135 newRDSUpdateF = func(updateHandler pubsub.UpdateHandler, updates map[string]interface{}) { 136 wantUpdates := map[string]xdsresource.RouteConfigUpdateErrTuple{} 137 for n, u := range updates { 138 wantUpdate := u.(xdsresource.RouteConfigUpdate) 139 wantUpdates[n] = xdsresource.RouteConfigUpdateErrTuple{Update: wantUpdate} 140 } 141 updateHandler.NewRouteConfigs(wantUpdates, xdsresource.UpdateMetadata{}) 142 } 143 verifyRDSUpdateF = func(ctx context.Context, t *testing.T, updateCh *testutils.Channel, update interface{}, err error) { 144 t.Helper() 145 wantUpdate := update.(xdsresource.RouteConfigUpdate) 146 if err := verifyRouteConfigUpdate(ctx, updateCh, wantUpdate, err); err != nil { 147 t.Fatal(err) 148 } 149 } 150 151 newCDSWatchF = func(client *clientImpl, resourceName string) (*testutils.Channel, func()) { 152 updateCh := testutils.NewChannel() 153 cancelLastWatch := client.WatchCluster(resourceName, func(update xdsresource.ClusterUpdate, err error) { 154 updateCh.Send(xdsresource.ClusterUpdateErrTuple{Update: update, Err: err}) 155 }) 156 return updateCh, cancelLastWatch 157 } 158 newCDSUpdateF = func(updateHandler pubsub.UpdateHandler, updates map[string]interface{}) { 159 wantUpdates := map[string]xdsresource.ClusterUpdateErrTuple{} 160 for n, u := range updates { 161 wantUpdate := u.(xdsresource.ClusterUpdate) 162 wantUpdates[n] = xdsresource.ClusterUpdateErrTuple{Update: wantUpdate} 163 } 164 updateHandler.NewClusters(wantUpdates, xdsresource.UpdateMetadata{}) 165 } 166 verifyCDSUpdateF = func(ctx context.Context, t *testing.T, updateCh *testutils.Channel, update interface{}, err error) { 167 t.Helper() 168 wantUpdate := update.(xdsresource.ClusterUpdate) 169 if err := verifyClusterUpdate(ctx, updateCh, wantUpdate, err); err != nil { 170 t.Fatal(err) 171 } 172 } 173 174 newEDSWatchF = func(client *clientImpl, resourceName string) (*testutils.Channel, func()) { 175 updateCh := testutils.NewChannel() 176 cancelLastWatch := client.WatchEndpoints(resourceName, func(update xdsresource.EndpointsUpdate, err error) { 177 updateCh.Send(xdsresource.EndpointsUpdateErrTuple{Update: update, Err: err}) 178 }) 179 return updateCh, cancelLastWatch 180 } 181 newEDSUpdateF = func(updateHandler pubsub.UpdateHandler, updates map[string]interface{}) { 182 wantUpdates := map[string]xdsresource.EndpointsUpdateErrTuple{} 183 for n, u := range updates { 184 wantUpdate := u.(xdsresource.EndpointsUpdate) 185 wantUpdates[n] = xdsresource.EndpointsUpdateErrTuple{Update: wantUpdate} 186 } 187 updateHandler.NewEndpoints(wantUpdates, xdsresource.UpdateMetadata{}) 188 } 189 verifyEDSUpdateF = func(ctx context.Context, t *testing.T, updateCh *testutils.Channel, update interface{}, err error) { 190 t.Helper() 191 wantUpdate := update.(xdsresource.EndpointsUpdate) 192 if err := verifyEndpointsUpdate(ctx, updateCh, wantUpdate, err); err != nil { 193 t.Fatal(err) 194 } 195 } 196 ) 197 198 func typeToTestFuncs(typ xdsresource.ResourceType) ( 199 newWatchF func(client *clientImpl, resourceName string) (*testutils.Channel, func()), 200 newUpdateF func(updateHandler pubsub.UpdateHandler, updates map[string]interface{}), 201 verifyUpdateF func(ctx context.Context, t *testing.T, updateCh *testutils.Channel, update interface{}, err error), 202 ) { 203 switch typ { 204 case xdsresource.ListenerResource: 205 newWatchF = newLDSWatchF 206 newUpdateF = newLDSUpdateF 207 verifyUpdateF = verifyLDSUpdateF 208 case xdsresource.RouteConfigResource: 209 newWatchF = newRDSWatchF 210 newUpdateF = newRDSUpdateF 211 verifyUpdateF = verifyRDSUpdateF 212 case xdsresource.ClusterResource: 213 newWatchF = newCDSWatchF 214 newUpdateF = newCDSUpdateF 215 verifyUpdateF = verifyCDSUpdateF 216 case xdsresource.EndpointsResource: 217 newWatchF = newEDSWatchF 218 newUpdateF = newEDSUpdateF 219 verifyUpdateF = verifyEDSUpdateF 220 } 221 return 222 } 223 224 // TestClusterWatch covers the cases: 225 // - an update is received after a watch() 226 // - an update for another resource name 227 // - an update is received after cancel() 228 func testWatch(t *testing.T, typ xdsresource.ResourceType, update interface{}, resourceName string) { 229 overrideFedEnvVar(t) 230 for _, rName := range []string{resourceName, xdstestutils.BuildResourceName(typ, testAuthority, resourceName, nil)} { 231 t.Run(rName, func(t *testing.T) { 232 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 233 defer cancel() 234 client, ctrlCh := testClientSetup(t, false) 235 updateCh, cancelWatch := newWatch(t, client, typ, rName) 236 _, updateHandler := getControllerAndPubsub(ctx, t, client, ctrlCh, typ, rName) 237 _, newUpdateF, verifyUpdateF := typeToTestFuncs(typ) 238 239 // Send an update, and check the result. 240 newUpdateF(updateHandler, map[string]interface{}{rName: update}) 241 verifyUpdateF(ctx, t, updateCh, update, nil) 242 243 // Push an update, with an extra resource for a different resource name. 244 // Specify a non-nil raw proto in the original resource to ensure that the 245 // new update is not considered equal to the old one. 246 var newUpdate interface{} 247 switch typ { 248 case xdsresource.ListenerResource: 249 newU := update.(xdsresource.ListenerUpdate) 250 newU.Raw = &anypb.Any{} 251 newUpdate = newU 252 case xdsresource.RouteConfigResource: 253 newU := update.(xdsresource.RouteConfigUpdate) 254 newU.Raw = &anypb.Any{} 255 newUpdate = newU 256 case xdsresource.ClusterResource: 257 newU := update.(xdsresource.ClusterUpdate) 258 newU.Raw = &anypb.Any{} 259 newUpdate = newU 260 case xdsresource.EndpointsResource: 261 newU := update.(xdsresource.EndpointsUpdate) 262 newU.Raw = &anypb.Any{} 263 newUpdate = newU 264 } 265 newUpdateF(updateHandler, map[string]interface{}{rName: newUpdate}) 266 verifyUpdateF(ctx, t, updateCh, newUpdate, nil) 267 268 // Cancel watch, and send update again. 269 cancelWatch() 270 newUpdateF(updateHandler, map[string]interface{}{rName: update}) 271 sCtx, sCancel := context.WithTimeout(ctx, defaultTestShortTimeout) 272 defer sCancel() 273 if u, err := updateCh.Receive(sCtx); err != context.DeadlineExceeded { 274 t.Errorf("unexpected update: %v, %v, want channel recv timeout", u, err) 275 } 276 }) 277 } 278 } 279 280 // testClusterTwoWatchSameResourceName covers the case where an update is 281 // received after two watch() for the same resource name. 282 func testTwoWatchSameResourceName(t *testing.T, typ xdsresource.ResourceType, update interface{}, resourceName string) { 283 overrideFedEnvVar(t) 284 for _, rName := range []string{resourceName, xdstestutils.BuildResourceName(typ, testAuthority, resourceName, nil)} { 285 t.Run(rName, func(t *testing.T) { 286 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 287 defer cancel() 288 client, ctrlCh := testClientSetup(t, false) 289 updateCh, _ := newWatch(t, client, typ, resourceName) 290 _, updateHandler := getControllerAndPubsub(ctx, t, client, ctrlCh, typ, resourceName) 291 newWatchF, newUpdateF, verifyUpdateF := typeToTestFuncs(typ) 292 293 updateChs := []*testutils.Channel{updateCh} 294 var cancelLastWatch func() 295 const count = 1 296 for i := 0; i < count; i++ { 297 var updateCh *testutils.Channel 298 updateCh, cancelLastWatch = newWatchF(client, resourceName) 299 updateChs = append(updateChs, updateCh) 300 } 301 302 newUpdateF(updateHandler, map[string]interface{}{resourceName: update}) 303 for i := 0; i < count+1; i++ { 304 verifyUpdateF(ctx, t, updateChs[i], update, nil) 305 } 306 307 // Cancel the last watch, and send update again. None of the watchers should 308 // be notified because one has been cancelled, and the other is receiving 309 // the same update. 310 cancelLastWatch() 311 newUpdateF(updateHandler, map[string]interface{}{resourceName: update}) 312 for i := 0; i < count+1; i++ { 313 func() { 314 sCtx, sCancel := context.WithTimeout(ctx, defaultTestShortTimeout) 315 defer sCancel() 316 if u, err := updateChs[i].Receive(sCtx); err != context.DeadlineExceeded { 317 t.Errorf("unexpected update: %v, %v, want channel recv timeout", u, err) 318 } 319 }() 320 } 321 322 // Push a new update and make sure the uncancelled watcher is invoked. 323 // Specify a non-nil raw proto to ensure that the new update is not 324 // considered equal to the old one. 325 var newUpdate interface{} 326 switch typ { 327 case xdsresource.ListenerResource: 328 newU := update.(xdsresource.ListenerUpdate) 329 newU.Raw = &anypb.Any{} 330 newUpdate = newU 331 case xdsresource.RouteConfigResource: 332 newU := update.(xdsresource.RouteConfigUpdate) 333 newU.Raw = &anypb.Any{} 334 newUpdate = newU 335 case xdsresource.ClusterResource: 336 newU := update.(xdsresource.ClusterUpdate) 337 newU.Raw = &anypb.Any{} 338 newUpdate = newU 339 case xdsresource.EndpointsResource: 340 newU := update.(xdsresource.EndpointsUpdate) 341 newU.Raw = &anypb.Any{} 342 newUpdate = newU 343 } 344 newUpdateF(updateHandler, map[string]interface{}{resourceName: newUpdate}) 345 verifyUpdateF(ctx, t, updateCh, newUpdate, nil) 346 }) 347 } 348 } 349 350 // testThreeWatchDifferentResourceName starts two watches for name1, and one 351 // watch for name2. This test verifies that two watches for name1 receive the 352 // same update, and name2 watch receives a different update. 353 func testThreeWatchDifferentResourceName(t *testing.T, typ xdsresource.ResourceType, update1 interface{}, resourceName1 string, update2 interface{}, resourceName2 string) { 354 overrideFedEnvVar(t) 355 for _, rName := range [][]string{ 356 {resourceName1, resourceName2}, 357 {xdstestutils.BuildResourceName(typ, testAuthority, resourceName1, nil), xdstestutils.BuildResourceName(typ, testAuthority, resourceName2, nil)}, 358 } { 359 t.Run(rName[0], func(t *testing.T) { 360 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 361 defer cancel() 362 client, ctrlCh := testClientSetup(t, false) 363 updateCh, _ := newWatch(t, client, typ, rName[0]) 364 _, updateHandler := getControllerAndPubsub(ctx, t, client, ctrlCh, typ, rName[0]) 365 newWatchF, newUpdateF, verifyUpdateF := typeToTestFuncs(typ) 366 367 // Two watches for the same name. 368 updateChs := []*testutils.Channel{updateCh} 369 const count = 1 370 for i := 0; i < count; i++ { 371 var updateCh *testutils.Channel 372 updateCh, _ = newWatchF(client, rName[0]) 373 updateChs = append(updateChs, updateCh) 374 } 375 // Third watch for a different name. 376 updateCh2, _ := newWatchF(client, rName[1]) 377 378 newUpdateF(updateHandler, map[string]interface{}{ 379 rName[0]: update1, 380 rName[1]: update2, 381 }) 382 383 // The first several watches for the same resource should all 384 // receive the first update. 385 for i := 0; i < count+1; i++ { 386 verifyUpdateF(ctx, t, updateChs[i], update1, nil) 387 } 388 // The last watch for the different resource should receive the 389 // second update. 390 verifyUpdateF(ctx, t, updateCh2, update2, nil) 391 }) 392 } 393 } 394 395 // testWatchAfterCache covers the case where watch is called after the update is 396 // in cache. 397 func testWatchAfterCache(t *testing.T, typ xdsresource.ResourceType, update interface{}, resourceName string) { 398 overrideFedEnvVar(t) 399 for _, rName := range []string{resourceName, xdstestutils.BuildResourceName(typ, testAuthority, resourceName, nil)} { 400 t.Run(rName, func(t *testing.T) { 401 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 402 defer cancel() 403 client, ctrlCh := testClientSetup(t, false) 404 updateCh, _ := newWatch(t, client, typ, rName) 405 _, updateHandler := getControllerAndPubsub(ctx, t, client, ctrlCh, typ, rName) 406 newWatchF, newUpdateF, verifyUpdateF := typeToTestFuncs(typ) 407 408 newUpdateF(updateHandler, map[string]interface{}{rName: update}) 409 verifyUpdateF(ctx, t, updateCh, update, nil) 410 411 // Another watch for the resource in cache. 412 updateCh2, _ := newWatchF(client, rName) 413 414 // New watch should receive the update. 415 verifyUpdateF(ctx, t, updateCh2, update, nil) 416 417 // Old watch should see nothing. 418 sCtx, sCancel := context.WithTimeout(ctx, defaultTestShortTimeout) 419 defer sCancel() 420 if u, err := updateCh.Receive(sCtx); err != context.DeadlineExceeded { 421 t.Errorf("unexpected update: %v, %v, want channel recv timeout", u, err) 422 } 423 }) 424 } 425 } 426 427 // testResourceRemoved covers the cases: 428 // - an update is received after a watch() 429 // - another update is received, with one resource removed 430 // - this should trigger callback with resource removed error 431 // 432 // - one more update without the removed resource 433 // - the callback (above) shouldn't receive any update 434 func testResourceRemoved(t *testing.T, typ xdsresource.ResourceType, update1 interface{}, resourceName1 string, update2 interface{}, resourceName2 string) { 435 overrideFedEnvVar(t) 436 for _, rName := range [][]string{ 437 {resourceName1, resourceName2}, 438 {xdstestutils.BuildResourceName(typ, testAuthority, resourceName1, nil), xdstestutils.BuildResourceName(typ, testAuthority, resourceName2, nil)}, 439 } { 440 t.Run(rName[0], func(t *testing.T) { 441 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 442 defer cancel() 443 client, ctrlCh := testClientSetup(t, false) 444 updateCh, _ := newWatch(t, client, typ, rName[0]) 445 _, updateHandler := getControllerAndPubsub(ctx, t, client, ctrlCh, typ, rName[0]) 446 newWatchF, newUpdateF, verifyUpdateF := typeToTestFuncs(typ) 447 448 // Another watch for a different name. 449 updateCh2, _ := newWatchF(client, rName[1]) 450 451 newUpdateF(updateHandler, map[string]interface{}{ 452 rName[0]: update1, 453 rName[1]: update2, 454 }) 455 verifyUpdateF(ctx, t, updateCh, update1, nil) 456 verifyUpdateF(ctx, t, updateCh2, update2, nil) 457 458 // Send another update to remove resource 1. 459 newUpdateF(updateHandler, map[string]interface{}{ 460 rName[1]: update2, 461 }) 462 463 // Watcher 1 should get an error. 464 if u, err := updateCh.Receive(ctx); err != nil { 465 t.Errorf("failed to receive update: %v", err) 466 } else { 467 var gotErr error 468 switch typ { 469 case xdsresource.ListenerResource: 470 newU := u.(xdsresource.ListenerUpdateErrTuple) 471 gotErr = newU.Err 472 case xdsresource.RouteConfigResource: 473 newU := u.(xdsresource.RouteConfigUpdateErrTuple) 474 gotErr = newU.Err 475 case xdsresource.ClusterResource: 476 newU := u.(xdsresource.ClusterUpdateErrTuple) 477 gotErr = newU.Err 478 case xdsresource.EndpointsResource: 479 newU := u.(xdsresource.EndpointsUpdateErrTuple) 480 gotErr = newU.Err 481 } 482 if xdsresource.ErrType(gotErr) != xdsresource.ErrorTypeResourceNotFound { 483 t.Errorf("unexpected clusterUpdate: %v, error receiving from channel: %v, want update with error resource not found", u, err) 484 } 485 } 486 487 // Watcher 2 should not see an update since the resource has not changed. 488 sCtx, sCancel := context.WithTimeout(ctx, defaultTestShortTimeout) 489 defer sCancel() 490 if u, err := updateCh2.Receive(sCtx); err != context.DeadlineExceeded { 491 t.Errorf("unexpected ClusterUpdate: %v, want receiving from channel timeout", u) 492 } 493 494 // Send another update with resource 2 modified. Specify a non-nil raw proto 495 // to ensure that the new update is not considered equal to the old one. 496 var newUpdate interface{} 497 switch typ { 498 case xdsresource.ListenerResource: 499 newU := update2.(xdsresource.ListenerUpdate) 500 newU.Raw = &anypb.Any{} 501 newUpdate = newU 502 case xdsresource.RouteConfigResource: 503 newU := update2.(xdsresource.RouteConfigUpdate) 504 newU.Raw = &anypb.Any{} 505 newUpdate = newU 506 case xdsresource.ClusterResource: 507 newU := update2.(xdsresource.ClusterUpdate) 508 newU.Raw = &anypb.Any{} 509 newUpdate = newU 510 case xdsresource.EndpointsResource: 511 newU := update2.(xdsresource.EndpointsUpdate) 512 newU.Raw = &anypb.Any{} 513 newUpdate = newU 514 } 515 newUpdateF(updateHandler, map[string]interface{}{ 516 rName[1]: newUpdate, 517 }) 518 519 // Watcher 1 should not see an update. 520 sCtx, sCancel = context.WithTimeout(ctx, defaultTestShortTimeout) 521 defer sCancel() 522 if u, err := updateCh.Receive(sCtx); err != context.DeadlineExceeded { 523 t.Errorf("unexpected Cluster: %v, want receiving from channel timeout", u) 524 } 525 526 // Watcher 2 should get the update. 527 verifyUpdateF(ctx, t, updateCh2, newUpdate, nil) 528 }) 529 } 530 } 531 532 // testWatchPartialValid covers the case that a response contains both 533 // valid and invalid resources. This response will be NACK'ed by the xdsclient. 534 // But the watchers with valid resources should receive the update, those with 535 // invalid resources should receive an error. 536 func testWatchPartialValid(t *testing.T, typ xdsresource.ResourceType, update interface{}, resourceName string) { 537 overrideFedEnvVar(t) 538 const badResourceName = "bad-resource" 539 540 for _, rName := range [][]string{ 541 {resourceName, badResourceName}, 542 {xdstestutils.BuildResourceName(typ, testAuthority, resourceName, nil), xdstestutils.BuildResourceName(typ, testAuthority, badResourceName, nil)}, 543 } { 544 t.Run(rName[0], func(t *testing.T) { 545 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 546 defer cancel() 547 client, ctrlCh := testClientSetup(t, false) 548 updateCh, _ := newWatch(t, client, typ, rName[0]) 549 _, updateHandler := getControllerAndPubsub(ctx, t, client, ctrlCh, typ, rName[0]) 550 newWatchF, _, verifyUpdateF := typeToTestFuncs(typ) 551 552 updateChs := map[string]*testutils.Channel{ 553 rName[0]: updateCh, 554 } 555 556 for _, name := range []string{rName[1]} { 557 updateChT, _ := newWatchF(client, rName[1]) 558 updateChs[name] = updateChT 559 } 560 561 wantError := fmt.Errorf("testing error") 562 wantError2 := fmt.Errorf("individual error") 563 564 switch typ { 565 case xdsresource.ListenerResource: 566 updateHandler.NewListeners(map[string]xdsresource.ListenerUpdateErrTuple{ 567 rName[0]: {Update: update.(xdsresource.ListenerUpdate)}, 568 rName[1]: {Err: wantError2}, 569 }, xdsresource.UpdateMetadata{ErrState: &xdsresource.UpdateErrorMetadata{Err: wantError}}) 570 case xdsresource.RouteConfigResource: 571 updateHandler.NewRouteConfigs(map[string]xdsresource.RouteConfigUpdateErrTuple{ 572 rName[0]: {Update: update.(xdsresource.RouteConfigUpdate)}, 573 rName[1]: {Err: wantError2}, 574 }, xdsresource.UpdateMetadata{ErrState: &xdsresource.UpdateErrorMetadata{Err: wantError}}) 575 case xdsresource.ClusterResource: 576 updateHandler.NewClusters(map[string]xdsresource.ClusterUpdateErrTuple{ 577 rName[0]: {Update: update.(xdsresource.ClusterUpdate)}, 578 rName[1]: {Err: wantError2}, 579 }, xdsresource.UpdateMetadata{ErrState: &xdsresource.UpdateErrorMetadata{Err: wantError}}) 580 case xdsresource.EndpointsResource: 581 updateHandler.NewEndpoints(map[string]xdsresource.EndpointsUpdateErrTuple{ 582 rName[0]: {Update: update.(xdsresource.EndpointsUpdate)}, 583 rName[1]: {Err: wantError2}, 584 }, xdsresource.UpdateMetadata{ErrState: &xdsresource.UpdateErrorMetadata{Err: wantError}}) 585 } 586 587 // The valid resource should be sent to the watcher. 588 verifyUpdateF(ctx, t, updateChs[rName[0]], update, nil) 589 590 // The failed watcher should receive an error. 591 verifyUpdateF(ctx, t, updateChs[rName[1]], update, wantError2) 592 }) 593 } 594 }