github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/grpc/balancer/rls/internal/helpers_test.go (about)

     1  /*
     2   *
     3   * Copyright 2021 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 rls
    20  
    21  import (
    22  	"context"
    23  	"net"
    24  	"strings"
    25  	"sync"
    26  	"testing"
    27  	"time"
    28  
    29  	grpc "github.com/hxx258456/ccgo/grpc"
    30  	"github.com/hxx258456/ccgo/grpc/balancer/rls/internal/test/e2e"
    31  	"github.com/hxx258456/ccgo/grpc/codes"
    32  	"github.com/hxx258456/ccgo/grpc/internal"
    33  	"github.com/hxx258456/ccgo/grpc/internal/balancergroup"
    34  	"github.com/hxx258456/ccgo/grpc/internal/grpctest"
    35  	rlspb "github.com/hxx258456/ccgo/grpc/internal/proto/grpc_lookup_v1"
    36  	internalserviceconfig "github.com/hxx258456/ccgo/grpc/internal/serviceconfig"
    37  	"github.com/hxx258456/ccgo/grpc/internal/stubserver"
    38  	"github.com/hxx258456/ccgo/grpc/internal/testutils"
    39  	"github.com/hxx258456/ccgo/grpc/resolver"
    40  	"github.com/hxx258456/ccgo/grpc/resolver/manual"
    41  	"github.com/hxx258456/ccgo/grpc/serviceconfig"
    42  	"github.com/hxx258456/ccgo/grpc/status"
    43  	testgrpc "github.com/hxx258456/ccgo/grpc/test/grpc_testing"
    44  	testpb "github.com/hxx258456/ccgo/grpc/test/grpc_testing"
    45  	"google.golang.org/protobuf/types/known/durationpb"
    46  )
    47  
    48  // TODO(easwars): Remove this once all RLS code is merged.
    49  //lint:file-ignore U1000 Ignore all unused code, not all code is merged yet.
    50  
    51  const (
    52  	defaultTestTimeout      = 5 * time.Second
    53  	defaultTestShortTimeout = 100 * time.Millisecond
    54  )
    55  
    56  func init() {
    57  	balancergroup.DefaultSubBalancerCloseTimeout = time.Millisecond
    58  }
    59  
    60  type s struct {
    61  	grpctest.Tester
    62  }
    63  
    64  func Test(t *testing.T) {
    65  	grpctest.RunSubTests(t, s{})
    66  }
    67  
    68  // connWrapper wraps a net.Conn and pushes on a channel when closed.
    69  type connWrapper struct {
    70  	net.Conn
    71  	closeCh *testutils.Channel
    72  }
    73  
    74  func (cw *connWrapper) Close() error {
    75  	err := cw.Conn.Close()
    76  	cw.closeCh.Replace(nil)
    77  	return err
    78  }
    79  
    80  // listenerWrapper wraps a net.Listener and the returned net.Conn.
    81  //
    82  // It pushes on a channel whenever it accepts a new connection.
    83  type listenerWrapper struct {
    84  	net.Listener
    85  	newConnCh *testutils.Channel
    86  }
    87  
    88  func (l *listenerWrapper) Accept() (net.Conn, error) {
    89  	c, err := l.Listener.Accept()
    90  	if err != nil {
    91  		return nil, err
    92  	}
    93  	closeCh := testutils.NewChannel()
    94  	conn := &connWrapper{Conn: c, closeCh: closeCh}
    95  	l.newConnCh.Send(conn)
    96  	return conn, nil
    97  }
    98  
    99  func newListenerWrapper(t *testing.T, lis net.Listener) *listenerWrapper {
   100  	if lis == nil {
   101  		var err error
   102  		lis, err = testutils.LocalTCPListener()
   103  		if err != nil {
   104  			t.Fatal(err)
   105  		}
   106  	}
   107  
   108  	return &listenerWrapper{
   109  		Listener:  lis,
   110  		newConnCh: testutils.NewChannel(),
   111  	}
   112  }
   113  
   114  // fakeBackoffStrategy is a fake implementation of the backoff.Strategy
   115  // interface, for tests to inject the backoff duration.
   116  type fakeBackoffStrategy struct {
   117  	backoff time.Duration
   118  }
   119  
   120  func (f *fakeBackoffStrategy) Backoff(retries int) time.Duration {
   121  	return f.backoff
   122  }
   123  
   124  // fakeThrottler is a fake implementation of the adaptiveThrottler interface.
   125  type fakeThrottler struct {
   126  	throttleFunc func() bool
   127  }
   128  
   129  func (f *fakeThrottler) ShouldThrottle() bool         { return f.throttleFunc() }
   130  func (f *fakeThrottler) RegisterBackendResponse(bool) {}
   131  
   132  // alwaysThrottlingThrottler returns a fake throttler which always throttles.
   133  func alwaysThrottlingThrottler() *fakeThrottler {
   134  	return &fakeThrottler{throttleFunc: func() bool { return true }}
   135  }
   136  
   137  // neverThrottlingThrottler returns a fake throttler which never throttles.
   138  func neverThrottlingThrottler() *fakeThrottler {
   139  	return &fakeThrottler{throttleFunc: func() bool { return false }}
   140  }
   141  
   142  // oneTimeAllowingThrottler returns a fake throttler which does not throttle the
   143  // first request, but throttles everything that comes after. This is useful for
   144  // tests which need to set up a valid cache entry before testing other cases.
   145  func oneTimeAllowingThrottler() *fakeThrottler {
   146  	var once sync.Once
   147  	return &fakeThrottler{
   148  		throttleFunc: func() bool {
   149  			throttle := true
   150  			once.Do(func() { throttle = false })
   151  			return throttle
   152  		},
   153  	}
   154  }
   155  
   156  func overrideAdaptiveThrottler(t *testing.T, f *fakeThrottler) {
   157  	origAdaptiveThrottler := newAdaptiveThrottler
   158  	newAdaptiveThrottler = func() adaptiveThrottler { return f }
   159  	t.Cleanup(func() { newAdaptiveThrottler = origAdaptiveThrottler })
   160  }
   161  
   162  // setupFakeRLSServer starts and returns a fake RouteLookupService server
   163  // listening on the given listener or on a random local port. Also returns a
   164  // channel for tests to get notified whenever the RouteLookup RPC is invoked on
   165  // the fake server.
   166  //
   167  // This function sets up the fake server to respond with an empty response for
   168  // the RouteLookup RPCs. Tests can override this by calling the
   169  // SetResponseCallback() method on the returned fake server.
   170  func setupFakeRLSServer(t *testing.T, lis net.Listener, opts ...grpc.ServerOption) (*e2e.FakeRouteLookupServer, chan struct{}) {
   171  	s, cancel := e2e.StartFakeRouteLookupServer(t, lis, opts...)
   172  	t.Logf("Started fake RLS server at %q", s.Address)
   173  
   174  	ch := make(chan struct{}, 1)
   175  	s.SetRequestCallback(func(request *rlspb.RouteLookupRequest) {
   176  		select {
   177  		case ch <- struct{}{}:
   178  		default:
   179  		}
   180  	})
   181  	t.Cleanup(cancel)
   182  	return s, ch
   183  }
   184  
   185  // buildBasicRLSConfig constructs a basic service config for the RLS LB policy
   186  // which header matching rules. This expects the passed child policy name to
   187  // have been registered by the caller.
   188  func buildBasicRLSConfig(childPolicyName, rlsServerAddress string) *e2e.RLSConfig {
   189  	return &e2e.RLSConfig{
   190  		RouteLookupConfig: &rlspb.RouteLookupConfig{
   191  			GrpcKeybuilders: []*rlspb.GrpcKeyBuilder{
   192  				{
   193  					Names: []*rlspb.GrpcKeyBuilder_Name{{Service: "grpc.testing.TestService"}},
   194  					Headers: []*rlspb.NameMatcher{
   195  						{Key: "k1", Names: []string{"n1"}},
   196  						{Key: "k2", Names: []string{"n2"}},
   197  					},
   198  				},
   199  			},
   200  			LookupService:        rlsServerAddress,
   201  			LookupServiceTimeout: durationpb.New(defaultTestTimeout),
   202  			CacheSizeBytes:       1024,
   203  		},
   204  		ChildPolicy:                      &internalserviceconfig.BalancerConfig{Name: childPolicyName},
   205  		ChildPolicyConfigTargetFieldName: e2e.RLSChildPolicyTargetNameField,
   206  	}
   207  }
   208  
   209  // buildBasicRLSConfigWithChildPolicy constructs a very basic service config for
   210  // the RLS LB policy. It also registers a test LB policy which is capable of
   211  // being a child of the RLS LB policy.
   212  func buildBasicRLSConfigWithChildPolicy(t *testing.T, childPolicyName, rlsServerAddress string) *e2e.RLSConfig {
   213  	childPolicyName = "test-child-policy" + childPolicyName
   214  	e2e.RegisterRLSChildPolicy(childPolicyName, nil)
   215  	t.Logf("Registered child policy with name %q", childPolicyName)
   216  
   217  	return &e2e.RLSConfig{
   218  		RouteLookupConfig: &rlspb.RouteLookupConfig{
   219  			GrpcKeybuilders:      []*rlspb.GrpcKeyBuilder{{Names: []*rlspb.GrpcKeyBuilder_Name{{Service: "grpc.testing.TestService"}}}},
   220  			LookupService:        rlsServerAddress,
   221  			LookupServiceTimeout: durationpb.New(defaultTestTimeout),
   222  			CacheSizeBytes:       1024,
   223  		},
   224  		ChildPolicy:                      &internalserviceconfig.BalancerConfig{Name: childPolicyName},
   225  		ChildPolicyConfigTargetFieldName: e2e.RLSChildPolicyTargetNameField,
   226  	}
   227  }
   228  
   229  // startBackend starts a backend implementing the TestService on a local port.
   230  // It returns a channel for tests to get notified whenever an RPC is invoked on
   231  // the backend. This allows tests to ensure that RPCs reach expected backends.
   232  // Also returns the address of the backend.
   233  func startBackend(t *testing.T, sopts ...grpc.ServerOption) (rpcCh chan struct{}, address string) {
   234  	t.Helper()
   235  
   236  	rpcCh = make(chan struct{}, 1)
   237  	backend := &stubserver.StubServer{
   238  		EmptyCallF: func(ctx context.Context, in *testpb.Empty) (*testpb.Empty, error) {
   239  			select {
   240  			case rpcCh <- struct{}{}:
   241  			default:
   242  			}
   243  			return &testpb.Empty{}, nil
   244  		},
   245  	}
   246  	if err := backend.StartServer(sopts...); err != nil {
   247  		t.Fatalf("Failed to start backend: %v", err)
   248  	}
   249  	t.Logf("Started TestService backend at: %q", backend.Address)
   250  	t.Cleanup(func() { backend.Stop() })
   251  	return rpcCh, backend.Address
   252  }
   253  
   254  // startManualResolverWithConfig registers and returns a manual resolver which
   255  // pushes the RLS LB policy's service config on the channel.
   256  func startManualResolverWithConfig(t *testing.T, rlsConfig *e2e.RLSConfig) *manual.Resolver {
   257  	t.Helper()
   258  
   259  	scJSON, err := rlsConfig.ServiceConfigJSON()
   260  	if err != nil {
   261  		t.Fatal(err)
   262  	}
   263  
   264  	sc := internal.ParseServiceConfigForTesting.(func(string) *serviceconfig.ParseResult)(scJSON)
   265  	r := manual.NewBuilderWithScheme("rls-e2e")
   266  	r.InitialState(resolver.State{ServiceConfig: sc})
   267  	t.Cleanup(r.Close)
   268  	return r
   269  }
   270  
   271  // makeTestRPCAndExpectItToReachBackend is a test helper function which makes
   272  // the EmptyCall RPC on the given ClientConn and verifies that it reaches a
   273  // backend. The latter is accomplished by listening on the provided channel
   274  // which gets pushed to whenever the backend in question gets an RPC.
   275  func makeTestRPCAndExpectItToReachBackend(ctx context.Context, t *testing.T, cc *grpc.ClientConn, ch chan struct{}) {
   276  	t.Helper()
   277  
   278  	client := testgrpc.NewTestServiceClient(cc)
   279  	if _, err := client.EmptyCall(ctx, &testpb.Empty{}); err != nil {
   280  		t.Fatalf("TestService/EmptyCall() failed with error: %v", err)
   281  	}
   282  	select {
   283  	case <-ctx.Done():
   284  		t.Fatalf("Timeout when waiting for backend to receive RPC")
   285  	case <-ch:
   286  	}
   287  }
   288  
   289  // makeTestRPCAndVerifyError is a test helper function which makes the EmptyCall
   290  // RPC on the given ClientConn and verifies that the RPC fails with the given
   291  // status code and error.
   292  func makeTestRPCAndVerifyError(ctx context.Context, t *testing.T, cc *grpc.ClientConn, wantCode codes.Code, wantErr error) {
   293  	t.Helper()
   294  
   295  	client := testgrpc.NewTestServiceClient(cc)
   296  	_, err := client.EmptyCall(ctx, &testpb.Empty{})
   297  	if err == nil {
   298  		t.Fatal("TestService/EmptyCall() succeeded when expected to fail")
   299  	}
   300  	if code := status.Code(err); code != wantCode {
   301  		t.Fatalf("TestService/EmptyCall() returned code: %v, want: %v", code, wantCode)
   302  	}
   303  	if wantErr != nil && !strings.Contains(err.Error(), wantErr.Error()) {
   304  		t.Fatalf("TestService/EmptyCall() returned err: %v, want: %v", err, wantErr)
   305  	}
   306  }
   307  
   308  // verifyRLSRequest is a test helper which listens on a channel to see if an RLS
   309  // request was received by the fake RLS server. Based on whether the test
   310  // expects a request to be sent out or not, it uses a different timeout.
   311  func verifyRLSRequest(t *testing.T, ch chan struct{}, wantRequest bool) {
   312  	t.Helper()
   313  
   314  	if wantRequest {
   315  		select {
   316  		case <-time.After(defaultTestTimeout):
   317  			t.Fatalf("Timeout when waiting for an RLS request to be sent out")
   318  		case <-ch:
   319  		}
   320  	} else {
   321  		select {
   322  		case <-time.After(defaultTestShortTimeout):
   323  		case <-ch:
   324  			t.Fatalf("RLS request sent out when not expecting one")
   325  		}
   326  	}
   327  }