@@ -774,3 +774,90 @@ func (s) TestReResolution(t *testing.T) {
774774 time .Sleep (100 * time .Millisecond )
775775 }
776776}
777+
778+ // TestUpdateLRSServerToNil verifies that updating the cluster's LRS server config from 'Self' to nil
779+ // correctly closes the LRS stream and ensures no more LRS reports are sent.
780+ func (s ) TestUpdateLRSServerToNil (t * testing.T ) {
781+ // Create an xDS management server that serves ADS and LRS requests.
782+ mgmtServer := e2e .StartManagementServer (t , e2e.ManagementServerOptions {SupportLoadReportingService : true })
783+ defer mgmtServer .Stop ()
784+
785+ // Create bootstrap configuration pointing to the above management server.
786+ nodeID := uuid .New ().String ()
787+ bc := e2e .DefaultBootstrapContents (t , nodeID , mgmtServer .Address )
788+ testutils .CreateBootstrapFileForTesting (t , bc )
789+
790+ // Create an xDS resolver with the above bootstrap configuration.
791+ if internal .NewXDSResolverWithConfigForTesting == nil {
792+ t .Fatalf ("internal.NewXDSResolverWithConfigForTesting is nil" )
793+ }
794+ resolverBuilder , err := internal .NewXDSResolverWithConfigForTesting .(func ([]byte ) (resolver.Builder , error ))(bc )
795+ if err != nil {
796+ t .Fatalf ("Failed to create xDS resolver for testing: %v" , err )
797+ }
798+
799+ // Start a server backend exposing the test service.
800+ server := stubserver .StartTestService (t , nil )
801+ defer server .Stop ()
802+
803+ // Configure the xDS management server with default resources.
804+ const serviceName = "my-test-xds-service"
805+ resources := e2e .DefaultClientResources (e2e.ResourceParams {
806+ DialTarget : serviceName ,
807+ NodeID : nodeID ,
808+ Host : "localhost" ,
809+ Port : testutils .ParsePort (t , server .Address ),
810+ SecLevel : e2e .SecurityLevelNone ,
811+ })
812+ resources .Clusters [0 ].LrsServer = & v3corepb.ConfigSource {
813+ ConfigSourceSpecifier : & v3corepb.ConfigSource_Self {
814+ Self : & v3corepb.SelfConfigSource {},
815+ },
816+ }
817+
818+ ctx , cancel := context .WithTimeout (context .Background (), defaultTestTimeout )
819+ defer cancel ()
820+ if err := mgmtServer .Update (ctx , resources ); err != nil {
821+ t .Fatal (err )
822+ }
823+
824+ // Create a ClientConn and make a successful RPC.
825+ cc , err := grpc .NewClient (fmt .Sprintf ("xds:///%s" , serviceName ),
826+ grpc .WithTransportCredentials (insecure .NewCredentials ()),
827+ grpc .WithResolvers (resolverBuilder ))
828+ if err != nil {
829+ t .Fatalf ("failed to dial local test server: %v" , err )
830+ }
831+
832+ cc .Connect ()
833+ defer cc .Close ()
834+ client := testgrpc .NewTestServiceClient (cc )
835+
836+ if _ , err := client .EmptyCall (ctx , & testpb.Empty {}); err != nil {
837+ t .Fatalf ("rpc EmptyCall() failed: %v" , err )
838+ }
839+
840+ // Ensure that an LRS stream is created.
841+ if _ , err := mgmtServer .LRSServer .LRSStreamOpenChan .Receive (ctx ); err != nil {
842+ t .Fatalf ("error waiting for initial LRS stream open: %v" , err )
843+ }
844+ if _ , err := mgmtServer .LRSServer .LRSRequestChan .Receive (ctx ); err != nil {
845+ t .Fatalf ("error waiting for initial LRS report: %v" , err )
846+ }
847+
848+ // Update LRS Server to nil
849+ resources .Clusters [0 ].LrsServer = nil
850+ if err := mgmtServer .Update (ctx , resources ); err != nil {
851+ t .Fatal (err )
852+ }
853+
854+ // Ensure that the old LRS stream is not closed.
855+ if _ , err := mgmtServer .LRSServer .LRSStreamCloseChan .Receive (ctx ); err != nil {
856+ t .Fatalf ("error waiting for initial LRS stream close : %v" , err )
857+ }
858+
859+ // Also ensure that a new LRS stream is not created.
860+ if _ , err := mgmtServer .LRSServer .LRSRequestChan .Receive (ctx ); err != context .DeadlineExceeded {
861+ t .Fatalf ("expected no LRS reports after disable, but got: %v" , err )
862+ }
863+ }
0 commit comments