From 495a384d41e8b4ed5a6e3e45375eda6aecd4f4fc Mon Sep 17 00:00:00 2001 From: John Cai Date: Thu, 27 Jun 2019 00:56:17 +0000 Subject: Add CloneFromPool and CloneFromPoolInternal RPCs --- internal/git/gittest/http_server.go | 57 ++++++++++++++++++++++++++++++ internal/git/objectpool/link.go | 11 +++--- internal/git/objectpool/link_test.go | 48 +++++++++++++++++++++---- internal/git/objectpool/testhelper_test.go | 17 +++++++++ 4 files changed, 122 insertions(+), 11 deletions(-) create mode 100644 internal/git/gittest/http_server.go create mode 100644 internal/git/objectpool/testhelper_test.go (limited to 'internal/git') diff --git a/internal/git/gittest/http_server.go b/internal/git/gittest/http_server.go new file mode 100644 index 000000000..4e5d1916a --- /dev/null +++ b/internal/git/gittest/http_server.go @@ -0,0 +1,57 @@ +package gittest + +import ( + "compress/gzip" + "context" + "fmt" + "net/http" + "net/http/httptest" + "os/exec" + "testing" + + "github.com/stretchr/testify/require" + "gitlab.com/gitlab-org/gitaly/internal/command" +) + +// RemoteUploadPackServer implements two HTTP routes for git-upload-pack by copying stdin and stdout into and out of the git upload-pack command +func RemoteUploadPackServer(ctx context.Context, t *testing.T, repoName, httpToken, repoPath string) (*httptest.Server, string) { + s := httptest.NewServer( + http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.URL.String() { + case fmt.Sprintf("/%s.git/git-upload-pack", repoName): + w.WriteHeader(http.StatusOK) + + var err error + reader := r.Body + + if r.Header.Get("Content-Encoding") == "gzip" { + reader, err = gzip.NewReader(r.Body) + require.NoError(t, err) + } + defer r.Body.Close() + + cmd, err := command.New(ctx, exec.Command("git", "-C", repoPath, "upload-pack", "--stateless-rpc", "."), reader, w, nil) + require.NoError(t, err) + require.NoError(t, cmd.Wait()) + case fmt.Sprintf("/%s.git/info/refs?service=git-upload-pack", repoName): + if httpToken != "" && r.Header.Get("Authorization") != httpToken { + w.WriteHeader(http.StatusUnauthorized) + return + } + w.Header().Set("Content-Type", "application/x-git-upload-pack-advertisement") + w.WriteHeader(http.StatusOK) + + w.Write([]byte("001e# service=git-upload-pack\n")) + w.Write([]byte("0000")) + + cmd, err := command.New(ctx, exec.Command("git", "-C", repoPath, "upload-pack", "--advertise-refs", "."), nil, w, nil) + require.NoError(t, err) + require.NoError(t, cmd.Wait()) + default: + w.WriteHeader(http.StatusNotFound) + } + }), + ) + + return s, fmt.Sprintf("%s/%s.git", s.URL, repoName) +} diff --git a/internal/git/objectpool/link.go b/internal/git/objectpool/link.go index ad3cfbc5f..0bc9e75e0 100644 --- a/internal/git/objectpool/link.go +++ b/internal/git/objectpool/link.go @@ -36,16 +36,19 @@ func (o *ObjectPool) Link(ctx context.Context, repo *gitalypb.Repository) error expectedContent := filepath.Join(relPath, "objects") - actualContent, err := ioutil.ReadFile(altPath) + actualContentBytes, err := ioutil.ReadFile(altPath) if err == nil { - if text.ChompBytes(actualContent) == expectedContent { + actualContent := text.ChompBytes(actualContentBytes) + if actualContent == expectedContent { return nil } - return fmt.Errorf("unexpected alternates content: %q", actualContent) + if filepath.Clean(actualContent) != filepath.Join(o.FullPath(), "objects") { + return fmt.Errorf("unexpected alternates content: %q", actualContent) + } } - if !os.IsNotExist(err) { + if err != nil && !os.IsNotExist(err) { return err } diff --git a/internal/git/objectpool/link_test.go b/internal/git/objectpool/link_test.go index 84f6d0d0a..c3a7318af 100644 --- a/internal/git/objectpool/link_test.go +++ b/internal/git/objectpool/link_test.go @@ -19,8 +19,8 @@ func TestLink(t *testing.T) { testRepo, _, cleanupFn := testhelper.NewTestRepo(t) defer cleanupFn() - pool, err := NewObjectPool(testRepo.GetStorageName(), testhelper.NewTestObjectPoolName(t)) - require.NoError(t, err) + pool, poolCleanup := NewTestObjectPool(ctx, t, testRepo.GetStorageName()) + defer poolCleanup() require.NoError(t, pool.Remove(ctx), "make sure pool does not exist prior to creation") require.NoError(t, pool.Create(ctx, testRepo), "create pool") @@ -56,8 +56,8 @@ func TestLinkRemoveBitmap(t *testing.T) { testRepo, testRepoPath, cleanupFn := testhelper.NewTestRepo(t) defer cleanupFn() - pool, err := NewObjectPool(testRepo.GetStorageName(), testhelper.NewTestObjectPoolName(t)) - require.NoError(t, err) + pool, poolCleanup := NewTestObjectPool(ctx, t, testRepo.GetStorageName()) + defer poolCleanup() require.NoError(t, pool.Init(ctx)) @@ -104,9 +104,8 @@ func TestUnlink(t *testing.T) { testRepo, _, cleanupFn := testhelper.NewTestRepo(t) defer cleanupFn() - pool, err := NewObjectPool(testRepo.GetStorageName(), t.Name()) - require.NoError(t, err) - defer pool.Remove(ctx) + pool, poolCleanup := NewTestObjectPool(ctx, t, testRepo.GetStorageName()) + defer poolCleanup() require.Error(t, pool.Unlink(ctx, testRepo), "removing a non-existing pool should be an error") @@ -118,3 +117,38 @@ func TestUnlink(t *testing.T) { require.NoError(t, pool.Unlink(ctx, testRepo), "unlink repo") require.False(t, testhelper.RemoteExists(t, pool.FullPath(), testRepo.GetGlRepository()), "pool remotes should no longer include %v", testRepo) } + +func TestLinkAbsoluteLinkExists(t *testing.T) { + ctx, cancel := testhelper.Context() + defer cancel() + + testRepo, testRepoPath, cleanupFn := testhelper.NewTestRepo(t) + defer cleanupFn() + + pool, poolCleanup := NewTestObjectPool(ctx, t, testRepo.GetStorageName()) + defer poolCleanup() + + require.NoError(t, pool.Remove(ctx), "make sure pool does not exist prior to creation") + require.NoError(t, pool.Create(ctx, testRepo), "create pool") + + altPath, err := git.InfoAlternatesPath(testRepo) + require.NoError(t, err) + + fullPath := filepath.Join(pool.FullPath(), "objects") + + require.NoError(t, ioutil.WriteFile(altPath, []byte(fullPath), 0644)) + + require.NoError(t, pool.Link(ctx, testRepo), "we expect this call to change the absolute link to a relative link") + + require.FileExists(t, altPath, "alternates file must exist after Link") + + content, err := ioutil.ReadFile(altPath) + require.NoError(t, err) + + require.False(t, filepath.IsAbs(string(content)), "expected %q to be relative path", content) + + testRepoObjectsPath := filepath.Join(testRepoPath, "objects") + require.Equal(t, fullPath, filepath.Join(testRepoObjectsPath, string(content)), "the content of the alternates file should be the relative version of the absolute pat") + + require.True(t, testhelper.RemoteExists(t, pool.FullPath(), "origin"), "pool remotes should include %v", testRepo) +} diff --git a/internal/git/objectpool/testhelper_test.go b/internal/git/objectpool/testhelper_test.go new file mode 100644 index 000000000..f616fdeae --- /dev/null +++ b/internal/git/objectpool/testhelper_test.go @@ -0,0 +1,17 @@ +package objectpool + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" + "gitlab.com/gitlab-org/gitaly/internal/testhelper" +) + +func NewTestObjectPool(ctx context.Context, t *testing.T, storageName string) (*ObjectPool, func()) { + pool, err := NewObjectPool(storageName, testhelper.NewTestObjectPoolName(t)) + require.NoError(t, err) + return pool, func() { + require.NoError(t, pool.Remove(ctx)) + } +} -- cgit v1.2.3