diff options
author | Douglas Barbosa Alexandre <dbalexandre@gmail.com> | 2018-03-28 03:56:28 +0300 |
---|---|---|
committer | Douglas Barbosa Alexandre <dbalexandre@gmail.com> | 2018-04-05 20:52:20 +0300 |
commit | c98c99c5d0ac8d91e3966f9de1a8476f914eecaf (patch) | |
tree | 0dd80df4bf7441ddd1da41b924bf7c00af73a66b | |
parent | e48707d1354f24fe67fec5a88f1d93541ac9cae3 (diff) |
Server implementation CalculateChecksum
-rw-r--r-- | internal/service/repository/calculate_checksum.go | 69 | ||||
-rw-r--r-- | internal/service/repository/calculate_checksum_test.go | 84 |
2 files changed, 151 insertions, 2 deletions
diff --git a/internal/service/repository/calculate_checksum.go b/internal/service/repository/calculate_checksum.go index 6f375d467..bbbe50e99 100644 --- a/internal/service/repository/calculate_checksum.go +++ b/internal/service/repository/calculate_checksum.go @@ -1,13 +1,78 @@ package repository import ( - pb "gitlab.com/gitlab-org/gitaly-proto/go" + "bufio" + "crypto/sha1" + "encoding/hex" + "math/big" + pb "gitlab.com/gitlab-org/gitaly-proto/go" + "gitlab.com/gitlab-org/gitaly/internal/command" + "gitlab.com/gitlab-org/gitaly/internal/git" "gitlab.com/gitlab-org/gitaly/internal/helper" "golang.org/x/net/context" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" ) +const blankChecksum = "0000000000000000000000000000000000000000" + func (s *server) CalculateChecksum(ctx context.Context, in *pb.CalculateChecksumRequest) (*pb.CalculateChecksumResponse, error) { - return nil, helper.Unimplemented + repo := in.GetRepository() + + _, err := helper.GetRepoPath(repo) + if err != nil { + return nil, err + } + + args := []string{ + "show-ref", + "--heads", + "--tags", + } + + cmd, err := git.Command(ctx, repo, args...) + if err != nil { + if _, ok := status.FromError(err); ok { + return nil, err + } + + return nil, status.Errorf(codes.Internal, "CalculateChecksum: gitCommand: %v", err) + } + + var checksum *big.Int + + scanner := bufio.NewScanner(cmd) + for scanner.Scan() { + ref := scanner.Text() + + h := sha1.New() + h.Write([]byte(ref)) + + hash := hex.EncodeToString(h.Sum(nil)) + hashIntBase16, _ := new(big.Int).SetString(hash, 16) + + if checksum == nil { + checksum = hashIntBase16 + } else { + checksum.Xor(checksum, hashIntBase16) + } + } + + if err := scanner.Err(); err != nil { + return nil, status.Errorf(codes.Internal, err.Error()) + } + + if err := cmd.Wait(); err != nil { + if code, ok := command.ExitStatus(err); ok && code == 1 { + // Exit code 1: the repository doesn't have any ref + return &pb.CalculateChecksumResponse{Checksum: blankChecksum}, nil + } + + // This will normally occur when exit code > 1 + return nil, status.Errorf(codes.Internal, err.Error()) + } + + return &pb.CalculateChecksumResponse{Checksum: hex.EncodeToString(checksum.Bytes())}, nil } diff --git a/internal/service/repository/calculate_checksum_test.go b/internal/service/repository/calculate_checksum_test.go new file mode 100644 index 000000000..421dde8cd --- /dev/null +++ b/internal/service/repository/calculate_checksum_test.go @@ -0,0 +1,84 @@ +package repository + +import ( + "testing" + + pb "gitlab.com/gitlab-org/gitaly-proto/go" + "gitlab.com/gitlab-org/gitaly/internal/testhelper" + "google.golang.org/grpc/codes" + + "github.com/stretchr/testify/require" +) + +func TestSuccessfulCalculateChecksum(t *testing.T) { + server, serverSocketPath := runRepoServer(t) + defer server.Stop() + + client, conn := newRepositoryClient(t, serverSocketPath) + defer conn.Close() + + testRepo, _, cleanupFn := testhelper.NewTestRepo(t) + defer cleanupFn() + + request := &pb.CalculateChecksumRequest{Repository: testRepo} + testCtx, cancelCtx := testhelper.Context() + defer cancelCtx() + + response, err := client.CalculateChecksum(testCtx, request) + require.NoError(t, err) + require.Equal(t, "8786527b0747d37d268adc75c5e5e54f3323891c", response.Checksum) +} + +func TestEmptyRepositoryCalculateChecksum(t *testing.T) { + server, serverSocketPath := runRepoServer(t) + defer server.Stop() + + client, conn := newRepositoryClient(t, serverSocketPath) + defer conn.Close() + + repo, _, cleanupFn := testhelper.InitBareRepo(t) + defer cleanupFn() + + request := &pb.CalculateChecksumRequest{Repository: repo} + testCtx, cancelCtx := testhelper.Context() + defer cancelCtx() + + response, err := client.CalculateChecksum(testCtx, request) + require.NoError(t, err) + require.Equal(t, "0000000000000000000000000000000000000000", response.Checksum) +} + +func TestFailedCalculateChecksum(t *testing.T) { + server, serverSocketPath := runRepoServer(t) + defer server.Stop() + + client, conn := newRepositoryClient(t, serverSocketPath) + defer conn.Close() + + invalidRepo := &pb.Repository{StorageName: "fake", RelativePath: "path"} + + testCases := []struct { + desc string + request *pb.CalculateChecksumRequest + code codes.Code + }{ + { + desc: "Invalid repository", + request: &pb.CalculateChecksumRequest{Repository: invalidRepo}, + code: codes.InvalidArgument, + }, + { + desc: "Repository is nil", + request: &pb.CalculateChecksumRequest{}, + code: codes.InvalidArgument, + }, + } + + for _, testCase := range testCases { + testCtx, cancelCtx := testhelper.Context() + defer cancelCtx() + + _, err := client.CalculateChecksum(testCtx, testCase.request) + testhelper.AssertGrpcError(t, err, testCase.code, "") + } +} |