diff options
author | Kim "BKC" Carlbäcker <kim.carlbacker@gmail.com> | 2017-10-22 21:39:53 +0300 |
---|---|---|
committer | Kim "BKC" Carlbäcker <kim.carlbacker@gmail.com> | 2017-10-31 16:11:25 +0300 |
commit | 86d4e13cb2a642df3d3cd31b78977b16d756a19a (patch) | |
tree | b788856243f494a98d2c4f0f0f98bcefb8ccc150 | |
parent | 9ef5784e9a5f95cebb5cfda6a6a7bac7842c2a28 (diff) |
WikiService::WikiUpdatePage
-rw-r--r-- | CHANGELOG.md | 2 | ||||
-rw-r--r-- | internal/service/wiki/testhelper_test.go | 17 | ||||
-rw-r--r-- | internal/service/wiki/update_page.go | 73 | ||||
-rw-r--r-- | internal/service/wiki/update_page_test.go | 205 | ||||
-rw-r--r-- | internal/service/wiki/write_page_test.go | 17 | ||||
-rw-r--r-- | ruby/lib/gitaly_server/wiki_service.rb | 25 |
6 files changed, 320 insertions, 19 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 81d229216..bdeb1ee32 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ v0.51.0 - Implement OperationService.UserFFMerge https://gitlab.com/gitlab-org/gitaly/merge_requests/426 +- Implement WikiUpdatePage RPC + https://gitlab.com/gitlab-org/gitaly/merge_requests/422 - Implement WikiFindFile RPC https://gitlab.com/gitlab-org/gitaly/merge_requests/425 - Implement WikiDeletePage RPC diff --git a/internal/service/wiki/testhelper_test.go b/internal/service/wiki/testhelper_test.go index 0de56997e..d41e97607 100644 --- a/internal/service/wiki/testhelper_test.go +++ b/internal/service/wiki/testhelper_test.go @@ -113,3 +113,20 @@ func writeWikiPage(t *testing.T, client pb.WikiServiceClient, name string, conte _, err = stream.CloseAndRecv() require.NoError(t, err) } + +func sendBytes(data []byte, chunkSize int, sender func([]byte) error) (int, error) { + i := 0 + for ; len(data) > 0; i++ { + n := chunkSize + if n > len(data) { + n = len(data) + } + + if err := sender(data[:n]); err != nil { + return i, err + } + data = data[n:] + } + + return i, nil +} diff --git a/internal/service/wiki/update_page.go b/internal/service/wiki/update_page.go index 880591544..450971bd6 100644 --- a/internal/service/wiki/update_page.go +++ b/internal/service/wiki/update_page.go @@ -1,10 +1,79 @@ package wiki import ( + "fmt" + + "gitlab.com/gitlab-org/gitaly/internal/rubyserver" + pb "gitlab.com/gitlab-org/gitaly-proto/go" - "gitlab.com/gitlab-org/gitaly/internal/helper" + + "google.golang.org/grpc" + "google.golang.org/grpc/codes" ) func (s *server) WikiUpdatePage(stream pb.WikiService_WikiUpdatePageServer) error { - return helper.Unimplemented + firstRequest, err := stream.Recv() + if err != nil { + return err + } + + if err := validateWikiUpdatePageRequest(firstRequest); err != nil { + return grpc.Errorf(codes.InvalidArgument, "WikiUpdatePage: %v", err) + } + + ctx := stream.Context() + + client, err := s.WikiServiceClient(ctx) + if err != nil { + return err + } + + clientCtx, err := rubyserver.SetHeaders(ctx, firstRequest.GetRepository()) + if err != nil { + return err + } + + rubyStream, err := client.WikiUpdatePage(clientCtx) + if err != nil { + return err + } + + if err := rubyStream.Send(firstRequest); err != nil { + return err + } + + err = rubyserver.Proxy(func() error { + request, err := stream.Recv() + if err != nil { + return err + } + return rubyStream.Send(request) + }) + + if err != nil { + return err + } + + response, err := rubyStream.CloseAndRecv() + if err != nil { + return err + } + + return stream.SendAndClose(response) +} + +func validateWikiUpdatePageRequest(request *pb.WikiUpdatePageRequest) error { + if len(request.GetPagePath()) == 0 { + return fmt.Errorf("empty Page Path") + } + + if len(request.GetTitle()) == 0 { + return fmt.Errorf("empty Title") + } + + if len(request.GetFormat()) == 0 { + return fmt.Errorf("empty Format") + } + + return validateRequestCommitDetails(request) } diff --git a/internal/service/wiki/update_page_test.go b/internal/service/wiki/update_page_test.go new file mode 100644 index 000000000..1a9ba0eb5 --- /dev/null +++ b/internal/service/wiki/update_page_test.go @@ -0,0 +1,205 @@ +package wiki + +import ( + "bytes" + "testing" + + gitlog "gitlab.com/gitlab-org/gitaly/internal/git/log" + "gitlab.com/gitlab-org/gitaly/internal/testhelper" + + pb "gitlab.com/gitlab-org/gitaly-proto/go" + + "github.com/stretchr/testify/require" + "google.golang.org/grpc/codes" +) + +func TestSuccessfulWikiUpdatePageRequest(t *testing.T) { + ctx, cancel := testhelper.Context() + defer cancel() + + server, serverSocketPath := runWikiServiceServer(t) + defer server.Stop() + + client, conn := newWikiClient(t, serverSocketPath) + defer conn.Close() + + writeWikiPage(t, client, "Installing Gitaly", []byte("foobar")) + + content := bytes.Repeat([]byte("Mock wiki page content"), 10000) + + authorName := []byte("Ahmad Sherif") + authorEmail := []byte("ahmad@gitlab.com") + message := []byte("Add installation instructions") + + request := &pb.WikiUpdatePageRequest{ + Repository: wikiRepo, + PagePath: []byte("//Installing Gitaly"), + Title: []byte("Installing Gitaly"), + Format: "markdown", + CommitDetails: &pb.WikiCommitDetails{ + Name: authorName, + Email: authorEmail, + Message: message, + }, + } + + stream, err := client.WikiUpdatePage(ctx) + require.NoError(t, err) + + nSends, err := sendBytes(content, 1000, func(p []byte) error { + request.Content = p + + if err := stream.Send(request); err != nil { + return err + } + + // Use a new response so we don't send other fields (Repository, ...) over and over + request = &pb.WikiUpdatePageRequest{} + + return nil + }) + + require.NoError(t, err) + require.True(t, nSends > 1, "should have sent more than one message") + + _, err = stream.CloseAndRecv() + require.NoError(t, err) + + headID := testhelper.MustRunCommand(t, nil, "git", "-C", wikiRepoPath, "show", "--format=format:%H", "--no-patch", "HEAD") + commit, err := gitlog.GetCommit(ctx, wikiRepo, string(headID), "") + require.NoError(t, err, "look up git commit before merge is applied") + + require.Equal(t, authorName, commit.Author.Name, "author name mismatched") + require.Equal(t, authorEmail, commit.Author.Email, "author email mismatched") + require.Equal(t, message, commit.Subject, "message mismatched") + + pageContent := testhelper.MustRunCommand(t, nil, "git", "-C", wikiRepoPath, "cat-file", "blob", "HEAD:Installing-Gitaly.md") + require.Equal(t, content, pageContent, "mismatched content") +} + +func TestFailedWikiUpdatePageDueToValidations(t *testing.T) { + server, serverSocketPath := runWikiServiceServer(t) + defer server.Stop() + + client, conn := newWikiClient(t, serverSocketPath) + defer conn.Close() + + writeWikiPage(t, client, "Installing Gitaly", []byte("foobar")) + + commitDetails := &pb.WikiCommitDetails{ + Name: []byte("Ahmad Sherif"), + Email: []byte("ahmad@gitlab.com"), + Message: []byte("Add installation instructions"), + } + + testCases := []struct { + desc string + request *pb.WikiUpdatePageRequest + code codes.Code + }{ + { + desc: "empty page_path", + request: &pb.WikiUpdatePageRequest{ + Repository: wikiRepo, + Title: []byte("Installing Gitaly"), + Format: "markdown", + CommitDetails: commitDetails, + Content: []byte(""), + }, + code: codes.InvalidArgument, + }, + { + desc: "empty title", + request: &pb.WikiUpdatePageRequest{ + Repository: wikiRepo, + PagePath: []byte("//Installing Gitaly"), + Format: "markdown", + CommitDetails: commitDetails, + Content: []byte(""), + }, + code: codes.InvalidArgument, + }, + { + desc: "empty format", + request: &pb.WikiUpdatePageRequest{ + Repository: wikiRepo, + PagePath: []byte("//Installing Gitaly.md"), + Title: []byte("Installing Gitaly"), + CommitDetails: commitDetails, + Content: []byte(""), + }, + code: codes.InvalidArgument, + }, + { + desc: "empty commit details", + request: &pb.WikiUpdatePageRequest{ + Repository: wikiRepo, + PagePath: []byte("//Installing Gitaly.md"), + Title: []byte("Installing Gitaly"), + Format: "markdown", + Content: []byte(""), + }, + code: codes.InvalidArgument, + }, + { + desc: "empty commit details' name", + request: &pb.WikiUpdatePageRequest{ + Repository: wikiRepo, + PagePath: []byte("//Installing Gitaly.md"), + Title: []byte("Installing Gitaly"), + Format: "markdown", + CommitDetails: &pb.WikiCommitDetails{ + Email: []byte("a@b.com"), + Message: []byte("A message"), + }, + Content: []byte(""), + }, + code: codes.InvalidArgument, + }, + { + desc: "empty commit details' email", + request: &pb.WikiUpdatePageRequest{ + Repository: wikiRepo, + PagePath: []byte("//Installing Gitaly.md"), + Title: []byte("Installing Gitaly"), + Format: "markdown", + CommitDetails: &pb.WikiCommitDetails{ + Name: []byte("A name"), + Message: []byte("A message"), + }, + Content: []byte(""), + }, + code: codes.InvalidArgument, + }, + { + desc: "empty commit details' message", + request: &pb.WikiUpdatePageRequest{ + Repository: wikiRepo, + PagePath: []byte("//Installing Gitaly.md"), + Title: []byte("Installing Gitaly"), + Format: "markdown", + CommitDetails: &pb.WikiCommitDetails{ + Name: []byte("A name"), + Email: []byte("a@b.com"), + }, + Content: []byte(""), + }, + code: codes.InvalidArgument, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.desc, func(t *testing.T) { + ctx, cancel := testhelper.Context() + defer cancel() + + stream, err := client.WikiUpdatePage(ctx) + require.NoError(t, err) + + require.NoError(t, stream.Send(testCase.request)) + + _, err = stream.CloseAndRecv() + testhelper.AssertGrpcError(t, err, testCase.code, "") + }) + } +} diff --git a/internal/service/wiki/write_page_test.go b/internal/service/wiki/write_page_test.go index b61724321..99b515c20 100644 --- a/internal/service/wiki/write_page_test.go +++ b/internal/service/wiki/write_page_test.go @@ -221,20 +221,3 @@ func TestFailedWikiWritePageDueToValidations(t *testing.T) { }) } } - -func sendBytes(data []byte, chunkSize int, sender func([]byte) error) (int, error) { - i := 0 - for ; len(data) > 0; i++ { - n := chunkSize - if n > len(data) { - n = len(data) - } - - if err := sender(data[:n]); err != nil { - return i, err - } - data = data[n:] - } - - return i, nil -} diff --git a/ruby/lib/gitaly_server/wiki_service.rb b/ruby/lib/gitaly_server/wiki_service.rb index 5cb6721c3..a22553705 100644 --- a/ruby/lib/gitaly_server/wiki_service.rb +++ b/ruby/lib/gitaly_server/wiki_service.rb @@ -119,5 +119,30 @@ module GitalyServer end end end + + def wiki_update_page(call) + bridge_exceptions do + repo = Gitlab::Git::Repository.from_call(call) + title = format = page_path = commit_details = nil + content = "" + + wiki = Gitlab::Git::Wiki.new(repo) + call.each_remote_read.with_index do |request, index| + if index.zero? + title = request.title + page_path = request.page_path + format = request.format + + commit_details = commit_details_from_gitaly(request.commit_details) + end + + content << request.content + end + + wiki.update_page(page_path, title, format.to_sym, content, commit_details) + + Gitaly::WikiUpdatePageResponse.new + end + end end end |