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:
authorZeger-Jan van de Weg <zegerjan@gitlab.com>2017-10-30 13:15:52 +0300
committerZeger-Jan van de Weg <zegerjan@gitlab.com>2017-10-30 13:15:52 +0300
commita35fdb3719289e4a3abf665b68f4ab91a5990b06 (patch)
tree5b548992f71050be7e424590eb51bd6065677eb2
parent53610026e03f02d4e10149cdae42c4d62c9f3552 (diff)
parent808241e24d2e8287384df066eeba1790ef2952fb (diff)
Merge branch 'feature/implement-wiki-find-page-rpc' into 'master'
Implement WikiFindPage RPC Closes #678 See merge request gitlab-org/gitaly!419
-rw-r--r--CHANGELOG.md2
-rw-r--r--internal/service/wiki/find_page.go43
-rw-r--r--internal/service/wiki/find_page_test.go219
-rw-r--r--internal/service/wiki/server.go4
-rw-r--r--internal/service/wiki/testhelper_test.go28
-rw-r--r--internal/service/wiki/write_page_test.go33
-rw-r--r--ruby/lib/gitaly_server/wiki_service.rb44
7 files changed, 349 insertions, 24 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4d51e4b60..c3e633dfd 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,8 @@
UNRELEASED
+- Implement WikiFindPage RPC
+ https://gitlab.com/gitlab-org/gitaly/merge_requests/419
- Update gitlab_git to b3ba3996e0bd329eaa574ff53c69673efaca6eef and set
`GL_USERNAME` env variable for hook excecution
https://gitlab.com/gitlab-org/gitaly/merge_requests/423
diff --git a/internal/service/wiki/find_page.go b/internal/service/wiki/find_page.go
new file mode 100644
index 000000000..79eea6900
--- /dev/null
+++ b/internal/service/wiki/find_page.go
@@ -0,0 +1,43 @@
+package wiki
+
+import (
+ "gitlab.com/gitlab-org/gitaly/internal/rubyserver"
+
+ pb "gitlab.com/gitlab-org/gitaly-proto/go"
+
+ "google.golang.org/grpc"
+ "google.golang.org/grpc/codes"
+)
+
+func (s *server) WikiFindPage(request *pb.WikiFindPageRequest, stream pb.WikiService_WikiFindPageServer) error {
+ ctx := stream.Context()
+
+ if len(request.GetTitle()) == 0 {
+ return grpc.Errorf(codes.InvalidArgument, "WikiFindPage: Empty Title")
+ }
+
+ client, err := s.WikiServiceClient(ctx)
+ if err != nil {
+ return err
+ }
+
+ clientCtx, err := rubyserver.SetHeaders(ctx, request.GetRepository())
+ if err != nil {
+ return err
+ }
+
+ rubyStream, err := client.WikiFindPage(clientCtx, request)
+ if err != nil {
+ return err
+ }
+
+ return rubyserver.Proxy(func() error {
+ resp, err := rubyStream.Recv()
+ if err != nil {
+ md := rubyStream.Trailer()
+ stream.SetTrailer(md)
+ return err
+ }
+ return stream.Send(resp)
+ })
+}
diff --git a/internal/service/wiki/find_page_test.go b/internal/service/wiki/find_page_test.go
new file mode 100644
index 000000000..67bde39e3
--- /dev/null
+++ b/internal/service/wiki/find_page_test.go
@@ -0,0 +1,219 @@
+package wiki
+
+import (
+ "bytes"
+ "io"
+ "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 TestSuccessfulWikiFindPageRequest(t *testing.T) {
+ ctx, cancel := testhelper.Context()
+ defer cancel()
+
+ server, serverSocketPath := runWikiServiceServer(t)
+ defer server.Stop()
+
+ client, conn := newWikiClient(t, serverSocketPath)
+ defer conn.Close()
+
+ content := bytes.Repeat([]byte("Mock wiki page content"), 10000)
+
+ page1Name := "Home Page"
+ page2Name := "Installing/Step 133-b"
+ page3Name := "Installing/Step 133-c"
+
+ writeWikiPage(t, client, page1Name, content)
+ head1ID := testhelper.MustRunCommand(t, nil, "git", "-C", wikiRepoPath, "show", "--format=format:%H", "--no-patch", "HEAD")
+ page1Commit, err := gitlog.GetCommit(ctx, wikiRepo, string(head1ID), "")
+ require.NoError(t, err, "look up git commit after writing a wiki page")
+
+ writeWikiPage(t, client, page2Name, content)
+
+ writeWikiPage(t, client, page3Name, content)
+ head3ID := testhelper.MustRunCommand(t, nil, "git", "-C", wikiRepoPath, "show", "--format=format:%H", "--no-patch", "HEAD")
+ page3Commit, err := gitlog.GetCommit(ctx, wikiRepo, string(head3ID), "")
+ require.NoError(t, err, "look up git commit after writing a wiki page")
+
+ testCases := []struct {
+ desc string
+ request *pb.WikiFindPageRequest
+ expectedPage *pb.WikiPage
+ }{
+ {
+ desc: "title only",
+ request: &pb.WikiFindPageRequest{
+ Repository: wikiRepo,
+ Title: []byte(page1Name),
+ },
+ expectedPage: &pb.WikiPage{
+ Version: &pb.WikiPageVersion{
+ Commit: page3Commit,
+ Format: "markdown",
+ },
+ Title: []byte(page1Name),
+ Format: "markdown",
+ UrlPath: "Home-Page",
+ Path: []byte("Home-Page.md"),
+ Name: []byte(page1Name),
+ Historical: false,
+ },
+ },
+ {
+ desc: "title + revision that includes the page",
+ request: &pb.WikiFindPageRequest{
+ Repository: wikiRepo,
+ Title: []byte(page1Name),
+ Revision: []byte(page1Commit.Id),
+ },
+ expectedPage: &pb.WikiPage{
+ Version: &pb.WikiPageVersion{
+ Commit: page1Commit,
+ Format: "markdown",
+ },
+ Title: []byte(page1Name),
+ Format: "markdown",
+ UrlPath: "Home-Page",
+ Path: []byte("Home-Page.md"),
+ Name: []byte(page1Name),
+ Historical: true,
+ },
+ },
+ {
+ desc: "title + revision that does not include the page",
+ request: &pb.WikiFindPageRequest{
+ Repository: wikiRepo,
+ Title: []byte(page2Name),
+ Revision: []byte(page1Commit.Id),
+ },
+ expectedPage: nil,
+ },
+ {
+ desc: "title + directory that includes the page",
+ request: &pb.WikiFindPageRequest{
+ Repository: wikiRepo,
+ Title: []byte("Step 133-b"),
+ Directory: []byte("Installing"),
+ },
+ expectedPage: &pb.WikiPage{
+ Version: &pb.WikiPageVersion{
+ Commit: page3Commit,
+ Format: "markdown",
+ },
+ Title: []byte("Step 133 b"),
+ Format: "markdown",
+ UrlPath: "Installing/Step-133-b",
+ Path: []byte("Installing/Step-133-b.md"),
+ Name: []byte("Step 133 b"),
+ Historical: false,
+ },
+ },
+ {
+ desc: "title + directory that does not include the page",
+ request: &pb.WikiFindPageRequest{
+ Repository: wikiRepo,
+ Title: []byte("Step 133-b"),
+ Directory: []byte("Installation"),
+ },
+ expectedPage: nil,
+ },
+ }
+
+ for _, testCase := range testCases {
+ t.Run(testCase.desc, func(t *testing.T) {
+ ctx, cancel := testhelper.Context()
+ defer cancel()
+
+ c, err := client.WikiFindPage(ctx, testCase.request)
+ require.NoError(t, err)
+
+ expectedPage := testCase.expectedPage
+ receivedPage := readFullWikiPageFromWikiFindPageClient(t, c)
+
+ // require.Equal doesn't display a proper diff when either expected/actual has a field
+ // with large data (RawData in our case), so we compare page attributes and content separately.
+ receivedContent := receivedPage.GetRawData()
+ if receivedPage != nil {
+ receivedPage.RawData = nil
+ }
+
+ require.Equal(t, expectedPage, receivedPage, "mismatched page attributes")
+ if expectedPage != nil {
+ require.Equal(t, content, receivedContent, "mismatched page content")
+ }
+ })
+ }
+}
+
+func TestFailedWikiFindPageDueToValidation(t *testing.T) {
+ server, serverSocketPath := runWikiServiceServer(t)
+ defer server.Stop()
+
+ client, conn := newWikiClient(t, serverSocketPath)
+ defer conn.Close()
+
+ testCases := []struct {
+ desc string
+ title string
+ code codes.Code
+ }{
+ {
+ desc: "empty page path",
+ title: "",
+ code: codes.InvalidArgument,
+ },
+ }
+
+ for _, testCase := range testCases {
+ t.Run(testCase.desc, func(t *testing.T) {
+ ctx, cancel := testhelper.Context()
+ defer cancel()
+
+ request := &pb.WikiFindPageRequest{
+ Repository: wikiRepo,
+ Title: []byte(testCase.title),
+ }
+
+ c, err := client.WikiFindPage(ctx, request)
+ require.NoError(t, err)
+
+ err = drainWikiFindPageResponse(c)
+ testhelper.AssertGrpcError(t, err, testCase.code, "")
+ })
+ }
+}
+
+func drainWikiFindPageResponse(c pb.WikiService_WikiFindPageClient) error {
+ for {
+ _, err := c.Recv()
+ if err != nil {
+ return err
+ }
+ }
+}
+
+func readFullWikiPageFromWikiFindPageClient(t *testing.T, c pb.WikiService_WikiFindPageClient) (wikiPage *pb.WikiPage) {
+ for {
+ resp, err := c.Recv()
+ if err == io.EOF {
+ break
+ } else if err != nil {
+ t.Fatal(err)
+ }
+
+ if wikiPage == nil {
+ wikiPage = resp.GetPage()
+ } else {
+ wikiPage.RawData = append(wikiPage.RawData, resp.GetPage().GetRawData()...)
+ }
+ }
+
+ return wikiPage
+}
diff --git a/internal/service/wiki/server.go b/internal/service/wiki/server.go
index 5091f0fe8..b2c589e10 100644
--- a/internal/service/wiki/server.go
+++ b/internal/service/wiki/server.go
@@ -19,7 +19,3 @@ func NewServer(rs *rubyserver.Server) pb.WikiServiceServer {
func (s *server) WikiGetPageVersions(_ *pb.WikiGetPageVersionsRequest, _ pb.WikiService_WikiGetPageVersionsServer) error {
return helper.Unimplemented
}
-
-func (s *server) WikiFindPage(_ *pb.WikiFindPageRequest, _ pb.WikiService_WikiFindPageServer) error {
- return helper.Unimplemented
-}
diff --git a/internal/service/wiki/testhelper_test.go b/internal/service/wiki/testhelper_test.go
index 1ee5769bd..0de56997e 100644
--- a/internal/service/wiki/testhelper_test.go
+++ b/internal/service/wiki/testhelper_test.go
@@ -13,6 +13,7 @@ import (
pb "gitlab.com/gitlab-org/gitaly-proto/go"
log "github.com/sirupsen/logrus"
+ "github.com/stretchr/testify/require"
"google.golang.org/grpc"
"google.golang.org/grpc/reflection"
)
@@ -85,3 +86,30 @@ func newWikiClient(t *testing.T, serverSocketPath string) (pb.WikiServiceClient,
return pb.NewWikiServiceClient(conn), conn
}
+
+func writeWikiPage(t *testing.T, client pb.WikiServiceClient, name string, content []byte) {
+ commitDetails := &pb.WikiCommitDetails{
+ Name: []byte("Ahmad Sherif"),
+ Email: []byte("ahmad@gitlab.com"),
+ Message: []byte("Add " + name),
+ }
+
+ request := &pb.WikiWritePageRequest{
+ Repository: wikiRepo,
+ Name: []byte(name),
+ Format: "markdown",
+ CommitDetails: commitDetails,
+ Content: content,
+ }
+
+ ctx, cancel := testhelper.Context()
+ defer cancel()
+
+ stream, err := client.WikiWritePage(ctx)
+ require.NoError(t, err)
+
+ require.NoError(t, stream.Send(request))
+
+ _, err = stream.CloseAndRecv()
+ require.NoError(t, err)
+}
diff --git a/internal/service/wiki/write_page_test.go b/internal/service/wiki/write_page_test.go
index edfb6e547..b61724321 100644
--- a/internal/service/wiki/write_page_test.go
+++ b/internal/service/wiki/write_page_test.go
@@ -64,7 +64,7 @@ func TestSuccessfulWikiWritePageRequest(t *testing.T) {
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.NoError(t, err, "look up git commit after writing a wiki page")
require.Equal(t, authorName, commit.Author.Name, "author name mismatched")
require.Equal(t, authorEmail, commit.Author.Email, "author email mismatched")
@@ -81,40 +81,33 @@ func TestFailedWikiWritePageDueToDuplicatePage(t *testing.T) {
client, conn := newWikiClient(t, serverSocketPath)
defer conn.Close()
+ pageName := "Installing Gitaly"
+ content := []byte("Mock wiki page content")
commitDetails := &pb.WikiCommitDetails{
Name: []byte("Ahmad Sherif"),
Email: []byte("ahmad@gitlab.com"),
- Message: []byte("Add installation instructions"),
+ Message: []byte("Add " + pageName),
}
+ writeWikiPage(t, client, pageName, content)
+
request := &pb.WikiWritePageRequest{
Repository: wikiRepo,
- Name: []byte("Installing Gitaly"),
+ Name: []byte(pageName),
Format: "markdown",
CommitDetails: commitDetails,
- Content: []byte("Mock wiki page content"),
+ Content: content,
}
- ctx1, cancel1 := testhelper.Context()
- defer cancel1()
-
- stream1, err := client.WikiWritePage(ctx1)
- require.NoError(t, err)
-
- require.NoError(t, stream1.Send(request))
-
- _, err = stream1.CloseAndRecv()
- require.NoError(t, err)
-
- ctx2, cancel2 := testhelper.Context()
- defer cancel2()
+ ctx, cancel := testhelper.Context()
+ defer cancel()
- stream2, err := client.WikiWritePage(ctx2)
+ stream, err := client.WikiWritePage(ctx)
require.NoError(t, err)
- require.NoError(t, stream2.Send(request))
+ require.NoError(t, stream.Send(request))
- response, err := stream2.CloseAndRecv()
+ response, err := stream.CloseAndRecv()
require.NoError(t, err)
expectedResponse := &pb.WikiWritePageResponse{DuplicateError: []byte("Cannot write //Installing-Gitaly.md, found //Installing-Gitaly.md.")}
diff --git a/ruby/lib/gitaly_server/wiki_service.rb b/ruby/lib/gitaly_server/wiki_service.rb
index 1077d4d1b..2fd56ae6b 100644
--- a/ruby/lib/gitaly_server/wiki_service.rb
+++ b/ruby/lib/gitaly_server/wiki_service.rb
@@ -34,5 +34,49 @@ module GitalyServer
end
end
end
+
+ def wiki_find_page(request, call)
+ bridge_exceptions do
+ repo = Gitlab::Git::Repository.from_call(call)
+ wiki = Gitlab::Git::Wiki.new(repo)
+
+ page = wiki.page(
+ title: request.title,
+ version: request.revision.presence,
+ dir: request.directory.presence
+ )
+
+ unless page
+ return Enumerator.new do |y|
+ y.yield Gitaly::WikiFindPageResponse.new
+ end
+ end
+
+ version = Gitaly::WikiPageVersion.new(
+ commit: gitaly_commit_from_rugged(page.version.commit.raw_commit),
+ format: page.version.format.to_s
+ )
+ gitaly_wiki_page = Gitaly::WikiPage.new(
+ version: version,
+ format: page.format.to_s,
+ title: page.title.b,
+ url_path: page.url_path.to_s,
+ path: page.path.b,
+ name: page.name.b,
+ historical: page.historical?
+ )
+
+ Enumerator.new do |y|
+ io = StringIO.new(page.text_data)
+ while chunk = io.read(Gitlab.config.git.write_buffer_size)
+ gitaly_wiki_page.raw_data = chunk
+
+ y.yield Gitaly::WikiFindPageResponse.new(page: gitaly_wiki_page)
+
+ gitaly_wiki_page = Gitaly::WikiPage.new
+ end
+ end
+ end
+ end
end
end