gitee.com/ks-custle/core-gm@v0.0.0-20230922171213-b83bdd97b62c/grpc/xds/internal/balancer/clusterresolver/configbuilder_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 "bytes" 23 "encoding/json" 24 "fmt" 25 "sort" 26 "testing" 27 28 "gitee.com/ks-custle/core-gm/grpc/attributes" 29 "gitee.com/ks-custle/core-gm/grpc/balancer" 30 "gitee.com/ks-custle/core-gm/grpc/balancer/roundrobin" 31 "gitee.com/ks-custle/core-gm/grpc/balancer/weightedroundrobin" 32 "gitee.com/ks-custle/core-gm/grpc/balancer/weightedtarget" 33 "gitee.com/ks-custle/core-gm/grpc/internal/hierarchy" 34 internalserviceconfig "gitee.com/ks-custle/core-gm/grpc/internal/serviceconfig" 35 "gitee.com/ks-custle/core-gm/grpc/resolver" 36 "gitee.com/ks-custle/core-gm/grpc/xds/internal" 37 "gitee.com/ks-custle/core-gm/grpc/xds/internal/balancer/clusterimpl" 38 "gitee.com/ks-custle/core-gm/grpc/xds/internal/balancer/priority" 39 "gitee.com/ks-custle/core-gm/grpc/xds/internal/balancer/ringhash" 40 "gitee.com/ks-custle/core-gm/grpc/xds/internal/xdsclient/xdsresource" 41 "github.com/google/go-cmp/cmp" 42 ) 43 44 const ( 45 testLRSServer = "test-lrs-server" 46 testMaxRequests = 314 47 testEDSServiceName = "service-name-from-parent" 48 testDropCategory = "test-drops" 49 testDropOverMillion = 1 50 51 localityCount = 5 52 addressPerLocality = 2 53 ) 54 55 var ( 56 testLocalityIDs []internal.LocalityID 57 testAddressStrs [][]string 58 testEndpoints [][]xdsresource.Endpoint 59 60 testLocalitiesP0, testLocalitiesP1 []xdsresource.Locality 61 62 addrCmpOpts = cmp.Options{ 63 cmp.AllowUnexported(attributes.Attributes{}), 64 cmp.Transformer("SortAddrs", func(in []resolver.Address) []resolver.Address { 65 out := append([]resolver.Address(nil), in...) // Copy input to avoid mutating it 66 sort.Slice(out, func(i, j int) bool { 67 return out[i].Addr < out[j].Addr 68 }) 69 return out 70 })} 71 ) 72 73 func init() { 74 for i := 0; i < localityCount; i++ { 75 testLocalityIDs = append(testLocalityIDs, internal.LocalityID{Zone: fmt.Sprintf("test-zone-%d", i)}) 76 var ( 77 addrs []string 78 ends []xdsresource.Endpoint 79 ) 80 for j := 0; j < addressPerLocality; j++ { 81 addr := fmt.Sprintf("addr-%d-%d", i, j) 82 addrs = append(addrs, addr) 83 ends = append(ends, xdsresource.Endpoint{ 84 Address: addr, 85 HealthStatus: xdsresource.EndpointHealthStatusHealthy, 86 }) 87 } 88 testAddressStrs = append(testAddressStrs, addrs) 89 testEndpoints = append(testEndpoints, ends) 90 } 91 92 testLocalitiesP0 = []xdsresource.Locality{ 93 { 94 Endpoints: testEndpoints[0], 95 ID: testLocalityIDs[0], 96 Weight: 20, 97 Priority: 0, 98 }, 99 { 100 Endpoints: testEndpoints[1], 101 ID: testLocalityIDs[1], 102 Weight: 80, 103 Priority: 0, 104 }, 105 } 106 testLocalitiesP1 = []xdsresource.Locality{ 107 { 108 Endpoints: testEndpoints[2], 109 ID: testLocalityIDs[2], 110 Weight: 20, 111 Priority: 1, 112 }, 113 { 114 Endpoints: testEndpoints[3], 115 ID: testLocalityIDs[3], 116 Weight: 80, 117 Priority: 1, 118 }, 119 } 120 } 121 122 // TestBuildPriorityConfigJSON is a sanity check that the built balancer config 123 // can be parsed. The behavior test is covered by TestBuildPriorityConfig. 124 func TestBuildPriorityConfigJSON(t *testing.T) { 125 gotConfig, _, err := buildPriorityConfigJSON([]priorityConfig{ 126 { 127 mechanism: DiscoveryMechanism{ 128 Cluster: testClusterName, 129 LoadReportingServerName: newString(testLRSServer), 130 MaxConcurrentRequests: newUint32(testMaxRequests), 131 Type: DiscoveryMechanismTypeEDS, 132 EDSServiceName: testEDSServiceName, 133 }, 134 edsResp: xdsresource.EndpointsUpdate{ 135 Drops: []xdsresource.OverloadDropConfig{ 136 { 137 Category: testDropCategory, 138 Numerator: testDropOverMillion, 139 Denominator: million, 140 }, 141 }, 142 Localities: []xdsresource.Locality{ 143 testLocalitiesP0[0], 144 testLocalitiesP0[1], 145 testLocalitiesP1[0], 146 testLocalitiesP1[1], 147 }, 148 }, 149 }, 150 { 151 mechanism: DiscoveryMechanism{ 152 Type: DiscoveryMechanismTypeLogicalDNS, 153 }, 154 addresses: testAddressStrs[4], 155 }, 156 }, nil) 157 if err != nil { 158 t.Fatalf("buildPriorityConfigJSON(...) failed: %v", err) 159 } 160 161 var prettyGot bytes.Buffer 162 if err := json.Indent(&prettyGot, gotConfig, ">>> ", " "); err != nil { 163 t.Fatalf("json.Indent() failed: %v", err) 164 } 165 // Print the indented json if this test fails. 166 t.Log(prettyGot.String()) 167 168 priorityB := balancer.Get(priority.Name) 169 if _, err = priorityB.(balancer.ConfigParser).ParseConfig(gotConfig); err != nil { 170 t.Fatalf("ParseConfig(%+v) failed: %v", gotConfig, err) 171 } 172 } 173 174 func TestBuildPriorityConfig(t *testing.T) { 175 gotConfig, gotAddrs, _ := buildPriorityConfig([]priorityConfig{ 176 { 177 mechanism: DiscoveryMechanism{ 178 Cluster: testClusterName, 179 LoadReportingServerName: newString(testLRSServer), 180 MaxConcurrentRequests: newUint32(testMaxRequests), 181 Type: DiscoveryMechanismTypeEDS, 182 EDSServiceName: testEDSServiceName, 183 }, 184 edsResp: xdsresource.EndpointsUpdate{ 185 Drops: []xdsresource.OverloadDropConfig{ 186 { 187 Category: testDropCategory, 188 Numerator: testDropOverMillion, 189 Denominator: million, 190 }, 191 }, 192 Localities: []xdsresource.Locality{ 193 testLocalitiesP0[0], 194 testLocalitiesP0[1], 195 testLocalitiesP1[0], 196 testLocalitiesP1[1], 197 }, 198 }, 199 }, 200 { 201 mechanism: DiscoveryMechanism{ 202 Type: DiscoveryMechanismTypeLogicalDNS, 203 }, 204 addresses: testAddressStrs[4], 205 }, 206 }, nil) 207 208 wantConfig := &priority.LBConfig{ 209 Children: map[string]*priority.Child{ 210 "priority-0-0": { 211 Config: &internalserviceconfig.BalancerConfig{ 212 Name: clusterimpl.Name, 213 Config: &clusterimpl.LBConfig{ 214 Cluster: testClusterName, 215 EDSServiceName: testEDSServiceName, 216 LoadReportingServerName: newString(testLRSServer), 217 MaxConcurrentRequests: newUint32(testMaxRequests), 218 DropCategories: []clusterimpl.DropConfig{ 219 { 220 Category: testDropCategory, 221 RequestsPerMillion: testDropOverMillion, 222 }, 223 }, 224 ChildPolicy: &internalserviceconfig.BalancerConfig{ 225 Name: weightedtarget.Name, 226 Config: &weightedtarget.LBConfig{ 227 Targets: map[string]weightedtarget.Target{ 228 assertString(testLocalityIDs[0].ToString): { 229 Weight: 20, 230 ChildPolicy: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}, 231 }, 232 assertString(testLocalityIDs[1].ToString): { 233 Weight: 80, 234 ChildPolicy: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}, 235 }, 236 }, 237 }, 238 }, 239 }, 240 }, 241 IgnoreReresolutionRequests: true, 242 }, 243 "priority-0-1": { 244 Config: &internalserviceconfig.BalancerConfig{ 245 Name: clusterimpl.Name, 246 Config: &clusterimpl.LBConfig{ 247 Cluster: testClusterName, 248 EDSServiceName: testEDSServiceName, 249 LoadReportingServerName: newString(testLRSServer), 250 MaxConcurrentRequests: newUint32(testMaxRequests), 251 DropCategories: []clusterimpl.DropConfig{ 252 { 253 Category: testDropCategory, 254 RequestsPerMillion: testDropOverMillion, 255 }, 256 }, 257 ChildPolicy: &internalserviceconfig.BalancerConfig{ 258 Name: weightedtarget.Name, 259 Config: &weightedtarget.LBConfig{ 260 Targets: map[string]weightedtarget.Target{ 261 assertString(testLocalityIDs[2].ToString): { 262 Weight: 20, 263 ChildPolicy: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}, 264 }, 265 assertString(testLocalityIDs[3].ToString): { 266 Weight: 80, 267 ChildPolicy: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}, 268 }, 269 }, 270 }, 271 }, 272 }, 273 }, 274 IgnoreReresolutionRequests: true, 275 }, 276 "priority-1": { 277 Config: &internalserviceconfig.BalancerConfig{ 278 Name: clusterimpl.Name, 279 Config: &clusterimpl.LBConfig{ 280 ChildPolicy: &internalserviceconfig.BalancerConfig{Name: "pick_first"}, 281 }, 282 }, 283 IgnoreReresolutionRequests: false, 284 }, 285 }, 286 Priorities: []string{"priority-0-0", "priority-0-1", "priority-1"}, 287 } 288 wantAddrs := []resolver.Address{ 289 testAddrWithAttrs(testAddressStrs[0][0], nil, "priority-0-0", &testLocalityIDs[0]), 290 testAddrWithAttrs(testAddressStrs[0][1], nil, "priority-0-0", &testLocalityIDs[0]), 291 testAddrWithAttrs(testAddressStrs[1][0], nil, "priority-0-0", &testLocalityIDs[1]), 292 testAddrWithAttrs(testAddressStrs[1][1], nil, "priority-0-0", &testLocalityIDs[1]), 293 testAddrWithAttrs(testAddressStrs[2][0], nil, "priority-0-1", &testLocalityIDs[2]), 294 testAddrWithAttrs(testAddressStrs[2][1], nil, "priority-0-1", &testLocalityIDs[2]), 295 testAddrWithAttrs(testAddressStrs[3][0], nil, "priority-0-1", &testLocalityIDs[3]), 296 testAddrWithAttrs(testAddressStrs[3][1], nil, "priority-0-1", &testLocalityIDs[3]), 297 testAddrWithAttrs(testAddressStrs[4][0], nil, "priority-1", nil), 298 testAddrWithAttrs(testAddressStrs[4][1], nil, "priority-1", nil), 299 } 300 301 if diff := cmp.Diff(gotConfig, wantConfig); diff != "" { 302 t.Errorf("buildPriorityConfig() diff (-got +want) %v", diff) 303 } 304 if diff := cmp.Diff(gotAddrs, wantAddrs, addrCmpOpts); diff != "" { 305 t.Errorf("buildPriorityConfig() diff (-got +want) %v", diff) 306 } 307 } 308 309 func TestBuildClusterImplConfigForDNS(t *testing.T) { 310 gotName, gotConfig, gotAddrs := buildClusterImplConfigForDNS(3, testAddressStrs[0]) 311 wantName := "priority-3" 312 wantConfig := &clusterimpl.LBConfig{ 313 ChildPolicy: &internalserviceconfig.BalancerConfig{ 314 Name: "pick_first", 315 }, 316 } 317 wantAddrs := []resolver.Address{ 318 hierarchy.Set(resolver.Address{Addr: testAddressStrs[0][0]}, []string{"priority-3"}), 319 hierarchy.Set(resolver.Address{Addr: testAddressStrs[0][1]}, []string{"priority-3"}), 320 } 321 322 if diff := cmp.Diff(gotName, wantName); diff != "" { 323 t.Errorf("buildClusterImplConfigForDNS() diff (-got +want) %v", diff) 324 } 325 if diff := cmp.Diff(gotConfig, wantConfig); diff != "" { 326 t.Errorf("buildClusterImplConfigForDNS() diff (-got +want) %v", diff) 327 } 328 if diff := cmp.Diff(gotAddrs, wantAddrs, addrCmpOpts); diff != "" { 329 t.Errorf("buildClusterImplConfigForDNS() diff (-got +want) %v", diff) 330 } 331 } 332 333 func TestBuildClusterImplConfigForEDS(t *testing.T) { 334 gotNames, gotConfigs, gotAddrs, _ := buildClusterImplConfigForEDS( 335 2, 336 xdsresource.EndpointsUpdate{ 337 Drops: []xdsresource.OverloadDropConfig{ 338 { 339 Category: testDropCategory, 340 Numerator: testDropOverMillion, 341 Denominator: million, 342 }, 343 }, 344 Localities: []xdsresource.Locality{ 345 { 346 Endpoints: testEndpoints[3], 347 ID: testLocalityIDs[3], 348 Weight: 80, 349 Priority: 1, 350 }, { 351 Endpoints: testEndpoints[1], 352 ID: testLocalityIDs[1], 353 Weight: 80, 354 Priority: 0, 355 }, { 356 Endpoints: testEndpoints[2], 357 ID: testLocalityIDs[2], 358 Weight: 20, 359 Priority: 1, 360 }, { 361 Endpoints: testEndpoints[0], 362 ID: testLocalityIDs[0], 363 Weight: 20, 364 Priority: 0, 365 }, 366 }, 367 }, 368 DiscoveryMechanism{ 369 Cluster: testClusterName, 370 MaxConcurrentRequests: newUint32(testMaxRequests), 371 LoadReportingServerName: newString(testLRSServer), 372 Type: DiscoveryMechanismTypeEDS, 373 EDSServiceName: testEDSServiceName, 374 }, 375 nil, 376 ) 377 378 wantNames := []string{ 379 fmt.Sprintf("priority-%v-%v", 2, 0), 380 fmt.Sprintf("priority-%v-%v", 2, 1), 381 } 382 wantConfigs := map[string]*clusterimpl.LBConfig{ 383 "priority-2-0": { 384 Cluster: testClusterName, 385 EDSServiceName: testEDSServiceName, 386 LoadReportingServerName: newString(testLRSServer), 387 MaxConcurrentRequests: newUint32(testMaxRequests), 388 DropCategories: []clusterimpl.DropConfig{ 389 { 390 Category: testDropCategory, 391 RequestsPerMillion: testDropOverMillion, 392 }, 393 }, 394 ChildPolicy: &internalserviceconfig.BalancerConfig{ 395 Name: weightedtarget.Name, 396 Config: &weightedtarget.LBConfig{ 397 Targets: map[string]weightedtarget.Target{ 398 assertString(testLocalityIDs[0].ToString): { 399 Weight: 20, 400 ChildPolicy: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}, 401 }, 402 assertString(testLocalityIDs[1].ToString): { 403 Weight: 80, 404 ChildPolicy: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}, 405 }, 406 }, 407 }, 408 }, 409 }, 410 "priority-2-1": { 411 Cluster: testClusterName, 412 EDSServiceName: testEDSServiceName, 413 LoadReportingServerName: newString(testLRSServer), 414 MaxConcurrentRequests: newUint32(testMaxRequests), 415 DropCategories: []clusterimpl.DropConfig{ 416 { 417 Category: testDropCategory, 418 RequestsPerMillion: testDropOverMillion, 419 }, 420 }, 421 ChildPolicy: &internalserviceconfig.BalancerConfig{ 422 Name: weightedtarget.Name, 423 Config: &weightedtarget.LBConfig{ 424 Targets: map[string]weightedtarget.Target{ 425 assertString(testLocalityIDs[2].ToString): { 426 Weight: 20, 427 ChildPolicy: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}, 428 }, 429 assertString(testLocalityIDs[3].ToString): { 430 Weight: 80, 431 ChildPolicy: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}, 432 }, 433 }, 434 }, 435 }, 436 }, 437 } 438 wantAddrs := []resolver.Address{ 439 testAddrWithAttrs(testAddressStrs[0][0], nil, "priority-2-0", &testLocalityIDs[0]), 440 testAddrWithAttrs(testAddressStrs[0][1], nil, "priority-2-0", &testLocalityIDs[0]), 441 testAddrWithAttrs(testAddressStrs[1][0], nil, "priority-2-0", &testLocalityIDs[1]), 442 testAddrWithAttrs(testAddressStrs[1][1], nil, "priority-2-0", &testLocalityIDs[1]), 443 testAddrWithAttrs(testAddressStrs[2][0], nil, "priority-2-1", &testLocalityIDs[2]), 444 testAddrWithAttrs(testAddressStrs[2][1], nil, "priority-2-1", &testLocalityIDs[2]), 445 testAddrWithAttrs(testAddressStrs[3][0], nil, "priority-2-1", &testLocalityIDs[3]), 446 testAddrWithAttrs(testAddressStrs[3][1], nil, "priority-2-1", &testLocalityIDs[3]), 447 } 448 449 if diff := cmp.Diff(gotNames, wantNames); diff != "" { 450 t.Errorf("buildClusterImplConfigForEDS() diff (-got +want) %v", diff) 451 } 452 if diff := cmp.Diff(gotConfigs, wantConfigs); diff != "" { 453 t.Errorf("buildClusterImplConfigForEDS() diff (-got +want) %v", diff) 454 } 455 if diff := cmp.Diff(gotAddrs, wantAddrs, addrCmpOpts); diff != "" { 456 t.Errorf("buildClusterImplConfigForEDS() diff (-got +want) %v", diff) 457 } 458 459 } 460 461 func TestGroupLocalitiesByPriority(t *testing.T) { 462 tests := []struct { 463 name string 464 localities []xdsresource.Locality 465 wantPriorities []string 466 wantLocalities map[string][]xdsresource.Locality 467 }{ 468 { 469 name: "1 locality 1 priority", 470 localities: []xdsresource.Locality{testLocalitiesP0[0]}, 471 wantPriorities: []string{"0"}, 472 wantLocalities: map[string][]xdsresource.Locality{ 473 "0": {testLocalitiesP0[0]}, 474 }, 475 }, 476 { 477 name: "2 locality 1 priority", 478 localities: []xdsresource.Locality{testLocalitiesP0[0], testLocalitiesP0[1]}, 479 wantPriorities: []string{"0"}, 480 wantLocalities: map[string][]xdsresource.Locality{ 481 "0": {testLocalitiesP0[0], testLocalitiesP0[1]}, 482 }, 483 }, 484 { 485 name: "1 locality in each", 486 localities: []xdsresource.Locality{testLocalitiesP0[0], testLocalitiesP1[0]}, 487 wantPriorities: []string{"0", "1"}, 488 wantLocalities: map[string][]xdsresource.Locality{ 489 "0": {testLocalitiesP0[0]}, 490 "1": {testLocalitiesP1[0]}, 491 }, 492 }, 493 { 494 name: "2 localities in each sorted", 495 localities: []xdsresource.Locality{ 496 testLocalitiesP0[0], testLocalitiesP0[1], 497 testLocalitiesP1[0], testLocalitiesP1[1]}, 498 wantPriorities: []string{"0", "1"}, 499 wantLocalities: map[string][]xdsresource.Locality{ 500 "0": {testLocalitiesP0[0], testLocalitiesP0[1]}, 501 "1": {testLocalitiesP1[0], testLocalitiesP1[1]}, 502 }, 503 }, 504 { 505 // The localities are given in order [p1, p0, p1, p0], but the 506 // returned priority list must be sorted [p0, p1], because the list 507 // order is the priority order. 508 name: "2 localities in each needs to sort", 509 localities: []xdsresource.Locality{ 510 testLocalitiesP1[1], testLocalitiesP0[1], 511 testLocalitiesP1[0], testLocalitiesP0[0]}, 512 wantPriorities: []string{"0", "1"}, 513 wantLocalities: map[string][]xdsresource.Locality{ 514 "0": {testLocalitiesP0[1], testLocalitiesP0[0]}, 515 "1": {testLocalitiesP1[1], testLocalitiesP1[0]}, 516 }, 517 }, 518 } 519 for _, tt := range tests { 520 t.Run(tt.name, func(t *testing.T) { 521 gotPriorities, gotLocalities := groupLocalitiesByPriority(tt.localities) 522 if diff := cmp.Diff(gotPriorities, tt.wantPriorities); diff != "" { 523 t.Errorf("groupLocalitiesByPriority() diff(-got +want) %v", diff) 524 } 525 if diff := cmp.Diff(gotLocalities, tt.wantLocalities); diff != "" { 526 t.Errorf("groupLocalitiesByPriority() diff(-got +want) %v", diff) 527 } 528 }) 529 } 530 } 531 532 func TestDedupSortedIntSlice(t *testing.T) { 533 tests := []struct { 534 name string 535 a []int 536 want []int 537 }{ 538 { 539 name: "empty", 540 a: []int{}, 541 want: []int{}, 542 }, 543 { 544 name: "no dup", 545 a: []int{0, 1, 2, 3}, 546 want: []int{0, 1, 2, 3}, 547 }, 548 { 549 name: "with dup", 550 a: []int{0, 0, 1, 1, 1, 2, 3}, 551 want: []int{0, 1, 2, 3}, 552 }, 553 } 554 for _, tt := range tests { 555 t.Run(tt.name, func(t *testing.T) { 556 if got := dedupSortedIntSlice(tt.a); !cmp.Equal(got, tt.want) { 557 t.Errorf("dedupSortedIntSlice() = %v, want %v, diff %v", got, tt.want, cmp.Diff(got, tt.want)) 558 } 559 }) 560 } 561 } 562 563 func TestPriorityLocalitiesToClusterImpl(t *testing.T) { 564 tests := []struct { 565 name string 566 localities []xdsresource.Locality 567 priorityName string 568 mechanism DiscoveryMechanism 569 childPolicy *internalserviceconfig.BalancerConfig 570 wantConfig *clusterimpl.LBConfig 571 wantAddrs []resolver.Address 572 wantErr bool 573 }{{ 574 name: "round robin as child, no LRS", 575 localities: []xdsresource.Locality{ 576 { 577 Endpoints: []xdsresource.Endpoint{ 578 {Address: "addr-1-1", HealthStatus: xdsresource.EndpointHealthStatusHealthy, Weight: 90}, 579 {Address: "addr-1-2", HealthStatus: xdsresource.EndpointHealthStatusHealthy, Weight: 10}, 580 }, 581 ID: internal.LocalityID{Zone: "test-zone-1"}, 582 Weight: 20, 583 }, 584 { 585 Endpoints: []xdsresource.Endpoint{ 586 {Address: "addr-2-1", HealthStatus: xdsresource.EndpointHealthStatusHealthy, Weight: 90}, 587 {Address: "addr-2-2", HealthStatus: xdsresource.EndpointHealthStatusHealthy, Weight: 10}, 588 }, 589 ID: internal.LocalityID{Zone: "test-zone-2"}, 590 Weight: 80, 591 }, 592 }, 593 priorityName: "test-priority", 594 childPolicy: &internalserviceconfig.BalancerConfig{Name: rrName}, 595 mechanism: DiscoveryMechanism{ 596 Cluster: testClusterName, 597 Type: DiscoveryMechanismTypeEDS, 598 EDSServiceName: testEDSServcie, 599 }, 600 // lrsServer is nil, so LRS policy will not be used. 601 wantConfig: &clusterimpl.LBConfig{ 602 Cluster: testClusterName, 603 EDSServiceName: testEDSServcie, 604 ChildPolicy: &internalserviceconfig.BalancerConfig{ 605 Name: weightedtarget.Name, 606 Config: &weightedtarget.LBConfig{ 607 Targets: map[string]weightedtarget.Target{ 608 assertString(internal.LocalityID{Zone: "test-zone-1"}.ToString): { 609 Weight: 20, 610 ChildPolicy: &internalserviceconfig.BalancerConfig{ 611 Name: roundrobin.Name, 612 }, 613 }, 614 assertString(internal.LocalityID{Zone: "test-zone-2"}.ToString): { 615 Weight: 80, 616 ChildPolicy: &internalserviceconfig.BalancerConfig{ 617 Name: roundrobin.Name, 618 }, 619 }, 620 }, 621 }, 622 }, 623 }, 624 wantAddrs: []resolver.Address{ 625 testAddrWithAttrs("addr-1-1", nil, "test-priority", &internal.LocalityID{Zone: "test-zone-1"}), 626 testAddrWithAttrs("addr-1-2", nil, "test-priority", &internal.LocalityID{Zone: "test-zone-1"}), 627 testAddrWithAttrs("addr-2-1", nil, "test-priority", &internal.LocalityID{Zone: "test-zone-2"}), 628 testAddrWithAttrs("addr-2-2", nil, "test-priority", &internal.LocalityID{Zone: "test-zone-2"}), 629 }, 630 }, 631 { 632 name: "ring_hash as child", 633 localities: []xdsresource.Locality{ 634 { 635 Endpoints: []xdsresource.Endpoint{ 636 {Address: "addr-1-1", HealthStatus: xdsresource.EndpointHealthStatusHealthy, Weight: 90}, 637 {Address: "addr-1-2", HealthStatus: xdsresource.EndpointHealthStatusHealthy, Weight: 10}, 638 }, 639 ID: internal.LocalityID{Zone: "test-zone-1"}, 640 Weight: 20, 641 }, 642 { 643 Endpoints: []xdsresource.Endpoint{ 644 {Address: "addr-2-1", HealthStatus: xdsresource.EndpointHealthStatusHealthy, Weight: 90}, 645 {Address: "addr-2-2", HealthStatus: xdsresource.EndpointHealthStatusHealthy, Weight: 10}, 646 }, 647 ID: internal.LocalityID{Zone: "test-zone-2"}, 648 Weight: 80, 649 }, 650 }, 651 priorityName: "test-priority", 652 childPolicy: &internalserviceconfig.BalancerConfig{Name: rhName, Config: &ringhash.LBConfig{MinRingSize: 1, MaxRingSize: 2}}, 653 // lrsServer is nil, so LRS policy will not be used. 654 wantConfig: &clusterimpl.LBConfig{ 655 ChildPolicy: &internalserviceconfig.BalancerConfig{ 656 Name: ringhash.Name, 657 Config: &ringhash.LBConfig{MinRingSize: 1, MaxRingSize: 2}, 658 }, 659 }, 660 wantAddrs: []resolver.Address{ 661 testAddrWithAttrs("addr-1-1", newUint32(1800), "test-priority", &internal.LocalityID{Zone: "test-zone-1"}), 662 testAddrWithAttrs("addr-1-2", newUint32(200), "test-priority", &internal.LocalityID{Zone: "test-zone-1"}), 663 testAddrWithAttrs("addr-2-1", newUint32(7200), "test-priority", &internal.LocalityID{Zone: "test-zone-2"}), 664 testAddrWithAttrs("addr-2-2", newUint32(800), "test-priority", &internal.LocalityID{Zone: "test-zone-2"}), 665 }, 666 }, 667 { 668 name: "unsupported child", 669 localities: []xdsresource.Locality{{ 670 Endpoints: []xdsresource.Endpoint{ 671 {Address: "addr-1-1", HealthStatus: xdsresource.EndpointHealthStatusHealthy, Weight: 90}, 672 {Address: "addr-1-2", HealthStatus: xdsresource.EndpointHealthStatusHealthy, Weight: 10}, 673 }, 674 ID: internal.LocalityID{Zone: "test-zone-1"}, 675 Weight: 20, 676 }}, 677 priorityName: "test-priority", 678 childPolicy: &internalserviceconfig.BalancerConfig{Name: "some-child"}, 679 wantErr: true, 680 }, 681 } 682 for _, tt := range tests { 683 t.Run(tt.name, func(t *testing.T) { 684 got, got1, err := priorityLocalitiesToClusterImpl(tt.localities, tt.priorityName, tt.mechanism, nil, tt.childPolicy) 685 if (err != nil) != tt.wantErr { 686 t.Fatalf("priorityLocalitiesToClusterImpl() error = %v, wantErr %v", err, tt.wantErr) 687 } 688 if diff := cmp.Diff(got, tt.wantConfig); diff != "" { 689 t.Errorf("localitiesToWeightedTarget() diff (-got +want) %v", diff) 690 } 691 if diff := cmp.Diff(got1, tt.wantAddrs, cmp.AllowUnexported(attributes.Attributes{})); diff != "" { 692 t.Errorf("localitiesToWeightedTarget() diff (-got +want) %v", diff) 693 } 694 }) 695 } 696 } 697 698 func TestLocalitiesToWeightedTarget(t *testing.T) { 699 tests := []struct { 700 name string 701 localities []xdsresource.Locality 702 priorityName string 703 childPolicy *internalserviceconfig.BalancerConfig 704 lrsServer *string 705 wantConfig *weightedtarget.LBConfig 706 wantAddrs []resolver.Address 707 }{ 708 { 709 name: "roundrobin as child, with LRS", 710 localities: []xdsresource.Locality{ 711 { 712 Endpoints: []xdsresource.Endpoint{ 713 {Address: "addr-1-1", HealthStatus: xdsresource.EndpointHealthStatusHealthy}, 714 {Address: "addr-1-2", HealthStatus: xdsresource.EndpointHealthStatusHealthy}, 715 }, 716 ID: internal.LocalityID{Zone: "test-zone-1"}, 717 Weight: 20, 718 }, 719 { 720 Endpoints: []xdsresource.Endpoint{ 721 {Address: "addr-2-1", HealthStatus: xdsresource.EndpointHealthStatusHealthy}, 722 {Address: "addr-2-2", HealthStatus: xdsresource.EndpointHealthStatusHealthy}, 723 }, 724 ID: internal.LocalityID{Zone: "test-zone-2"}, 725 Weight: 80, 726 }, 727 }, 728 priorityName: "test-priority", 729 childPolicy: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}, 730 lrsServer: newString("test-lrs-server"), 731 wantConfig: &weightedtarget.LBConfig{ 732 Targets: map[string]weightedtarget.Target{ 733 assertString(internal.LocalityID{Zone: "test-zone-1"}.ToString): { 734 Weight: 20, 735 ChildPolicy: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}, 736 }, 737 assertString(internal.LocalityID{Zone: "test-zone-2"}.ToString): { 738 Weight: 80, 739 ChildPolicy: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}, 740 }, 741 }, 742 }, 743 wantAddrs: []resolver.Address{ 744 testAddrWithAttrs("addr-1-1", nil, "test-priority", &internal.LocalityID{Zone: "test-zone-1"}), 745 testAddrWithAttrs("addr-1-2", nil, "test-priority", &internal.LocalityID{Zone: "test-zone-1"}), 746 testAddrWithAttrs("addr-2-1", nil, "test-priority", &internal.LocalityID{Zone: "test-zone-2"}), 747 testAddrWithAttrs("addr-2-2", nil, "test-priority", &internal.LocalityID{Zone: "test-zone-2"}), 748 }, 749 }, 750 { 751 name: "roundrobin as child, no LRS", 752 localities: []xdsresource.Locality{ 753 { 754 Endpoints: []xdsresource.Endpoint{ 755 {Address: "addr-1-1", HealthStatus: xdsresource.EndpointHealthStatusHealthy}, 756 {Address: "addr-1-2", HealthStatus: xdsresource.EndpointHealthStatusHealthy}, 757 }, 758 ID: internal.LocalityID{Zone: "test-zone-1"}, 759 Weight: 20, 760 }, 761 { 762 Endpoints: []xdsresource.Endpoint{ 763 {Address: "addr-2-1", HealthStatus: xdsresource.EndpointHealthStatusHealthy}, 764 {Address: "addr-2-2", HealthStatus: xdsresource.EndpointHealthStatusHealthy}, 765 }, 766 ID: internal.LocalityID{Zone: "test-zone-2"}, 767 Weight: 80, 768 }, 769 }, 770 priorityName: "test-priority", 771 childPolicy: &internalserviceconfig.BalancerConfig{Name: roundrobin.Name}, 772 // lrsServer is nil, so LRS policy will not be used. 773 wantConfig: &weightedtarget.LBConfig{ 774 Targets: map[string]weightedtarget.Target{ 775 assertString(internal.LocalityID{Zone: "test-zone-1"}.ToString): { 776 Weight: 20, 777 ChildPolicy: &internalserviceconfig.BalancerConfig{ 778 Name: roundrobin.Name, 779 }, 780 }, 781 assertString(internal.LocalityID{Zone: "test-zone-2"}.ToString): { 782 Weight: 80, 783 ChildPolicy: &internalserviceconfig.BalancerConfig{ 784 Name: roundrobin.Name, 785 }, 786 }, 787 }, 788 }, 789 wantAddrs: []resolver.Address{ 790 testAddrWithAttrs("addr-1-1", nil, "test-priority", &internal.LocalityID{Zone: "test-zone-1"}), 791 testAddrWithAttrs("addr-1-2", nil, "test-priority", &internal.LocalityID{Zone: "test-zone-1"}), 792 testAddrWithAttrs("addr-2-1", nil, "test-priority", &internal.LocalityID{Zone: "test-zone-2"}), 793 testAddrWithAttrs("addr-2-2", nil, "test-priority", &internal.LocalityID{Zone: "test-zone-2"}), 794 }, 795 }, 796 { 797 name: "weighted round robin as child, no LRS", 798 localities: []xdsresource.Locality{ 799 { 800 Endpoints: []xdsresource.Endpoint{ 801 {Address: "addr-1-1", HealthStatus: xdsresource.EndpointHealthStatusHealthy, Weight: 90}, 802 {Address: "addr-1-2", HealthStatus: xdsresource.EndpointHealthStatusHealthy, Weight: 10}, 803 }, 804 ID: internal.LocalityID{Zone: "test-zone-1"}, 805 Weight: 20, 806 }, 807 { 808 Endpoints: []xdsresource.Endpoint{ 809 {Address: "addr-2-1", HealthStatus: xdsresource.EndpointHealthStatusHealthy, Weight: 90}, 810 {Address: "addr-2-2", HealthStatus: xdsresource.EndpointHealthStatusHealthy, Weight: 10}, 811 }, 812 ID: internal.LocalityID{Zone: "test-zone-2"}, 813 Weight: 80, 814 }, 815 }, 816 priorityName: "test-priority", 817 childPolicy: &internalserviceconfig.BalancerConfig{Name: weightedroundrobin.Name}, 818 // lrsServer is nil, so LRS policy will not be used. 819 wantConfig: &weightedtarget.LBConfig{ 820 Targets: map[string]weightedtarget.Target{ 821 assertString(internal.LocalityID{Zone: "test-zone-1"}.ToString): { 822 Weight: 20, 823 ChildPolicy: &internalserviceconfig.BalancerConfig{ 824 Name: weightedroundrobin.Name, 825 }, 826 }, 827 assertString(internal.LocalityID{Zone: "test-zone-2"}.ToString): { 828 Weight: 80, 829 ChildPolicy: &internalserviceconfig.BalancerConfig{ 830 Name: weightedroundrobin.Name, 831 }, 832 }, 833 }, 834 }, 835 wantAddrs: []resolver.Address{ 836 testAddrWithAttrs("addr-1-1", newUint32(90), "test-priority", &internal.LocalityID{Zone: "test-zone-1"}), 837 testAddrWithAttrs("addr-1-2", newUint32(10), "test-priority", &internal.LocalityID{Zone: "test-zone-1"}), 838 testAddrWithAttrs("addr-2-1", newUint32(90), "test-priority", &internal.LocalityID{Zone: "test-zone-2"}), 839 testAddrWithAttrs("addr-2-2", newUint32(10), "test-priority", &internal.LocalityID{Zone: "test-zone-2"}), 840 }, 841 }, 842 } 843 for _, tt := range tests { 844 t.Run(tt.name, func(t *testing.T) { 845 got, got1 := localitiesToWeightedTarget(tt.localities, tt.priorityName, tt.childPolicy) 846 if diff := cmp.Diff(got, tt.wantConfig); diff != "" { 847 t.Errorf("localitiesToWeightedTarget() diff (-got +want) %v", diff) 848 } 849 if diff := cmp.Diff(got1, tt.wantAddrs, cmp.AllowUnexported(attributes.Attributes{})); diff != "" { 850 t.Errorf("localitiesToWeightedTarget() diff (-got +want) %v", diff) 851 } 852 }) 853 } 854 } 855 856 func TestLocalitiesToRingHash(t *testing.T) { 857 tests := []struct { 858 name string 859 localities []xdsresource.Locality 860 priorityName string 861 wantAddrs []resolver.Address 862 }{ 863 { 864 // Check that address weights are locality_weight * endpoint_weight. 865 name: "with locality and endpoint weight", 866 localities: []xdsresource.Locality{ 867 { 868 Endpoints: []xdsresource.Endpoint{ 869 {Address: "addr-1-1", HealthStatus: xdsresource.EndpointHealthStatusHealthy, Weight: 90}, 870 {Address: "addr-1-2", HealthStatus: xdsresource.EndpointHealthStatusHealthy, Weight: 10}, 871 }, 872 ID: internal.LocalityID{Zone: "test-zone-1"}, 873 Weight: 20, 874 }, 875 { 876 Endpoints: []xdsresource.Endpoint{ 877 {Address: "addr-2-1", HealthStatus: xdsresource.EndpointHealthStatusHealthy, Weight: 90}, 878 {Address: "addr-2-2", HealthStatus: xdsresource.EndpointHealthStatusHealthy, Weight: 10}, 879 }, 880 ID: internal.LocalityID{Zone: "test-zone-2"}, 881 Weight: 80, 882 }, 883 }, 884 priorityName: "test-priority", 885 wantAddrs: []resolver.Address{ 886 testAddrWithAttrs("addr-1-1", newUint32(1800), "test-priority", &internal.LocalityID{Zone: "test-zone-1"}), 887 testAddrWithAttrs("addr-1-2", newUint32(200), "test-priority", &internal.LocalityID{Zone: "test-zone-1"}), 888 testAddrWithAttrs("addr-2-1", newUint32(7200), "test-priority", &internal.LocalityID{Zone: "test-zone-2"}), 889 testAddrWithAttrs("addr-2-2", newUint32(800), "test-priority", &internal.LocalityID{Zone: "test-zone-2"}), 890 }, 891 }, 892 { 893 // Check that endpoint_weight is 0, weight is the locality weight. 894 name: "locality weight only", 895 localities: []xdsresource.Locality{ 896 { 897 Endpoints: []xdsresource.Endpoint{ 898 {Address: "addr-1-1", HealthStatus: xdsresource.EndpointHealthStatusHealthy}, 899 {Address: "addr-1-2", HealthStatus: xdsresource.EndpointHealthStatusHealthy}, 900 }, 901 ID: internal.LocalityID{Zone: "test-zone-1"}, 902 Weight: 20, 903 }, 904 { 905 Endpoints: []xdsresource.Endpoint{ 906 {Address: "addr-2-1", HealthStatus: xdsresource.EndpointHealthStatusHealthy}, 907 {Address: "addr-2-2", HealthStatus: xdsresource.EndpointHealthStatusHealthy}, 908 }, 909 ID: internal.LocalityID{Zone: "test-zone-2"}, 910 Weight: 80, 911 }, 912 }, 913 priorityName: "test-priority", 914 wantAddrs: []resolver.Address{ 915 testAddrWithAttrs("addr-1-1", newUint32(20), "test-priority", &internal.LocalityID{Zone: "test-zone-1"}), 916 testAddrWithAttrs("addr-1-2", newUint32(20), "test-priority", &internal.LocalityID{Zone: "test-zone-1"}), 917 testAddrWithAttrs("addr-2-1", newUint32(80), "test-priority", &internal.LocalityID{Zone: "test-zone-2"}), 918 testAddrWithAttrs("addr-2-2", newUint32(80), "test-priority", &internal.LocalityID{Zone: "test-zone-2"}), 919 }, 920 }, 921 { 922 // Check that locality_weight is 0, weight is the endpoint weight. 923 name: "endpoint weight only", 924 localities: []xdsresource.Locality{ 925 { 926 Endpoints: []xdsresource.Endpoint{ 927 {Address: "addr-1-1", HealthStatus: xdsresource.EndpointHealthStatusHealthy, Weight: 90}, 928 {Address: "addr-1-2", HealthStatus: xdsresource.EndpointHealthStatusHealthy, Weight: 10}, 929 }, 930 ID: internal.LocalityID{Zone: "test-zone-1"}, 931 }, 932 { 933 Endpoints: []xdsresource.Endpoint{ 934 {Address: "addr-2-1", HealthStatus: xdsresource.EndpointHealthStatusHealthy, Weight: 90}, 935 {Address: "addr-2-2", HealthStatus: xdsresource.EndpointHealthStatusHealthy, Weight: 10}, 936 }, 937 ID: internal.LocalityID{Zone: "test-zone-2"}, 938 }, 939 }, 940 priorityName: "test-priority", 941 wantAddrs: []resolver.Address{ 942 testAddrWithAttrs("addr-1-1", newUint32(90), "test-priority", &internal.LocalityID{Zone: "test-zone-1"}), 943 testAddrWithAttrs("addr-1-2", newUint32(10), "test-priority", &internal.LocalityID{Zone: "test-zone-1"}), 944 testAddrWithAttrs("addr-2-1", newUint32(90), "test-priority", &internal.LocalityID{Zone: "test-zone-2"}), 945 testAddrWithAttrs("addr-2-2", newUint32(10), "test-priority", &internal.LocalityID{Zone: "test-zone-2"}), 946 }, 947 }, 948 } 949 for _, tt := range tests { 950 t.Run(tt.name, func(t *testing.T) { 951 got := localitiesToRingHash(tt.localities, tt.priorityName) 952 if diff := cmp.Diff(got, tt.wantAddrs, cmp.AllowUnexported(attributes.Attributes{})); diff != "" { 953 t.Errorf("localitiesToWeightedTarget() diff (-got +want) %v", diff) 954 } 955 }) 956 } 957 } 958 959 func assertString(f func() (string, error)) string { 960 s, err := f() 961 if err != nil { 962 panic(err.Error()) 963 } 964 return s 965 } 966 967 func testAddrWithAttrs(addrStr string, weight *uint32, priority string, lID *internal.LocalityID) resolver.Address { 968 addr := resolver.Address{Addr: addrStr} 969 if weight != nil { 970 addr = weightedroundrobin.SetAddrInfo(addr, weightedroundrobin.AddrInfo{Weight: *weight}) 971 } 972 path := []string{priority} 973 if lID != nil { 974 path = append(path, assertString(lID.ToString)) 975 addr = internal.SetLocalityID(addr, *lID) 976 } 977 addr = hierarchy.Set(addr, path) 978 return addr 979 }