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:
authorPatrick Steinhardt <psteinhardt@gitlab.com>2021-06-17 15:53:17 +0300
committerPatrick Steinhardt <psteinhardt@gitlab.com>2021-07-02 14:12:08 +0300
commit1dacf986e0ba6558efa2f60818515fa0e293d8a0 (patch)
tree5ab05a5f0d81834a0e43c3712205a7d112e4cffc
parent979fe249ad84c4f6b60beffc1420a355e9f87f83 (diff)
repository: Add test to exercise CreateFromBundle with transactions
We recently got a bug report about `CreateFromBundle()` seemingly misbehaving when transactions are enabled. Symptoms are that voters drop out at seemingly random steps with weird error messages like e.g. "Unable to read current working directory". While this likely indicates some kind of external race, I still took the opportunity to write a test verifying that `CreateFromBundle()` works as expect with transactions enabled and that the votes are in fact computed deterministically.
-rw-r--r--internal/gitaly/service/repository/create_from_bundle_test.go73
1 files changed, 73 insertions, 0 deletions
diff --git a/internal/gitaly/service/repository/create_from_bundle_test.go b/internal/gitaly/service/repository/create_from_bundle_test.go
index c1cb14348..55155212e 100644
--- a/internal/gitaly/service/repository/create_from_bundle_test.go
+++ b/internal/gitaly/service/repository/create_from_bundle_test.go
@@ -2,6 +2,8 @@ package repository
import (
"bytes"
+ "context"
+ "fmt"
"io"
"os"
"path/filepath"
@@ -9,11 +11,18 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
+ "gitlab.com/gitlab-org/gitaly/internal/git"
"gitlab.com/gitlab-org/gitaly/internal/git/gittest"
"gitlab.com/gitlab-org/gitaly/internal/git/localrepo"
"gitlab.com/gitlab-org/gitaly/internal/gitaly/config"
+ "gitlab.com/gitlab-org/gitaly/internal/gitaly/transaction"
+ "gitlab.com/gitlab-org/gitaly/internal/helper"
+ "gitlab.com/gitlab-org/gitaly/internal/helper/text"
"gitlab.com/gitlab-org/gitaly/internal/tempdir"
"gitlab.com/gitlab-org/gitaly/internal/testhelper"
+ "gitlab.com/gitlab-org/gitaly/internal/testhelper/testserver"
+ "gitlab.com/gitlab-org/gitaly/internal/transaction/txinfo"
+ "gitlab.com/gitlab-org/gitaly/internal/transaction/voting"
"gitlab.com/gitlab-org/gitaly/proto/go/gitalypb"
"gitlab.com/gitlab-org/gitaly/streamio"
"google.golang.org/grpc/codes"
@@ -81,6 +90,70 @@ func TestServer_CreateRepositoryFromBundle_successful(t *testing.T) {
require.NotNil(t, commit)
}
+func TestServer_CreateRepositoryFromBundle_transactional(t *testing.T) {
+ var votes []voting.Vote
+ txManager := &transaction.MockManager{
+ VoteFn: func(ctx context.Context, tx txinfo.Transaction, server txinfo.PraefectServer, vote voting.Vote) error {
+ votes = append(votes, vote)
+ return nil
+ },
+ }
+
+ cfg, repoProto, repoPath, client := setupRepositoryService(t,
+ testserver.WithTransactionManager(txManager))
+
+ ctx, cancel := testhelper.Context()
+ defer cancel()
+ ctx, err := (&txinfo.PraefectServer{SocketPath: "idontcare"}).Inject(ctx)
+ require.NoError(t, err)
+ ctx, err = txinfo.InjectTransaction(ctx, 1, "primary", true)
+ require.NoError(t, err)
+ ctx = helper.IncomingToOutgoing(ctx)
+
+ stream, err := client.CreateRepositoryFromBundle(ctx)
+ require.NoError(t, err)
+
+ require.NoError(t, stream.Send(&gitalypb.CreateRepositoryFromBundleRequest{
+ Repository: &gitalypb.Repository{
+ StorageName: repoProto.GetStorageName(),
+ RelativePath: "create.git",
+ },
+ }))
+
+ bundle := gittest.Exec(t, cfg, "-C", repoPath, "bundle", "create", "-", "master", "feature")
+ require.Greater(t, len(bundle), 100*1024)
+
+ _, err = io.Copy(streamio.NewWriter(func(p []byte) error {
+ require.NoError(t, stream.Send(&gitalypb.CreateRepositoryFromBundleRequest{
+ Data: p,
+ }))
+ return nil
+ }), bytes.NewReader(bundle))
+ require.NoError(t, err)
+
+ _, err = stream.CloseAndRecv()
+ require.NoError(t, err)
+
+ masterOID := text.ChompBytes(gittest.Exec(t, cfg, "-C", repoPath, "rev-parse", "master"))
+ featureOID := text.ChompBytes(gittest.Exec(t, cfg, "-C", repoPath, "rev-parse", "feature"))
+
+ // This accounts for the first vote which first do a git-clone(1) followed by a fetch. Given
+ // that voting is done via git's reference-transaction hook, the format is `<oldrev>
+ // <newrev> <reference>`.
+ fetchInput := fmt.Sprintf("%s %s refs/heads/feature\n%s %s refs/heads/master\n",
+ git.ZeroOID, featureOID, git.ZeroOID, masterOID)
+
+ // And this accounts for the final vote in `Create()`, which does vote on all references in
+ // the target repo as listed by git-for-each-ref(1).
+ refsInput := fmt.Sprintf("%s commit\trefs/heads/feature\n%s commit\trefs/heads/master\n",
+ featureOID, masterOID)
+
+ require.Equal(t, []voting.Vote{
+ voting.VoteFromData([]byte(fetchInput)),
+ voting.VoteFromData([]byte(refsInput)),
+ }, votes)
+}
+
func TestServer_CreateRepositoryFromBundle_failed_invalid_bundle(t *testing.T) {
cfg, client := setupRepositoryServiceWithoutRepo(t)