Skip to content

Commit 23c6cdd

Browse files
committed
addressing comments
1 parent 8283487 commit 23c6cdd

1 file changed

Lines changed: 113 additions & 81 deletions

File tree

internal/xds/balancer/clusterimpl/tests/balancer_test.go

Lines changed: 113 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828
"testing"
2929
"time"
3030

31+
"github.com/google/go-cmp/cmp"
3132
"github.com/google/uuid"
3233
"google.golang.org/grpc"
3334
"google.golang.org/grpc/codes"
@@ -44,6 +45,7 @@ import (
4445
"google.golang.org/grpc/status"
4546
"google.golang.org/protobuf/types/known/durationpb"
4647
"google.golang.org/protobuf/types/known/wrapperspb"
48+
"google.golang.org/protobuf/testing/protocmp"
4749

4850
v3clusterpb "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3"
4951
v3corepb "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
@@ -86,13 +88,12 @@ func (s) TestConfigUpdateWithSameLoadReportingServerConfig(t *testing.T) {
8688
testutils.CreateBootstrapFileForTesting(t, bc)
8789

8890
// Create an xDS resolver with the above bootstrap configuration.
89-
var resolverBuilder resolver.Builder
90-
var err error
91-
if newResolver := internal.NewXDSResolverWithConfigForTesting; newResolver != nil {
92-
resolverBuilder, err = newResolver.(func([]byte) (resolver.Builder, error))(bc)
93-
if err != nil {
94-
t.Fatalf("Failed to create xDS resolver for testing: %v", err)
95-
}
91+
if internal.NewXDSResolverWithConfigForTesting == nil {
92+
t.Fatalf("internal.NewXDSResolverWithConfigForTesting is nil")
93+
}
94+
resolverBuilder, err := internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))(bc)
95+
if err != nil {
96+
t.Fatalf("Failed to create xDS resolver for testing: %v", err)
9697
}
9798

9899
// Start a server backend exposing the test service.
@@ -195,13 +196,12 @@ func (s) TestLoadReportingPickFirstMultiLocality(t *testing.T) {
195196
bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address)
196197

197198
// Create an xDS resolver with the above bootstrap configuration.
198-
var resolverBuilder resolver.Builder
199-
var err error
200-
if newResolver := internal.NewXDSResolverWithConfigForTesting; newResolver != nil {
201-
resolverBuilder, err = newResolver.(func([]byte) (resolver.Builder, error))(bc)
202-
if err != nil {
203-
t.Fatalf("Failed to create xDS resolver for testing: %v", err)
204-
}
199+
if internal.NewXDSResolverWithConfigForTesting == nil {
200+
t.Fatalf("internal.NewXDSResolverWithConfigForTesting is nil")
201+
}
202+
resolverBuilder, err := internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))(bc)
203+
if err != nil {
204+
t.Fatalf("Failed to create xDS resolver for testing: %v", err)
205205
}
206206

207207
// Start two server backends exposing the test service.
@@ -360,8 +360,8 @@ func waitForSuccessfulLoadReport(ctx context.Context, lrsServer *fakeserver.Serv
360360
}
361361

