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:
authorSiddharth Asthana <siddharthasthana31@gmail.com>2023-07-20 23:09:28 +0300
committerSiddharth Asthana <siddharthasthana31@gmail.com>2023-09-08 02:50:42 +0300
commitc622bdf031dfb5105e5cfe36f36fc7c975a4a722 (patch)
tree67b63255ff8898c9ebedbaa0ddd86a47f199f5b8
parenta73c61703276f8afea28c76eda913fd65a608f6c (diff)
Rangediff: Implement RawRangeDiff Service and Range Notation Validationissue_5123_rangediff
Implement the RawRangeDiff function in the rangediff service to process RangeDiffRequests and send the results back to the client. The revisions and range notation from the request are validated, with unsupported range notations returning appropriate errors. An error is also returned when any revision is empty. The sendRawOutput function is introduced to execute the provided git.Command and direct the output to the supplied io.Writer. Signed-off-by: Siddharth Asthana <siddharthasthana31@gmail.com>
-rw-r--r--internal/gitaly/service/rangediff/rangediff.go56
-rw-r--r--internal/gitaly/service/rangediff/rangediff_test.go134
-rw-r--r--internal/gitaly/service/rangediff/server.go21
3 files changed, 211 insertions, 0 deletions
diff --git a/internal/gitaly/service/rangediff/rangediff.go b/internal/gitaly/service/rangediff/rangediff.go
new file mode 100644
index 000000000..21409dd4d
--- /dev/null
+++ b/internal/gitaly/service/rangediff/rangediff.go
@@ -0,0 +1,56 @@
+package rangediff
+
+import (
+ "context"
+ "io"
+
+ "gitlab.com/gitlab-org/gitaly/v16/internal/git"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/structerr"
+ "gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb"
+ "gitlab.com/gitlab-org/gitaly/v16/streamio"
+)
+
+// RawRangeDiff processes the RangeDiffRequest and sends the result back to the client.
+func (s *server) RawRangeDiff(in *gitalypb.RangeDiffRequest, stream gitalypb.RangeDiffService_RawRangeDiffServer) error {
+ if in.GetRangeNotation() != gitalypb.RangeDiffRequest_TWO_REVS {
+ return structerr.NewInvalidArgument("only TWO_REVS range notation is supported")
+ }
+
+ if !isValidRevision(stream.Context(), in.GetRev1OrRange1()) || !isValidRevision(stream.Context(), in.GetRev2OrRange2()) {
+ return structerr.NewInvalidArgument("revisions are not valid")
+ }
+
+ // Create the range-diff command
+ cmd := git.Command{
+ Name: "range-diff",
+ Flags: []git.Option{},
+ Args: []string{in.GetRev1OrRange1(), "...", in.GetRev2OrRange2()},
+ }
+
+ sw := streamio.NewWriter(func(p []byte) error {
+ return stream.Send(&gitalypb.RawRangeDiffResponse{Data: p})
+ })
+
+ return sendRawOutput(stream.Context(), s.gitCmdFactory, in.Repository, sw, cmd)
+}
+
+// sendRawOutput runs the provided git.Command and sends the output to the provided io.Writer.
+func sendRawOutput(ctx context.Context, gitCmdFactory git.CommandFactory, repo *gitalypb.Repository, sender io.Writer, subCmd git.Command) error {
+ cmd, err := gitCmdFactory.New(ctx, repo, subCmd)
+ if err != nil {
+ return structerr.NewInternal("cmd: %w", err)
+ }
+
+ if _, err := io.Copy(sender, cmd); err != nil {
+ return structerr.NewAborted("send: %w", err)
+ }
+
+ return cmd.Wait()
+}
+
+func isValidRevision(ctx context.Context, revision string) bool {
+ if len(revision) == 0 {
+ return false
+ }
+ return true
+}
diff --git a/internal/gitaly/service/rangediff/rangediff_test.go b/internal/gitaly/service/rangediff/rangediff_test.go
new file mode 100644
index 000000000..ece1a09fb
--- /dev/null
+++ b/internal/gitaly/service/rangediff/rangediff_test.go
@@ -0,0 +1,134 @@
+package rangediff
+
+import (
+ "bytes"
+ "context"
+ "io"
+ "testing"
+
+ "github.com/stretchr/testify/require"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/config"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/service"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/structerr"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testcfg"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/testhelper/testserver"
+ "gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb"
+ "google.golang.org/grpc"
+ "google.golang.org/grpc/credentials/insecure"
+)
+
+func setupRangeDiffService(tb testing.TB, ctx context.Context, opt ...testserver.GitalyServerOpt) (config.Cfg, *gitalypb.Repository, string, gitalypb.RangeDiffServiceClient) {
+ cfg := testcfg.Build(tb)
+
+ addr := testserver.RunGitalyServer(tb, cfg, func(srv *grpc.Server, deps *service.Dependencies) {
+ gitalypb.RegisterRangeDiffServiceServer(srv, NewServer(
+ deps.GetLocator(),
+ deps.GetGitCmdFactory(),
+ ))
+ }, opt...)
+ cfg.SocketPath = addr
+
+ conn, err := grpc.Dial(addr, grpc.WithTransportCredentials(insecure.NewCredentials()))
+ require.NoError(tb, err)
+ tb.Cleanup(func() { testhelper.MustClose(tb, conn) })
+
+ client := gitalypb.NewRangeDiffServiceClient(conn)
+
+ repo, repoPath := gittest.CreateRepository(tb, ctx, cfg, gittest.CreateRepositoryConfig{
+ Seed: gittest.SeedGitLabTest,
+ })
+
+ return cfg, repo, repoPath, client
+}
+
+func TestRawRangeDiff_successful(t *testing.T) {
+ t.Parallel()
+
+ ctx := testhelper.Context(t)
+ cfg, repoProto, _, client := setupRangeDiffService(t, ctx)
+ repoProto, _ = gittest.CreateRepository(t, ctx, cfg)
+
+ request := &gitalypb.RangeDiffRequest{
+ Repository: repoProto,
+ Rev1OrRange1: "master~2",
+ Rev2OrRange2: "master",
+ RangeNotation: gitalypb.RangeDiffRequest_TWO_REVS,
+ }
+
+ stream, err := client.RawRangeDiff(ctx, request)
+ require.NoError(t, err)
+
+ var buffer bytes.Buffer
+ writer := io.Writer(&buffer)
+
+ for {
+ resp, err := stream.Recv()
+ if err == io.EOF {
+ break
+ }
+ require.NoError(t, err)
+ _, err = writer.Write(resp.GetData())
+ require.NoError(t, err)
+ }
+}
+
+func TestRawRangeDiff_inputValidation(t *testing.T) {
+ t.Parallel()
+
+ ctx := testhelper.Context(t)
+ cfg, repoProto, _, client := setupRangeDiffService(t, ctx)
+ repoProto, _ = gittest.CreateRepository(t, ctx, cfg)
+
+ tests := []struct {
+ desc string
+ request *gitalypb.RangeDiffRequest
+ expectedErr error
+ }{
+ {
+ desc: "empty rev1 or range1",
+ request: &gitalypb.RangeDiffRequest{
+ Repository: repoProto,
+ Rev2OrRange2: "master",
+ RangeNotation: gitalypb.RangeDiffRequest_TWO_REVS,
+ },
+ expectedErr: structerr.NewInvalidArgument("revisions cannot be empty"),
+ },
+ {
+ desc: "empty rev2 or range2",
+ request: &gitalypb.RangeDiffRequest{
+ Repository: repoProto,
+ Rev1OrRange1: "master~2",
+ RangeNotation: gitalypb.RangeDiffRequest_TWO_REVS,
+ },
+ expectedErr: structerr.NewInvalidArgument("revisions cannot be empty"),
+ },
+ {
+ desc: "unsupported range notation",
+ request: &gitalypb.RangeDiffRequest{
+ Repository: repoProto,
+ Rev1OrRange1: "master~2",
+ Rev2OrRange2: "master",
+ },
+ expectedErr: structerr.NewInvalidArgument("only TWO_REVS range notation is supported"),
+ },
+ }
+
+ for _, tc := range tests {
+ t.Run(tc.desc, func(t *testing.T) {
+ stream, err := client.RawRangeDiff(ctx, tc.request)
+ require.NoError(t, err)
+ err = drainRawRangeDiffResponse(stream)
+ testhelper.RequireGrpcError(t, tc.expectedErr, err)
+ })
+ }
+}
+
+func drainRawRangeDiffResponse(c gitalypb.RangeDiffService_RawRangeDiffClient) error {
+ var err error
+ for err == nil {
+ _, err = c.Recv()
+ }
+ return err
+}
diff --git a/internal/gitaly/service/rangediff/server.go b/internal/gitaly/service/rangediff/server.go
new file mode 100644
index 000000000..c444be16a
--- /dev/null
+++ b/internal/gitaly/service/rangediff/server.go
@@ -0,0 +1,21 @@
+package rangediff
+
+import (
+ "gitlab.com/gitlab-org/gitaly/v16/internal/git"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/storage"
+ "gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb"
+)
+
+type server struct {
+ gitalypb.UnimplementedRangeDiffServiceServer
+ locator storage.Locator
+ gitCmdFactory git.CommandFactory
+}
+
+// NewServer creates a new instance of a grpc RangeDiffServiceServer
+func NewServer(locator storage.Locator, gitCmdFactory git.CommandFactory) gitalypb.RangeDiffServiceServer {
+ return &server{
+ locator: locator,
+ gitCmdFactory: gitCmdFactory,
+ }
+}