diff options
author | Paul Okstad <pokstad@gitlab.com> | 2020-10-14 08:58:44 +0300 |
---|---|---|
committer | Paul Okstad <pokstad@gitlab.com> | 2020-10-14 08:58:44 +0300 |
commit | c0ba6b3b67598563a14ea7be5f538787354d39be (patch) | |
tree | 6758a9480e104dc4079886891ff20cac146ae0fa | |
parent | add508ab63a157dc9a89bcbc7a56eb42465aa732 (diff) | |
parent | 31953a811f40d0ef9a9b1722ecd4611336e4c66f (diff) |
Merge branch 'smh-user-commit-files-tests' into 'master'
Extend UserCommitFiles test suite
See merge request gitlab-org/gitaly!2636
-rw-r--r-- | internal/gitaly/service/operations/commit_files_test.go | 936 |
1 files changed, 878 insertions, 58 deletions
diff --git a/internal/gitaly/service/operations/commit_files_test.go b/internal/gitaly/service/operations/commit_files_test.go index 391ba9c24..5ef05f171 100644 --- a/internal/gitaly/service/operations/commit_files_test.go +++ b/internal/gitaly/service/operations/commit_files_test.go @@ -1,7 +1,9 @@ package operations import ( + "bytes" "context" + "encoding/base64" "fmt" "strconv" "testing" @@ -13,13 +15,784 @@ import ( "gitlab.com/gitlab-org/gitaly/proto/go/gitalypb" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" ) var ( commitFilesMessage = []byte("Change files") ) -func testSuccessfulUserCommitFilesRequest(t *testing.T, ctxWithFeatureFlags context.Context) { +func testImplementations(t *testing.T, test func(t *testing.T, ctx context.Context)) { + ctx, cancel := testhelper.Context() + defer cancel() + + for _, tc := range []struct { + desc string + context context.Context + }{ + {desc: "ruby", context: ctx}, + } { + t.Run(tc.desc, func(t *testing.T) { test(t, tc.context) }) + } +} + +func TestUserCommitFiles(t *testing.T) { + testImplementations(t, testUserCommitFiles) +} + +func testUserCommitFiles(t *testing.T, ctx context.Context) { + type treeEntry struct { + Mode string + Path string + Content string + } + + requireTreeEntries := func(t testing.TB, repoPath, branch string, expectedEntries []treeEntry) { + t.Helper() + + var actualEntries []treeEntry + + output := bytes.TrimSpace(testhelper.MustRunCommand(t, nil, "git", "-C", repoPath, "ls-tree", "-r", branch)) + + if len(output) > 0 { + for _, line := range bytes.Split(output, []byte("\n")) { + // Format: <mode> SP <type> SP <object> TAB <file> + tabSplit := bytes.Split(line, []byte("\t")) + spaceSplit := bytes.Split(tabSplit[0], []byte(" ")) + path := string(tabSplit[1]) + actualEntries = append(actualEntries, treeEntry{ + Mode: string(spaceSplit[0]), + Path: path, + Content: string(testhelper.MustRunCommand(t, nil, "git", "-C", repoPath, "show", branch+":"+path)), + }) + } + } + + require.Equal(t, expectedEntries, actualEntries) + } + + const ( + DefaultMode = "100644" + ExecutableMode = "100755" + ) + + type step struct { + actions []*gitalypb.UserCommitFilesRequest + error error + indexError string + repoCreated bool + branchCreated bool + treeEntries []treeEntry + } + + for _, tc := range []struct { + desc string + steps []step + }{ + { + desc: "create directory", + steps: []step{ + { + actions: []*gitalypb.UserCommitFilesRequest{ + createDirHeaderRequest("directory-1"), + }, + repoCreated: true, + branchCreated: true, + treeEntries: []treeEntry{ + {Mode: DefaultMode, Path: "directory-1/.gitkeep"}, + }, + }, + }, + }, + { + desc: "create directory ignores mode and content", + steps: []step{ + { + actions: []*gitalypb.UserCommitFilesRequest{ + actionRequest(&gitalypb.UserCommitFilesAction{ + UserCommitFilesActionPayload: &gitalypb.UserCommitFilesAction_Header{ + Header: &gitalypb.UserCommitFilesActionHeader{ + Action: gitalypb.UserCommitFilesActionHeader_CREATE_DIR, + FilePath: []byte("directory-1"), + ExecuteFilemode: true, + Base64Content: true, + }, + }, + }), + actionContentRequest("content-1"), + }, + repoCreated: true, + branchCreated: true, + treeEntries: []treeEntry{ + {Mode: DefaultMode, Path: "directory-1/.gitkeep"}, + }, + }, + }, + }, + { + desc: "create directory created duplicate", + steps: []step{ + { + actions: []*gitalypb.UserCommitFilesRequest{ + createDirHeaderRequest("directory-1"), + createDirHeaderRequest("directory-1"), + }, + indexError: "A directory with this name already exists", + }, + }, + }, + { + desc: "create directory with traversal", + steps: []step{ + { + actions: []*gitalypb.UserCommitFilesRequest{ + createDirHeaderRequest("../directory-1"), + }, + indexError: "Path cannot include directory traversal", + }, + }, + }, + { + desc: "create directory existing duplicate", + steps: []step{ + { + actions: []*gitalypb.UserCommitFilesRequest{ + createDirHeaderRequest("directory-1"), + }, + repoCreated: true, + branchCreated: true, + treeEntries: []treeEntry{ + {Mode: DefaultMode, Path: "directory-1/.gitkeep"}, + }, + }, + { + actions: []*gitalypb.UserCommitFilesRequest{ + createDirHeaderRequest("directory-1"), + }, + indexError: "A directory with this name already exists", + }, + }, + }, + { + desc: "create directory with files name", + steps: []step{ + { + actions: []*gitalypb.UserCommitFilesRequest{ + createFileHeaderRequest("file-1"), + actionContentRequest("content-1"), + }, + repoCreated: true, + branchCreated: true, + treeEntries: []treeEntry{ + {Mode: DefaultMode, Path: "file-1", Content: "content-1"}, + }, + }, + { + actions: []*gitalypb.UserCommitFilesRequest{ + createDirHeaderRequest("file-1"), + }, + indexError: "A file with this name already exists", + }, + }, + }, + { + desc: "create file with directory traversal", + steps: []step{ + { + actions: []*gitalypb.UserCommitFilesRequest{ + createFileHeaderRequest("../file-1"), + actionContentRequest("content-1"), + }, + indexError: "Path cannot include directory traversal", + }, + }, + }, + { + desc: "create file without content", + steps: []step{ + { + actions: []*gitalypb.UserCommitFilesRequest{ + createFileHeaderRequest("file-1"), + }, + repoCreated: true, + branchCreated: true, + treeEntries: []treeEntry{ + {Mode: DefaultMode, Path: "file-1"}, + }, + }, + }, + }, + { + desc: "create file", + steps: []step{ + { + actions: []*gitalypb.UserCommitFilesRequest{ + createFileHeaderRequest("file-1"), + actionContentRequest("content-1"), + actionContentRequest(" content-2"), + }, + repoCreated: true, + branchCreated: true, + treeEntries: []treeEntry{ + {Mode: DefaultMode, Path: "file-1", Content: "content-1 content-2"}, + }, + }, + }, + }, + { + desc: "create file with base64 content", + steps: []step{ + { + actions: []*gitalypb.UserCommitFilesRequest{ + createBase64FileHeaderRequest("file-1"), + actionContentRequest(base64.StdEncoding.EncodeToString([]byte("content-1"))), + actionContentRequest(base64.StdEncoding.EncodeToString([]byte(" content-2"))), + }, + repoCreated: true, + branchCreated: true, + treeEntries: []treeEntry{ + {Mode: DefaultMode, Path: "file-1", Content: "content-1 content-2"}, + }, + }, + }, + }, + { + desc: "create duplicate file", + steps: []step{ + { + actions: []*gitalypb.UserCommitFilesRequest{ + createFileHeaderRequest("file-1"), + actionContentRequest("content-1"), + createFileHeaderRequest("file-1"), + }, + indexError: "A file with this name already exists", + }, + }, + }, + { + desc: "create file overwrites directory", + steps: []step{ + { + actions: []*gitalypb.UserCommitFilesRequest{ + createDirHeaderRequest("file-1"), + createFileHeaderRequest("file-1"), + actionContentRequest("content-1"), + }, + repoCreated: true, + branchCreated: true, + treeEntries: []treeEntry{ + {Mode: DefaultMode, Path: "file-1", Content: "content-1"}, + }, + }, + }, + }, + { + desc: "update created file", + steps: []step{ + { + actions: []*gitalypb.UserCommitFilesRequest{ + createFileHeaderRequest("file-1"), + actionContentRequest("content-1"), + updateFileHeaderRequest("file-1"), + actionContentRequest("content-2"), + }, + repoCreated: true, + branchCreated: true, + treeEntries: []treeEntry{ + {Mode: DefaultMode, Path: "file-1", Content: "content-2"}, + }, + }, + }, + }, + { + desc: "update base64 content", + steps: []step{ + { + actions: []*gitalypb.UserCommitFilesRequest{ + createFileHeaderRequest("file-1"), + actionContentRequest("content-1"), + updateBase64FileHeaderRequest("file-1"), + actionContentRequest(base64.StdEncoding.EncodeToString([]byte("content-2"))), + }, + repoCreated: true, + branchCreated: true, + treeEntries: []treeEntry{ + {Mode: DefaultMode, Path: "file-1", Content: "content-2"}, + }, + }, + }, + }, + { + desc: "update ignores mode", + steps: []step{ + { + actions: []*gitalypb.UserCommitFilesRequest{ + createFileHeaderRequest("file-1"), + actionContentRequest("content-1"), + actionRequest(&gitalypb.UserCommitFilesAction{ + UserCommitFilesActionPayload: &gitalypb.UserCommitFilesAction_Header{ + Header: &gitalypb.UserCommitFilesActionHeader{ + Action: gitalypb.UserCommitFilesActionHeader_UPDATE, + FilePath: []byte("file-1"), + ExecuteFilemode: true, + }, + }, + }), + actionContentRequest("content-2"), + }, + repoCreated: true, + branchCreated: true, + treeEntries: []treeEntry{ + {Mode: DefaultMode, Path: "file-1", Content: "content-2"}, + }, + }, + }, + }, + { + desc: "update existing file", + steps: []step{ + { + actions: []*gitalypb.UserCommitFilesRequest{ + createFileHeaderRequest("file-1"), + actionContentRequest("content-1"), + }, + repoCreated: true, + branchCreated: true, + treeEntries: []treeEntry{ + {Mode: DefaultMode, Path: "file-1", Content: "content-1"}, + }, + }, + { + actions: []*gitalypb.UserCommitFilesRequest{ + updateFileHeaderRequest("file-1"), + actionContentRequest("content-2"), + }, + treeEntries: []treeEntry{ + {Mode: DefaultMode, Path: "file-1", Content: "content-2"}, + }, + }, + }, + }, + { + desc: "update non-existing file", + steps: []step{ + { + actions: []*gitalypb.UserCommitFilesRequest{ + updateFileHeaderRequest("non-existing"), + actionContentRequest("content"), + }, + indexError: "A file with this name doesn't exist", + }, + }, + }, + { + desc: "move file with traversal in source", + steps: []step{ + { + actions: []*gitalypb.UserCommitFilesRequest{ + moveFileHeaderRequest("../original-file", "moved-file", true), + }, + indexError: "Path cannot include directory traversal", + }, + }, + }, + { + desc: "move file with traversal in destination", + steps: []step{ + { + actions: []*gitalypb.UserCommitFilesRequest{ + moveFileHeaderRequest("original-file", "../moved-file", true), + }, + indexError: "Path cannot include directory traversal", + }, + }, + }, + { + desc: "move created file", + steps: []step{ + { + actions: []*gitalypb.UserCommitFilesRequest{ + createFileHeaderRequest("original-file"), + actionContentRequest("content-1"), + moveFileHeaderRequest("original-file", "moved-file", true), + }, + repoCreated: true, + branchCreated: true, + treeEntries: []treeEntry{ + {Mode: DefaultMode, Path: "moved-file", Content: "content-1"}, + }, + }, + }, + }, + { + desc: "move ignores mode", + steps: []step{ + { + actions: []*gitalypb.UserCommitFilesRequest{ + createFileHeaderRequest("original-file"), + actionContentRequest("content-1"), + actionRequest(&gitalypb.UserCommitFilesAction{ + UserCommitFilesActionPayload: &gitalypb.UserCommitFilesAction_Header{ + Header: &gitalypb.UserCommitFilesActionHeader{ + Action: gitalypb.UserCommitFilesActionHeader_MOVE, + FilePath: []byte("moved-file"), + PreviousPath: []byte("original-file"), + ExecuteFilemode: true, + InferContent: true, + }, + }, + }), + }, + repoCreated: true, + branchCreated: true, + treeEntries: []treeEntry{ + {Mode: DefaultMode, Path: "moved-file", Content: "content-1"}, + }, + }, + }, + }, + { + desc: "moving directory fails", + steps: []step{ + { + actions: []*gitalypb.UserCommitFilesRequest{ + createDirHeaderRequest("directory"), + moveFileHeaderRequest("directory", "moved-directory", true), + }, + indexError: "A file with this name doesn't exist", + }, + }, + }, + { + desc: "move file inferring content", + steps: []step{ + { + actions: []*gitalypb.UserCommitFilesRequest{ + createFileHeaderRequest("original-file"), + actionContentRequest("original-content"), + }, + repoCreated: true, + branchCreated: true, + treeEntries: []treeEntry{ + {Mode: DefaultMode, Path: "original-file", Content: "original-content"}, + }, + }, + { + actions: []*gitalypb.UserCommitFilesRequest{ + moveFileHeaderRequest("original-file", "moved-file", true), + actionContentRequest("ignored-content"), + }, + treeEntries: []treeEntry{ + {Mode: DefaultMode, Path: "moved-file", Content: "original-content"}, + }, + }, + }, + }, + { + desc: "move file with non-existing source", + steps: []step{ + { + actions: []*gitalypb.UserCommitFilesRequest{ + moveFileHeaderRequest("non-existing", "destination-file", true), + }, + indexError: "A file with this name doesn't exist", + }, + }, + }, + { + desc: "move file with already existing destination file", + steps: []step{ + { + actions: []*gitalypb.UserCommitFilesRequest{ + createFileHeaderRequest("source-file"), + createFileHeaderRequest("already-existing"), + moveFileHeaderRequest("source-file", "already-existing", true), + }, + indexError: "A file with this name already exists", + }, + }, + }, + { + // seems like a bug in the original implementation to allow overwriting a + // directory + desc: "move file with already existing destination directory", + steps: []step{ + { + actions: []*gitalypb.UserCommitFilesRequest{ + createFileHeaderRequest("source-file"), + actionContentRequest("source-content"), + createDirHeaderRequest("already-existing"), + moveFileHeaderRequest("source-file", "already-existing", true), + }, + repoCreated: true, + branchCreated: true, + treeEntries: []treeEntry{ + {Mode: DefaultMode, Path: "already-existing", Content: "source-content"}, + }, + }, + }, + }, + { + desc: "move file providing content", + steps: []step{ + { + actions: []*gitalypb.UserCommitFilesRequest{ + createFileHeaderRequest("original-file"), + actionContentRequest("original-content"), + }, + repoCreated: true, + branchCreated: true, + treeEntries: []treeEntry{ + {Mode: DefaultMode, Path: "original-file", Content: "original-content"}, + }, + }, + { + actions: []*gitalypb.UserCommitFilesRequest{ + moveFileHeaderRequest("original-file", "moved-file", false), + actionContentRequest("new-content"), + }, + treeEntries: []treeEntry{ + {Mode: DefaultMode, Path: "moved-file", Content: "new-content"}, + }, + }, + }, + }, + { + desc: "mark non-existing file executable", + steps: []step{ + { + actions: []*gitalypb.UserCommitFilesRequest{ + chmodFileHeaderRequest("file-1", true), + }, + indexError: "A file with this name doesn't exist", + }, + }, + }, + { + desc: "mark executable file executable", + steps: []step{ + { + actions: []*gitalypb.UserCommitFilesRequest{ + createFileHeaderRequest("file-1"), + chmodFileHeaderRequest("file-1", true), + }, + repoCreated: true, + branchCreated: true, + treeEntries: []treeEntry{ + {Mode: ExecutableMode, Path: "file-1"}, + }, + }, + { + actions: []*gitalypb.UserCommitFilesRequest{ + chmodFileHeaderRequest("file-1", true), + }, + treeEntries: []treeEntry{ + {Mode: ExecutableMode, Path: "file-1"}, + }, + }, + }, + }, + { + desc: "mark file executable with directory traversal", + steps: []step{ + { + actions: []*gitalypb.UserCommitFilesRequest{ + chmodFileHeaderRequest("../file-1", true), + }, + indexError: "Path cannot include directory traversal", + }, + }, + }, + { + desc: "mark created file executable", + steps: []step{ + { + actions: []*gitalypb.UserCommitFilesRequest{ + createFileHeaderRequest("file-1"), + actionContentRequest("content-1"), + chmodFileHeaderRequest("file-1", true), + }, + repoCreated: true, + branchCreated: true, + treeEntries: []treeEntry{ + {Mode: ExecutableMode, Path: "file-1", Content: "content-1"}, + }, + }, + }, + }, + { + desc: "mark existing file executable", + steps: []step{ + { + actions: []*gitalypb.UserCommitFilesRequest{ + createFileHeaderRequest("file-1"), + actionContentRequest("content-1"), + }, + repoCreated: true, + branchCreated: true, + treeEntries: []treeEntry{ + {Mode: DefaultMode, Path: "file-1", Content: "content-1"}, + }, + }, + { + actions: []*gitalypb.UserCommitFilesRequest{ + chmodFileHeaderRequest("file-1", true), + }, + treeEntries: []treeEntry{ + {Mode: ExecutableMode, Path: "file-1", Content: "content-1"}, + }, + }, + }, + }, + { + desc: "move non-existing file", + steps: []step{ + { + actions: []*gitalypb.UserCommitFilesRequest{ + moveFileHeaderRequest("non-existing", "should-not-be-created", true), + }, + indexError: "A file with this name doesn't exist", + }, + }, + }, + { + desc: "move doesn't overwrite a file", + steps: []step{ + { + actions: []*gitalypb.UserCommitFilesRequest{ + createFileHeaderRequest("file-1"), + actionContentRequest("content-1"), + createFileHeaderRequest("file-2"), + actionContentRequest("content-2"), + moveFileHeaderRequest("file-1", "file-2", true), + }, + indexError: "A file with this name already exists", + }, + }, + }, + { + desc: "delete non-existing file", + steps: []step{ + { + actions: []*gitalypb.UserCommitFilesRequest{ + deleteFileHeaderRequest("non-existing"), + }, + indexError: "A file with this name doesn't exist", + }, + }, + }, + { + desc: "delete file with directory traversal", + steps: []step{ + { + actions: []*gitalypb.UserCommitFilesRequest{ + deleteFileHeaderRequest("../file-1"), + }, + indexError: "Path cannot include directory traversal", + }, + }, + }, + { + desc: "delete created file", + steps: []step{ + { + actions: []*gitalypb.UserCommitFilesRequest{ + createFileHeaderRequest("file-1"), + actionContentRequest("content-1"), + deleteFileHeaderRequest("file-1"), + }, + branchCreated: true, + repoCreated: true, + }, + }, + }, + { + desc: "delete existing file", + steps: []step{ + { + actions: []*gitalypb.UserCommitFilesRequest{ + createFileHeaderRequest("file-1"), + actionContentRequest("content-1"), + }, + branchCreated: true, + repoCreated: true, + treeEntries: []treeEntry{ + {Mode: DefaultMode, Path: "file-1", Content: "content-1"}, + }, + }, + { + actions: []*gitalypb.UserCommitFilesRequest{ + deleteFileHeaderRequest("file-1"), + }, + }, + }, + }, + { + desc: "invalid action", + steps: []step{ + { + actions: []*gitalypb.UserCommitFilesRequest{ + actionRequest(&gitalypb.UserCommitFilesAction{ + UserCommitFilesActionPayload: &gitalypb.UserCommitFilesAction_Header{ + Header: &gitalypb.UserCommitFilesActionHeader{ + Action: -1, + }, + }, + }), + }, + error: status.Error(codes.Unknown, "NoMethodError: undefined method `downcase' for -1:Integer"), + }, + }, + }, + } { + t.Run(tc.desc, func(t *testing.T) { + repo, repoPath, clean := testhelper.InitBareRepo(t) + defer clean() + + serverSocketPath, stop := runOperationServiceServer(t) + defer stop() + + client, conn := newOperationClient(t, serverSocketPath) + defer conn.Close() + + const branch = "master" + + for i, step := range tc.steps { + stream, err := client.UserCommitFiles(ctx) + require.NoError(t, err) + + headerRequest := headerRequest(repo, testhelper.TestUser, branch, []byte("commit message")) + setAuthorAndEmail(headerRequest, []byte("Author Name"), []byte("author.email@example.com")) + require.NoError(t, stream.Send(headerRequest)) + + for j, action := range step.actions { + require.NoError(t, stream.Send(action), "step %d, action %d", i+1, j+1) + } + + resp, err := stream.CloseAndRecv() + require.Equal(t, step.error, err) + if step.error != nil { + continue + } + + require.Equal(t, step.indexError, resp.IndexError, "step %d", i+1) + if step.indexError != "" { + continue + } + + require.Equal(t, step.branchCreated, resp.BranchUpdate.BranchCreated, "step %d", i+1) + require.Equal(t, step.repoCreated, resp.BranchUpdate.RepoCreated, "step %d", i+1) + requireTreeEntries(t, repoPath, branch, step.treeEntries) + } + }) + } +} + +func TestSuccessfulUserCommitFilesRequest(t *testing.T) { + testImplementations(t, testSuccessfulUserCommitFilesRequest) +} + +func testSuccessfulUserCommitFilesRequest(t *testing.T, ctx context.Context) { testRepo, testRepoPath, cleanup := testhelper.NewTestRepo(t) defer cleanup() @@ -32,7 +805,6 @@ func testSuccessfulUserCommitFilesRequest(t *testing.T, ctxWithFeatureFlags cont newRepo, newRepoPath, newRepoCleanupFn := testhelper.InitBareRepo(t) defer newRepoCleanupFn() - md := testhelper.GitalyServersMetadata(t, serverSocketPath) filePath := "héllo/wörld" authorName := []byte("Jane Doe") authorEmail := []byte("janedoe@gitlab.com") @@ -82,7 +854,6 @@ func testSuccessfulUserCommitFilesRequest(t *testing.T, ctxWithFeatureFlags cont for _, tc := range testCases { t.Run(tc.desc, func(t *testing.T) { - ctx := metadata.NewOutgoingContext(ctxWithFeatureFlags, md) headerRequest := headerRequest(tc.repo, testhelper.TestUser, tc.branchName, commitFilesMessage) setAuthorAndEmail(headerRequest, authorName, authorEmail) @@ -104,7 +875,7 @@ func testSuccessfulUserCommitFilesRequest(t *testing.T, ctxWithFeatureFlags cont require.Equal(t, tc.repoCreated, resp.GetBranchUpdate().GetRepoCreated()) require.Equal(t, tc.branchCreated, resp.GetBranchUpdate().GetBranchCreated()) - headCommit, err := log.GetCommit(ctxWithFeatureFlags, tc.repo, tc.branchName) + headCommit, err := log.GetCommit(ctx, tc.repo, tc.branchName) require.NoError(t, err) require.Equal(t, authorName, headCommit.Author.Name) require.Equal(t, testhelper.TestUser.Name, headCommit.Committer.Name) @@ -125,23 +896,17 @@ func testSuccessfulUserCommitFilesRequest(t *testing.T, ctxWithFeatureFlags cont } } -func TestSuccessfulUserCommitFilesRequest(t *testing.T) { - ctx, cancel := testhelper.Context() - defer cancel() - - testSuccessfulUserCommitFilesRequest(t, ctx) +func TestSuccessfulUserCommitFilesRequestMove(t *testing.T) { + testImplementations(t, testSuccessfulUserCommitFilesRequestMove) } -func TestSuccessfulUserCommitFilesRequestMove(t *testing.T) { +func testSuccessfulUserCommitFilesRequestMove(t *testing.T, ctx context.Context) { serverSocketPath, stop := runOperationServiceServer(t) defer stop() client, conn := newOperationClient(t, serverSocketPath) defer conn.Close() - ctxOuter, cancel := testhelper.Context() - defer cancel() - branchName := "master" previousFilePath := "README" filePath := "NEWREADME" @@ -162,8 +927,6 @@ func TestSuccessfulUserCommitFilesRequestMove(t *testing.T) { defer cleanupFn() origFileContent := testhelper.MustRunCommand(t, nil, "git", "-C", testRepoPath, "show", branchName+":"+previousFilePath) - md := testhelper.GitalyServersMetadata(t, serverSocketPath) - ctx := metadata.NewOutgoingContext(ctxOuter, md) headerRequest := headerRequest(testRepo, testhelper.TestUser, branchName, commitFilesMessage) setAuthorAndEmail(headerRequest, authorName, authorEmail) actionsRequest1 := moveFileHeaderRequest(previousFilePath, filePath, tc.infer) @@ -196,6 +959,10 @@ func TestSuccessfulUserCommitFilesRequestMove(t *testing.T) { } func TestSuccessfulUserCommitFilesRequestForceCommit(t *testing.T) { + testImplementations(t, testSuccessfulUserCommitFilesRequestForceCommit) +} + +func testSuccessfulUserCommitFilesRequestForceCommit(t *testing.T, ctx context.Context) { serverSocketPath, stop := runOperationServiceServer(t) defer stop() @@ -205,20 +972,15 @@ func TestSuccessfulUserCommitFilesRequestForceCommit(t *testing.T) { testRepo, testRepoPath, cleanupFn := testhelper.NewTestRepo(t) defer cleanupFn() - ctxOuter, cancel := testhelper.Context() - defer cancel() - - md := testhelper.GitalyServersMetadata(t, serverSocketPath) - ctx := metadata.NewOutgoingContext(ctxOuter, md) authorName := []byte("Jane Doe") authorEmail := []byte("janedoe@gitlab.com") targetBranchName := "feature" startBranchName := []byte("master") - startBranchCommit, err := log.GetCommit(ctxOuter, testRepo, string(startBranchName)) + startBranchCommit, err := log.GetCommit(ctx, testRepo, string(startBranchName)) require.NoError(t, err) - targetBranchCommit, err := log.GetCommit(ctxOuter, testRepo, targetBranchName) + targetBranchCommit, err := log.GetCommit(ctx, testRepo, targetBranchName) require.NoError(t, err) mergeBaseOut := testhelper.MustRunCommand(t, nil, "git", "-C", testRepoPath, "merge-base", targetBranchCommit.Id, startBranchCommit.Id) @@ -240,7 +1002,7 @@ func TestSuccessfulUserCommitFilesRequestForceCommit(t *testing.T) { require.NoError(t, err) update := resp.GetBranchUpdate() - newTargetBranchCommit, err := log.GetCommit(ctxOuter, testRepo, targetBranchName) + newTargetBranchCommit, err := log.GetCommit(ctx, testRepo, targetBranchName) require.NoError(t, err) require.Equal(t, newTargetBranchCommit.Id, update.CommitId) @@ -248,6 +1010,10 @@ func TestSuccessfulUserCommitFilesRequestForceCommit(t *testing.T) { } func TestSuccessfulUserCommitFilesRequestStartSha(t *testing.T) { + testImplementations(t, testSuccessfulUserCommitFilesRequestStartSha) +} + +func testSuccessfulUserCommitFilesRequestStartSha(t *testing.T, ctx context.Context) { serverSocketPath, stop := runOperationServiceServer(t) defer stop() @@ -257,14 +1023,9 @@ func TestSuccessfulUserCommitFilesRequestStartSha(t *testing.T) { testRepo, _, cleanupFn := testhelper.NewTestRepo(t) defer cleanupFn() - ctxOuter, cancel := testhelper.Context() - defer cancel() - - md := testhelper.GitalyServersMetadata(t, serverSocketPath) - ctx := metadata.NewOutgoingContext(ctxOuter, md) targetBranchName := "new" - startCommit, err := log.GetCommit(ctxOuter, testRepo, "master") + startCommit, err := log.GetCommit(ctx, testRepo, "master") require.NoError(t, err) headerRequest := headerRequest(testRepo, testhelper.TestUser, targetBranchName, commitFilesMessage) @@ -280,7 +1041,7 @@ func TestSuccessfulUserCommitFilesRequestStartSha(t *testing.T) { require.NoError(t, err) update := resp.GetBranchUpdate() - newTargetBranchCommit, err := log.GetCommit(ctxOuter, testRepo, targetBranchName) + newTargetBranchCommit, err := log.GetCommit(ctx, testRepo, targetBranchName) require.NoError(t, err) require.Equal(t, newTargetBranchCommit.Id, update.CommitId) @@ -288,6 +1049,10 @@ func TestSuccessfulUserCommitFilesRequestStartSha(t *testing.T) { } func TestSuccessfulUserCommitFilesRequestStartShaRemoteRepository(t *testing.T) { + testImplementations(t, testSuccessfulUserCommitFilesRequestStartShaRemoteRepository) +} + +func testSuccessfulUserCommitFilesRequestStartShaRemoteRepository(t *testing.T, ctx context.Context) { serverSocketPath, stop := runOperationServiceServer(t) defer stop() @@ -297,17 +1062,18 @@ func TestSuccessfulUserCommitFilesRequestStartShaRemoteRepository(t *testing.T) testRepo, _, cleanupFn := testhelper.NewTestRepo(t) defer cleanupFn() - ctxOuter, cancel := testhelper.Context() - defer cancel() - newRepo, _, newRepoCleanupFn := testhelper.InitBareRepo(t) defer newRepoCleanupFn() - md := testhelper.GitalyServersMetadata(t, serverSocketPath) - ctx := metadata.NewOutgoingContext(ctxOuter, md) + for key, values := range testhelper.GitalyServersMetadata(t, serverSocketPath) { + for _, value := range values { + ctx = metadata.AppendToOutgoingContext(ctx, key, value) + } + } + targetBranchName := "new" - startCommit, err := log.GetCommit(ctxOuter, testRepo, "master") + startCommit, err := log.GetCommit(ctx, testRepo, "master") require.NoError(t, err) headerRequest := headerRequest(newRepo, testhelper.TestUser, targetBranchName, commitFilesMessage) @@ -324,7 +1090,7 @@ func TestSuccessfulUserCommitFilesRequestStartShaRemoteRepository(t *testing.T) require.NoError(t, err) update := resp.GetBranchUpdate() - newTargetBranchCommit, err := log.GetCommit(ctxOuter, newRepo, targetBranchName) + newTargetBranchCommit, err := log.GetCommit(ctx, newRepo, targetBranchName) require.NoError(t, err) require.Equal(t, newTargetBranchCommit.Id, update.CommitId) @@ -332,6 +1098,10 @@ func TestSuccessfulUserCommitFilesRequestStartShaRemoteRepository(t *testing.T) } func TestSuccessfulUserCommitFilesRequestWithSpecialCharactersInSignature(t *testing.T) { + testImplementations(t, testSuccessfulUserCommitFilesRequestWithSpecialCharactersInSignature) +} + +func testSuccessfulUserCommitFilesRequestWithSpecialCharactersInSignature(t *testing.T, ctx context.Context) { serverSocketPath, stop := runOperationServiceServer(t) defer stop() @@ -341,10 +1111,6 @@ func TestSuccessfulUserCommitFilesRequestWithSpecialCharactersInSignature(t *tes testRepo, _, cleanupFn := testhelper.InitBareRepo(t) defer cleanupFn() - ctxOuter, cancel := testhelper.Context() - defer cancel() - - md := testhelper.GitalyServersMetadata(t, serverSocketPath) targetBranchName := "master" testCases := []struct { @@ -366,7 +1132,6 @@ func TestSuccessfulUserCommitFilesRequestWithSpecialCharactersInSignature(t *tes for _, tc := range testCases { t.Run(tc.desc, func(t *testing.T) { - ctx := metadata.NewOutgoingContext(ctxOuter, md) headerRequest := headerRequest(testRepo, tc.user, targetBranchName, commitFilesMessage) setAuthorAndEmail(headerRequest, tc.user.Name, tc.user.Email) @@ -377,7 +1142,7 @@ func TestSuccessfulUserCommitFilesRequestWithSpecialCharactersInSignature(t *tes _, err = stream.CloseAndRecv() require.NoError(t, err) - newCommit, err := log.GetCommit(ctxOuter, testRepo, targetBranchName) + newCommit, err := log.GetCommit(ctx, testRepo, targetBranchName) require.NoError(t, err) require.Equal(t, tc.author.Name, newCommit.Author.Name, "author name") @@ -389,6 +1154,10 @@ func TestSuccessfulUserCommitFilesRequestWithSpecialCharactersInSignature(t *tes } func TestFailedUserCommitFilesRequestDueToHooks(t *testing.T) { + testImplementations(t, testFailedUserCommitFilesRequestDueToHooks) +} + +func testFailedUserCommitFilesRequestDueToHooks(t *testing.T, ctx context.Context) { serverSocketPath, stop := runOperationServiceServer(t) defer stop() @@ -398,9 +1167,6 @@ func TestFailedUserCommitFilesRequestDueToHooks(t *testing.T) { testRepo, testRepoPath, cleanupFn := testhelper.NewTestRepo(t) defer cleanupFn() - ctxOuter, cancel := testhelper.Context() - defer cancel() - branchName := "feature" filePath := "my/file.txt" headerRequest := headerRequest(testRepo, testhelper.TestUser, branchName, commitFilesMessage) @@ -413,8 +1179,7 @@ func TestFailedUserCommitFilesRequestDueToHooks(t *testing.T) { remove, err := testhelper.WriteCustomHook(testRepoPath, hookName, hookContent) require.NoError(t, err) defer remove() - md := testhelper.GitalyServersMetadata(t, serverSocketPath) - ctx := metadata.NewOutgoingContext(ctxOuter, md) + stream, err := client.UserCommitFiles(ctx) require.NoError(t, err) require.NoError(t, stream.Send(headerRequest)) @@ -431,6 +1196,10 @@ func TestFailedUserCommitFilesRequestDueToHooks(t *testing.T) { } func TestFailedUserCommitFilesRequestDueToIndexError(t *testing.T) { + testImplementations(t, testFailedUserCommitFilesRequestDueToIndexError) +} + +func testFailedUserCommitFilesRequestDueToIndexError(t *testing.T, ctx context.Context) { serverSocketPath, stop := runOperationServiceServer(t) defer stop() @@ -440,11 +1209,6 @@ func TestFailedUserCommitFilesRequestDueToIndexError(t *testing.T) { testRepo, _, cleanupFn := testhelper.NewTestRepo(t) defer cleanupFn() - ctxOuter, cancel := testhelper.Context() - defer cancel() - - md := testhelper.GitalyServersMetadata(t, serverSocketPath) - ctx := metadata.NewOutgoingContext(ctxOuter, md) testCases := []struct { desc string requests []*gitalypb.UserCommitFilesRequest @@ -503,6 +1267,10 @@ func TestFailedUserCommitFilesRequestDueToIndexError(t *testing.T) { } func TestFailedUserCommitFilesRequest(t *testing.T) { + testImplementations(t, testFailedUserCommitFilesRequest) +} + +func testFailedUserCommitFilesRequest(t *testing.T, ctx context.Context) { serverSocketPath, stop := runOperationServiceServer(t) defer stop() @@ -512,11 +1280,6 @@ func TestFailedUserCommitFilesRequest(t *testing.T) { testRepo, _, cleanupFn := testhelper.NewTestRepo(t) defer cleanupFn() - ctxOuter, cancel := testhelper.Context() - defer cancel() - - md := testhelper.GitalyServersMetadata(t, serverSocketPath) - ctx := metadata.NewOutgoingContext(ctxOuter, md) branchName := "feature" testCases := []struct { @@ -626,6 +1389,17 @@ func getHeader(headerRequest *gitalypb.UserCommitFilesRequest) *gitalypb.UserCom return headerRequest.UserCommitFilesRequestPayload.(*gitalypb.UserCommitFilesRequest_Header).Header } +func createDirHeaderRequest(filePath string) *gitalypb.UserCommitFilesRequest { + return actionRequest(&gitalypb.UserCommitFilesAction{ + UserCommitFilesActionPayload: &gitalypb.UserCommitFilesAction_Header{ + Header: &gitalypb.UserCommitFilesActionHeader{ + Action: gitalypb.UserCommitFilesActionHeader_CREATE_DIR, + FilePath: []byte(filePath), + }, + }, + }) +} + func createFileHeaderRequest(filePath string) *gitalypb.UserCommitFilesRequest { return actionRequest(&gitalypb.UserCommitFilesAction{ UserCommitFilesActionPayload: &gitalypb.UserCommitFilesAction_Header{ @@ -638,6 +1412,41 @@ func createFileHeaderRequest(filePath string) *gitalypb.UserCommitFilesRequest { }) } +func createBase64FileHeaderRequest(filePath string) *gitalypb.UserCommitFilesRequest { + return actionRequest(&gitalypb.UserCommitFilesAction{ + UserCommitFilesActionPayload: &gitalypb.UserCommitFilesAction_Header{ + Header: &gitalypb.UserCommitFilesActionHeader{ + Action: gitalypb.UserCommitFilesActionHeader_CREATE, + Base64Content: true, + FilePath: []byte(filePath), + }, + }, + }) +} + +func updateFileHeaderRequest(filePath string) *gitalypb.UserCommitFilesRequest { + return actionRequest(&gitalypb.UserCommitFilesAction{ + UserCommitFilesActionPayload: &gitalypb.UserCommitFilesAction_Header{ + Header: &gitalypb.UserCommitFilesActionHeader{ + Action: gitalypb.UserCommitFilesActionHeader_UPDATE, + FilePath: []byte(filePath), + }, + }, + }) +} + +func updateBase64FileHeaderRequest(filePath string) *gitalypb.UserCommitFilesRequest { + return actionRequest(&gitalypb.UserCommitFilesAction{ + UserCommitFilesActionPayload: &gitalypb.UserCommitFilesAction_Header{ + Header: &gitalypb.UserCommitFilesActionHeader{ + Action: gitalypb.UserCommitFilesActionHeader_UPDATE, + FilePath: []byte(filePath), + Base64Content: true, + }, + }, + }) +} + func chmodFileHeaderRequest(filePath string, executeFilemode bool) *gitalypb.UserCommitFilesRequest { return actionRequest(&gitalypb.UserCommitFilesAction{ UserCommitFilesActionPayload: &gitalypb.UserCommitFilesAction_Header{ @@ -663,6 +1472,17 @@ func moveFileHeaderRequest(previousPath, filePath string, infer bool) *gitalypb. }) } +func deleteFileHeaderRequest(filePath string) *gitalypb.UserCommitFilesRequest { + return actionRequest(&gitalypb.UserCommitFilesAction{ + UserCommitFilesActionPayload: &gitalypb.UserCommitFilesAction_Header{ + Header: &gitalypb.UserCommitFilesActionHeader{ + Action: gitalypb.UserCommitFilesActionHeader_DELETE, + FilePath: []byte(filePath), + }, + }, + }) +} + func actionContentRequest(content string) *gitalypb.UserCommitFilesRequest { return actionRequest(&gitalypb.UserCommitFilesAction{ UserCommitFilesActionPayload: &gitalypb.UserCommitFilesAction_Content{ |