package diff import ( "fmt" "io" "testing" "github.com/stretchr/testify/require" "gitlab.com/gitlab-org/gitaly/v16/internal/git/gittest" "gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/storage" "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/proto/go/gitalypb" "gitlab.com/gitlab-org/gitaly/v16/streamio" ) func TestRawDiff_successful(t *testing.T) { t.Parallel() ctx := testhelper.Context(t) cfg, client := setupDiffService(t) testcfg.BuildGitalyGit2Go(t, cfg) repoProto, repoPath := gittest.CreateRepository(t, ctx, cfg) oldBlob := gittest.WriteBlob(t, cfg, repoPath, []byte("old\n")) newBlob := gittest.WriteBlob(t, cfg, repoPath, []byte("new\n")) leftCommit := gittest.WriteCommit(t, cfg, repoPath, gittest.WithTreeEntries( gittest.TreeEntry{Path: "file", Mode: "100644", OID: oldBlob}, )) rightCommit := gittest.WriteCommit(t, cfg, repoPath, gittest.WithTreeEntries( gittest.TreeEntry{Path: "file", Mode: "100644", OID: newBlob}, )) stream, err := client.RawDiff(ctx, &gitalypb.RawDiffRequest{ Repository: repoProto, LeftCommitId: leftCommit.String(), RightCommitId: rightCommit.String(), }) require.NoError(t, err) rawDiff, err := io.ReadAll(streamio.NewReader(func() ([]byte, error) { response, err := stream.Recv() return response.GetData(), err })) require.NoError(t, err) require.Equal(t, fmt.Sprintf(`diff --git a/file b/file index %s..%s 100644 --- a/file +++ b/file @@ -1 +1 @@ -old +new `, oldBlob, newBlob), string(rawDiff)) } func TestRawDiff_inputValidation(t *testing.T) { t.Parallel() ctx := testhelper.Context(t) cfg, client := setupDiffService(t) repo, repoPath := gittest.CreateRepository(t, ctx, cfg) commit := gittest.WriteCommit(t, cfg, repoPath) for _, tc := range []struct { desc string request *gitalypb.RawDiffRequest expectedErr error }{ { desc: "empty left commit", request: &gitalypb.RawDiffRequest{ Repository: repo, LeftCommitId: "", RightCommitId: commit.String(), }, expectedErr: structerr.NewInvalidArgument("empty LeftCommitId"), }, { desc: "empty right commit", request: &gitalypb.RawDiffRequest{ Repository: repo, LeftCommitId: commit.String(), RightCommitId: "", }, expectedErr: structerr.NewInvalidArgument("empty RightCommitId"), }, { desc: "empty repo", request: &gitalypb.RawDiffRequest{ Repository: nil, RightCommitId: commit.String(), LeftCommitId: commit.String(), }, expectedErr: structerr.NewInvalidArgument("%w", storage.ErrRepositoryNotSet), }, } { t.Run(tc.desc, func(t *testing.T) { stream, err := client.RawDiff(ctx, tc.request) require.NoError(t, err) testhelper.RequireGrpcError(t, tc.expectedErr, drainRawDiffResponse(stream)) }) } } func TestRawPatch_successful(t *testing.T) { t.Parallel() ctx := testhelper.Context(t) cfg, client := setupDiffService(t) repoProto, repoPath := gittest.CreateRepository(t, ctx, cfg) oldBlob := gittest.WriteBlob(t, cfg, repoPath, []byte("old\n")) newBlob := gittest.WriteBlob(t, cfg, repoPath, []byte("new\n")) leftCommit := gittest.WriteCommit(t, cfg, repoPath, gittest.WithTreeEntries( gittest.TreeEntry{Path: "file", Mode: "100644", OID: oldBlob}, )) rightCommit := gittest.WriteCommit(t, cfg, repoPath, gittest.WithParents(leftCommit), gittest.WithTreeEntries( gittest.TreeEntry{Path: "file", Mode: "100644", OID: newBlob}, )) stream, err := client.RawPatch(ctx, &gitalypb.RawPatchRequest{ Repository: repoProto, LeftCommitId: leftCommit.String(), RightCommitId: rightCommit.String(), }) require.NoError(t, err) rawPatch, err := io.ReadAll(streamio.NewReader(func() ([]byte, error) { response, err := stream.Recv() return response.GetData(), err })) require.NoError(t, err) // Note that the date in From is actually static. This is actually hardcoded in Git itself, please refer to // git-format-patch(1). expectedPatch := fmt.Sprintf( `From %s Mon Sep 17 00:00:00 2001 From: %s <%s> Date: %s Subject: [PATCH] message --- file | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/file b/file index %s..%s 100644 --- a/file +++ b/file @@ -1 +1 @@ -old +new --%c GitLab `, rightCommit, gittest.DefaultCommitterName, gittest.DefaultCommitterMail, gittest.DefaultCommitTime.Format("Mon, 2 Jan 2006 15:04:05 -0700"), oldBlob[:7], newBlob[:7], ' ') require.Equal(t, expectedPatch, string(rawPatch)) } func TestRawPatch_inputValidation(t *testing.T) { t.Parallel() ctx := testhelper.Context(t) cfg, client := setupDiffService(t) repo, repoPath := gittest.CreateRepository(t, ctx, cfg) commit := gittest.WriteCommit(t, cfg, repoPath) for _, tc := range []struct { desc string request *gitalypb.RawPatchRequest expectedErr error }{ { desc: "empty left commit", request: &gitalypb.RawPatchRequest{ Repository: repo, LeftCommitId: "", RightCommitId: commit.String(), }, expectedErr: structerr.NewInvalidArgument("empty LeftCommitId"), }, { desc: "empty right commit", request: &gitalypb.RawPatchRequest{ Repository: repo, RightCommitId: "", LeftCommitId: commit.String(), }, expectedErr: structerr.NewInvalidArgument("empty RightCommitId"), }, { desc: "empty repo", request: &gitalypb.RawPatchRequest{ Repository: nil, RightCommitId: commit.String(), LeftCommitId: commit.String(), }, expectedErr: structerr.NewInvalidArgument("%w", storage.ErrRepositoryNotSet), }, } { t.Run(tc.desc, func(t *testing.T) { stream, _ := client.RawPatch(ctx, tc.request) testhelper.RequireGrpcError(t, tc.expectedErr, drainRawPatchResponse(stream)) }) } } func drainRawDiffResponse(c gitalypb.DiffService_RawDiffClient) error { var err error for err == nil { _, err = c.Recv() } return err } func drainRawPatchResponse(c gitalypb.DiffService_RawPatchClient) error { var err error for err == nil { _, err = c.Recv() } return err }