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:
authorPavlo Strokov <pstrokov@gitlab.com>2023-02-17 11:54:38 +0300
committerPavlo Strokov <pstrokov@gitlab.com>2023-02-17 11:54:38 +0300
commit8d2bce18d28dcffcaac90d0b2cb8815af07beef1 (patch)
treef5610992cbd68771c9c3374566be52287a5be9be
parentcfc26d1625b38163a88a48c67fdf7e1598e38f81 (diff)
parentf022a521f0a4b2d73cd9bb8991aaa0a2ac7b305e (diff)
Merge branch 'pks-remote-support-sha256-object-format' into 'master'
remote: Support for SHA256 object format See merge request https://gitlab.com/gitlab-org/gitaly/-/merge_requests/5368 Merged-by: Pavlo Strokov <pstrokov@gitlab.com> Approved-by: Pavlo Strokov <pstrokov@gitlab.com> Reviewed-by: Patrick Steinhardt <psteinhardt@gitlab.com> Reviewed-by: Pavlo Strokov <pstrokov@gitlab.com> Co-authored-by: Patrick Steinhardt <psteinhardt@gitlab.com>
-rw-r--r--internal/gitaly/service/remote/find_remote_repository.go28
-rw-r--r--internal/gitaly/service/remote/find_remote_repository_test.go109
-rw-r--r--internal/gitaly/service/remote/find_remote_root_ref_test.go203
-rw-r--r--internal/gitaly/service/remote/testdata/lsremotedata.txtbin7418 -> 0 bytes
-rw-r--r--internal/gitaly/service/remote/testhelper_test.go17
-rw-r--r--internal/gitaly/service/remote/update_remote_mirror_test.go4
6 files changed, 195 insertions, 166 deletions
diff --git a/internal/gitaly/service/remote/find_remote_repository.go b/internal/gitaly/service/remote/find_remote_repository.go
index bd6f54e82..c4b018a64 100644
--- a/internal/gitaly/service/remote/find_remote_repository.go
+++ b/internal/gitaly/service/remote/find_remote_repository.go
@@ -36,11 +36,27 @@ func (s *server) FindRemoteRepository(ctx context.Context, req *gitalypb.FindRem
return &gitalypb.FindRemoteRepositoryResponse{Exists: false}, nil
}
- // The output of a successful command is structured like
- // Regexp would've read better, but this is faster
- // 58fbff2e0d3b620f591a748c158799ead87b51cd HEAD
- fields := bytes.Fields(output)
- match := len(fields) == 2 && len(fields[0]) == 40 && string(fields[1]) == "HEAD"
+ // The output of git-ls-remote is expected to be of the format:
+ //
+ // 58fbff2e0d3b620f591a748c158799ead87b51cd HEAD\n
+ objectID, refname, ok := bytes.Cut(output, []byte("\t"))
+ if !ok {
+ return &gitalypb.FindRemoteRepositoryResponse{Exists: false}, nil
+ }
- return &gitalypb.FindRemoteRepositoryResponse{Exists: match}, nil
+ // We've asked for HEAD, so the refname should match that.
+ if !bytes.Equal(refname, []byte("HEAD\n")) {
+ return &gitalypb.FindRemoteRepositoryResponse{Exists: false}, nil
+ }
+
+ // We have no way to ask the remote's object format via git-ls-remote(1), so all we can do
+ // is to verify that the object hash matches something we know.
+ switch len(objectID) {
+ case git.ObjectHashSHA1.EncodedLen():
+ return &gitalypb.FindRemoteRepositoryResponse{Exists: true}, nil
+ case git.ObjectHashSHA256.EncodedLen():
+ return &gitalypb.FindRemoteRepositoryResponse{Exists: true}, nil
+ default:
+ return &gitalypb.FindRemoteRepositoryResponse{Exists: false}, nil
+ }
}
diff --git a/internal/gitaly/service/remote/find_remote_repository_test.go b/internal/gitaly/service/remote/find_remote_repository_test.go
index 9279648b0..f54383702 100644
--- a/internal/gitaly/service/remote/find_remote_repository_test.go
+++ b/internal/gitaly/service/remote/find_remote_repository_test.go
@@ -1,65 +1,94 @@
-//go:build !gitaly_test_sha256
-
package remote
import (
- "bytes"
- "io"
+ "fmt"
"net/http"
"net/http/httptest"
+ "path/filepath"
"testing"
- "github.com/stretchr/testify/require"
+ "gitlab.com/gitlab-org/gitaly/v15/internal/git/gittest"
+ "gitlab.com/gitlab-org/gitaly/v15/internal/structerr"
"gitlab.com/gitlab-org/gitaly/v15/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v15/proto/go/gitalypb"
- "google.golang.org/grpc/codes"
)
func TestFindRemoteRepository(t *testing.T) {
t.Parallel()
ctx := testhelper.Context(t)
- _, repo, _, client := setupRemoteService(t, ctx)
+ cfg, client := setupRemoteService(t, ctx)
+ gitCmdFactory := gittest.NewCommandFactory(t, cfg)
- ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- infoRefs := testhelper.MustReadFile(t, "testdata/lsremotedata.txt")
- w.Header().Set("Content-Type", "application/x-git-upload-pack-advertisement")
- _, err := io.Copy(w, bytes.NewReader(infoRefs))
- require.NoError(t, err)
- }))
- defer ts.Close()
+ type setupData struct {
+ request *gitalypb.FindRemoteRepositoryRequest
+ expectedErr error
+ expectedResponse *gitalypb.FindRemoteRepositoryResponse
+ }
- resp, err := client.FindRemoteRepository(ctx, &gitalypb.FindRemoteRepositoryRequest{Remote: ts.URL, StorageName: repo.GetStorageName()})
- require.NoError(t, err)
+ for _, tc := range []struct {
+ desc string
+ setup func(t *testing.T) setupData
+ }{
+ {
+ desc: "empty remote",
+ setup: func(t *testing.T) setupData {
+ return setupData{
+ request: &gitalypb.FindRemoteRepositoryRequest{
+ Remote: "",
+ StorageName: cfg.Storages[0].Name,
+ },
+ expectedErr: structerr.NewInvalidArgument("empty remote can't be checked."),
+ }
+ },
+ },
+ {
+ desc: "nonexistent remote repository",
+ setup: func(t *testing.T) setupData {
+ server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
+ w.WriteHeader(404)
+ }))
+ t.Cleanup(server.Close)
- require.True(t, resp.Exists)
-}
+ return setupData{
+ request: &gitalypb.FindRemoteRepositoryRequest{
+ Remote: server.URL + "/does-not-exist.git",
+ StorageName: cfg.Storages[0].Name,
+ },
+ expectedResponse: &gitalypb.FindRemoteRepositoryResponse{},
+ }
+ },
+ },
+ {
+ desc: "successful",
+ setup: func(t *testing.T) setupData {
+ _, remoteRepoPath := gittest.CreateRepository(t, ctx, cfg)
+ gittest.WriteCommit(t, cfg, remoteRepoPath, gittest.WithBranch("main"))
-func TestFailedFindRemoteRepository(t *testing.T) {
- t.Parallel()
+ port := gittest.HTTPServer(t, ctx, gitCmdFactory, remoteRepoPath, nil)
- ctx := testhelper.Context(t)
- _, repo, _, client := setupRemoteService(t, ctx)
+ return setupData{
+ request: &gitalypb.FindRemoteRepositoryRequest{
+ Remote: fmt.Sprintf("http://127.0.0.1:%d/%s", port, filepath.Base(remoteRepoPath)),
+ StorageName: cfg.Storages[0].Name,
+ },
+ expectedResponse: &gitalypb.FindRemoteRepositoryResponse{
+ Exists: true,
+ },
+ }
+ },
+ },
+ } {
+ tc := tc
- testCases := []struct {
- description string
- remote string
- exists bool
- code codes.Code
- }{
- {"non existing remote", "http://example.com/test.git", false, codes.OK},
- {"empty remote", "", false, codes.InvalidArgument},
- }
+ t.Run(tc.desc, func(t *testing.T) {
+ t.Parallel()
- for _, tc := range testCases {
- resp, err := client.FindRemoteRepository(ctx, &gitalypb.FindRemoteRepositoryRequest{Remote: tc.remote, StorageName: repo.GetStorageName()})
- if tc.code == codes.OK {
- require.NoError(t, err)
- } else {
- testhelper.RequireGrpcCode(t, err, tc.code)
- continue
- }
+ setup := tc.setup(t)
- require.Equal(t, tc.exists, resp.GetExists(), tc.description)
+ response, err := client.FindRemoteRepository(ctx, setup.request)
+ testhelper.RequireGrpcError(t, setup.expectedErr, err)
+ testhelper.ProtoEqual(t, setup.expectedResponse, response)
+ })
}
}
diff --git a/internal/gitaly/service/remote/find_remote_root_ref_test.go b/internal/gitaly/service/remote/find_remote_root_ref_test.go
index 61d5f82bb..42e20dcfb 100644
--- a/internal/gitaly/service/remote/find_remote_root_ref_test.go
+++ b/internal/gitaly/service/remote/find_remote_root_ref_test.go
@@ -1,5 +1,3 @@
-//go:build !gitaly_test_sha256
-
package remote
import (
@@ -18,129 +16,132 @@ import (
"google.golang.org/grpc/status"
)
-func TestFindRemoteRootRefSuccess(t *testing.T) {
+func TestFindRemoteRootRef(t *testing.T) {
t.Parallel()
ctx := testhelper.Context(t)
- cfg, repo, repoPath, client := setupRemoteService(t, ctx)
+ cfg, client := setupRemoteService(t, ctx)
gitCmdFactory := gittest.NewCommandFactory(t, cfg)
- const (
- host = "example.com"
- secret = "mysecret"
- )
-
- port := gittest.HTTPServer(t, ctx, gitCmdFactory, repoPath, newGitRequestValidationMiddleware(host, secret))
+ // Even though FindRemoteRootRef does theoretically not require a local repository it is
+ // still bound to one right now. We thus create an empty repository up front that we can
+ // reuse.
+ localRepo, _ := gittest.CreateRepository(t, ctx, cfg)
- originURL := fmt.Sprintf("http://127.0.0.1:%d/%s", port, filepath.Base(repoPath))
+ type setupData struct {
+ request *gitalypb.FindRemoteRootRefRequest
+ expectedErr error
+ expectedResponse *gitalypb.FindRemoteRootRefResponse
+ }
for _, tc := range []struct {
- desc string
- request *gitalypb.FindRemoteRootRefRequest
+ desc string
+ setup func(t *testing.T) setupData
}{
{
- desc: "with remote URL",
- request: &gitalypb.FindRemoteRootRefRequest{
- Repository: repo,
- RemoteUrl: originURL,
- HttpAuthorizationHeader: secret,
- HttpHost: host,
+ desc: "invalid repository",
+ setup: func(t *testing.T) setupData {
+ return setupData{
+ request: &gitalypb.FindRemoteRootRefRequest{
+ Repository: &gitalypb.Repository{StorageName: "fake", RelativePath: "path"},
+ RemoteUrl: "remote-url",
+ },
+ expectedErr: structerr.NewInvalidArgument(testhelper.GitalyOrPraefect(
+ `GetStorageByName: no such storage: "fake"`,
+ "repo scoped: invalid Repository",
+ )),
+ }
},
},
- } {
- t.Run(tc.desc, func(t *testing.T) {
- response, err := client.FindRemoteRootRef(ctx, tc.request)
- require.NoError(t, err)
- require.Equal(t, "master", response.Ref)
- })
- }
-}
-
-func TestFindRemoteRootRefWithUnbornRemoteHead(t *testing.T) {
- t.Parallel()
-
- ctx := testhelper.Context(t)
- cfg, remoteRepo, remoteRepoPath, client := setupRemoteService(t, ctx)
-
- // We're creating an empty repository. Empty repositories do have a HEAD set up, but they
- // point to an unborn branch because the default branch hasn't yet been created.
- _, clientRepoPath := gittest.CreateRepository(t, ctx, cfg)
- gittest.Exec(t, cfg, "-C", remoteRepoPath, "remote", "add", "foo", "file://"+clientRepoPath)
- response, err := client.FindRemoteRootRef(ctx, &gitalypb.FindRemoteRootRefRequest{
- Repository: remoteRepo,
- RemoteUrl: "file://" + clientRepoPath,
- },
- )
- testhelper.RequireGrpcError(t, status.Error(codes.NotFound, "no remote HEAD found"), err)
- require.Nil(t, response)
-}
-
-func TestFindRemoteRootRefFailedDueToValidation(t *testing.T) {
- t.Parallel()
-
- ctx := testhelper.Context(t)
- _, repo, _, client := setupRemoteService(t, ctx)
-
- testCases := []struct {
- desc string
- request *gitalypb.FindRemoteRootRefRequest
- expectedErr error
- }{
{
- desc: "Invalid repository",
- request: &gitalypb.FindRemoteRootRefRequest{
- Repository: &gitalypb.Repository{StorageName: "fake", RelativePath: "path"},
- RemoteUrl: "remote-url",
+ desc: "missing repository",
+ setup: func(t *testing.T) setupData {
+ return setupData{
+ request: &gitalypb.FindRemoteRootRefRequest{
+ RemoteUrl: "remote-url",
+ },
+ expectedErr: structerr.NewInvalidArgument(testhelper.GitalyOrPraefect(
+ "empty Repository",
+ "repo scoped: empty Repository",
+ )),
+ }
},
- expectedErr: structerr.NewInvalidArgument(testhelper.GitalyOrPraefect(
- `GetStorageByName: no such storage: "fake"`,
- "repo scoped: invalid Repository",
- )),
},
{
- desc: "Repository is nil",
- request: &gitalypb.FindRemoteRootRefRequest{
- RemoteUrl: "remote-url",
+ desc: "missing remote URL",
+ setup: func(t *testing.T) setupData {
+ return setupData{
+ request: &gitalypb.FindRemoteRootRefRequest{
+ Repository: localRepo,
+ },
+ expectedErr: structerr.NewInvalidArgument("missing remote URL"),
+ }
},
- expectedErr: structerr.NewInvalidArgument(testhelper.GitalyOrPraefect(
- "empty Repository",
- "repo scoped: empty Repository",
- )),
},
{
- desc: "Remote URL is empty",
- request: &gitalypb.FindRemoteRootRefRequest{
- Repository: repo,
+ desc: "successful",
+ setup: func(t *testing.T) setupData {
+ host := "example.com"
+ secret := "mysecret"
+
+ _, remoteRepoPath := gittest.CreateRepository(t, ctx, cfg)
+ gittest.WriteCommit(t, cfg, remoteRepoPath, gittest.WithBranch("main"))
+
+ port := gittest.HTTPServer(t, ctx, gitCmdFactory, remoteRepoPath, newGitRequestValidationMiddleware(host, secret))
+ originURL := fmt.Sprintf("http://127.0.0.1:%d/%s", port, filepath.Base(remoteRepoPath))
+
+ return setupData{
+ request: &gitalypb.FindRemoteRootRefRequest{
+ Repository: localRepo,
+ RemoteUrl: originURL,
+ HttpAuthorizationHeader: secret,
+ HttpHost: host,
+ },
+ expectedResponse: &gitalypb.FindRemoteRootRefResponse{
+ Ref: "main",
+ },
+ }
},
- expectedErr: structerr.NewInvalidArgument("missing remote URL"),
},
- }
-
- for _, testCase := range testCases {
- t.Run(testCase.desc, func(t *testing.T) {
- _, err := client.FindRemoteRootRef(ctx, testCase.request)
- testhelper.RequireGrpcError(t, testCase.expectedErr, err)
- })
- }
-}
-
-func TestFindRemoteRootRefFailedDueToInvalidRemote(t *testing.T) {
- t.Parallel()
-
- ctx := testhelper.Context(t)
- _, repo, _, client := setupRemoteService(t, ctx)
+ {
+ desc: "unborn HEAD",
+ setup: func(t *testing.T) setupData {
+ _, remoteRepoPath := gittest.CreateRepository(t, ctx, cfg)
+
+ return setupData{
+ request: &gitalypb.FindRemoteRootRefRequest{
+ Repository: localRepo,
+ RemoteUrl: "file://" + remoteRepoPath,
+ },
+ expectedErr: status.Error(codes.NotFound, "no remote HEAD found"),
+ }
+ },
+ },
+ {
+ desc: "invalid remote URL",
+ setup: func(t *testing.T) setupData {
+ return setupData{
+ request: &gitalypb.FindRemoteRootRefRequest{
+ Repository: localRepo,
+ RemoteUrl: "file://" + testhelper.TempDir(t),
+ },
+ expectedErr: structerr.New("exit status 128"),
+ }
+ },
+ },
+ } {
+ tc := tc
- t.Run("invalid remote URL", func(t *testing.T) {
- fakeRepoDir := testhelper.TempDir(t)
+ t.Run(tc.desc, func(t *testing.T) {
+ t.Parallel()
- // We're using a nonexistent filepath remote URL so we avoid hitting the internet.
- request := &gitalypb.FindRemoteRootRefRequest{
- Repository: repo, RemoteUrl: "file://" + fakeRepoDir,
- }
+ setup := tc.setup(t)
- _, err := client.FindRemoteRootRef(ctx, request)
- testhelper.RequireGrpcCode(t, err, codes.Internal)
- })
+ response, err := client.FindRemoteRootRef(ctx, setup.request)
+ testhelper.RequireGrpcError(t, setup.expectedErr, err)
+ testhelper.ProtoEqual(t, setup.expectedResponse, response)
+ })
+ }
}
func newGitRequestValidationMiddleware(host, secret string) func(http.ResponseWriter, *http.Request, http.Handler) {
diff --git a/internal/gitaly/service/remote/testdata/lsremotedata.txt b/internal/gitaly/service/remote/testdata/lsremotedata.txt
deleted file mode 100644
index 197c975d1..000000000
--- a/internal/gitaly/service/remote/testdata/lsremotedata.txt
+++ /dev/null
Binary files differ
diff --git a/internal/gitaly/service/remote/testhelper_test.go b/internal/gitaly/service/remote/testhelper_test.go
index 3172d9984..fec38a447 100644
--- a/internal/gitaly/service/remote/testhelper_test.go
+++ b/internal/gitaly/service/remote/testhelper_test.go
@@ -1,12 +1,9 @@
-//go:build !gitaly_test_sha256
-
package remote
import (
"context"
"testing"
- "gitlab.com/gitlab-org/gitaly/v15/internal/git/gittest"
"gitlab.com/gitlab-org/gitaly/v15/internal/gitaly/config"
"gitlab.com/gitlab-org/gitaly/v15/internal/gitaly/service"
"gitlab.com/gitlab-org/gitaly/v15/internal/gitaly/service/repository"
@@ -22,7 +19,7 @@ func TestMain(m *testing.M) {
testhelper.Run(m)
}
-func setupRemoteServiceWithoutRepo(t *testing.T, ctx context.Context, opts ...testserver.GitalyServerOpt) (config.Cfg, gitalypb.RemoteServiceClient) {
+func setupRemoteService(t *testing.T, ctx context.Context, opts ...testserver.GitalyServerOpt) (config.Cfg, gitalypb.RemoteServiceClient) {
t.Helper()
cfg := testcfg.Build(t)
@@ -55,18 +52,6 @@ func setupRemoteServiceWithoutRepo(t *testing.T, ctx context.Context, opts ...te
return cfg, client
}
-func setupRemoteService(t *testing.T, ctx context.Context, opts ...testserver.GitalyServerOpt) (config.Cfg, *gitalypb.Repository, string, gitalypb.RemoteServiceClient) {
- t.Helper()
-
- cfg, client := setupRemoteServiceWithoutRepo(t, ctx, opts...)
-
- repo, repoPath := gittest.CreateRepository(t, ctx, cfg, gittest.CreateRepositoryConfig{
- Seed: gittest.SeedGitLabTest,
- })
-
- return cfg, repo, repoPath, client
-}
-
func newRemoteClient(t *testing.T, serverSocketPath string) (gitalypb.RemoteServiceClient, *grpc.ClientConn) {
t.Helper()
diff --git a/internal/gitaly/service/remote/update_remote_mirror_test.go b/internal/gitaly/service/remote/update_remote_mirror_test.go
index 39b9ca09e..a564d52b6 100644
--- a/internal/gitaly/service/remote/update_remote_mirror_test.go
+++ b/internal/gitaly/service/remote/update_remote_mirror_test.go
@@ -1,5 +1,3 @@
-//go:build !gitaly_test_sha256
-
package remote
import (
@@ -721,7 +719,7 @@ func TestUpdateRemoteMirror_Validations(t *testing.T) {
t.Parallel()
ctx := testhelper.Context(t)
- cfg, client := setupRemoteServiceWithoutRepo(t, ctx)
+ cfg, client := setupRemoteService(t, ctx)
testCases := []struct {
expectedErr error