362362
// Tests that circuit breaking limits RPCs E2E.
363-
func TestCircuitBreaking(t *testing.T) {
364-
// Create an xDS management server that serves ADS requests.
363+
func (s) TestCircuitBreaking(t *testing.T) {
364+
// Create an xDS management server that serves ADS and LRS requests.
365365
mgmtServer := e2e.StartManagementServer(t, e2e.ManagementServerOptions{SupportLoadReportingService: true})
366366

367367
// Create bootstrap configuration pointing to the above management server.
@@ -370,13 +370,12 @@ func TestCircuitBreaking(t *testing.T) {
370370
testutils.CreateBootstrapFileForTesting(t, bc)
371371

372372
// Create an xDS resolver with the above bootstrap configuration.
373-
var resolverBuilder resolver.Builder
374-
var err error
375-
if newResolver := internal.NewXDSResolverWithConfigForTesting; newResolver != nil {
376-
resolverBuilder, err = newResolver.(func([]byte) (resolver.Builder, error))(bc)
377-
if err != nil {
378-
t.Fatalf("Failed to create xDS resolver for testing: %v", err)
379-
}
373+
if internal.NewXDSResolverWithConfigForTesting == nil {
374+
t.Fatalf("internal.NewXDSResolverWithConfigForTesting is nil")
375+
}
376+
resolverBuilder, err := internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))(bc)
377+
if err != nil {
378+
t.Fatalf("Failed to create xDS resolver for testing: %v", err)
380379
}
381380

382381
// Start a server backend exposing the test service.
@@ -392,15 +391,15 @@ func TestCircuitBreaking(t *testing.T) {
392391
server := stubserver.StartTestService(t, f)
393392
defer server.Stop()
394393

395-
// Configure the xDS management server with default resources.
394+
// Configure xDS resources on the management server with a circuit breaking
395+
// policy that limits the maximum number of concurrent requests to 3.
396396
const serviceName = "my-test-xds-service"
397397
const maxRequests = 3
398398
resources := e2e.DefaultClientResources(e2e.ResourceParams{
399399
DialTarget: serviceName,
400400
NodeID: nodeID,
401401
Host: "localhost",
402402
Port: testutils.ParsePort(t, server.Address),
403-
SecLevel: e2e.SecurityLevelNone,
404403
})
405404
resources.Clusters[0].CircuitBreakers = &v3clusterpb.CircuitBreakers{
406405
Thresholds: []*v3clusterpb.CircuitBreakers_Thresholds{
@@ -429,6 +428,7 @@ func TestCircuitBreaking(t *testing.T) {
429428
}
430429
defer cc.Close()
431430

431+
cc.Connect()
432432
client := testgrpc.NewTestServiceClient(cc)
433433

434434
// Start maxRequests streams.
@@ -442,6 +442,9 @@ func TestCircuitBreaking(t *testing.T) {
442442
// allowed due to inherent raciness in the tracking, however.
443443
const droppedRPCCount = 100
444444
for i := 0; i < droppedRPCCount; i++ {
445+
if ctx.Err() != nil {
446+
t.Fatalf("Context error: %v", ctx.Err())
447+
}
445448
_, err := client.FullDuplexCall(ctx)
446449
switch {
447450
case err == nil:
@@ -451,7 +454,6 @@ func TestCircuitBreaking(t *testing.T) {
451454
default:
452455
t.Errorf("client.FullDuplexCall(_) failed with unexpected error = %v", err)
453456
}
454-
time.Sleep(10 * time.Millisecond)
455457
}
456458

457459
if _, err = mgmtServer.LRSServer.LRSStreamOpenChan.Receive(ctx); err != nil {
@@ -462,27 +464,37 @@ func TestCircuitBreaking(t *testing.T) {
462464
t.Fatalf("Failure waiting for initial LRS request: %v", err)
463465
}
464466

465-
resp := fakeserver.Response{
467+
mgmtServer.LRSServer.LRSResponseChan <- &fakeserver.Response{
466468
Resp: &v3lrspb.LoadStatsResponse{
467469
SendAllClusters: true,
468470
LoadReportingInterval: durationpb.New(10 * time.Millisecond),
469471
},
470472
}
471-
mgmtServer.LRSServer.LRSResponseChan <- &resp
472473

473474
select {
474475
case req := <-mgmtServer.LRSServer.LRSRequestChan.C:
475-
loadStats := req.(*fakeserver.Request).Req.(*v3lrspb.LoadStatsRequest)
476-
for _, cs := range loadStats.ClusterStats {
477-
if cs.TotalDroppedRequests != droppedRPCCount {
478-
t.Errorf("Failed with unexpected diff got: %v, want: %v", cs.TotalDroppedRequests, droppedRPCCount)
479-
}
480-
if cs.UpstreamLocalityStats[0].TotalIssuedRequests != maxRequests {
481-
t.Errorf("Failed with unexpected diff got: %v, want: %v", cs.UpstreamLocalityStats[0].TotalIssuedRequests, maxRequests)
482-
}
476+
clusterStats := req.(*fakeserver.Request).Req.(*v3lrspb.LoadStatsRequest).ClusterStats
477+
if l := len(clusterStats); l != 1 {
478+
t.Fatalf("Received load for %d clusters, want 1", l)
479+
}
480+
clusterStats[0].LoadReportInterval = nil
481+
wantLoad := &v3endpointpb.ClusterStats{
482+
ClusterName: "cluster-my-test-xds-service",
483+
ClusterServiceName: "endpoints-my-test-xds-service",
484+
UpstreamLocalityStats: []*v3endpointpb.UpstreamLocalityStats{
485+
{
486+
Locality: &v3corepb.Locality{Region: "region-1", Zone: "zone-1", SubZone: "subzone-1"},
487+
TotalIssuedRequests: maxRequests,
488+
TotalRequestsInProgress: maxRequests,
489+
},
490+
},
491+
TotalDroppedRequests: droppedRPCCount,
492+
}
493+
if diff := cmp.Diff(wantLoad, clusterStats[0], protocmp.Transform()); diff != "" {
494+
t.Errorf("Failed with unexpected diff (-want +got):\n%s", diff)
483495
}
484496
case <-ctx.Done():
485-
t.Fatalf("Timeout while waiting for LRS stream: %v", ctx.Err())
497+
t.Fatalf("Timeout while waiting for load report on LRS stream: %v", ctx.Err())
486498
}
487499
}
488500

@@ -493,16 +505,15 @@ func TestCircuitBreaking(t *testing.T) {
493505
// distribution. The function aims to find a number of RPCs such that
494506
// the observed probability is within a certain error_tolerance of the expected
495507
// probability (p).
496-
func computeIdealNumRpcs(p float64, errorTolerance float64) uint64 {
497-
numRpcs :=
498-
uint64(math.Ceil(p * (1 - p) * 5.00 * 5.00 / errorTolerance / errorTolerance))
508+
func computeIdealNumRpcs(p, errorTolerance float64) uint64 {
509+
numRpcs := uint64(math.Ceil(p * (1 - p) * 5.00 * 5.00 / errorTolerance / errorTolerance))
499510
return numRpcs
500511
}
501512

502513
// TestDropByCategory verifies that the balancer correctly drops the picks, and
503514
// that the drops are reported.
504-
func TestDropByCategory(t *testing.T) {
505-
// Create an xDS management server that serves ADS requests.
515+
func (s) TestDropByCategory(t *testing.T) {
516+
// Create an xDS management server that serves ADS and LRS requests.
506517
mgmtServer := e2e.StartManagementServer(t, e2e.ManagementServerOptions{SupportLoadReportingService: true})
507518

508519
// Create bootstrap configuration pointing to the above management server.
@@ -511,13 +522,12 @@ func TestDropByCategory(t *testing.T) {
511522
testutils.CreateBootstrapFileForTesting(t, bc)
512523

513524
// Create an xDS resolver with the above bootstrap configuration.
514-
var resolverBuilder resolver.Builder
515-
var err error
516-
if newResolver := internal.NewXDSResolverWithConfigForTesting; newResolver != nil {
517-
resolverBuilder, err = newResolver.(func([]byte) (resolver.Builder, error))(bc)
518-
if err != nil {
519-
t.Fatalf("Failed to create xDS resolver for testing: %v", err)
520-
}
525+
if internal.NewXDSResolverWithConfigForTesting == nil {
526+
t.Fatalf("internal.NewXDSResolverWithConfigForTesting is nil")
527+
}
528+
resolverBuilder, err := internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))(bc)
529+
if err != nil {
530+
t.Fatalf("Failed to create xDS resolver for testing: %v", err)
521531
}
522532

523533
// Start a server backend exposing the test service.
@@ -533,23 +543,24 @@ func TestDropByCategory(t *testing.T) {
533543
server := stubserver.StartTestService(t, f)
534544
defer server.Stop()
535545

536-
// Configure the xDS management server with default resources.
546+
// Configure xDS resources on the management server with drops configuration
547+
// that drops one RPC for every 50 RPCs made.
537548
const (
538549
dropReason = "test-dropping-category"
539550
dropNumerator = 1
540551
dropDenominator = 50
541552
serviceName = "my-test-xds-service"
542-
errortolerance = 0.05
553+
errorTolerance = 0.05
543554
)
544-
rpcDropRate := float64(dropNumerator) / float64(dropDenominator)
545-
rpcCount := computeIdealNumRpcs(rpcDropRate, errortolerance)
555+
wantRPCDropRate := float64(dropNumerator) / float64(dropDenominator)
556+
rpcCount := computeIdealNumRpcs(wantRPCDropRate, errorTolerance)
557+
t.Logf("Computed rpcCount: %d", rpcCount)
546558

547559
resources := e2e.DefaultClientResources(e2e.ResourceParams{
548560
DialTarget: serviceName,
549561
NodeID: nodeID,
550562
Host: "localhost",
551563
Port: testutils.ParsePort(t, server.Address),
552-
SecLevel: e2e.SecurityLevelNone,
553564
})
554565
resources.Clusters[0].LrsServer = &v3corepb.ConfigSource{
555566
ConfigSourceSpecifier: &v3corepb.ConfigSource_Self{
@@ -582,9 +593,10 @@ func TestDropByCategory(t *testing.T) {
582593
if err != nil {
583594
t.Fatalf("failed to dial local test server: %v", err)
584595
}
585-
cc.Connect()
586596
defer cc.Close()
587597

598+
// Ensure the gRPC channel is READY before issuing RPCs to get accurate drop count.
599+
cc.Connect()
588600
client := testgrpc.NewTestServiceClient(cc)
589601
testutils.AwaitState(ctx, t, cc, connectivity.Ready)
590602

@@ -615,24 +627,34 @@ func TestDropByCategory(t *testing.T) {
615627
resp := fakeserver.Response{
616628
Resp: &v3lrspb.LoadStatsResponse{
617629
SendAllClusters: true,
618-
LoadReportingInterval: durationpb.New(10 * time.Millisecond),
630+
LoadReportingInterval: durationpb.New(time.Second),
619631
},
620632
}
621633
mgmtServer.LRSServer.LRSResponseChan <- &resp
622634

635+
time.Sleep(time.Second)
623636
select {
624637
case req := <-mgmtServer.LRSServer.LRSRequestChan.C:
625638
loadStats := req.(*fakeserver.Request).Req.(*v3lrspb.LoadStatsRequest)
626639
for _, cs := range loadStats.ClusterStats {
627-
dropRate := float64(cs.TotalDroppedRequests / rpcCount)
628-
if math.Abs(dropRate-rpcDropRate) > errortolerance {
629-
t.Errorf("Drop rate goes out of errortolerance got %v, want %v", math.Abs(dropRate-rpcDropRate), errortolerance)
640+
if len(cs.DroppedRequests) > 0 {
641+
if cs.DroppedRequests[0].Category != dropReason {
642+
t.Errorf("Unexpected drop category got: %q, want: %q", cs.DroppedRequests[0].Category, dropReason)
643+
}
644+
gotRPCDropRate := float64(cs.DroppedRequests[0].DroppedCount) / float64(rpcCount)
645+
if math.Abs(gotRPCDropRate-wantRPCDropRate) > errorTolerance {
646+
t.Errorf("Drop rate goes out of errortolerance got: %v, want: %v, totalDroppedRequest: %v, totalIssuesRequest: %v", math.Abs(gotRPCDropRate-wantRPCDropRate), errorTolerance, cs.TotalDroppedRequests, cs.UpstreamLocalityStats[0].TotalIssuedRequests)
647+
}
648+
} else {
649+
t.Errorf("No DroppedRequests reported, want at least one with category %q", dropReason)
630650
}
631651
}
632652
case <-ctx.Done():
633-
t.Fatalf("Timeout while waiting for LRS stream: %v", ctx.Err())
653+
t.Fatalf("Timeout while waiting for load report on LRS stream: %v", ctx.Err())
634654
}
635655

656+
// Update the drop configuration to drop 1 out of every 40 RPCs,
657+
// and verify that the observed drop rate matches this new config.
636658
const (
637659
dropReason2 = "test-dropping-category-2"
638660
dropNumerator2 = 1
@@ -650,16 +672,17 @@ func TestDropByCategory(t *testing.T) {
650672
},
651673
},
652674
DropPercents: map[string]int{
653-
dropReason2: dropNumerator2 * 100 / dropDenominator2,
675+
dropReason2: dropNumerator2 * 100 / dropDenominator2, // drops one RPC for every 40 RPCs made
654676
},
655677
})}
656678

657679
if err := mgmtServer.Update(ctx, resources); err != nil {
658680
t.Fatal(err)
659681
}
660682

661-
rpcDropRate = float64(dropNumerator2) / float64(dropDenominator2)
662-
rpcCount = computeIdealNumRpcs(rpcDropRate, errortolerance)
683+
wantRPCDropRate = float64(dropNumerator2) / float64(dropDenominator2)
684+
rpcCount = computeIdealNumRpcs(wantRPCDropRate, errorTolerance)
685+
t.Logf("Computed rpcCount: %d", rpcCount)
663686

664687
for i := 0; i < int(rpcCount); i++ {
665688
if ctx.Err() != nil {
@@ -677,17 +700,28 @@ func TestDropByCategory(t *testing.T) {
677700
}
678701
}
679702

703+
time.Sleep(time.Second)
680704
select {
681705
case req := <-mgmtServer.LRSServer.LRSRequestChan.C:
682706
loadStats := req.(*fakeserver.Request).Req.(*v3lrspb.LoadStatsRequest)
683707
for _, cs := range loadStats.ClusterStats {
684-
dropRate := float64(cs.TotalDroppedRequests / rpcCount)
685-
if math.Abs(dropRate-rpcDropRate) > errortolerance {
686-
t.Errorf("Drop rate goes out of errortolerance got %v, want %v", math.Abs(dropRate-rpcDropRate), errortolerance)
708+
found := false
709+
for _, dr := range cs.DroppedRequests {
710+
if dr.Category == dropReason2 {
711+
found = true
712+
gotRPCDropRate := float64(dr.DroppedCount) / float64(rpcCount)
713+
if math.Abs(gotRPCDropRate-wantRPCDropRate) > errorTolerance {
714+
t.Errorf("Drop rate goes out of errortolerance got: %v, want: %v, totalDroppedRequest: %v, totalIssuesRequest: %v", math.Abs(gotRPCDropRate-wantRPCDropRate), errorTolerance, cs.TotalDroppedRequests, cs.UpstreamLocalityStats[0].TotalIssuedRequests)
715+
}
716+
break
717+
}
718+
}
719+
if !found {
720+
t.Errorf("No DroppedRequests reported for expected category %q", dropReason2)
687721
}
688722
}
689723
case <-ctx.Done():
690-
t.Fatalf("Timeout while waiting for LRS stream: %v", ctx.Err())
724+
t.Fatalf("Timeout while waiting for load report on LRS stream: %v", ctx.Err())
691725
}
692726
}
693727

@@ -702,13 +736,12 @@ func (s) TestCircuitBreakingLogicalDNS(t *testing.T) {
702736
testutils.CreateBootstrapFileForTesting(t, bc)
703737

704738
// Create an xDS resolver with the above bootstrap configuration.
705-
var resolverBuilder resolver.Builder
706-
var err error
707-
if newResolver := internal.NewXDSResolverWithConfigForTesting; newResolver != nil {
708-
resolverBuilder, err = newResolver.(func([]byte) (resolver.Builder, error))(bc)
709-
if err != nil {
710-
t.Fatalf("Failed to create xDS resolver for testing: %v", err)
711-
}
739+
if internal.NewXDSResolverWithConfigForTesting == nil {
740+
t.Fatalf("internal.NewXDSResolverWithConfigForTesting is nil")
741+
}
742+
resolverBuilder, err := internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))(bc)
743+
if err != nil {
744+
t.Fatalf("Failed to create xDS resolver for testing: %v", err)
712745
}
713746

714747
// Start a server backend exposing the test service.
@@ -822,13 +855,12 @@ func (s) TestLRSLogicalDNS(t *testing.T) {
822855
testutils.CreateBootstrapFileForTesting(t, bc)
823856

824857
// Create an xDS resolver with the above bootstrap configuration.
825-
var resolverBuilder resolver.Builder
826-
var err error
827-
if newResolver := internal.NewXDSResolverWithConfigForTesting; newResolver != nil {
828-
resolverBuilder, err = newResolver.(func([]byte) (resolver.Builder, error))(bc)
829-
if err != nil {
830-
t.Fatalf("Failed to create xDS resolver for testing: %v", err)
831-
}
858+
if internal.NewXDSResolverWithConfigForTesting == nil {
859+
t.Fatalf("internal.NewXDSResolverWithConfigForTesting is nil")
860+
}
861+
resolverBuilder, err := internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))(bc)
862+
if err != nil {
863+
t.Fatalf("Failed to create xDS resolver for testing: %v", err)
832864
}
833865

834866
// Start a server backend exposing the test service.

0 commit comments

Comments
 (0)