Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitaly.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorQuang-Minh Nguyen <qmnguyen@gitlab.com>2022-12-30 13:22:26 +0300
committerQuang-Minh Nguyen <qmnguyen@gitlab.com>2023-01-11 12:03:19 +0300
commit1cf417be0ae0663e0f2da788e78ecec0795890fc (patch)
tree0c8208675e49f2473fa2227f136cc557530d5884
parent58fd97ff5fb521e0f908ba53da1110b5cfae68c5 (diff)
Add an integration test to verify auto-retry policyqmnguyen0711/add-loadbalancing-config-to-gitaly-clients
The test starts a so-called Gitaly server serving an Unary call. Client dials with different dialers and enabled WithDefaultLoadBalancing dial option. Unavailable and DeadlineExceeded errors should invoke auto-retry mechanism so that client retry the RPC until reaching the upper limit. Due to the difficulties when setting up tests, it's not feasible to verify the round-robin behaviors at this point.
-rw-r--r--client/dial_test.go101
1 files changed, 101 insertions, 0 deletions
diff --git a/client/dial_test.go b/client/dial_test.go
index 9fa4b9d30..5f0d62b79 100644
--- a/client/dial_test.go
+++ b/client/dial_test.go
@@ -22,6 +22,7 @@ import (
internalclient "gitlab.com/gitlab-org/gitaly/v15/internal/gitaly/client"
"gitlab.com/gitlab-org/gitaly/v15/internal/testhelper"
gitalyx509 "gitlab.com/gitlab-org/gitaly/v15/internal/x509"
+ "gitlab.com/gitlab-org/gitaly/v15/proto/go/gitalypb"
"gitlab.com/gitlab-org/labkit/correlation"
grpccorrelation "gitlab.com/gitlab-org/labkit/correlation/grpc"
grpctracing "gitlab.com/gitlab-org/labkit/tracing/grpc"
@@ -651,3 +652,103 @@ func TestHealthCheckDialer(t *testing.T) {
func newLogger(tb testing.TB) *logrus.Entry {
return logrus.NewEntry(testhelper.NewDiscardingLogger(tb))
}
+
+func TestWithDefaultLoadBalancing(t *testing.T) {
+ t.Parallel()
+
+ for dialerName, dialer := range map[string]Dialer{
+ "Dial": func(ctx context.Context, address string, dialOptions []grpc.DialOption) (*grpc.ClientConn, error) {
+ return Dial(address, dialOptions)
+ },
+ "DialContext": func(ctx context.Context, address string, dialOptions []grpc.DialOption) (*grpc.ClientConn, error) {
+ return DialContext(ctx, address, dialOptions)
+ },
+ "DialSidechannel": func(ctx context.Context, address string, dialOptions []grpc.DialOption) (*grpc.ClientConn, error) {
+ return DialSidechannel(ctx, address, NewSidechannelRegistry(testhelper.NewDiscardingLogEntry(t)), dialOptions)
+ },
+ } {
+ t.Run(dialerName, func(t *testing.T) {
+ for _, tc := range []struct {
+ desc string
+ returnedError error
+ succeedsWithRetry bool
+ }{
+ {
+ desc: "unavailable",
+ returnedError: status.Error(codes.Unavailable, "intentionally unavailable"),
+ succeedsWithRetry: true,
+ },
+ {
+ desc: "deadline exceeded",
+ returnedError: status.Error(codes.DeadlineExceeded, "intentionally timeout"),
+ succeedsWithRetry: true,
+ },
+ {
+ // Internal error does not trigger client-side auto-retry
+ desc: "non-retryable code",
+ returnedError: status.Error(codes.Internal, "something goes wrong"),
+ succeedsWithRetry: false,
+ },
+ } {
+ t.Run(tc.desc, func(t *testing.T) {
+ t.Run("without retry", func(t *testing.T) {
+ testWithDefaultLoadBalancing(t, dialer, false, tc.returnedError, false)
+ })
+
+ t.Run("with retry", func(t *testing.T) {
+ testWithDefaultLoadBalancing(t, dialer, true, tc.returnedError, tc.succeedsWithRetry)
+ })
+ })
+ }
+ })
+ }
+}
+
+func testWithDefaultLoadBalancing(t *testing.T, dialer Dialer, retry bool, returnedError error, shouldSucceed bool) {
+ ctx := testhelper.Context(t)
+ serverSocketPath := startFakeGitalyServer(t, returnedError)
+
+ conn, err := dialer(ctx, "unix://"+serverSocketPath, []grpc.DialOption{WithClientLoadBalancing(retry)})
+ require.NoError(t, err)
+ defer testhelper.MustClose(t, conn)
+
+ client := gitalypb.NewCommitServiceClient(conn)
+ _, err = client.FindCommit(ctx, &gitalypb.FindCommitRequest{})
+
+ var expectedError error
+ if !shouldSucceed {
+ expectedError = returnedError
+ }
+
+ testhelper.ProtoEqual(t, expectedError, err)
+}
+
+// Due to circular dependency, we could not create a proper Gitaly server with real handler. Thus,
+// this is a fake server, returns an empty response. It is for testing dialing anyway, the response
+// does not matter.
+type fakeCommitServer struct {
+ failsRemaining int
+ returnedError error
+ gitalypb.UnimplementedCommitServiceServer
+}
+
+func (s *fakeCommitServer) FindCommit(_ context.Context, _ *gitalypb.FindCommitRequest) (*gitalypb.FindCommitResponse, error) {
+ if s.failsRemaining > 0 {
+ s.failsRemaining--
+ return nil, s.returnedError
+ }
+ return &gitalypb.FindCommitResponse{}, nil
+}
+
+func startFakeGitalyServer(t *testing.T, returnedError error) string {
+ serverSocketPath := testhelper.GetTemporaryGitalySocketFileName(t)
+ listener, err := net.Listen("unix", serverSocketPath)
+ require.NoError(t, err)
+
+ srv := grpc.NewServer(SidechannelServer(newLogger(t), insecure.NewCredentials()))
+ gitalypb.RegisterCommitServiceServer(srv, &fakeCommitServer{failsRemaining: 2, returnedError: returnedError})
+ go testhelper.MustServe(t, srv, listener)
+ t.Cleanup(srv.Stop)
+
+ return serverSocketPath
+}