@@ -29,6 +29,7 @@ import (
2929 "google.golang.org/grpc/codes"
3030 "google.golang.org/grpc/connectivity"
3131 "google.golang.org/grpc/credentials/insecure"
32+ "google.golang.org/grpc/internal"
3233 "google.golang.org/grpc/internal/channelz"
3334 "google.golang.org/grpc/internal/envconfig"
3435 "google.golang.org/grpc/internal/grpcrand"
@@ -37,6 +38,7 @@ import (
3738 "google.golang.org/grpc/internal/testutils/pickfirst"
3839 "google.golang.org/grpc/resolver"
3940 "google.golang.org/grpc/resolver/manual"
41+ "google.golang.org/grpc/serviceconfig"
4042 "google.golang.org/grpc/status"
4143
4244 testgrpc "google.golang.org/grpc/interop/grpc_testing"
@@ -468,6 +470,107 @@ func (s) TestPickFirst_ShuffleAddressListDisabled(t *testing.T) {
468470 }
469471}
470472
473+ // Test config parsing with the env var turned on and off for various scenarios.
474+ func (s ) TestPickFirst_ParseConfig_Success (t * testing.T ) {
475+ // Install a shuffler that always reverses two entries.
476+ origShuf := grpcrand .Shuffle
477+ defer func () { grpcrand .Shuffle = origShuf }()
478+ grpcrand .Shuffle = func (n int , f func (int , int )) {
479+ if n != 2 {
480+ t .Errorf ("Shuffle called with n=%v; want 2" , n )
481+ return
482+ }
483+ f (0 , 1 ) // reverse the two addresses
484+ }
485+
486+ tests := []struct {
487+ name string
488+ envVar bool
489+ serviceConfig string
490+ wantFirstAddr bool
491+ }{
492+ {
493+ name : "env var disabled with empty pickfirst config" ,
494+ envVar : false ,
495+ serviceConfig : `{"loadBalancingConfig": [{"pick_first":{}}]}` ,
496+ wantFirstAddr : true ,
497+ },
498+ {
499+ name : "env var disabled with non-empty good pickfirst config" ,
500+ envVar : false ,
501+ serviceConfig : `{"loadBalancingConfig": [{"pick_first":{ "shuffleAddressList": true }}]}` ,
502+ wantFirstAddr : true ,
503+ },
504+ {
505+ name : "env var disabled with non-empty bad pickfirst config" ,
506+ envVar : false ,
507+ serviceConfig : `{"loadBalancingConfig": [{"pick_first":{ "shuffleAddressList": 666 }}]}` ,
508+ wantFirstAddr : true ,
509+ },
510+ {
511+ name : "env var enabled with empty pickfirst config" ,
512+ envVar : true ,
513+ serviceConfig : `{"loadBalancingConfig": [{"pick_first":{}}]}` ,
514+ wantFirstAddr : true ,
515+ },
516+ {
517+ name : "env var enabled with empty good pickfirst config" ,
518+ envVar : true ,
519+ serviceConfig : `{"loadBalancingConfig": [{"pick_first":{ "shuffleAddressList": true }}]}` ,
520+ wantFirstAddr : false ,
521+ },
522+ }
523+
524+ for _ , test := range tests {
525+ t .Run (test .name , func (t * testing.T ) {
526+ // Set the env var as specified by the test table.
527+ origPickFirstLBConfig := envconfig .PickFirstLBConfig
528+ envconfig .PickFirstLBConfig = test .envVar
529+ defer func () { envconfig .PickFirstLBConfig = origPickFirstLBConfig }()
530+
531+ // Set up our backends.
532+ cc , r , backends := setupPickFirst (t , 2 )
533+ addrs := stubBackendsToResolverAddrs (backends )
534+
535+ r .UpdateState (resolver.State {
536+ ServiceConfig : parseServiceConfig (t , r , test .serviceConfig ),
537+ Addresses : addrs ,
538+ })
539+
540+ // Some tests expect address shuffling to happen, and indicate that
541+ // by setting wantFirstAddr to false (since our shuffling function
542+ // defined at the top of this test, simply reverses the list of
543+ // addresses provided to it).
544+ wantAddr := addrs [0 ]
545+ if ! test .wantFirstAddr {
546+ wantAddr = addrs [1 ]
547+ }
548+
549+ ctx , cancel := context .WithTimeout (context .Background (), defaultTestTimeout )
550+ defer cancel ()
551+ if err := pickfirst .CheckRPCsToBackend (ctx , cc , wantAddr ); err != nil {
552+ t .Fatal (err )
553+ }
554+ })
555+ }
556+ }
557+
558+ // Test config parsing for a bad service config.
559+ func (s ) TestPickFirst_ParseConfig_Failure (t * testing.T ) {
560+ origPickFirstLBConfig := envconfig .PickFirstLBConfig
561+ envconfig .PickFirstLBConfig = true
562+ defer func () { envconfig .PickFirstLBConfig = origPickFirstLBConfig }()
563+
564+ // Service config should fail with the below config. Name resolvers are
565+ // expected to perform this parsing before they push the parsed service
566+ // config to the channel.
567+ const sc = `{"loadBalancingConfig": [{"pick_first":{ "shuffleAddressList": 666 }}]}`
568+ scpr := internal .ParseServiceConfig .(func (string ) * serviceconfig.ParseResult )(sc )
569+ if scpr .Err == nil {
570+ t .Fatalf ("ParseConfig() succeeded and returned %+v, when expected to fail" , scpr )
571+ }
572+ }
573+
471574// setupPickFirstWithListenerWrapper is very similar to setupPickFirst, but uses
472575// a wrapped listener that the test can use to track accepted connections.
473576func setupPickFirstWithListenerWrapper (t * testing.T , backendCount int , opts ... grpc.DialOption ) (* grpc.ClientConn , * manual.Resolver , []* stubserver.StubServer , []* testutils.ListenerWrapper ) {
0 commit comments