google.golang.org/grpc@v1.72.2/xds/internal/balancer/clusterimpl/tests/balancer_test.go (about)

     1  /*
     2   *
     3   * Copyright 2023 gRPC authors.
     4   *
     5   * Licensed under the Apache License, Version 2.0 (the "License");
     6   * you may not use this file except in compliance with the License.
     7   * You may obtain a copy of the License at
     8   *
     9   *     http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   *
    17   */
    18  
    19  package clusterimpl_test
    20  
    21  import (
    22  	"context"
    23  	"fmt"
    24  	"net"
    25  	"strconv"
    26  	"strings"
    27  	"testing"
    28  	"time"
    29  
    30  	"github.com/google/uuid"
    31  	"google.golang.org/grpc"
    32  	"google.golang.org/grpc/codes"
    33  	"google.golang.org/grpc/connectivity"
    34  	"google.golang.org/grpc/credentials/insecure"
    35  	"google.golang.org/grpc/internal"
    36  	"google.golang.org/grpc/internal/grpctest"
    37  	"google.golang.org/grpc/internal/stubserver"
    38  	"google.golang.org/grpc/internal/testutils"
    39  	"google.golang.org/grpc/internal/testutils/xds/e2e"
    40  	"google.golang.org/grpc/internal/testutils/xds/fakeserver"
    41  	"google.golang.org/grpc/peer"
    42  	"google.golang.org/grpc/resolver"
    43  	"google.golang.org/grpc/status"
    44  	"google.golang.org/protobuf/types/known/durationpb"
    45  	"google.golang.org/protobuf/types/known/wrapperspb"
    46  
    47  	v3clusterpb "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3"
    48  	v3corepb "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
    49  	v3endpointpb "github.com/envoyproxy/go-control-plane/envoy/config/endpoint/v3"
    50  	v3listenerpb "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3"
    51  	v3routepb "github.com/envoyproxy/go-control-plane/envoy/config/route/v3"
    52  	v3pickfirstpb "github.com/envoyproxy/go-control-plane/envoy/extensions/load_balancing_policies/pick_first/v3"
    53  	v3lrspb "github.com/envoyproxy/go-control-plane/envoy/service/load_stats/v3"
    54  	testgrpc "google.golang.org/grpc/interop/grpc_testing"
    55  	testpb "google.golang.org/grpc/interop/grpc_testing"
    56  
    57  	_ "google.golang.org/grpc/xds"
    58  )
    59  
    60  const (
    61  	defaultTestTimeout      = 5 * time.Second
    62  	defaultTestShortTimeout = 100 * time.Millisecond
    63  )
    64  
    65  type s struct {
    66  	grpctest.Tester
    67  }
    68  
    69  func Test(t *testing.T) {
    70  	grpctest.RunSubTests(t, s{})
    71  }
    72  
    73  // TestConfigUpdateWithSameLoadReportingServerConfig tests the scenario where
    74  // the clusterimpl LB policy receives a config update with no change in the load
    75  // reporting server configuration. The test verifies that the existing load
    76  // reporting stream is not terminated and that a new load reporting stream is not
    77  // created.
    78  func (s) TestConfigUpdateWithSameLoadReportingServerConfig(t *testing.T) {
    79  	// Create an xDS management server that serves ADS and LRS requests.
    80  	mgmtServer := e2e.StartManagementServer(t, e2e.ManagementServerOptions{SupportLoadReportingService: true})
    81  
    82  	// Create bootstrap configuration pointing to the above management server.
    83  	nodeID := uuid.New().String()
    84  	bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address)
    85  	testutils.CreateBootstrapFileForTesting(t, bc)
    86  
    87  	// Create an xDS resolver with the above bootstrap configuration.
    88  	var resolverBuilder resolver.Builder
    89  	var err error
    90  	if newResolver := internal.NewXDSResolverWithConfigForTesting; newResolver != nil {
    91  		resolverBuilder, err = newResolver.(func([]byte) (resolver.Builder, error))(bc)
    92  		if err != nil {
    93  			t.Fatalf("Failed to create xDS resolver for testing: %v", err)
    94  		}
    95  	}
    96  
    97  	// Start a server backend exposing the test service.
    98  	server := stubserver.StartTestService(t, nil)
    99  	defer server.Stop()
   100  
   101  	// Configure the xDS management server with default resources. Override the
   102  	// default cluster to include an LRS server config pointing to self.
   103  	const serviceName = "my-test-xds-service"
   104  	resources := e2e.DefaultClientResources(e2e.ResourceParams{
   105  		DialTarget: serviceName,
   106  		NodeID:     nodeID,
   107  		Host:       "localhost",
   108  		Port:       testutils.ParsePort(t, server.Address),
   109  		SecLevel:   e2e.SecurityLevelNone,
   110  	})
   111  	resources.Clusters[0].LrsServer = &v3corepb.ConfigSource{
   112  		ConfigSourceSpecifier: &v3corepb.ConfigSource_Self{
   113  			Self: &v3corepb.SelfConfigSource{},
   114  		},
   115  	}
   116  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   117  	defer cancel()
   118  	if err := mgmtServer.Update(ctx, resources); err != nil {
   119  		t.Fatal(err)
   120  	}
   121  
   122  	// Create a ClientConn and make a successful RPC.
   123  	cc, err := grpc.NewClient(fmt.Sprintf("xds:///%s", serviceName), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithResolvers(resolverBuilder))
   124  	if err != nil {
   125  		t.Fatalf("failed to dial local test server: %v", err)
   126  	}
   127  	defer cc.Close()
   128  
   129  	client := testgrpc.NewTestServiceClient(cc)
   130  	if _, err := client.EmptyCall(ctx, &testpb.Empty{}); err != nil {
   131  		t.Fatalf("rpc EmptyCall() failed: %v", err)
   132  	}
   133  
   134  	// Ensure that an LRS stream is created.
   135  	if _, err := mgmtServer.LRSServer.LRSStreamOpenChan.Receive(ctx); err != nil {
   136  		t.Fatalf("Failure when waiting for an LRS stream to be opened: %v", err)
   137  	}
   138  
   139  	// Configure a new resource on the management server with drop config that
   140  	// drops all RPCs, but with no change in the load reporting server config.
   141  	resources.Endpoints = []*v3endpointpb.ClusterLoadAssignment{
   142  		e2e.EndpointResourceWithOptions(e2e.EndpointOptions{
   143  			ClusterName: "endpoints-" + serviceName,
   144  			Host:        "localhost",
   145  			Localities: []e2e.LocalityOptions{
   146  				{
   147  					Backends: []e2e.BackendOptions{{Ports: []uint32{testutils.ParsePort(t, server.Address)}}},
   148  					Weight:   1,
   149  				},
   150  			},
   151  			DropPercents: map[string]int{"test-drop-everything": 100},
   152  		}),
   153  	}
   154  	if err := mgmtServer.Update(ctx, resources); err != nil {
   155  		t.Fatal(err)
   156  	}
   157  
   158  	// Repeatedly send RPCs until we sees that they are getting dropped, or the
   159  	// test context deadline expires. The former indicates that new config with
   160  	// drops has been applied.
   161  	for ; ctx.Err() == nil; <-time.After(defaultTestShortTimeout) {
   162  		_, err := client.EmptyCall(ctx, &testpb.Empty{})
   163  		if err != nil && status.Code(err) == codes.Unavailable && strings.Contains(err.Error(), "RPC is dropped") {
   164  			break
   165  		}
   166  	}
   167  	if ctx.Err() != nil {
   168  		t.Fatalf("Timeout when waiting for RPCs to be dropped after config update")
   169  	}
   170  
   171  	// Ensure that the old LRS stream is not closed.
   172  	sCtx, sCancel := context.WithTimeout(ctx, defaultTestShortTimeout)
   173  	defer sCancel()
   174  	if _, err := mgmtServer.LRSServer.LRSStreamCloseChan.Receive(sCtx); err == nil {
   175  		t.Fatal("LRS stream closed when expected not to")
   176  	}
   177  
   178  	// Also ensure that a new LRS stream is not created.
   179  	sCtx, sCancel = context.WithTimeout(ctx, defaultTestShortTimeout)
   180  	defer sCancel()
   181  	if _, err := mgmtServer.LRSServer.LRSStreamOpenChan.Receive(sCtx); err == nil {
   182  		t.Fatal("New LRS stream created when expected not to")
   183  	}
   184  }
   185  
   186  // Tests whether load is reported correctly when using pickfirst with endpoints
   187  // in multiple localities.
   188  func (s) TestLoadReportingPickFirstMultiLocality(t *testing.T) {
   189  	// Create an xDS management server that serves ADS and LRS requests.
   190  	mgmtServer := e2e.StartManagementServer(t, e2e.ManagementServerOptions{SupportLoadReportingService: true})
   191  
   192  	// Create bootstrap configuration pointing to the above management server.
   193  	nodeID := uuid.New().String()
   194  	bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address)
   195  
   196  	// Create an xDS resolver with the above bootstrap configuration.
   197  	var resolverBuilder resolver.Builder
   198  	var err error
   199  	if newResolver := internal.NewXDSResolverWithConfigForTesting; newResolver != nil {
   200  		resolverBuilder, err = newResolver.(func([]byte) (resolver.Builder, error))(bc)
   201  		if err != nil {
   202  			t.Fatalf("Failed to create xDS resolver for testing: %v", err)
   203  		}
   204  	}
   205  
   206  	// Start two server backends exposing the test service.
   207  	server1 := stubserver.StartTestService(t, nil)
   208  	defer server1.Stop()
   209  
   210  	server2 := stubserver.StartTestService(t, nil)
   211  	defer server2.Stop()
   212  
   213  	// Configure the xDS management server.
   214  	const serviceName = "my-test-xds-service"
   215  	routeConfigName := "route-" + serviceName
   216  	clusterName := "cluster-" + serviceName
   217  	endpointsName := "endpoints-" + serviceName
   218  	resources := e2e.UpdateOptions{
   219  		NodeID:    nodeID,
   220  		Listeners: []*v3listenerpb.Listener{e2e.DefaultClientListener(serviceName, routeConfigName)},
   221  		Routes:    []*v3routepb.RouteConfiguration{e2e.DefaultRouteConfig(routeConfigName, serviceName, clusterName)},
   222  		Clusters: []*v3clusterpb.Cluster{
   223  			{
   224  				Name:                 clusterName,
   225  				ClusterDiscoveryType: &v3clusterpb.Cluster_Type{Type: v3clusterpb.Cluster_EDS},
   226  				EdsClusterConfig: &v3clusterpb.Cluster_EdsClusterConfig{
   227  					EdsConfig: &v3corepb.ConfigSource{
   228  						ConfigSourceSpecifier: &v3corepb.ConfigSource_Ads{
   229  							Ads: &v3corepb.AggregatedConfigSource{},
   230  						},
   231  					},
   232  					ServiceName: endpointsName,
   233  				},
   234  				// Specify a custom load balancing policy to use pickfirst.
   235  				LoadBalancingPolicy: &v3clusterpb.LoadBalancingPolicy{
   236  					Policies: []*v3clusterpb.LoadBalancingPolicy_Policy{
   237  						{
   238  							TypedExtensionConfig: &v3corepb.TypedExtensionConfig{
   239  								TypedConfig: testutils.MarshalAny(t, &v3pickfirstpb.PickFirst{}),
   240  							},
   241  						},
   242  					},
   243  				},
   244  				// Include a fake LRS server config pointing to self.
   245  				LrsServer: &v3corepb.ConfigSource{
   246  					ConfigSourceSpecifier: &v3corepb.ConfigSource_Self{
   247  						Self: &v3corepb.SelfConfigSource{},
   248  					},
   249  				},
   250  			},
   251  		},
   252  		Endpoints: []*v3endpointpb.ClusterLoadAssignment{e2e.EndpointResourceWithOptions(e2e.EndpointOptions{
   253  			ClusterName: endpointsName,
   254  			Host:        "localhost",
   255  			Localities: []e2e.LocalityOptions{
   256  				{
   257  					Backends: []e2e.BackendOptions{
   258  						{Ports: []uint32{testutils.ParsePort(t, server1.Address)}},
   259  					},
   260  					Weight: 1,
   261  				},
   262  				{
   263  					Backends: []e2e.BackendOptions{
   264  						{Ports: []uint32{testutils.ParsePort(t, server2.Address)}},
   265  					},
   266  					Weight: 2,
   267  				},
   268  			},
   269  		})},
   270  	}
   271  
   272  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   273  	defer cancel()
   274  	if err := mgmtServer.Update(ctx, resources); err != nil {
   275  		t.Fatal(err)
   276  	}
   277  
   278  	// Create a ClientConn and make a successful RPC.
   279  	cc, err := grpc.NewClient(fmt.Sprintf("xds:///%s", serviceName),
   280  		grpc.WithTransportCredentials(insecure.NewCredentials()),
   281  		grpc.WithResolvers(resolverBuilder))
   282  	if err != nil {
   283  		t.Fatalf("Failed to dial local test server: %v", err)
   284  	}
   285  	defer cc.Close()
   286  
   287  	client := testgrpc.NewTestServiceClient(cc)
   288  	var peer peer.Peer
   289  	if _, err := client.EmptyCall(ctx, &testpb.Empty{}, grpc.Peer(&peer)); err != nil {
   290  		t.Fatalf("rpc EmptyCall() failed: %v", err)
   291  	}
   292  
   293  	// Verify that the request was sent to server 1.
   294  	if got, want := peer.Addr.String(), server1.Address; got != want {
   295  		t.Errorf("peer.Addr = %q, want = %q", got, want)
   296  	}
   297  
   298  	// Ensure that an LRS stream is created.
   299  	if _, err = mgmtServer.LRSServer.LRSStreamOpenChan.Receive(ctx); err != nil {
   300  		t.Fatalf("Failure when waiting for an LRS stream to be opened: %v", err)
   301  	}
   302  
   303  	// Handle the initial LRS request from the xDS client.
   304  	if _, err = mgmtServer.LRSServer.LRSRequestChan.Receive(ctx); err != nil {
   305  		t.Fatalf("Failure waiting for initial LRS request: %v", err)
   306  	}
   307  
   308  	resp := fakeserver.Response{
   309  		Resp: &v3lrspb.LoadStatsResponse{
   310  			SendAllClusters:       true,
   311  			LoadReportingInterval: durationpb.New(10 * time.Millisecond),
   312  		},
   313  	}
   314  	mgmtServer.LRSServer.LRSResponseChan <- &resp
   315  
   316  	// Wait for load to be reported for locality of server 1.
   317  	if err := waitForSuccessfulLoadReport(ctx, mgmtServer.LRSServer, "region-1"); err != nil {
   318  		t.Fatalf("Server 1 did not receive load due to error: %v", err)
   319  	}
   320  
   321  	// Stop server 1 and send one more rpc. Now the request should go to server 2.
   322  	server1.Stop()
   323  
   324  	// Wait for the balancer to pick up the server state change.
   325  	testutils.AwaitState(ctx, t, cc, connectivity.Idle)
   326  	if _, err := client.EmptyCall(ctx, &testpb.Empty{}, grpc.Peer(&peer)); err != nil {
   327  		t.Fatalf("rpc EmptyCall() failed: %v", err)
   328  	}
   329  
   330  	// Verify that the request was sent to server 2.
   331  	if got, want := peer.Addr.String(), server2.Address; got != want {
   332  		t.Errorf("peer.Addr = %q, want = %q", got, want)
   333  	}
   334  
   335  	// Wait for load to be reported for locality of server 2.
   336  	if err := waitForSuccessfulLoadReport(ctx, mgmtServer.LRSServer, "region-2"); err != nil {
   337  		t.Fatalf("Server 2 did not receive load due to error: %v", err)
   338  	}
   339  }
   340  
   341  // waitForSuccessfulLoadReport waits for a successful request to be reported for
   342  // the specified locality region.
   343  func waitForSuccessfulLoadReport(ctx context.Context, lrsServer *fakeserver.Server, region string) error {
   344  	for {
   345  		select {
   346  		case <-ctx.Done():
   347  			return ctx.Err()
   348  		case req := <-lrsServer.LRSRequestChan.C:
   349  			loadStats := req.(*fakeserver.Request).Req.(*v3lrspb.LoadStatsRequest)
   350  			for _, load := range loadStats.ClusterStats {
   351  				for _, locality := range load.UpstreamLocalityStats {
   352  					if locality.TotalSuccessfulRequests > 0 && locality.Locality.Region == region {
   353  						return nil
   354  					}
   355  				}
   356  			}
   357  		}
   358  	}
   359  }
   360  
   361  // Tests that circuit breaking limits RPCs E2E.
   362  func (s) TestCircuitBreaking(t *testing.T) {
   363  	// Create an xDS management server that serves ADS requests.
   364  	mgmtServer := e2e.StartManagementServer(t, e2e.ManagementServerOptions{})
   365  
   366  	// Create bootstrap configuration pointing to the above management server.
   367  	nodeID := uuid.New().String()
   368  	bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address)
   369  	testutils.CreateBootstrapFileForTesting(t, bc)
   370  
   371  	// Create an xDS resolver with the above bootstrap configuration.
   372  	var resolverBuilder resolver.Builder
   373  	var err error
   374  	if newResolver := internal.NewXDSResolverWithConfigForTesting; newResolver != nil {
   375  		resolverBuilder, err = newResolver.(func([]byte) (resolver.Builder, error))(bc)
   376  		if err != nil {
   377  			t.Fatalf("Failed to create xDS resolver for testing: %v", err)
   378  		}
   379  	}
   380  
   381  	// Start a server backend exposing the test service.
   382  	f := &stubserver.StubServer{
   383  		EmptyCallF: func(ctx context.Context, _ *testpb.Empty) (*testpb.Empty, error) {
   384  			return &testpb.Empty{}, nil
   385  		},
   386  		FullDuplexCallF: func(stream testgrpc.TestService_FullDuplexCallServer) error {
   387  			for {
   388  				if _, err := stream.Recv(); err != nil {
   389  					return err
   390  				}
   391  			}
   392  		},
   393  	}
   394  	server := stubserver.StartTestService(t, f)
   395  	defer server.Stop()
   396  
   397  	// Configure the xDS management server with default resources.
   398  	const serviceName = "my-test-xds-service"
   399  	const maxRequests = 3
   400  	resources := e2e.DefaultClientResources(e2e.ResourceParams{
   401  		DialTarget: serviceName,
   402  		NodeID:     nodeID,
   403  		Host:       "localhost",
   404  		Port:       testutils.ParsePort(t, server.Address),
   405  	})
   406  	resources.Clusters[0].CircuitBreakers = &v3clusterpb.CircuitBreakers{
   407  		Thresholds: []*v3clusterpb.CircuitBreakers_Thresholds{
   408  			{
   409  				Priority:    v3corepb.RoutingPriority_DEFAULT,
   410  				MaxRequests: wrapperspb.UInt32(maxRequests),
   411  			},
   412  		},
   413  	}
   414  
   415  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   416  	defer cancel()
   417  	if err := mgmtServer.Update(ctx, resources); err != nil {
   418  		t.Fatal(err)
   419  	}
   420  
   421  	// Create a ClientConn and make a successful RPC.
   422  	cc, err := grpc.NewClient(fmt.Sprintf("xds:///%s", serviceName), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithResolvers(resolverBuilder))
   423  	if err != nil {
   424  		t.Fatalf("failed to dial local test server: %v", err)
   425  	}
   426  	defer cc.Close()
   427  
   428  	client := testgrpc.NewTestServiceClient(cc)
   429  
   430  	// Start maxRequests streams.
   431  	for range maxRequests {
   432  		if _, err := client.FullDuplexCall(ctx); err != nil {
   433  			t.Fatalf("rpc FullDuplexCall() failed: %v", err)
   434  		}
   435  	}
   436  
   437  	// Since we are at the max, new streams should fail.  It's possible some are
   438  	// allowed due to inherent raciness in the tracking, however.
   439  	for i := 0; i < 100; i++ {
   440  		stream, err := client.FullDuplexCall(ctx)
   441  		if status.Code(err) == codes.Unavailable {
   442  			return
   443  		}
   444  		if err == nil {
   445  			// Terminate the stream (the server immediately exits upon a client
   446  			// CloseSend) to ensure we never go over the limit.
   447  			stream.CloseSend()
   448  			stream.Recv()
   449  		}
   450  		time.Sleep(10 * time.Millisecond)
   451  	}
   452  
   453  	t.Fatalf("RPCs unexpectedly allowed beyond circuit breaking maximum")
   454  }
   455  
   456  // Tests that circuit breaking limits RPCs in LOGICAL_DNS clusters E2E.
   457  func (s) TestCircuitBreakingLogicalDNS(t *testing.T) {
   458  	// Create an xDS management server that serves ADS requests.
   459  	mgmtServer := e2e.StartManagementServer(t, e2e.ManagementServerOptions{})
   460  
   461  	// Create bootstrap configuration pointing to the above management server.
   462  	nodeID := uuid.New().String()
   463  	bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address)
   464  	testutils.CreateBootstrapFileForTesting(t, bc)
   465  
   466  	// Create an xDS resolver with the above bootstrap configuration.
   467  	var resolverBuilder resolver.Builder
   468  	var err error
   469  	if newResolver := internal.NewXDSResolverWithConfigForTesting; newResolver != nil {
   470  		resolverBuilder, err = newResolver.(func([]byte) (resolver.Builder, error))(bc)
   471  		if err != nil {
   472  			t.Fatalf("Failed to create xDS resolver for testing: %v", err)
   473  		}
   474  	}
   475  
   476  	// Start a server backend exposing the test service.
   477  	f := &stubserver.StubServer{
   478  		EmptyCallF: func(ctx context.Context, _ *testpb.Empty) (*testpb.Empty, error) {
   479  			return &testpb.Empty{}, nil
   480  		},
   481  		FullDuplexCallF: func(stream testgrpc.TestService_FullDuplexCallServer) error {
   482  			for {
   483  				if _, err := stream.Recv(); err != nil {
   484  					return err
   485  				}
   486  			}
   487  		},
   488  	}
   489  	server := stubserver.StartTestService(t, f)
   490  	defer server.Stop()
   491  	host, port := hostAndPortFromAddress(t, server.Address)
   492  
   493  	// Configure the xDS management server with default resources. Override the
   494  	// default cluster to include a circuit breaking config.
   495  	const serviceName = "my-test-xds-service"
   496  	const maxRequests = 3
   497  	resources := e2e.DefaultClientResources(e2e.ResourceParams{
   498  		DialTarget: serviceName,
   499  		NodeID:     nodeID,
   500  		Host:       "localhost",
   501  		Port:       testutils.ParsePort(t, server.Address),
   502  	})
   503  	resources.Clusters = []*v3clusterpb.Cluster{
   504  		e2e.ClusterResourceWithOptions(e2e.ClusterOptions{
   505  			ClusterName: "cluster-" + serviceName,
   506  			Type:        e2e.ClusterTypeLogicalDNS,
   507  			DNSHostName: host,
   508  			DNSPort:     port,
   509  		}),
   510  	}
   511  	resources.Clusters[0].CircuitBreakers = &v3clusterpb.CircuitBreakers{
   512  		Thresholds: []*v3clusterpb.CircuitBreakers_Thresholds{
   513  			{
   514  				Priority:    v3corepb.RoutingPriority_DEFAULT,
   515  				MaxRequests: wrapperspb.UInt32(maxRequests),
   516  			},
   517  		},
   518  	}
   519  	resources.Endpoints = nil
   520  
   521  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   522  	defer cancel()
   523  	if err := mgmtServer.Update(ctx, resources); err != nil {
   524  		t.Fatal(err)
   525  	}
   526  
   527  	// Create a ClientConn and make a successful RPC.
   528  	cc, err := grpc.NewClient(fmt.Sprintf("xds:///%s", serviceName), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithResolvers(resolverBuilder))
   529  	if err != nil {
   530  		t.Fatalf("failed to dial local test server: %v", err)
   531  	}
   532  	defer cc.Close()
   533  
   534  	client := testgrpc.NewTestServiceClient(cc)
   535  
   536  	// Start maxRequests streams.
   537  	for range maxRequests {
   538  		if _, err := client.FullDuplexCall(ctx); err != nil {
   539  			t.Fatalf("rpc FullDuplexCall() failed: %v", err)
   540  		}
   541  	}
   542  
   543  	// Since we are at the max, new streams should fail.  It's possible some are
   544  	// allowed due to inherent raciness in the tracking, however.
   545  	for i := 0; i < 100; i++ {
   546  		stream, err := client.FullDuplexCall(ctx)
   547  		if status.Code(err) == codes.Unavailable {
   548  			return
   549  		}
   550  		if err == nil {
   551  			// Terminate the stream (the server immediately exits upon a client
   552  			// CloseSend) to ensure we never go over the limit.
   553  			stream.CloseSend()
   554  			stream.Recv()
   555  		}
   556  		time.Sleep(10 * time.Millisecond)
   557  	}
   558  
   559  	t.Fatalf("RPCs unexpectedly allowed beyond circuit breaking maximum")
   560  }
   561  
   562  func hostAndPortFromAddress(t *testing.T, addr string) (string, uint32) {
   563  	t.Helper()
   564  
   565  	host, p, err := net.SplitHostPort(addr)
   566  	if err != nil {
   567  		t.Fatalf("Invalid serving address: %v", addr)
   568  	}
   569  	port, err := strconv.ParseUint(p, 10, 32)
   570  	if err != nil {
   571  		t.Fatalf("Invalid serving port %q: %v", p, err)
   572  	}
   573  	return host, uint32(port)
   574  }
   575  
   576  // Tests that LRS works correctly in a LOGICAL_DNS cluster.
   577  func (s) TestLRSLogicalDNS(t *testing.T) {
   578  	// Create an xDS management server that serves ADS and LRS requests.
   579  	mgmtServer := e2e.StartManagementServer(t, e2e.ManagementServerOptions{SupportLoadReportingService: true})
   580  
   581  	// Create bootstrap configuration pointing to the above management server.
   582  	nodeID := uuid.New().String()
   583  	bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address)
   584  	testutils.CreateBootstrapFileForTesting(t, bc)
   585  
   586  	// Create an xDS resolver with the above bootstrap configuration.
   587  	var resolverBuilder resolver.Builder
   588  	var err error
   589  	if newResolver := internal.NewXDSResolverWithConfigForTesting; newResolver != nil {
   590  		resolverBuilder, err = newResolver.(func([]byte) (resolver.Builder, error))(bc)
   591  		if err != nil {
   592  			t.Fatalf("Failed to create xDS resolver for testing: %v", err)
   593  		}
   594  	}
   595  
   596  	// Start a server backend exposing the test service.
   597  	server := stubserver.StartTestService(t, nil)
   598  	defer server.Stop()
   599  	host, port := hostAndPortFromAddress(t, server.Address)
   600  
   601  	// Configure the xDS management server with default resources. Override the
   602  	// default cluster to include an LRS server config pointing to self.
   603  	const serviceName = "my-test-xds-service"
   604  	resources := e2e.DefaultClientResources(e2e.ResourceParams{
   605  		DialTarget: serviceName,
   606  		NodeID:     nodeID,
   607  		Host:       "localhost",
   608  		Port:       testutils.ParsePort(t, server.Address),
   609  		SecLevel:   e2e.SecurityLevelNone,
   610  	})
   611  	resources.Clusters = []*v3clusterpb.Cluster{
   612  		e2e.ClusterResourceWithOptions(e2e.ClusterOptions{
   613  			ClusterName: "cluster-" + serviceName,
   614  			Type:        e2e.ClusterTypeLogicalDNS,
   615  			DNSHostName: host,
   616  			DNSPort:     port,
   617  		}),
   618  	}
   619  	resources.Clusters[0].LrsServer = &v3corepb.ConfigSource{
   620  		ConfigSourceSpecifier: &v3corepb.ConfigSource_Self{
   621  			Self: &v3corepb.SelfConfigSource{},
   622  		},
   623  	}
   624  	resources.Endpoints = nil
   625  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   626  	defer cancel()
   627  	if err := mgmtServer.Update(ctx, resources); err != nil {
   628  		t.Fatal(err)
   629  	}
   630  
   631  	// Create a ClientConn and make a successful RPC.
   632  	cc, err := grpc.NewClient(fmt.Sprintf("xds:///%s", serviceName), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithResolvers(resolverBuilder))
   633  	if err != nil {
   634  		t.Fatalf("failed to dial local test server: %v", err)
   635  	}
   636  	defer cc.Close()
   637  
   638  	client := testgrpc.NewTestServiceClient(cc)
   639  	if _, err := client.EmptyCall(ctx, &testpb.Empty{}); err != nil {
   640  		t.Fatalf("rpc EmptyCall() failed: %v", err)
   641  	}
   642  
   643  	// Ensure that an LRS stream is created.
   644  	if _, err := mgmtServer.LRSServer.LRSStreamOpenChan.Receive(ctx); err != nil {
   645  		t.Fatalf("Failure when waiting for an LRS stream to be opened: %v", err)
   646  	}
   647  
   648  	// Handle the initial LRS request from the xDS client.
   649  	if _, err = mgmtServer.LRSServer.LRSRequestChan.Receive(ctx); err != nil {
   650  		t.Fatalf("Failure waiting for initial LRS request: %v", err)
   651  	}
   652  
   653  	resp := fakeserver.Response{
   654  		Resp: &v3lrspb.LoadStatsResponse{
   655  			SendAllClusters:       true,
   656  			LoadReportingInterval: durationpb.New(10 * time.Millisecond),
   657  		},
   658  	}
   659  	mgmtServer.LRSServer.LRSResponseChan <- &resp
   660  
   661  	// Wait for load to be reported for locality of server 1.
   662  	if err := waitForSuccessfulLoadReport(ctx, mgmtServer.LRSServer, ""); err != nil {
   663  		t.Fatalf("Server did not receive load due to error: %v", err)
   664  	}
   665  }