From e035e088a48a88effedd87579c392e6798de54ef Mon Sep 17 00:00:00 2001 From: Eshita Chandwani Date: Wed, 30 Jul 2025 13:40:23 +0530 Subject: [PATCH 01/11] create lrs at creation time --- xds/internal/xdsclient/clientimpl.go | 9 +++++++++ xds/internal/xdsclient/clientimpl_loadreport.go | 11 ++--------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/xds/internal/xdsclient/clientimpl.go b/xds/internal/xdsclient/clientimpl.go index 967182740719..322b65527caf 100644 --- a/xds/internal/xdsclient/clientimpl.go +++ b/xds/internal/xdsclient/clientimpl.go @@ -130,6 +130,15 @@ func newClientImpl(config *bootstrap.Config, metricsRecorder estats.MetricsRecor return nil, err } c := &clientImpl{XDSClient: client, xdsClientConfig: gConfig, bootstrapConfig: config, target: target, refCount: 1} + lrsC, err := lrsclient.New(lrsclient.Config{ + Node: c.xdsClientConfig.Node, + TransportBuilder: c.xdsClientConfig.TransportBuilder, + }) + if err != nil { + c.logger.Warningf("Failed to create an lrs client to the management server to report load: %v", err) + return nil, err + } + c.lrsClient = lrsC c.logger = prefixLogger(c) return c, nil } diff --git a/xds/internal/xdsclient/clientimpl_loadreport.go b/xds/internal/xdsclient/clientimpl_loadreport.go index 39004ae7ef77..1679bdc391fa 100644 --- a/xds/internal/xdsclient/clientimpl_loadreport.go +++ b/xds/internal/xdsclient/clientimpl_loadreport.go @@ -33,15 +33,8 @@ import ( // It returns a lrsclient.LoadStore for the user to report loads. func (c *clientImpl) ReportLoad(server *bootstrap.ServerConfig) (*lrsclient.LoadStore, func(context.Context)) { if c.lrsClient == nil { - lrsC, err := lrsclient.New(lrsclient.Config{ - Node: c.xdsClientConfig.Node, - TransportBuilder: c.xdsClientConfig.TransportBuilder, - }) - if err != nil { - c.logger.Warningf("Failed to create an lrs client to the management server to report load: %v", server, err) - return nil, func(context.Context) {} - } - c.lrsClient = lrsC + c.logger.Warningf("lrs Client not found") + return nil, func(context.Context) {} } load, err := c.lrsClient.ReportLoad(clients.ServerIdentifier{ From 339ac57f0d4a15f83fb5985e8ffb75695ca79286 Mon Sep 17 00:00:00 2001 From: Eshita Chandwani Date: Fri, 1 Aug 2025 13:35:42 +0530 Subject: [PATCH 02/11] test race --- .../xdsclient/tests/loadreport_test.go | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/xds/internal/xdsclient/tests/loadreport_test.go b/xds/internal/xdsclient/tests/loadreport_test.go index a93b5bc1cbee..1149261ef500 100644 --- a/xds/internal/xdsclient/tests/loadreport_test.go +++ b/xds/internal/xdsclient/tests/loadreport_test.go @@ -437,3 +437,34 @@ func (s) TestReportLoad_StreamCreation(t *testing.T) { defer sCancel3() cancel3(sCtx3) } + +// TestConcurrentReportLoad verifies that the client can safely handle concurrent +// requests to initiate load reporting streams. It launches multiple goroutines +// that all call client.ReportLoad simultaneously. +func (s) TestConcurrentReportLoad(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) + defer cancel() + + // Create a management server that serves LRS. + mgmtServer := e2e.StartManagementServer(t, e2e.ManagementServerOptions{SupportLoadReportingService: true}) + + // Create an xDS client with bootstrap pointing to the above server. + nodeID := uuid.New().String() + bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address) + client := createXDSClient(t, bc) + + serverConfig, err := bootstrap.ServerConfigForTesting(bootstrap.ServerConfigTestingOptions{URI: mgmtServer.Address}) + if err != nil { + t.Fatalf("Failed to create server config for testing: %v", err) + } + // Call ReportLoad() concurrently from multiple go routines. + const numGoroutines = 10 + for i := 0; i < numGoroutines; i++ { + go func() { + store, cancelStore := client.ReportLoad(serverConfig) + if store != nil { + defer cancelStore(ctx) + } + }() + } +} From 8f53b149fcb1f7c33cbb95749f8688d6d3f12f20 Mon Sep 17 00:00:00 2001 From: Eshita Chandwani Date: Fri, 1 Aug 2025 13:57:22 +0530 Subject: [PATCH 03/11] add waitgroup --- xds/internal/xdsclient/tests/loadreport_test.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/xds/internal/xdsclient/tests/loadreport_test.go b/xds/internal/xdsclient/tests/loadreport_test.go index 1149261ef500..a87c2ae25d1e 100644 --- a/xds/internal/xdsclient/tests/loadreport_test.go +++ b/xds/internal/xdsclient/tests/loadreport_test.go @@ -23,6 +23,7 @@ import ( "encoding/json" "fmt" "net" + "sync" "testing" "github.com/google/go-cmp/cmp" @@ -458,13 +459,15 @@ func (s) TestConcurrentReportLoad(t *testing.T) { t.Fatalf("Failed to create server config for testing: %v", err) } // Call ReportLoad() concurrently from multiple go routines. + var wg sync.WaitGroup const numGoroutines = 10 + wg.Add(numGoroutines) for i := 0; i < numGoroutines; i++ { go func() { - store, cancelStore := client.ReportLoad(serverConfig) - if store != nil { - defer cancelStore(ctx) - } + defer wg.Done() + _, cancelStore := client.ReportLoad(serverConfig) + defer cancelStore(ctx) }() } + wg.Wait() } From 56d3a584f4929a5c0ac561c1a181debe6e9ec619 Mon Sep 17 00:00:00 2001 From: Eshita Chandwani Date: Fri, 1 Aug 2025 14:19:55 +0530 Subject: [PATCH 04/11] error --- xds/internal/xdsclient/tests/loadreport_test.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/xds/internal/xdsclient/tests/loadreport_test.go b/xds/internal/xdsclient/tests/loadreport_test.go index a87c2ae25d1e..2aaf0dcffcd8 100644 --- a/xds/internal/xdsclient/tests/loadreport_test.go +++ b/xds/internal/xdsclient/tests/loadreport_test.go @@ -465,7 +465,10 @@ func (s) TestConcurrentReportLoad(t *testing.T) { for i := 0; i < numGoroutines; i++ { go func() { defer wg.Done() - _, cancelStore := client.ReportLoad(serverConfig) + store, cancelStore := client.ReportLoad(serverConfig) + if store == nil { + t.Errorf("ReportLoad() got nil store, want non-nil") + } defer cancelStore(ctx) }() } From 2f6d3b407ad5eb4dc338a80fc74fd69a4432dddf Mon Sep 17 00:00:00 2001 From: Eshita Chandwani Date: Fri, 1 Aug 2025 20:56:46 +0530 Subject: [PATCH 05/11] remove nil checks --- xds/internal/xdsclient/clientimpl.go | 8 +++----- xds/internal/xdsclient/clientimpl_loadreport.go | 5 ----- xds/internal/xdsclient/tests/loadreport_test.go | 5 +---- 3 files changed, 4 insertions(+), 14 deletions(-) diff --git a/xds/internal/xdsclient/clientimpl.go b/xds/internal/xdsclient/clientimpl.go index 322b65527caf..901b96392561 100644 --- a/xds/internal/xdsclient/clientimpl.go +++ b/xds/internal/xdsclient/clientimpl.go @@ -129,16 +129,14 @@ func newClientImpl(config *bootstrap.Config, metricsRecorder estats.MetricsRecor if err != nil { return nil, err } - c := &clientImpl{XDSClient: client, xdsClientConfig: gConfig, bootstrapConfig: config, target: target, refCount: 1} lrsC, err := lrsclient.New(lrsclient.Config{ - Node: c.xdsClientConfig.Node, - TransportBuilder: c.xdsClientConfig.TransportBuilder, + Node: gConfig.Node, + TransportBuilder: gConfig.TransportBuilder, }) if err != nil { - c.logger.Warningf("Failed to create an lrs client to the management server to report load: %v", err) return nil, err } - c.lrsClient = lrsC + c := &clientImpl{XDSClient: client, xdsClientConfig: gConfig, bootstrapConfig: config, target: target, refCount: 1, lrsClient: lrsC} c.logger = prefixLogger(c) return c, nil } diff --git a/xds/internal/xdsclient/clientimpl_loadreport.go b/xds/internal/xdsclient/clientimpl_loadreport.go index 1679bdc391fa..d1202876db4b 100644 --- a/xds/internal/xdsclient/clientimpl_loadreport.go +++ b/xds/internal/xdsclient/clientimpl_loadreport.go @@ -32,11 +32,6 @@ import ( // // It returns a lrsclient.LoadStore for the user to report loads. func (c *clientImpl) ReportLoad(server *bootstrap.ServerConfig) (*lrsclient.LoadStore, func(context.Context)) { - if c.lrsClient == nil { - c.logger.Warningf("lrs Client not found") - return nil, func(context.Context) {} - } - load, err := c.lrsClient.ReportLoad(clients.ServerIdentifier{ ServerURI: server.ServerURI(), Extensions: grpctransport.ServerIdentifierExtension{ diff --git a/xds/internal/xdsclient/tests/loadreport_test.go b/xds/internal/xdsclient/tests/loadreport_test.go index 2aaf0dcffcd8..a87c2ae25d1e 100644 --- a/xds/internal/xdsclient/tests/loadreport_test.go +++ b/xds/internal/xdsclient/tests/loadreport_test.go @@ -465,10 +465,7 @@ func (s) TestConcurrentReportLoad(t *testing.T) { for i := 0; i < numGoroutines; i++ { go func() { defer wg.Done() - store, cancelStore := client.ReportLoad(serverConfig) - if store == nil { - t.Errorf("ReportLoad() got nil store, want non-nil") - } + _, cancelStore := client.ReportLoad(serverConfig) defer cancelStore(ctx) }() } From 90bc53cbb483f324ee6f5a1a07c8eceaab64fa4c Mon Sep 17 00:00:00 2001 From: Eshita Chandwani Date: Tue, 5 Aug 2025 14:16:11 +0530 Subject: [PATCH 06/11] format --- xds/internal/xdsclient/clientimpl.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/xds/internal/xdsclient/clientimpl.go b/xds/internal/xdsclient/clientimpl.go index 901b96392561..6f71dc6b0811 100644 --- a/xds/internal/xdsclient/clientimpl.go +++ b/xds/internal/xdsclient/clientimpl.go @@ -136,7 +136,14 @@ func newClientImpl(config *bootstrap.Config, metricsRecorder estats.MetricsRecor if err != nil { return nil, err } - c := &clientImpl{XDSClient: client, xdsClientConfig: gConfig, bootstrapConfig: config, target: target, refCount: 1, lrsClient: lrsC} + c := &clientImpl{ + XDSClient: client, + xdsClientConfig: gConfig, + bootstrapConfig: config, + target: target, + refCount: 1, + lrsClient: lrsC, + } c.logger = prefixLogger(c) return c, nil } From 40674fc9be9b45299aafadd67c3a22de1133999f Mon Sep 17 00:00:00 2001 From: eshitachandwani Date: Wed, 13 Aug 2025 22:06:10 +0530 Subject: [PATCH 07/11] optional node id --- xds/internal/clients/lrsclient/lrsclient.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/xds/internal/clients/lrsclient/lrsclient.go b/xds/internal/clients/lrsclient/lrsclient.go index af163e22019c..4a1c75d888d6 100644 --- a/xds/internal/clients/lrsclient/lrsclient.go +++ b/xds/internal/clients/lrsclient/lrsclient.go @@ -62,8 +62,6 @@ type LRSClient struct { // New returns a new LRS Client configured with the provided config. func New(config Config) (*LRSClient, error) { switch { - case config.Node.ID == "": - return nil, errors.New("lrsclient: node ID in node is empty") case config.TransportBuilder == nil: return nil, errors.New("lrsclient: transport builder is nil") } From 51309ec0486e126fc7759ee505d6d7e7a832e787 Mon Sep 17 00:00:00 2001 From: eshitachandwani Date: Wed, 13 Aug 2025 22:45:21 +0530 Subject: [PATCH 08/11] optional node id --- xds/internal/clients/lrsclient/lrsclient.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/xds/internal/clients/lrsclient/lrsclient.go b/xds/internal/clients/lrsclient/lrsclient.go index 4a1c75d888d6..21636fd8a5c6 100644 --- a/xds/internal/clients/lrsclient/lrsclient.go +++ b/xds/internal/clients/lrsclient/lrsclient.go @@ -61,8 +61,7 @@ type LRSClient struct { // New returns a new LRS Client configured with the provided config. func New(config Config) (*LRSClient, error) { - switch { - case config.TransportBuilder == nil: + if config.TransportBuilder == nil { return nil, errors.New("lrsclient: transport builder is nil") } From c0ebd9946dc6dd3a063423c340dea784df9490d8 Mon Sep 17 00:00:00 2001 From: eshitachandwani Date: Wed, 20 Aug 2025 15:58:56 +0530 Subject: [PATCH 09/11] e2e test --- .../xdsclient/tests/loadreport_test.go | 100 ++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/xds/internal/xdsclient/tests/loadreport_test.go b/xds/internal/xdsclient/tests/loadreport_test.go index a87c2ae25d1e..e0accff1b44d 100644 --- a/xds/internal/xdsclient/tests/loadreport_test.go +++ b/xds/internal/xdsclient/tests/loadreport_test.go @@ -31,12 +31,19 @@ import ( "github.com/google/uuid" "google.golang.org/grpc" "google.golang.org/grpc/codes" + "google.golang.org/grpc/credentials/insecure" + "google.golang.org/grpc/internal" + "google.golang.org/grpc/internal/stubserver" "google.golang.org/grpc/internal/testutils" "google.golang.org/grpc/internal/testutils/xds/e2e" "google.golang.org/grpc/internal/testutils/xds/fakeserver" "google.golang.org/grpc/internal/xds/bootstrap" + testgrpc "google.golang.org/grpc/interop/grpc_testing" + testpb "google.golang.org/grpc/interop/grpc_testing" + "google.golang.org/grpc/resolver" "google.golang.org/grpc/status" "google.golang.org/grpc/xds/internal/clients" + "google.golang.org/grpc/xds/internal/xdsclient" "google.golang.org/protobuf/testing/protocmp" v3corepb "github.com/envoyproxy/go-control-plane/envoy/config/core/v3" @@ -471,3 +478,96 @@ func (s) TestConcurrentReportLoad(t *testing.T) { } wg.Wait() } + +// TestConcurrentChannels verifies that we can create mutliple gRPC channels +// concurrently with a shared XDSClient, each of which will create a new LRS +// stream without any race. +func (s) TestConcurrentChannels(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) + defer cancel() + + // Create a management server that serves LRS. + mgmtServer := e2e.StartManagementServer(t, e2e.ManagementServerOptions{AllowResourceSubset: true, SupportLoadReportingService: true}) + + // Create bootstrap configuration pointing to the above management server. + nodeID := uuid.New().String() + bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address) + + // // Create an xDS resolver with the above bootstrap configuration. + if internal.NewXDSResolverWithPoolForTesting == nil { + t.Fatalf("internal.NewXDSResolverWithConfigForTesting is nil") + } + + config, err := bootstrap.NewConfigFromContents(bc) + if err != nil { + t.Fatalf("Failed to parse bootstrap contents: %s, %v", string(bc), err) + } + pool := xdsclient.NewPool(config) + + // Get the xDS resolver to use the above xDS client. + resolverBuilder := internal.NewXDSResolverWithPoolForTesting.(func(*xdsclient.Pool) (resolver.Builder, error)) + xdsResolver, err := resolverBuilder(pool) + if err != nil { + t.Fatalf("Failed to create xDS resolver for testing: %v", err) + } + + // Start a backend test service. + server := stubserver.StartTestService(t, nil) + defer server.Stop() + + // Configure the management server with resources that enable LRS. + const serviceName = "my-service-e2e-lrs-test" + resources := e2e.DefaultClientResources(e2e.ResourceParams{ + DialTarget: serviceName, + NodeID: nodeID, + Host: "localhost", + Port: testutils.ParsePort(t, server.Address), + SecLevel: e2e.SecurityLevelNone, + }) + resources.Clusters[0].LrsServer = &v3corepb.ConfigSource{ + ConfigSourceSpecifier: &v3corepb.ConfigSource_Self{ + Self: &v3corepb.SelfConfigSource{}, + }, + } + if err := mgmtServer.Update(ctx, resources); err != nil { + t.Fatal(err) + } + + var wg sync.WaitGroup + const ( + numGoroutines = 10 + numRPCs = 10 + ) + start := make(chan struct{}) + for i := 0; i < numGoroutines; i++ { + wg.Add(1) + go func() { + <-start + defer wg.Done() + for range numRPCs { + cc, err := grpc.NewClient(fmt.Sprintf("xds:///%s", serviceName), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithResolvers(xdsResolver)) + if err != nil { + // This can happen if the test context is cancelled. + if ctx.Err() != nil { + return + } + t.Errorf("grpc.NewClient() failed: %v", err) + return + } + defer cc.Close() + + testClient := testgrpc.NewTestServiceClient(cc) + if _, err := testClient.EmptyCall(ctx, &testpb.Empty{}); err != nil { + // This can happen if the test context is cancelled. + if ctx.Err() != nil { + return + } + t.Errorf("EmptyCall() failed: %v", err) + return + } + } + }() + } + close(start) + wg.Wait() +} From b8905c8efe33628484eb2e11b6d75543565e871e Mon Sep 17 00:00:00 2001 From: eshitachandwani Date: Thu, 21 Aug 2025 17:11:26 +0530 Subject: [PATCH 10/11] comments --- .../xdsclient/tests/loadreport_test.go | 28 ++++--------------- 1 file changed, 6 insertions(+), 22 deletions(-) diff --git a/xds/internal/xdsclient/tests/loadreport_test.go b/xds/internal/xdsclient/tests/loadreport_test.go index e0accff1b44d..90a344d07bd1 100644 --- a/xds/internal/xdsclient/tests/loadreport_test.go +++ b/xds/internal/xdsclient/tests/loadreport_test.go @@ -453,10 +453,7 @@ func (s) TestConcurrentReportLoad(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) defer cancel() - // Create a management server that serves LRS. mgmtServer := e2e.StartManagementServer(t, e2e.ManagementServerOptions{SupportLoadReportingService: true}) - - // Create an xDS client with bootstrap pointing to the above server. nodeID := uuid.New().String() bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address) client := createXDSClient(t, bc) @@ -465,11 +462,12 @@ func (s) TestConcurrentReportLoad(t *testing.T) { if err != nil { t.Fatalf("Failed to create server config for testing: %v", err) } + // Call ReportLoad() concurrently from multiple go routines. var wg sync.WaitGroup const numGoroutines = 10 wg.Add(numGoroutines) - for i := 0; i < numGoroutines; i++ { + for range numGoroutines { go func() { defer wg.Done() _, cancelStore := client.ReportLoad(serverConfig) @@ -479,21 +477,20 @@ func (s) TestConcurrentReportLoad(t *testing.T) { wg.Wait() } -// TestConcurrentChannels verifies that we can create mutliple gRPC channels +// TestConcurrentChannels verifies that we can create multiple gRPC channels // concurrently with a shared XDSClient, each of which will create a new LRS // stream without any race. func (s) TestConcurrentChannels(t *testing.T) { + // TODO(emchandwani) : Remove after https://github.com/grpc/grpc-go/pull/8526 gets merged. + t.Skip() ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) defer cancel() - // Create a management server that serves LRS. mgmtServer := e2e.StartManagementServer(t, e2e.ManagementServerOptions{AllowResourceSubset: true, SupportLoadReportingService: true}) - // Create bootstrap configuration pointing to the above management server. nodeID := uuid.New().String() bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address) - // // Create an xDS resolver with the above bootstrap configuration. if internal.NewXDSResolverWithPoolForTesting == nil { t.Fatalf("internal.NewXDSResolverWithConfigForTesting is nil") } @@ -504,14 +501,12 @@ func (s) TestConcurrentChannels(t *testing.T) { } pool := xdsclient.NewPool(config) - // Get the xDS resolver to use the above xDS client. resolverBuilder := internal.NewXDSResolverWithPoolForTesting.(func(*xdsclient.Pool) (resolver.Builder, error)) xdsResolver, err := resolverBuilder(pool) if err != nil { t.Fatalf("Failed to create xDS resolver for testing: %v", err) } - // Start a backend test service. server := stubserver.StartTestService(t, nil) defer server.Stop() @@ -538,19 +533,13 @@ func (s) TestConcurrentChannels(t *testing.T) { numGoroutines = 10 numRPCs = 10 ) - start := make(chan struct{}) - for i := 0; i < numGoroutines; i++ { + for range numGoroutines { wg.Add(1) go func() { - <-start defer wg.Done() for range numRPCs { cc, err := grpc.NewClient(fmt.Sprintf("xds:///%s", serviceName), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithResolvers(xdsResolver)) if err != nil { - // This can happen if the test context is cancelled. - if ctx.Err() != nil { - return - } t.Errorf("grpc.NewClient() failed: %v", err) return } @@ -558,16 +547,11 @@ func (s) TestConcurrentChannels(t *testing.T) { testClient := testgrpc.NewTestServiceClient(cc) if _, err := testClient.EmptyCall(ctx, &testpb.Empty{}); err != nil { - // This can happen if the test context is cancelled. - if ctx.Err() != nil { - return - } t.Errorf("EmptyCall() failed: %v", err) return } } }() } - close(start) wg.Wait() } From c8c3ee4366b324fe3f72eff99719a48260d5f32c Mon Sep 17 00:00:00 2001 From: eshitachandwani Date: Tue, 26 Aug 2025 10:40:14 +0530 Subject: [PATCH 11/11] final comments --- internal/xds/xdsclient/tests/loadreport_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/xds/xdsclient/tests/loadreport_test.go b/internal/xds/xdsclient/tests/loadreport_test.go index 9ca9f49c4532..e33f3799cd8b 100644 --- a/internal/xds/xdsclient/tests/loadreport_test.go +++ b/internal/xds/xdsclient/tests/loadreport_test.go @@ -40,8 +40,6 @@ import ( "google.golang.org/grpc/internal/xds/bootstrap" "google.golang.org/grpc/internal/xds/clients" "google.golang.org/grpc/internal/xds/xdsclient" - testgrpc "google.golang.org/grpc/interop/grpc_testing" - testpb "google.golang.org/grpc/interop/grpc_testing" "google.golang.org/grpc/resolver" "google.golang.org/grpc/status" "google.golang.org/protobuf/testing/protocmp" @@ -49,6 +47,8 @@ import ( v3corepb "github.com/envoyproxy/go-control-plane/envoy/config/core/v3" v3endpointpb "github.com/envoyproxy/go-control-plane/envoy/config/endpoint/v3" v3lrspb "github.com/envoyproxy/go-control-plane/envoy/service/load_stats/v3" + testgrpc "google.golang.org/grpc/interop/grpc_testing" + testpb "google.golang.org/grpc/interop/grpc_testing" "google.golang.org/protobuf/types/known/durationpb" ) @@ -481,7 +481,7 @@ func (s) TestConcurrentReportLoad(t *testing.T) { // concurrently with a shared XDSClient, each of which will create a new LRS // stream without any race. func (s) TestConcurrentChannels(t *testing.T) { - // TODO(emchandwani) : Remove after https://github.com/grpc/grpc-go/pull/8526 gets merged. + // TODO(emchandwani) : Unskip after https://github.com/grpc/grpc-go/pull/8526 gets merged. t.Skip() ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) defer cancel()