diff options
author | Patrick Steinhardt <psteinhardt@gitlab.com> | 2020-09-07 10:29:19 +0300 |
---|---|---|
committer | Patrick Steinhardt <psteinhardt@gitlab.com> | 2020-09-07 11:16:11 +0300 |
commit | 86c5d708df567f605fe44f48389c504b9f170b3d (patch) | |
tree | 33274ea1d9cc584cce18df4763294c2582ab0960 /internal/gitaly/service/repository/fetch_test.go | |
parent | 8a0d83b496eaff459d55bc6825428f648059e8d9 (diff) |
gitaly: Move Gitaly-specific code into `internal/gitaly`
Since the introduction of Praefect, our code layout started to become
confusing: while Praefect code lives in `internal/praefect`,
Gitaly-specific code is all over the place and not neatly singled out.
This makes it hard at times to tell apart Praefect- and Gitaly-specific
from generic code.
To improve the situation, this commit thus moves most of the server
specific code into a new `internal/gitaly` package. Currently, this is
the `internal/config`, `internal/server`, `internal/service` and
`internal/rubyserver` packages, which are all main components of Gitaly.
The move was realized with the following script:
#!/bin/sh
mkdir -p internal/gitaly
git mv internal/{config,server,service,rubyserver} internal/gitaly/
find . -name '*.go' -exec sed -i \
-e 's|gitlab-org/gitaly/internal/rubyserver|gitlab-org/gitaly/internal/gitaly/rubyserver|' \
-e 's|gitlab-org/gitaly/internal/server|gitlab-org/gitaly/internal/gitaly/server|' \
-e 's|gitlab-org/gitaly/internal/service|gitlab-org/gitaly/internal/gitaly/service|' \
-e 's|gitlab-org/gitaly/internal/config|gitlab-org/gitaly/internal/gitaly/config|' {} \;
In addition to that, some minor adjustments were needed for tests which
used relative paths.
Diffstat (limited to 'internal/gitaly/service/repository/fetch_test.go')
-rw-r--r-- | internal/gitaly/service/repository/fetch_test.go | 409 |
1 files changed, 409 insertions, 0 deletions
diff --git a/internal/gitaly/service/repository/fetch_test.go b/internal/gitaly/service/repository/fetch_test.go new file mode 100644 index 000000000..d38f61f63 --- /dev/null +++ b/internal/gitaly/service/repository/fetch_test.go @@ -0,0 +1,409 @@ +package repository_test + +import ( + "net" + "os" + "testing" + + "github.com/stretchr/testify/require" + gitLog "gitlab.com/gitlab-org/gitaly/internal/git/log" + "gitlab.com/gitlab-org/gitaly/internal/gitaly/config" + serverPkg "gitlab.com/gitlab-org/gitaly/internal/gitaly/server" + "gitlab.com/gitlab-org/gitaly/internal/gitaly/service/repository" + "gitlab.com/gitlab-org/gitaly/internal/helper" + "gitlab.com/gitlab-org/gitaly/internal/metadata/featureflag" + "gitlab.com/gitlab-org/gitaly/internal/testhelper" + "gitlab.com/gitlab-org/gitaly/proto/go/gitalypb" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + healthpb "google.golang.org/grpc/health/grpc_health_v1" +) + +func TestFetchSourceBranchSourceRepositorySuccess(t *testing.T) { + server, serverSocketPath := runFullServer(t) + defer server.Stop() + + client, conn := repository.NewRepositoryClient(t, serverSocketPath) + defer conn.Close() + + for _, tc := range []struct { + desc string + disabledFeatures []featureflag.FeatureFlag + }{ + { + desc: "go", + }, + { + desc: "ruby", + disabledFeatures: []featureflag.FeatureFlag{featureflag.GoFetchSourceBranch}, + }, + } { + t.Run(tc.desc, func(t *testing.T) { + ctx, cancel := testhelper.Context() + defer cancel() + + md := testhelper.GitalyServersMetadata(t, serverSocketPath) + ctx = testhelper.MergeOutgoingMetadata(ctx, md) + + for _, feature := range tc.disabledFeatures { + ctx = featureflag.OutgoingCtxWithFeatureFlagValue(ctx, feature, "true") + } + + targetRepo, _, cleanup := newTestRepo(t, "fetch-source-target.git") + defer cleanup() + + sourceRepo, sourcePath, cleanup := newTestRepo(t, "fetch-source-source.git") + defer cleanup() + + sourceBranch := "fetch-source-branch-test-branch" + newCommitID := testhelper.CreateCommit(t, sourcePath, sourceBranch, nil) + + targetRef := "refs/tmp/fetch-source-branch-test" + req := &gitalypb.FetchSourceBranchRequest{ + Repository: targetRepo, + SourceRepository: sourceRepo, + SourceBranch: []byte(sourceBranch), + TargetRef: []byte(targetRef), + } + + resp, err := client.FetchSourceBranch(ctx, req) + require.NoError(t, err) + require.True(t, resp.Result, "response.Result should be true") + + fetchedCommit, err := gitLog.GetCommit(ctx, targetRepo, targetRef) + require.NoError(t, err) + require.Equal(t, newCommitID, fetchedCommit.GetId()) + }) + } +} + +func TestFetchSourceBranchSameRepositorySuccess(t *testing.T) { + server, serverSocketPath := runFullServer(t) + defer server.Stop() + + client, conn := repository.NewRepositoryClient(t, serverSocketPath) + defer conn.Close() + + for _, tc := range []struct { + desc string + disabledFeatures []featureflag.FeatureFlag + }{ + { + desc: "go", + }, + { + desc: "ruby", + disabledFeatures: []featureflag.FeatureFlag{featureflag.GoFetchSourceBranch}, + }, + } { + t.Run(tc.desc, func(t *testing.T) { + ctx, cancel := testhelper.Context() + defer cancel() + + md := testhelper.GitalyServersMetadata(t, serverSocketPath) + ctx = testhelper.MergeOutgoingMetadata(ctx, md) + + for _, feature := range tc.disabledFeatures { + ctx = featureflag.OutgoingCtxWithFeatureFlagValue(ctx, feature, "false") + } + + repo, repoPath, cleanup := newTestRepo(t, "fetch-source-source.git") + defer cleanup() + + sourceBranch := "fetch-source-branch-test-branch" + newCommitID := testhelper.CreateCommit(t, repoPath, sourceBranch, nil) + + targetRef := "refs/tmp/fetch-source-branch-test" + req := &gitalypb.FetchSourceBranchRequest{ + Repository: repo, + SourceRepository: repo, + SourceBranch: []byte(sourceBranch), + TargetRef: []byte(targetRef), + } + + resp, err := client.FetchSourceBranch(ctx, req) + require.NoError(t, err) + require.True(t, resp.Result, "response.Result should be true") + + fetchedCommit, err := gitLog.GetCommit(ctx, repo, targetRef) + require.NoError(t, err) + require.Equal(t, newCommitID, fetchedCommit.GetId()) + }) + } +} + +func TestFetchSourceBranchBranchNotFound(t *testing.T) { + server, serverSocketPath := runFullServer(t) + defer server.Stop() + + client, conn := repository.NewRepositoryClient(t, serverSocketPath) + defer conn.Close() + + for _, tc := range []struct { + desc string + disabledFeatures []featureflag.FeatureFlag + }{ + { + desc: "go", + }, + { + desc: "ruby", + disabledFeatures: []featureflag.FeatureFlag{featureflag.GoFetchSourceBranch}, + }, + } { + t.Run(tc.desc, func(t *testing.T) { + ctx, cancel := testhelper.Context() + defer cancel() + + md := testhelper.GitalyServersMetadata(t, serverSocketPath) + ctx = testhelper.MergeOutgoingMetadata(ctx, md) + + for _, feature := range tc.disabledFeatures { + ctx = featureflag.OutgoingCtxWithFeatureFlagValue(ctx, feature, "false") + } + + targetRepo, _, cleanup := newTestRepo(t, "fetch-source-target.git") + defer cleanup() + + sourceRepo, _, cleanup := newTestRepo(t, "fetch-source-source.git") + defer cleanup() + + sourceBranch := "does-not-exist" + targetRef := "refs/tmp/fetch-source-branch-test" + + testCases := []struct { + req *gitalypb.FetchSourceBranchRequest + desc string + }{ + { + desc: "target different from source", + req: &gitalypb.FetchSourceBranchRequest{ + Repository: targetRepo, + SourceRepository: sourceRepo, + SourceBranch: []byte(sourceBranch), + TargetRef: []byte(targetRef), + }, + }, + { + desc: "target same as source", + req: &gitalypb.FetchSourceBranchRequest{ + Repository: sourceRepo, + SourceRepository: sourceRepo, + SourceBranch: []byte(sourceBranch), + TargetRef: []byte(targetRef), + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.desc, func(t *testing.T) { + resp, err := client.FetchSourceBranch(ctx, tc.req) + require.NoError(t, err) + require.False(t, resp.Result, "response.Result should be false") + }) + } + }) + } +} + +func TestFetchSourceBranchWrongRef(t *testing.T) { + server, serverSocketPath := runFullServer(t) + defer server.Stop() + + client, conn := repository.NewRepositoryClient(t, serverSocketPath) + defer conn.Close() + + ctx, cancel := testhelper.Context() + defer cancel() + + md := testhelper.GitalyServersMetadata(t, serverSocketPath) + ctx = testhelper.MergeOutgoingMetadata(ctx, md) + + targetRepo, _, cleanup := newTestRepo(t, "fetch-source-target.git") + defer cleanup() + + sourceRepo, sourceRepoPath, cleanup := newTestRepo(t, "fetch-source-source.git") + defer cleanup() + + sourceBranch := "fetch-source-branch-testmas-branch" + testhelper.CreateCommit(t, sourceRepoPath, sourceBranch, nil) + + targetRef := "refs/tmp/fetch-source-branch-test" + + testCases := []struct { + req *gitalypb.FetchSourceBranchRequest + desc string + }{ + { + desc: "source branch empty", + req: &gitalypb.FetchSourceBranchRequest{ + Repository: targetRepo, + SourceRepository: sourceRepo, + SourceBranch: []byte(""), + TargetRef: []byte(targetRef), + }, + }, + { + desc: "source branch blank", + req: &gitalypb.FetchSourceBranchRequest{ + Repository: targetRepo, + SourceRepository: sourceRepo, + SourceBranch: []byte(" "), + TargetRef: []byte(targetRef), + }, + }, + { + desc: "source branch starts with -", + req: &gitalypb.FetchSourceBranchRequest{ + Repository: targetRepo, + SourceRepository: sourceRepo, + SourceBranch: []byte("-ref"), + TargetRef: []byte(targetRef), + }, + }, + { + desc: "source branch with :", + req: &gitalypb.FetchSourceBranchRequest{ + Repository: targetRepo, + SourceRepository: sourceRepo, + SourceBranch: []byte("some:ref"), + TargetRef: []byte(targetRef), + }, + }, + { + desc: "source branch with NULL", + req: &gitalypb.FetchSourceBranchRequest{ + Repository: targetRepo, + SourceRepository: sourceRepo, + SourceBranch: []byte("some\x00ref"), + TargetRef: []byte(targetRef), + }, + }, + { + desc: "target branch empty", + req: &gitalypb.FetchSourceBranchRequest{ + Repository: targetRepo, + SourceRepository: sourceRepo, + SourceBranch: []byte(sourceBranch), + TargetRef: []byte(""), + }, + }, + { + desc: "target branch blank", + req: &gitalypb.FetchSourceBranchRequest{ + Repository: targetRepo, + SourceRepository: sourceRepo, + SourceBranch: []byte(sourceBranch), + TargetRef: []byte(" "), + }, + }, + { + desc: "target branch starts with -", + req: &gitalypb.FetchSourceBranchRequest{ + Repository: targetRepo, + SourceRepository: sourceRepo, + SourceBranch: []byte(sourceBranch), + TargetRef: []byte("-ref"), + }, + }, + { + desc: "target branch with :", + req: &gitalypb.FetchSourceBranchRequest{ + Repository: targetRepo, + SourceRepository: sourceRepo, + SourceBranch: []byte(sourceBranch), + TargetRef: []byte("some:ref"), + }, + }, + { + desc: "target branch with NULL", + req: &gitalypb.FetchSourceBranchRequest{ + Repository: targetRepo, + SourceRepository: sourceRepo, + SourceBranch: []byte(sourceBranch), + TargetRef: []byte("some\x00ref"), + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.desc, func(t *testing.T) { + _, err := client.FetchSourceBranch(ctx, tc.req) + testhelper.RequireGrpcError(t, err, codes.InvalidArgument) + }) + } +} + +func TestFetchFullServerRequiresAuthentication(t *testing.T) { + // The purpose of this test is to ensure that the server started by + // 'runFullServer' requires authentication. The RPC under test in this + // file (FetchSourceBranch) makes calls to a "remote" Gitaly server and + // we want to be sure that authentication is handled correctly. If the + // tests in this file were using a server without authentication we could + // not be confident that authentication is done right. + server, serverSocketPath := runFullServer(t) + defer server.Stop() + + connOpts := []grpc.DialOption{ + grpc.WithInsecure(), + } + + conn, err := grpc.Dial(serverSocketPath, connOpts...) + require.NoError(t, err) + defer conn.Close() + + ctx, cancel := testhelper.Context() + defer cancel() + + client := healthpb.NewHealthClient(conn) + _, err = client.Check(ctx, &healthpb.HealthCheckRequest{}) + testhelper.RequireGrpcError(t, err, codes.Unauthenticated) +} + +func newTestRepo(t *testing.T, relativePath string) (*gitalypb.Repository, string, func()) { + _, testRepoPath, cleanupFn := testhelper.NewTestRepo(t) + defer cleanupFn() + + repo := &gitalypb.Repository{StorageName: "default", RelativePath: relativePath} + + repoPath, err := helper.GetPath(repo) + require.NoError(t, err) + + require.NoError(t, os.RemoveAll(repoPath)) + testhelper.MustRunCommand(t, nil, "git", "clone", "--bare", testRepoPath, repoPath) + + return repo, repoPath, func() { require.NoError(t, os.RemoveAll(repoPath)) } +} + +func runFullServer(t *testing.T) (*grpc.Server, string) { + server := serverPkg.NewInsecure(repository.RubyServer, nil, config.Config) + serverSocketPath := testhelper.GetTemporaryGitalySocketFileName() + + listener, err := net.Listen("unix", serverSocketPath) + require.NoError(t, err) + + //listen on internal socket + internalListener, err := net.Listen("unix", config.GitalyInternalSocketPath()) + require.NoError(t, err) + + go server.Serve(internalListener) + go server.Serve(listener) + + return server, "unix://" + serverSocketPath +} + +func runFullSecureServer(t *testing.T) (*grpc.Server, string, testhelper.Cleanup) { + server := serverPkg.NewSecure(repository.RubyServer, nil, config.Config) + listener, addr := testhelper.GetLocalhostListener(t) + + errQ := make(chan error) + + go func() { errQ <- server.Serve(listener) }() + + cleanup := func() { + server.Stop() + require.NoError(t, <-errQ) + } + + return server, "tls://" + addr, cleanup +} |