github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/grpc/xds/internal/balancer/clusterresolver/resource_resolver_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 19 package clusterresolver 20 21 import ( 22 "context" 23 "fmt" 24 "testing" 25 26 "github.com/google/go-cmp/cmp" 27 "github.com/hxx258456/ccgo/grpc/resolver" 28 "github.com/hxx258456/ccgo/grpc/resolver/manual" 29 "github.com/hxx258456/ccgo/grpc/xds/internal/testutils" 30 "github.com/hxx258456/ccgo/grpc/xds/internal/testutils/fakeclient" 31 "github.com/hxx258456/ccgo/grpc/xds/internal/xdsclient/xdsresource" 32 ) 33 34 const ( 35 testDNSTarget = "dns.com" 36 ) 37 38 var ( 39 testEDSUpdates []xdsresource.EndpointsUpdate 40 ) 41 42 func init() { 43 clab1 := testutils.NewClusterLoadAssignmentBuilder(testClusterNames[0], nil) 44 clab1.AddLocality(testSubZones[0], 1, 0, testEndpointAddrs[:1], nil) 45 testEDSUpdates = append(testEDSUpdates, parseEDSRespProtoForTesting(clab1.Build())) 46 clab2 := testutils.NewClusterLoadAssignmentBuilder(testClusterNames[0], nil) 47 clab2.AddLocality(testSubZones[1], 1, 0, testEndpointAddrs[1:2], nil) 48 testEDSUpdates = append(testEDSUpdates, parseEDSRespProtoForTesting(clab2.Build())) 49 } 50 51 // Test the simple case with one EDS resource to watch. 52 func (s) TestResourceResolverOneEDSResource(t *testing.T) { 53 for _, test := range []struct { 54 name string 55 clusterName, edsName string 56 wantName string 57 edsUpdate xdsresource.EndpointsUpdate 58 want []priorityConfig 59 }{ 60 {name: "watch EDS", 61 clusterName: testClusterName, 62 edsName: testEDSServcie, 63 wantName: testEDSServcie, 64 edsUpdate: testEDSUpdates[0], 65 want: []priorityConfig{{ 66 mechanism: DiscoveryMechanism{ 67 Type: DiscoveryMechanismTypeEDS, 68 Cluster: testClusterName, 69 EDSServiceName: testEDSServcie, 70 }, 71 edsResp: testEDSUpdates[0], 72 }}, 73 }, 74 { 75 name: "watch EDS no EDS name", // Will watch for cluster name. 76 clusterName: testClusterName, 77 wantName: testClusterName, 78 edsUpdate: testEDSUpdates[1], 79 want: []priorityConfig{{ 80 mechanism: DiscoveryMechanism{ 81 Type: DiscoveryMechanismTypeEDS, 82 Cluster: testClusterName, 83 }, 84 edsResp: testEDSUpdates[1], 85 }}, 86 }, 87 } { 88 t.Run(test.name, func(t *testing.T) { 89 fakeClient := fakeclient.NewClient() 90 rr := newResourceResolver(&clusterResolverBalancer{xdsClient: fakeClient}) 91 rr.updateMechanisms([]DiscoveryMechanism{{ 92 Type: DiscoveryMechanismTypeEDS, 93 Cluster: test.clusterName, 94 EDSServiceName: test.edsName, 95 }}) 96 ctx, ctxCancel := context.WithTimeout(context.Background(), defaultTestTimeout) 97 defer ctxCancel() 98 gotEDSName, err := fakeClient.WaitForWatchEDS(ctx) 99 if err != nil { 100 t.Fatalf("xdsClient.WatchCDS failed with error: %v", err) 101 } 102 if gotEDSName != test.wantName { 103 t.Fatalf("xdsClient.WatchEDS called for cluster: %v, want: %v", gotEDSName, test.wantName) 104 } 105 106 // Invoke callback, should get an update. 107 fakeClient.InvokeWatchEDSCallback("", test.edsUpdate, nil) 108 select { 109 case u := <-rr.updateChannel: 110 if diff := cmp.Diff(u.priorities, test.want, cmp.AllowUnexported(priorityConfig{})); diff != "" { 111 t.Fatalf("got unexpected resource update, diff (-got, +want): %v", diff) 112 } 113 case <-ctx.Done(): 114 t.Fatal("Timed out waiting for update from update channel.") 115 } 116 // Close the resource resolver. Should stop EDS watch. 117 rr.stop() 118 edsNameCanceled, err := fakeClient.WaitForCancelEDSWatch(ctx) 119 if err != nil { 120 t.Fatalf("xdsClient.CancelCDS failed with error: %v", err) 121 } 122 if edsNameCanceled != test.wantName { 123 t.Fatalf("xdsClient.CancelEDS called for %v, want: %v", edsNameCanceled, testEDSServcie) 124 } 125 }) 126 } 127 } 128 129 func setupDNS() (chan resolver.Target, chan struct{}, chan resolver.ResolveNowOptions, *manual.Resolver, func()) { 130 dnsTargetCh := make(chan resolver.Target, 1) 131 dnsCloseCh := make(chan struct{}, 1) 132 resolveNowCh := make(chan resolver.ResolveNowOptions, 1) 133 134 mr := manual.NewBuilderWithScheme("dns") 135 mr.BuildCallback = func(target resolver.Target, _ resolver.ClientConn, _ resolver.BuildOptions) { dnsTargetCh <- target } 136 mr.CloseCallback = func() { dnsCloseCh <- struct{}{} } 137 mr.ResolveNowCallback = func(opts resolver.ResolveNowOptions) { resolveNowCh <- opts } 138 oldNewDNS := newDNS 139 newDNS = func(target resolver.Target, cc resolver.ClientConn, opts resolver.BuildOptions) (resolver.Resolver, error) { 140 return mr.Build(target, cc, opts) 141 } 142 return dnsTargetCh, dnsCloseCh, resolveNowCh, mr, func() { newDNS = oldNewDNS } 143 } 144 145 // Test the simple case of one DNS resolver. 146 func (s) TestResourceResolverOneDNSResource(t *testing.T) { 147 for _, test := range []struct { 148 name string 149 target string 150 wantTarget resolver.Target 151 addrs []resolver.Address 152 want []priorityConfig 153 }{ 154 { 155 name: "watch DNS", 156 target: testDNSTarget, 157 wantTarget: resolver.Target{Scheme: "dns", Endpoint: testDNSTarget}, 158 addrs: []resolver.Address{{Addr: "1.1.1.1"}, {Addr: "2.2.2.2"}}, 159 want: []priorityConfig{{ 160 mechanism: DiscoveryMechanism{ 161 Type: DiscoveryMechanismTypeLogicalDNS, 162 DNSHostname: testDNSTarget, 163 }, 164 addresses: []string{"1.1.1.1", "2.2.2.2"}, 165 }}, 166 }, 167 } { 168 t.Run(test.name, func(t *testing.T) { 169 dnsTargetCh, dnsCloseCh, _, dnsR, cleanup := setupDNS() 170 defer cleanup() 171 fakeClient := fakeclient.NewClient() 172 rr := newResourceResolver(&clusterResolverBalancer{xdsClient: fakeClient}) 173 rr.updateMechanisms([]DiscoveryMechanism{{ 174 Type: DiscoveryMechanismTypeLogicalDNS, 175 DNSHostname: test.target, 176 }}) 177 ctx, ctxCancel := context.WithTimeout(context.Background(), defaultTestTimeout) 178 defer ctxCancel() 179 select { 180 case target := <-dnsTargetCh: 181 if diff := cmp.Diff(target, test.wantTarget); diff != "" { 182 t.Fatalf("got unexpected DNS target to watch, diff (-got, +want): %v", diff) 183 } 184 case <-ctx.Done(): 185 t.Fatal("Timed out waiting for building DNS resolver") 186 } 187 188 // Invoke callback, should get an update. 189 dnsR.UpdateState(resolver.State{Addresses: test.addrs}) 190 select { 191 case u := <-rr.updateChannel: 192 if diff := cmp.Diff(u.priorities, test.want, cmp.AllowUnexported(priorityConfig{})); diff != "" { 193 t.Fatalf("got unexpected resource update, diff (-got, +want): %v", diff) 194 } 195 case <-ctx.Done(): 196 t.Fatal("Timed out waiting for update from update channel.") 197 } 198 // Close the resource resolver. Should close the underlying resolver. 199 rr.stop() 200 select { 201 case <-dnsCloseCh: 202 case <-ctx.Done(): 203 t.Fatal("Timed out waiting for closing DNS resolver") 204 } 205 }) 206 } 207 } 208 209 // Test that changing EDS name would cause a cancel and a new watch. 210 // 211 // Also, changes that don't actually change EDS names (e.g. changing cluster 212 // name but not service name, or change circuit breaking count) doesn't do 213 // anything. 214 // 215 // - update DiscoveryMechanism 216 // - same EDS name to watch, but different MaxCurrentCount: no new watch 217 // - different cluster name, but same EDS name: no new watch 218 func (s) TestResourceResolverChangeEDSName(t *testing.T) { 219 fakeClient := fakeclient.NewClient() 220 rr := newResourceResolver(&clusterResolverBalancer{xdsClient: fakeClient}) 221 rr.updateMechanisms([]DiscoveryMechanism{{ 222 Type: DiscoveryMechanismTypeEDS, 223 Cluster: testClusterName, 224 EDSServiceName: testEDSServcie, 225 }}) 226 ctx, ctxCancel := context.WithTimeout(context.Background(), defaultTestTimeout) 227 defer ctxCancel() 228 gotEDSName1, err := fakeClient.WaitForWatchEDS(ctx) 229 if err != nil { 230 t.Fatalf("xdsClient.WatchCDS failed with error: %v", err) 231 } 232 if gotEDSName1 != testEDSServcie { 233 t.Fatalf("xdsClient.WatchEDS called for cluster: %v, want: %v", gotEDSName1, testEDSServcie) 234 } 235 236 // Invoke callback, should get an update. 237 fakeClient.InvokeWatchEDSCallback(gotEDSName1, testEDSUpdates[0], nil) 238 select { 239 case u := <-rr.updateChannel: 240 if diff := cmp.Diff(u.priorities, []priorityConfig{{ 241 mechanism: DiscoveryMechanism{ 242 Type: DiscoveryMechanismTypeEDS, 243 Cluster: testClusterName, 244 EDSServiceName: testEDSServcie, 245 }, 246 edsResp: testEDSUpdates[0], 247 }}, cmp.AllowUnexported(priorityConfig{})); diff != "" { 248 t.Fatalf("got unexpected resource update, diff (-got, +want): %v", diff) 249 } 250 case <-ctx.Done(): 251 t.Fatal("Timed out waiting for update from update channel.") 252 } 253 254 // Change name to watch. 255 rr.updateMechanisms([]DiscoveryMechanism{{ 256 Type: DiscoveryMechanismTypeEDS, 257 Cluster: testClusterName, 258 }}) 259 edsNameCanceled1, err := fakeClient.WaitForCancelEDSWatch(ctx) 260 if err != nil { 261 t.Fatalf("xdsClient.CancelCDS failed with error: %v", err) 262 } 263 if edsNameCanceled1 != gotEDSName1 { 264 t.Fatalf("xdsClient.CancelEDS called for %v, want: %v", edsNameCanceled1, testEDSServcie) 265 } 266 gotEDSName2, err := fakeClient.WaitForWatchEDS(ctx) 267 if err != nil { 268 t.Fatalf("xdsClient.WatchCDS failed with error: %v", err) 269 } 270 if gotEDSName2 != testClusterName { 271 t.Fatalf("xdsClient.WatchEDS called for cluster: %v, want: %v", gotEDSName2, testClusterName) 272 } 273 // Shouldn't get any update, because the new resource hasn't received any 274 // update. 275 shortCtx, shortCancel := context.WithTimeout(context.Background(), defaultTestShortTimeout) 276 defer shortCancel() 277 select { 278 case u := <-rr.updateChannel: 279 t.Fatalf("get unexpected update %+v", u) 280 case <-shortCtx.Done(): 281 } 282 283 // Invoke callback, should get an update. 284 fakeClient.InvokeWatchEDSCallback(gotEDSName2, testEDSUpdates[1], nil) 285 select { 286 case u := <-rr.updateChannel: 287 if diff := cmp.Diff(u.priorities, []priorityConfig{{ 288 mechanism: DiscoveryMechanism{ 289 Type: DiscoveryMechanismTypeEDS, 290 Cluster: testClusterName, 291 }, 292 edsResp: testEDSUpdates[1], 293 }}, cmp.AllowUnexported(priorityConfig{})); diff != "" { 294 t.Fatalf("got unexpected resource update, diff (-got, +want): %v", diff) 295 } 296 case <-ctx.Done(): 297 t.Fatal("Timed out waiting for update from update channel.") 298 } 299 300 // Change circuit breaking count, should get an update with new circuit 301 // breaking count, but shouldn't trigger new watch. 302 rr.updateMechanisms([]DiscoveryMechanism{{ 303 Type: DiscoveryMechanismTypeEDS, 304 Cluster: testClusterName, 305 MaxConcurrentRequests: newUint32(123), 306 }}) 307 shortCtx, shortCancel = context.WithTimeout(context.Background(), defaultTestShortTimeout) 308 defer shortCancel() 309 if n, err := fakeClient.WaitForWatchEDS(shortCtx); err == nil { 310 t.Fatalf("unexpected watch started for EDS: %v", n) 311 } 312 select { 313 case u := <-rr.updateChannel: 314 if diff := cmp.Diff(u.priorities, []priorityConfig{{ 315 mechanism: DiscoveryMechanism{ 316 Type: DiscoveryMechanismTypeEDS, 317 Cluster: testClusterName, 318 MaxConcurrentRequests: newUint32(123), 319 }, 320 edsResp: testEDSUpdates[1], 321 }}, cmp.AllowUnexported(priorityConfig{})); diff != "" { 322 t.Fatalf("got unexpected resource update, diff (-got, +want): %v", diff) 323 } 324 case <-ctx.Done(): 325 t.Fatal("Timed out waiting for update from update channel.") 326 } 327 328 // Close the resource resolver. Should stop EDS watch. 329 rr.stop() 330 edsNameCanceled, err := fakeClient.WaitForCancelEDSWatch(ctx) 331 if err != nil { 332 t.Fatalf("xdsClient.CancelCDS failed with error: %v", err) 333 } 334 if edsNameCanceled != gotEDSName2 { 335 t.Fatalf("xdsClient.CancelEDS called for %v, want: %v", edsNameCanceled, gotEDSName2) 336 } 337 } 338 339 // Test the case that same resources with the same priority should not add new 340 // EDS watch, and also should not trigger an update. 341 func (s) TestResourceResolverNoChangeNoUpdate(t *testing.T) { 342 fakeClient := fakeclient.NewClient() 343 rr := newResourceResolver(&clusterResolverBalancer{xdsClient: fakeClient}) 344 rr.updateMechanisms([]DiscoveryMechanism{ 345 { 346 Type: DiscoveryMechanismTypeEDS, 347 Cluster: testClusterNames[0], 348 }, 349 { 350 Type: DiscoveryMechanismTypeEDS, 351 Cluster: testClusterNames[1], 352 MaxConcurrentRequests: newUint32(100), 353 }, 354 }) 355 ctx, ctxCancel := context.WithTimeout(context.Background(), defaultTestTimeout) 356 defer ctxCancel() 357 gotEDSName1, err := fakeClient.WaitForWatchEDS(ctx) 358 if err != nil { 359 t.Fatalf("xdsClient.WatchCDS failed with error: %v", err) 360 } 361 if gotEDSName1 != testClusterNames[0] { 362 t.Fatalf("xdsClient.WatchEDS called for cluster: %v, want: %v", gotEDSName1, testClusterNames[0]) 363 } 364 gotEDSName2, err := fakeClient.WaitForWatchEDS(ctx) 365 if err != nil { 366 t.Fatalf("xdsClient.WatchCDS failed with error: %v", err) 367 } 368 if gotEDSName2 != testClusterNames[1] { 369 t.Fatalf("xdsClient.WatchEDS called for cluster: %v, want: %v", gotEDSName2, testClusterNames[1]) 370 } 371 372 // Invoke callback, should get an update. 373 fakeClient.InvokeWatchEDSCallback(gotEDSName1, testEDSUpdates[0], nil) 374 // Shouldn't send update, because only one resource received an update. 375 shortCtx, shortCancel := context.WithTimeout(context.Background(), defaultTestShortTimeout) 376 defer shortCancel() 377 select { 378 case u := <-rr.updateChannel: 379 t.Fatalf("get unexpected update %+v", u) 380 case <-shortCtx.Done(): 381 } 382 fakeClient.InvokeWatchEDSCallback(gotEDSName2, testEDSUpdates[1], nil) 383 select { 384 case u := <-rr.updateChannel: 385 if diff := cmp.Diff(u.priorities, []priorityConfig{ 386 { 387 mechanism: DiscoveryMechanism{ 388 Type: DiscoveryMechanismTypeEDS, 389 Cluster: testClusterNames[0], 390 }, 391 edsResp: testEDSUpdates[0], 392 }, 393 { 394 mechanism: DiscoveryMechanism{ 395 Type: DiscoveryMechanismTypeEDS, 396 Cluster: testClusterNames[1], 397 MaxConcurrentRequests: newUint32(100), 398 }, 399 edsResp: testEDSUpdates[1], 400 }, 401 }, cmp.AllowUnexported(priorityConfig{})); diff != "" { 402 t.Fatalf("got unexpected resource update, diff (-got, +want): %v", diff) 403 } 404 case <-ctx.Done(): 405 t.Fatal("Timed out waiting for update from update channel.") 406 } 407 408 // Send the same resources with the same priorities, shouldn't any change. 409 rr.updateMechanisms([]DiscoveryMechanism{ 410 { 411 Type: DiscoveryMechanismTypeEDS, 412 Cluster: testClusterNames[0], 413 }, 414 { 415 Type: DiscoveryMechanismTypeEDS, 416 Cluster: testClusterNames[1], 417 MaxConcurrentRequests: newUint32(100), 418 }, 419 }) 420 shortCtx, shortCancel = context.WithTimeout(context.Background(), defaultTestShortTimeout) 421 defer shortCancel() 422 if n, err := fakeClient.WaitForWatchEDS(shortCtx); err == nil { 423 t.Fatalf("unexpected watch started for EDS: %v", n) 424 } 425 shortCtx, shortCancel = context.WithTimeout(context.Background(), defaultTestShortTimeout) 426 defer shortCancel() 427 select { 428 case u := <-rr.updateChannel: 429 t.Fatalf("unexpected update: %+v", u) 430 case <-shortCtx.Done(): 431 } 432 433 // Close the resource resolver. Should stop EDS watch. 434 rr.stop() 435 edsNameCanceled1, err := fakeClient.WaitForCancelEDSWatch(ctx) 436 if err != nil { 437 t.Fatalf("xdsClient.CancelCDS failed with error: %v", err) 438 } 439 if edsNameCanceled1 != gotEDSName1 && edsNameCanceled1 != gotEDSName2 { 440 t.Fatalf("xdsClient.CancelEDS called for %v, want: %v or %v", edsNameCanceled1, gotEDSName1, gotEDSName2) 441 } 442 edsNameCanceled2, err := fakeClient.WaitForCancelEDSWatch(ctx) 443 if err != nil { 444 t.Fatalf("xdsClient.CancelCDS failed with error: %v", err) 445 } 446 if edsNameCanceled2 != gotEDSName2 && edsNameCanceled2 != gotEDSName1 { 447 t.Fatalf("xdsClient.CancelEDS called for %v, want: %v or %v", edsNameCanceled2, gotEDSName1, gotEDSName2) 448 } 449 } 450 451 // Test the case that same resources are watched, but with different priority. 452 // Should not add new EDS watch, but should trigger an update with the new 453 // priorities. 454 func (s) TestResourceResolverChangePriority(t *testing.T) { 455 fakeClient := fakeclient.NewClient() 456 rr := newResourceResolver(&clusterResolverBalancer{xdsClient: fakeClient}) 457 rr.updateMechanisms([]DiscoveryMechanism{ 458 { 459 Type: DiscoveryMechanismTypeEDS, 460 Cluster: testClusterNames[0], 461 }, 462 { 463 Type: DiscoveryMechanismTypeEDS, 464 Cluster: testClusterNames[1], 465 }, 466 }) 467 ctx, ctxCancel := context.WithTimeout(context.Background(), defaultTestTimeout) 468 defer ctxCancel() 469 gotEDSName1, err := fakeClient.WaitForWatchEDS(ctx) 470 if err != nil { 471 t.Fatalf("xdsClient.WatchCDS failed with error: %v", err) 472 } 473 if gotEDSName1 != testClusterNames[0] { 474 t.Fatalf("xdsClient.WatchEDS called for cluster: %v, want: %v", gotEDSName1, testClusterNames[0]) 475 } 476 gotEDSName2, err := fakeClient.WaitForWatchEDS(ctx) 477 if err != nil { 478 t.Fatalf("xdsClient.WatchCDS failed with error: %v", err) 479 } 480 if gotEDSName2 != testClusterNames[1] { 481 t.Fatalf("xdsClient.WatchEDS called for cluster: %v, want: %v", gotEDSName2, testClusterNames[1]) 482 } 483 484 // Invoke callback, should get an update. 485 fakeClient.InvokeWatchEDSCallback(gotEDSName1, testEDSUpdates[0], nil) 486 // Shouldn't send update, because only one resource received an update. 487 shortCtx, shortCancel := context.WithTimeout(context.Background(), defaultTestShortTimeout) 488 defer shortCancel() 489 select { 490 case u := <-rr.updateChannel: 491 t.Fatalf("get unexpected update %+v", u) 492 case <-shortCtx.Done(): 493 } 494 fakeClient.InvokeWatchEDSCallback(gotEDSName2, testEDSUpdates[1], nil) 495 select { 496 case u := <-rr.updateChannel: 497 if diff := cmp.Diff(u.priorities, []priorityConfig{ 498 { 499 mechanism: DiscoveryMechanism{ 500 Type: DiscoveryMechanismTypeEDS, 501 Cluster: testClusterNames[0], 502 }, 503 edsResp: testEDSUpdates[0], 504 }, 505 { 506 mechanism: DiscoveryMechanism{ 507 Type: DiscoveryMechanismTypeEDS, 508 Cluster: testClusterNames[1], 509 }, 510 edsResp: testEDSUpdates[1], 511 }, 512 }, cmp.AllowUnexported(priorityConfig{})); diff != "" { 513 t.Fatalf("got unexpected resource update, diff (-got, +want): %v", diff) 514 } 515 case <-ctx.Done(): 516 t.Fatal("Timed out waiting for update from update channel.") 517 } 518 519 // Send the same resources with different priorities, shouldn't trigger 520 // watch, but should trigger an update with the new priorities. 521 rr.updateMechanisms([]DiscoveryMechanism{ 522 { 523 Type: DiscoveryMechanismTypeEDS, 524 Cluster: testClusterNames[1], 525 }, 526 { 527 Type: DiscoveryMechanismTypeEDS, 528 Cluster: testClusterNames[0], 529 }, 530 }) 531 shortCtx, shortCancel = context.WithTimeout(context.Background(), defaultTestShortTimeout) 532 defer shortCancel() 533 if n, err := fakeClient.WaitForWatchEDS(shortCtx); err == nil { 534 t.Fatalf("unexpected watch started for EDS: %v", n) 535 } 536 select { 537 case u := <-rr.updateChannel: 538 if diff := cmp.Diff(u.priorities, []priorityConfig{ 539 { 540 mechanism: DiscoveryMechanism{ 541 Type: DiscoveryMechanismTypeEDS, 542 Cluster: testClusterNames[1], 543 }, 544 edsResp: testEDSUpdates[1], 545 }, 546 { 547 mechanism: DiscoveryMechanism{ 548 Type: DiscoveryMechanismTypeEDS, 549 Cluster: testClusterNames[0], 550 }, 551 edsResp: testEDSUpdates[0], 552 }, 553 }, cmp.AllowUnexported(priorityConfig{})); diff != "" { 554 t.Fatalf("got unexpected resource update, diff (-got, +want): %v", diff) 555 } 556 case <-ctx.Done(): 557 t.Fatal("Timed out waiting for update from update channel.") 558 } 559 560 // Close the resource resolver. Should stop EDS watch. 561 rr.stop() 562 edsNameCanceled1, err := fakeClient.WaitForCancelEDSWatch(ctx) 563 if err != nil { 564 t.Fatalf("xdsClient.CancelCDS failed with error: %v", err) 565 } 566 if edsNameCanceled1 != gotEDSName1 && edsNameCanceled1 != gotEDSName2 { 567 t.Fatalf("xdsClient.CancelEDS called for %v, want: %v or %v", edsNameCanceled1, gotEDSName1, gotEDSName2) 568 } 569 edsNameCanceled2, err := fakeClient.WaitForCancelEDSWatch(ctx) 570 if err != nil { 571 t.Fatalf("xdsClient.CancelCDS failed with error: %v", err) 572 } 573 if edsNameCanceled2 != gotEDSName2 && edsNameCanceled2 != gotEDSName1 { 574 t.Fatalf("xdsClient.CancelEDS called for %v, want: %v or %v", edsNameCanceled2, gotEDSName1, gotEDSName2) 575 } 576 } 577 578 // Test the case that covers resource for both EDS and DNS. 579 func (s) TestResourceResolverEDSAndDNS(t *testing.T) { 580 dnsTargetCh, dnsCloseCh, _, dnsR, cleanup := setupDNS() 581 defer cleanup() 582 fakeClient := fakeclient.NewClient() 583 rr := newResourceResolver(&clusterResolverBalancer{xdsClient: fakeClient}) 584 rr.updateMechanisms([]DiscoveryMechanism{ 585 { 586 Type: DiscoveryMechanismTypeEDS, 587 Cluster: testClusterName, 588 }, 589 { 590 Type: DiscoveryMechanismTypeLogicalDNS, 591 DNSHostname: testDNSTarget, 592 }, 593 }) 594 ctx, ctxCancel := context.WithTimeout(context.Background(), defaultTestTimeout) 595 defer ctxCancel() 596 gotEDSName1, err := fakeClient.WaitForWatchEDS(ctx) 597 if err != nil { 598 t.Fatalf("xdsClient.WatchCDS failed with error: %v", err) 599 } 600 if gotEDSName1 != testClusterName { 601 t.Fatalf("xdsClient.WatchEDS called for cluster: %v, want: %v", gotEDSName1, testClusterName) 602 } 603 select { 604 case target := <-dnsTargetCh: 605 if diff := cmp.Diff(target, resolver.Target{Scheme: "dns", Endpoint: testDNSTarget}); diff != "" { 606 t.Fatalf("got unexpected DNS target to watch, diff (-got, +want): %v", diff) 607 } 608 case <-ctx.Done(): 609 t.Fatal("Timed out waiting for building DNS resolver") 610 } 611 612 fakeClient.InvokeWatchEDSCallback(gotEDSName1, testEDSUpdates[0], nil) 613 // Shouldn't send update, because only one resource received an update. 614 shortCtx, shortCancel := context.WithTimeout(context.Background(), defaultTestShortTimeout) 615 defer shortCancel() 616 select { 617 case u := <-rr.updateChannel: 618 t.Fatalf("get unexpected update %+v", u) 619 case <-shortCtx.Done(): 620 } 621 // Invoke DNS, should get an update. 622 dnsR.UpdateState(resolver.State{Addresses: []resolver.Address{{Addr: "1.1.1.1"}, {Addr: "2.2.2.2"}}}) 623 select { 624 case u := <-rr.updateChannel: 625 if diff := cmp.Diff(u.priorities, []priorityConfig{ 626 { 627 mechanism: DiscoveryMechanism{ 628 Type: DiscoveryMechanismTypeEDS, 629 Cluster: testClusterName, 630 }, 631 edsResp: testEDSUpdates[0], 632 }, 633 { 634 mechanism: DiscoveryMechanism{ 635 Type: DiscoveryMechanismTypeLogicalDNS, 636 DNSHostname: testDNSTarget, 637 }, 638 addresses: []string{"1.1.1.1", "2.2.2.2"}, 639 }, 640 }, cmp.AllowUnexported(priorityConfig{})); diff != "" { 641 t.Fatalf("got unexpected resource update, diff (-got, +want): %v", diff) 642 } 643 case <-ctx.Done(): 644 t.Fatal("Timed out waiting for update from update channel.") 645 } 646 647 // Close the resource resolver. Should stop EDS watch. 648 rr.stop() 649 edsNameCanceled1, err := fakeClient.WaitForCancelEDSWatch(ctx) 650 if err != nil { 651 t.Fatalf("xdsClient.CancelCDS failed with error: %v", err) 652 } 653 if edsNameCanceled1 != gotEDSName1 { 654 t.Fatalf("xdsClient.CancelEDS called for %v, want: %v", edsNameCanceled1, gotEDSName1) 655 } 656 select { 657 case <-dnsCloseCh: 658 case <-ctx.Done(): 659 t.Fatal("Timed out waiting for closing DNS resolver") 660 } 661 } 662 663 // Test the case that covers resource changing between EDS and DNS. 664 func (s) TestResourceResolverChangeFromEDSToDNS(t *testing.T) { 665 dnsTargetCh, dnsCloseCh, _, dnsR, cleanup := setupDNS() 666 defer cleanup() 667 fakeClient := fakeclient.NewClient() 668 rr := newResourceResolver(&clusterResolverBalancer{xdsClient: fakeClient}) 669 rr.updateMechanisms([]DiscoveryMechanism{{ 670 Type: DiscoveryMechanismTypeEDS, 671 Cluster: testClusterName, 672 }}) 673 ctx, ctxCancel := context.WithTimeout(context.Background(), defaultTestTimeout) 674 defer ctxCancel() 675 gotEDSName1, err := fakeClient.WaitForWatchEDS(ctx) 676 if err != nil { 677 t.Fatalf("xdsClient.WatchCDS failed with error: %v", err) 678 } 679 if gotEDSName1 != testClusterName { 680 t.Fatalf("xdsClient.WatchEDS called for cluster: %v, want: %v", gotEDSName1, testClusterName) 681 } 682 683 // Invoke callback, should get an update. 684 fakeClient.InvokeWatchEDSCallback(gotEDSName1, testEDSUpdates[0], nil) 685 select { 686 case u := <-rr.updateChannel: 687 if diff := cmp.Diff(u.priorities, []priorityConfig{{ 688 mechanism: DiscoveryMechanism{ 689 Type: DiscoveryMechanismTypeEDS, 690 Cluster: testClusterName, 691 }, 692 edsResp: testEDSUpdates[0], 693 }}, cmp.AllowUnexported(priorityConfig{})); diff != "" { 694 t.Fatalf("got unexpected resource update, diff (-got, +want): %v", diff) 695 } 696 case <-ctx.Done(): 697 t.Fatal("Timed out waiting for update from update channel.") 698 } 699 700 // Update to watch DNS instead. Should cancel EDS, and start DNS. 701 rr.updateMechanisms([]DiscoveryMechanism{{ 702 Type: DiscoveryMechanismTypeLogicalDNS, 703 DNSHostname: testDNSTarget, 704 }}) 705 select { 706 case target := <-dnsTargetCh: 707 if diff := cmp.Diff(target, resolver.Target{Scheme: "dns", Endpoint: testDNSTarget}); diff != "" { 708 t.Fatalf("got unexpected DNS target to watch, diff (-got, +want): %v", diff) 709 } 710 case <-ctx.Done(): 711 t.Fatal("Timed out waiting for building DNS resolver") 712 } 713 edsNameCanceled1, err := fakeClient.WaitForCancelEDSWatch(ctx) 714 if err != nil { 715 t.Fatalf("xdsClient.CancelCDS failed with error: %v", err) 716 } 717 if edsNameCanceled1 != gotEDSName1 { 718 t.Fatalf("xdsClient.CancelEDS called for %v, want: %v", edsNameCanceled1, gotEDSName1) 719 } 720 721 dnsR.UpdateState(resolver.State{Addresses: []resolver.Address{{Addr: "1.1.1.1"}, {Addr: "2.2.2.2"}}}) 722 select { 723 case u := <-rr.updateChannel: 724 if diff := cmp.Diff(u.priorities, []priorityConfig{{ 725 mechanism: DiscoveryMechanism{ 726 Type: DiscoveryMechanismTypeLogicalDNS, 727 DNSHostname: testDNSTarget, 728 }, 729 addresses: []string{"1.1.1.1", "2.2.2.2"}, 730 }}, cmp.AllowUnexported(priorityConfig{})); diff != "" { 731 t.Fatalf("got unexpected resource update, diff (-got, +want): %v", diff) 732 } 733 case <-ctx.Done(): 734 t.Fatal("Timed out waiting for update from update channel.") 735 } 736 737 // Close the resource resolver. Should stop DNS. 738 rr.stop() 739 select { 740 case <-dnsCloseCh: 741 case <-ctx.Done(): 742 t.Fatal("Timed out waiting for closing DNS resolver") 743 } 744 } 745 746 // Test the case that covers errors for both EDS and DNS. 747 func (s) TestResourceResolverError(t *testing.T) { 748 dnsTargetCh, dnsCloseCh, _, dnsR, cleanup := setupDNS() 749 defer cleanup() 750 fakeClient := fakeclient.NewClient() 751 rr := newResourceResolver(&clusterResolverBalancer{xdsClient: fakeClient}) 752 rr.updateMechanisms([]DiscoveryMechanism{ 753 { 754 Type: DiscoveryMechanismTypeEDS, 755 Cluster: testClusterName, 756 }, 757 { 758 Type: DiscoveryMechanismTypeLogicalDNS, 759 DNSHostname: testDNSTarget, 760 }, 761 }) 762 ctx, ctxCancel := context.WithTimeout(context.Background(), defaultTestTimeout) 763 defer ctxCancel() 764 gotEDSName1, err := fakeClient.WaitForWatchEDS(ctx) 765 if err != nil { 766 t.Fatalf("xdsClient.WatchCDS failed with error: %v", err) 767 } 768 if gotEDSName1 != testClusterName { 769 t.Fatalf("xdsClient.WatchEDS called for cluster: %v, want: %v", gotEDSName1, testClusterName) 770 } 771 select { 772 case target := <-dnsTargetCh: 773 if diff := cmp.Diff(target, resolver.Target{Scheme: "dns", Endpoint: testDNSTarget}); diff != "" { 774 t.Fatalf("got unexpected DNS target to watch, diff (-got, +want): %v", diff) 775 } 776 case <-ctx.Done(): 777 t.Fatal("Timed out waiting for building DNS resolver") 778 } 779 780 // Invoke callback with an error, should get an update. 781 edsErr := fmt.Errorf("EDS error") 782 fakeClient.InvokeWatchEDSCallback(gotEDSName1, xdsresource.EndpointsUpdate{}, edsErr) 783 select { 784 case u := <-rr.updateChannel: 785 if u.err != edsErr { 786 t.Fatalf("got unexpected error from update, want %v, got %v", edsErr, u.err) 787 } 788 case <-ctx.Done(): 789 t.Fatal("Timed out waiting for update from update channel.") 790 } 791 792 // Invoke DNS with an error, should get an update. 793 dnsErr := fmt.Errorf("DNS error") 794 dnsR.ReportError(dnsErr) 795 select { 796 case u := <-rr.updateChannel: 797 if u.err != dnsErr { 798 t.Fatalf("got unexpected error from update, want %v, got %v", dnsErr, u.err) 799 } 800 case <-ctx.Done(): 801 t.Fatal("Timed out waiting for update from update channel.") 802 } 803 804 // Close the resource resolver. Should stop EDS watch. 805 rr.stop() 806 edsNameCanceled1, err := fakeClient.WaitForCancelEDSWatch(ctx) 807 if err != nil { 808 t.Fatalf("xdsClient.CancelCDS failed with error: %v", err) 809 } 810 if edsNameCanceled1 != gotEDSName1 { 811 t.Fatalf("xdsClient.CancelEDS called for %v, want: %v", edsNameCanceled1, gotEDSName1) 812 } 813 select { 814 case <-dnsCloseCh: 815 case <-ctx.Done(): 816 t.Fatal("Timed out waiting for closing DNS resolver") 817 } 818 } 819 820 // Test re-resolve of the DNS resolver. 821 func (s) TestResourceResolverDNSResolveNow(t *testing.T) { 822 dnsTargetCh, dnsCloseCh, resolveNowCh, dnsR, cleanup := setupDNS() 823 defer cleanup() 824 fakeClient := fakeclient.NewClient() 825 rr := newResourceResolver(&clusterResolverBalancer{xdsClient: fakeClient}) 826 rr.updateMechanisms([]DiscoveryMechanism{{ 827 Type: DiscoveryMechanismTypeLogicalDNS, 828 DNSHostname: testDNSTarget, 829 }}) 830 ctx, ctxCancel := context.WithTimeout(context.Background(), defaultTestTimeout) 831 defer ctxCancel() 832 select { 833 case target := <-dnsTargetCh: 834 if diff := cmp.Diff(target, resolver.Target{Scheme: "dns", Endpoint: testDNSTarget}); diff != "" { 835 t.Fatalf("got unexpected DNS target to watch, diff (-got, +want): %v", diff) 836 } 837 case <-ctx.Done(): 838 t.Fatal("Timed out waiting for building DNS resolver") 839 } 840 841 // Invoke callback, should get an update. 842 dnsR.UpdateState(resolver.State{Addresses: []resolver.Address{{Addr: "1.1.1.1"}, {Addr: "2.2.2.2"}}}) 843 select { 844 case u := <-rr.updateChannel: 845 if diff := cmp.Diff(u.priorities, []priorityConfig{{ 846 mechanism: DiscoveryMechanism{ 847 Type: DiscoveryMechanismTypeLogicalDNS, 848 DNSHostname: testDNSTarget, 849 }, 850 addresses: []string{"1.1.1.1", "2.2.2.2"}, 851 }}, cmp.AllowUnexported(priorityConfig{})); diff != "" { 852 t.Fatalf("got unexpected resource update, diff (-got, +want): %v", diff) 853 } 854 case <-ctx.Done(): 855 t.Fatal("Timed out waiting for update from update channel.") 856 } 857 rr.resolveNow() 858 select { 859 case <-resolveNowCh: 860 case <-ctx.Done(): 861 t.Fatal("Timed out waiting for re-resolve") 862 } 863 // Close the resource resolver. Should close the underlying resolver. 864 rr.stop() 865 select { 866 case <-dnsCloseCh: 867 case <-ctx.Done(): 868 t.Fatal("Timed out waiting for closing DNS resolver") 869 } 870 }