@@ -22,6 +22,7 @@ import (
22
22
"encoding/json"
23
23
"fmt"
24
24
"strings"
25
+ "sync"
25
26
"testing"
26
27
"time"
27
28
@@ -455,3 +456,57 @@ func (s) TestLeastRequestPersistsCounts(t *testing.T) {
455
456
t .Fatalf ("addr count (-got:, +want): %v" , diff )
456
457
}
457
458
}
459
+
460
+ // TestConcurrentRPCs tests concurrent RPCs on the least request balancer. It
461
+ // configures a channel with a least request balancer as the top level balancer,
462
+ // and makes 100 RPCs asynchronously. This makes sure no race conditions happen
463
+ // in this scenario.
464
+ func (s ) TestConcurrentRPCs (t * testing.T ) {
465
+ addresses := setupBackends (t )
466
+
467
+ mr := manual .NewBuilderWithScheme ("lr-e2e" )
468
+ defer mr .Close ()
469
+
470
+ // Configure least request as top level balancer of channel.
471
+ lrscJSON := `
472
+ {
473
+ "loadBalancingConfig": [
474
+ {
475
+ "least_request_experimental": {
476
+ "choiceCount": 2
477
+ }
478
+ }
479
+ ]
480
+ }`
481
+ sc := internal .ParseServiceConfig .(func (string ) * serviceconfig.ParseResult )(lrscJSON )
482
+ firstTwoAddresses := []resolver.Address {
483
+ {Addr : addresses [0 ]},
484
+ {Addr : addresses [1 ]},
485
+ }
486
+ mr .InitialState (resolver.State {
487
+ Addresses : firstTwoAddresses ,
488
+ ServiceConfig : sc ,
489
+ })
490
+
491
+ cc , err := grpc .Dial (mr .Scheme ()+ ":///" , grpc .WithResolvers (mr ), grpc .WithTransportCredentials (insecure .NewCredentials ()))
492
+ if err != nil {
493
+ t .Fatalf ("grpc.Dial() failed: %v" , err )
494
+ }
495
+ defer cc .Close ()
496
+ ctx , cancel := context .WithTimeout (context .Background (), defaultTestTimeout )
497
+ defer cancel ()
498
+ testServiceClient := testgrpc .NewTestServiceClient (cc )
499
+
500
+ var wg sync.WaitGroup
501
+ for i := 0 ; i < 100 ; i ++ {
502
+ wg .Add (1 )
503
+ go func () {
504
+ defer wg .Done ()
505
+ for j := 0 ; j < 5 ; j ++ {
506
+ testServiceClient .EmptyCall (ctx , & testpb.Empty {})
507
+ }
508
+ }()
509
+ }
510
+ wg .Wait ()
511
+
512
+ }
0 commit comments