|
1 | 1 | package resolver
|
2 | 2 |
|
3 | 3 | import (
|
| 4 | + "fmt" |
4 | 5 | "testing"
|
5 | 6 |
|
6 | 7 | "github.com/google/go-cmp/cmp"
|
| 8 | + . "github.com/onsi/gomega" |
7 | 9 | v1 "k8s.io/api/core/v1"
|
8 | 10 | discoveryV1 "k8s.io/api/discovery/v1"
|
9 | 11 | "k8s.io/apimachinery/pkg/util/intstr"
|
@@ -470,3 +472,134 @@ func TestFindPort(t *testing.T) {
|
470 | 472 | }
|
471 | 473 | }
|
472 | 474 | }
|
| 475 | + |
| 476 | +func TestCalculateReadyEndpoints(t *testing.T) { |
| 477 | + g := NewGomegaWithT(t) |
| 478 | + |
| 479 | + slices := []discoveryV1.EndpointSlice{ |
| 480 | + { |
| 481 | + Endpoints: []discoveryV1.Endpoint{ |
| 482 | + { |
| 483 | + Addresses: []string{"1.0.0.1"}, |
| 484 | + Conditions: discoveryV1.EndpointConditions{ |
| 485 | + Ready: helpers.GetBoolPointer(true), |
| 486 | + }, |
| 487 | + }, |
| 488 | + { |
| 489 | + Addresses: []string{"1.1.0.1", "1.1.0.2", "1.1.0.3, 1.1.0.4, 1.1.0.5"}, |
| 490 | + Conditions: discoveryV1.EndpointConditions{ |
| 491 | + // nil conditions should be treated as not ready |
| 492 | + }, |
| 493 | + }, |
| 494 | + }, |
| 495 | + }, |
| 496 | + { |
| 497 | + Endpoints: []discoveryV1.Endpoint{ |
| 498 | + { |
| 499 | + Addresses: []string{"2.0.0.1", "2.0.0.2", "2.0.0.3"}, |
| 500 | + Conditions: discoveryV1.EndpointConditions{ |
| 501 | + Ready: helpers.GetBoolPointer(true), |
| 502 | + }, |
| 503 | + }, |
| 504 | + }, |
| 505 | + }, |
| 506 | + } |
| 507 | + |
| 508 | + result := calculateReadyEndpoints(slices) |
| 509 | + |
| 510 | + g.Expect(result).To(Equal(4)) |
| 511 | +} |
| 512 | + |
| 513 | +func generateEndpointSliceList(n int) discoveryV1.EndpointSliceList { |
| 514 | + const maxEndpointsPerSlice = 100 // use the Kubernetes default max for endpoints in a slice. |
| 515 | + |
| 516 | + slicesCount := (n + maxEndpointsPerSlice - 1) / maxEndpointsPerSlice |
| 517 | + |
| 518 | + result := discoveryV1.EndpointSliceList{ |
| 519 | + Items: make([]discoveryV1.EndpointSlice, 0, slicesCount), |
| 520 | + } |
| 521 | + |
| 522 | + ready := true |
| 523 | + |
| 524 | + for i := 0; n > 0; i++ { |
| 525 | + c := maxEndpointsPerSlice |
| 526 | + if n < maxEndpointsPerSlice { |
| 527 | + c = n |
| 528 | + } |
| 529 | + n -= maxEndpointsPerSlice |
| 530 | + |
| 531 | + slice := discoveryV1.EndpointSlice{ |
| 532 | + Endpoints: make([]discoveryV1.Endpoint, c), |
| 533 | + AddressType: discoveryV1.AddressTypeIPv4, |
| 534 | + Ports: []discoveryV1.EndpointPort{ |
| 535 | + { |
| 536 | + Port: nil, // will match any port in the service |
| 537 | + }, |
| 538 | + }, |
| 539 | + } |
| 540 | + |
| 541 | + for j := 0; j < c; j++ { |
| 542 | + slice.Endpoints[j] = discoveryV1.Endpoint{ |
| 543 | + Addresses: []string{fmt.Sprintf("10.0.%d.%d", i, j)}, |
| 544 | + Conditions: discoveryV1.EndpointConditions{ |
| 545 | + Ready: &ready, |
| 546 | + }, |
| 547 | + } |
| 548 | + } |
| 549 | + |
| 550 | + result.Items = append(result.Items, slice) |
| 551 | + } |
| 552 | + |
| 553 | + return result |
| 554 | +} |
| 555 | + |
| 556 | +func BenchmarkResolve(b *testing.B) { |
| 557 | + counts := []int{ |
| 558 | + 1, |
| 559 | + 2, |
| 560 | + 5, |
| 561 | + 10, |
| 562 | + 25, |
| 563 | + 50, |
| 564 | + 100, |
| 565 | + 500, |
| 566 | + 1000, |
| 567 | + } |
| 568 | + |
| 569 | + svc := &v1.Service{ |
| 570 | + Spec: v1.ServiceSpec{ |
| 571 | + Ports: []v1.ServicePort{ |
| 572 | + { |
| 573 | + Port: 80, |
| 574 | + }, |
| 575 | + }, |
| 576 | + }, |
| 577 | + } |
| 578 | + |
| 579 | + initEndpointSet := func([]discoveryV1.EndpointSlice) map[Endpoint]struct{} { |
| 580 | + return make(map[Endpoint]struct{}) |
| 581 | + } |
| 582 | + |
| 583 | + for _, count := range counts { |
| 584 | + list := generateEndpointSliceList(count) |
| 585 | + |
| 586 | + b.Run(fmt.Sprintf("%d endpoints", count), func(b *testing.B) { |
| 587 | + bench(b, svc, list, initEndpointSet, count) |
| 588 | + }) |
| 589 | + b.Run(fmt.Sprintf("%d endpoints with optimization", count), func(b *testing.B) { |
| 590 | + bench(b, svc, list, initEndpointSetWithCalculatedSize, count) |
| 591 | + }) |
| 592 | + } |
| 593 | +} |
| 594 | + |
| 595 | +func bench(b *testing.B, svc *v1.Service, list discoveryV1.EndpointSliceList, initSet initEndpointSetFunc, n int) { |
| 596 | + for i := 0; i < b.N; i++ { |
| 597 | + res, err := resolveEndpoints(svc, 80, list, initSet) |
| 598 | + if len(res) != n { |
| 599 | + b.Fatalf("expected %d endpoints, got %d", n, len(res)) |
| 600 | + } |
| 601 | + if err != nil { |
| 602 | + b.Fatal(err) |
| 603 | + } |
| 604 | + } |
| 605 | +} |
0 commit comments