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:
authorQuang-Minh Nguyen <qmnguyen@gitlab.com>2023-12-06 10:13:03 +0300
committerQuang-Minh Nguyen <qmnguyen@gitlab.com>2023-12-08 08:18:04 +0300
commit190e94fa5f05b01325a7f2da0cf474f6b0e85ae0 (patch)
tree75cc7e28e7a7b0c3d4d357f22fcdf62a3ff3b2e2
parent6dbbea15a4d71c8d30ebdf4fff84082f85469782 (diff)
Split tests related to custom hooks out of TransactionManager
-rw-r--r--internal/gitaly/storage/storagemgr/transaction_manager_hook_test.go465
-rw-r--r--internal/gitaly/storage/storagemgr/transaction_manager_test.go455
2 files changed, 466 insertions, 454 deletions
diff --git a/internal/gitaly/storage/storagemgr/transaction_manager_hook_test.go b/internal/gitaly/storage/storagemgr/transaction_manager_hook_test.go
index 95fceadd7..f849f1c6f 100644
--- a/internal/gitaly/storage/storagemgr/transaction_manager_hook_test.go
+++ b/internal/gitaly/storage/storagemgr/transaction_manager_hook_test.go
@@ -1,6 +1,7 @@
package storagemgr
import (
+ "io/fs"
"regexp"
"runtime"
"strings"
@@ -8,6 +9,9 @@ import (
"github.com/dgraph-io/badger/v4"
"github.com/stretchr/testify/require"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/git"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/helper/perm"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
)
// hookFunc is a function that is executed at a specific point. It gets a hookContext that allows it to
@@ -170,3 +174,464 @@ type testingHook struct {
func (t testingHook) FailNow() {
t.Fail()
}
+
+func generateCustomHooksTests(t *testing.T, setup testTransactionSetup) []transactionTestCase {
+ umask := testhelper.Umask()
+
+ return []transactionTestCase{
+ {
+ desc: "set custom hooks successfully",
+ steps: steps{
+ StartManager{},
+ Begin{
+ TransactionID: 1,
+ RelativePath: setup.RelativePath,
+ },
+ Commit{
+ TransactionID: 1,
+ CustomHooksUpdate: &CustomHooksUpdate{
+ CustomHooksTAR: validCustomHooks(t),
+ },
+ },
+ Begin{
+ TransactionID: 2,
+ RelativePath: setup.RelativePath,
+ ExpectedSnapshotLSN: 1,
+ },
+ Commit{
+ TransactionID: 2,
+ CustomHooksUpdate: &CustomHooksUpdate{},
+ },
+ },
+ expectedState: StateAssertion{
+ Database: DatabaseState{
+ string(keyAppliedLSN(setup.PartitionID)): LSN(2).toProto(),
+ },
+ Directory: testhelper.DirectoryState{
+ "/": {Mode: fs.ModeDir | perm.PrivateDir},
+ "/wal": {Mode: fs.ModeDir | perm.PrivateDir},
+ },
+ Repositories: RepositoryStates{
+ setup.RelativePath: {
+ CustomHooks: testhelper.DirectoryState{
+ "/": {Mode: fs.ModeDir | perm.PrivateDir},
+ },
+ },
+ },
+ },
+ },
+ {
+ desc: "rejects invalid custom hooks",
+ steps: steps{
+ StartManager{},
+ Begin{
+ TransactionID: 1,
+ RelativePath: setup.RelativePath,
+ },
+ Commit{
+ TransactionID: 1,
+ CustomHooksUpdate: &CustomHooksUpdate{
+ CustomHooksTAR: []byte("corrupted tar"),
+ },
+ ExpectedError: func(tb testing.TB, actualErr error) {
+ require.ErrorContains(tb, actualErr, "stage hooks: extract hooks: waiting for tar command completion: exit status")
+ },
+ },
+ },
+ },
+ {
+ desc: "reapplying custom hooks works",
+ steps: steps{
+ StartManager{
+ Hooks: testTransactionHooks{
+ BeforeStoreAppliedLSN: func(hookContext) {
+ panic(errSimulatedCrash)
+ },
+ },
+ ExpectedError: errSimulatedCrash,
+ },
+ Begin{
+ TransactionID: 1,
+ RelativePath: setup.RelativePath,
+ },
+ Commit{
+ TransactionID: 1,
+ CustomHooksUpdate: &CustomHooksUpdate{
+ CustomHooksTAR: validCustomHooks(t),
+ },
+ ExpectedError: ErrTransactionProcessingStopped,
+ },
+ AssertManager{
+ ExpectedError: errSimulatedCrash,
+ },
+ StartManager{},
+ },
+ expectedState: StateAssertion{
+ Database: DatabaseState{
+ string(keyAppliedLSN(setup.PartitionID)): LSN(1).toProto(),
+ },
+ Directory: testhelper.DirectoryState{
+ "/": {Mode: fs.ModeDir | perm.PrivateDir},
+ "/wal": {Mode: fs.ModeDir | perm.PrivateDir},
+ },
+ Repositories: RepositoryStates{
+ setup.RelativePath: {
+ CustomHooks: testhelper.DirectoryState{
+ "/": {Mode: fs.ModeDir | perm.PrivateDir},
+ "/pre-receive": {
+ Mode: umask.Mask(fs.ModePerm),
+ Content: []byte("hook content"),
+ },
+ "/private-dir": {Mode: fs.ModeDir | perm.PrivateDir},
+ "/private-dir/private-file": {Mode: umask.Mask(perm.PrivateFile), Content: []byte("private content")},
+ },
+ },
+ },
+ },
+ },
+ {
+ desc: "hook index is correctly determined from log and disk",
+ steps: steps{
+ StartManager{
+ Hooks: testTransactionHooks{
+ BeforeApplyLogEntry: func(hookContext) {
+ panic(errSimulatedCrash)
+ },
+ },
+ ExpectedError: errSimulatedCrash,
+ },
+ Begin{
+ TransactionID: 1,
+ RelativePath: setup.RelativePath,
+ },
+ Commit{
+ TransactionID: 1,
+ CustomHooksUpdate: &CustomHooksUpdate{
+ CustomHooksTAR: validCustomHooks(t),
+ },
+ ExpectedError: ErrTransactionProcessingStopped,
+ },
+ AssertManager{
+ ExpectedError: errSimulatedCrash,
+ },
+ StartManager{},
+ Begin{
+ TransactionID: 2,
+ RelativePath: setup.RelativePath,
+ ExpectedSnapshotLSN: 1,
+ },
+ Commit{
+ TransactionID: 2,
+ CustomHooksUpdate: &CustomHooksUpdate{},
+ },
+ Begin{
+ TransactionID: 3,
+ RelativePath: setup.RelativePath,
+ ExpectedSnapshotLSN: 2,
+ },
+ CloseManager{},
+ StartManager{},
+ Begin{
+ TransactionID: 4,
+ RelativePath: setup.RelativePath,
+ ExpectedSnapshotLSN: 2,
+ },
+ Rollback{
+ TransactionID: 4,
+ },
+ },
+ expectedState: StateAssertion{
+ Database: DatabaseState{
+ string(keyAppliedLSN(setup.PartitionID)): LSN(2).toProto(),
+ },
+ Directory: testhelper.DirectoryState{
+ "/": {Mode: fs.ModeDir | perm.PrivateDir},
+ "/wal": {Mode: fs.ModeDir | perm.PrivateDir},
+ },
+ Repositories: RepositoryStates{
+ setup.RelativePath: {
+ CustomHooks: testhelper.DirectoryState{
+ "/": {Mode: fs.ModeDir | perm.PrivateDir},
+ },
+ },
+ },
+ },
+ },
+ {
+ desc: "continues processing after reference verification failure",
+ steps: steps{
+ StartManager{},
+ Begin{
+ TransactionID: 1,
+ RelativePath: setup.RelativePath,
+ },
+ Commit{
+ TransactionID: 1,
+ ReferenceUpdates: ReferenceUpdates{
+ "refs/heads/main": {OldOID: setup.Commits.First.OID, NewOID: setup.Commits.Second.OID},
+ },
+ ExpectedError: ReferenceVerificationError{
+ ReferenceName: "refs/heads/main",
+ ExpectedOID: setup.Commits.First.OID,
+ ActualOID: setup.ObjectHash.ZeroOID,
+ },
+ },
+ Begin{
+ TransactionID: 2,
+ RelativePath: setup.RelativePath,
+ },
+ Commit{
+ TransactionID: 2,
+ ReferenceUpdates: ReferenceUpdates{
+ "refs/heads/main": {OldOID: setup.ObjectHash.ZeroOID, NewOID: setup.Commits.Second.OID},
+ },
+ },
+ },
+ expectedState: StateAssertion{
+ Database: DatabaseState{
+ string(keyAppliedLSN(setup.PartitionID)): LSN(1).toProto(),
+ },
+ Repositories: RepositoryStates{
+ setup.RelativePath: {
+ DefaultBranch: "refs/heads/main",
+ References: []git.Reference{{Name: "refs/heads/main", Target: setup.Commits.Second.OID.String()}},
+ },
+ },
+ },
+ },
+ {
+ desc: "continues processing after a restart",
+ steps: steps{
+ StartManager{},
+ Begin{
+ TransactionID: 1,
+ RelativePath: setup.RelativePath,
+ },
+ Commit{
+ TransactionID: 1,
+ ReferenceUpdates: ReferenceUpdates{
+ "refs/heads/main": {OldOID: setup.ObjectHash.ZeroOID, NewOID: setup.Commits.First.OID},
+ },
+ },
+ AssertManager{},
+ CloseManager{},
+ StartManager{},
+ Begin{
+ TransactionID: 2,
+ RelativePath: setup.RelativePath,
+ ExpectedSnapshotLSN: 1,
+ },
+ Commit{
+ TransactionID: 2,
+ ReferenceUpdates: ReferenceUpdates{
+ "refs/heads/main": {OldOID: setup.Commits.First.OID, NewOID: setup.Commits.Second.OID},
+ },
+ },
+ },
+ expectedState: StateAssertion{
+ Database: DatabaseState{
+ string(keyAppliedLSN(setup.PartitionID)): LSN(2).toProto(),
+ },
+ Repositories: RepositoryStates{
+ setup.RelativePath: {
+ DefaultBranch: "refs/heads/main",
+ References: []git.Reference{{Name: "refs/heads/main", Target: setup.Commits.Second.OID.String()}},
+ },
+ },
+ },
+ },
+ {
+ desc: "continues processing after restarting after a reference verification failure",
+ steps: steps{
+ StartManager{},
+ Begin{
+ TransactionID: 1,
+ RelativePath: setup.RelativePath,
+ },
+ Commit{
+ TransactionID: 1,
+ ReferenceUpdates: ReferenceUpdates{
+ "refs/heads/main": {OldOID: setup.Commits.First.OID, NewOID: setup.Commits.Second.OID},
+ },
+ ExpectedError: ReferenceVerificationError{
+ ReferenceName: "refs/heads/main",
+ ExpectedOID: setup.Commits.First.OID,
+ ActualOID: setup.ObjectHash.ZeroOID,
+ },
+ },
+ CloseManager{},
+ StartManager{},
+ Begin{
+ TransactionID: 2,
+ RelativePath: setup.RelativePath,
+ },
+ Commit{
+ TransactionID: 2,
+ ReferenceUpdates: ReferenceUpdates{
+ "refs/heads/main": {OldOID: setup.ObjectHash.ZeroOID, NewOID: setup.Commits.Second.OID},
+ },
+ },
+ },
+ expectedState: StateAssertion{
+ Database: DatabaseState{
+ string(keyAppliedLSN(setup.PartitionID)): LSN(1).toProto(),
+ },
+ Repositories: RepositoryStates{
+ setup.RelativePath: {
+ DefaultBranch: "refs/heads/main",
+ References: []git.Reference{{Name: "refs/heads/main", Target: setup.Commits.Second.OID.String()}},
+ },
+ },
+ },
+ },
+ {
+ desc: "continues processing after failing to store log index",
+ steps: steps{
+ StartManager{
+ Hooks: testTransactionHooks{
+ BeforeStoreAppliedLSN: func(hookCtx hookContext) {
+ panic(errSimulatedCrash)
+ },
+ },
+ ExpectedError: errSimulatedCrash,
+ },
+ Begin{
+ TransactionID: 1,
+ RelativePath: setup.RelativePath,
+ },
+ Commit{
+ TransactionID: 1,
+ ReferenceUpdates: ReferenceUpdates{
+ "refs/heads/main": {OldOID: setup.ObjectHash.ZeroOID, NewOID: setup.Commits.First.OID},
+ },
+ ExpectedError: ErrTransactionProcessingStopped,
+ },
+ AssertManager{
+ ExpectedError: errSimulatedCrash,
+ },
+ StartManager{},
+ Begin{
+ TransactionID: 2,
+ RelativePath: setup.RelativePath,
+ ExpectedSnapshotLSN: 1,
+ },
+ Commit{
+ TransactionID: 2,
+ ReferenceUpdates: ReferenceUpdates{
+ "refs/heads/main": {OldOID: setup.Commits.First.OID, NewOID: setup.Commits.Second.OID},
+ },
+ },
+ },
+ expectedState: StateAssertion{
+ Database: DatabaseState{
+ string(keyAppliedLSN(setup.PartitionID)): LSN(2).toProto(),
+ },
+ Repositories: RepositoryStates{
+ setup.RelativePath: {
+ DefaultBranch: "refs/heads/main",
+ References: []git.Reference{{Name: "refs/heads/main", Target: setup.Commits.Second.OID.String()}},
+ },
+ },
+ },
+ },
+ {
+ desc: "recovers from the write-ahead log on start up",
+ steps: steps{
+ StartManager{
+ Hooks: testTransactionHooks{
+ BeforeApplyLogEntry: func(hookCtx hookContext) {
+ hookCtx.closeManager()
+ },
+ },
+ },
+ Begin{
+ TransactionID: 1,
+ RelativePath: setup.RelativePath,
+ },
+ Commit{
+ TransactionID: 1,
+ ReferenceUpdates: ReferenceUpdates{
+ "refs/heads/main": {OldOID: setup.ObjectHash.ZeroOID, NewOID: setup.Commits.First.OID},
+ },
+ ExpectedError: ErrTransactionProcessingStopped,
+ },
+ AssertManager{},
+ StartManager{},
+ Begin{
+ TransactionID: 2,
+ RelativePath: setup.RelativePath,
+ ExpectedSnapshotLSN: 1,
+ },
+ Commit{
+ TransactionID: 2,
+ ReferenceUpdates: ReferenceUpdates{
+ "refs/heads/main": {OldOID: setup.Commits.First.OID, NewOID: setup.Commits.Second.OID},
+ },
+ },
+ },
+ expectedState: StateAssertion{
+ Database: DatabaseState{
+ string(keyAppliedLSN(setup.PartitionID)): LSN(2).toProto(),
+ },
+ Repositories: RepositoryStates{
+ setup.RelativePath: {
+ DefaultBranch: "refs/heads/main",
+ References: []git.Reference{{Name: "refs/heads/main", Target: setup.Commits.Second.OID.String()}},
+ },
+ },
+ },
+ },
+ {
+ desc: "reference verification fails after recovering logged writes",
+ steps: steps{
+ StartManager{
+ Hooks: testTransactionHooks{
+ BeforeApplyLogEntry: func(hookCtx hookContext) {
+ hookCtx.closeManager()
+ },
+ },
+ },
+ Begin{
+ TransactionID: 1,
+ RelativePath: setup.RelativePath,
+ },
+ Commit{
+ TransactionID: 1,
+ ReferenceUpdates: ReferenceUpdates{
+ "refs/heads/main": {OldOID: setup.ObjectHash.ZeroOID, NewOID: setup.Commits.First.OID},
+ },
+ ExpectedError: ErrTransactionProcessingStopped,
+ },
+ AssertManager{},
+ StartManager{},
+ Begin{
+ TransactionID: 2,
+ RelativePath: setup.RelativePath,
+ ExpectedSnapshotLSN: 1,
+ },
+ Commit{
+ TransactionID: 2,
+ ReferenceUpdates: ReferenceUpdates{
+ "refs/heads/main": {OldOID: setup.Commits.Second.OID, NewOID: setup.Commits.First.OID},
+ },
+ ExpectedError: ReferenceVerificationError{
+ ReferenceName: "refs/heads/main",
+ ExpectedOID: setup.Commits.Second.OID,
+ ActualOID: setup.Commits.First.OID,
+ },
+ },
+ },
+ expectedState: StateAssertion{
+ Database: DatabaseState{
+ string(keyAppliedLSN(setup.PartitionID)): LSN(1).toProto(),
+ },
+ Repositories: RepositoryStates{
+ setup.RelativePath: {
+ DefaultBranch: "refs/heads/main",
+ References: []git.Reference{{Name: "refs/heads/main", Target: setup.Commits.First.OID.String()}},
+ },
+ },
+ },
+ },
+ }
+}
diff --git a/internal/gitaly/storage/storagemgr/transaction_manager_test.go b/internal/gitaly/storage/storagemgr/transaction_manager_test.go
index 43cb6f2cb..fb0bea1ea 100644
--- a/internal/gitaly/storage/storagemgr/transaction_manager_test.go
+++ b/internal/gitaly/storage/storagemgr/transaction_manager_test.go
@@ -250,460 +250,6 @@ func TestTransactionManager(t *testing.T) {
testCases := []transactionTestCase{
{
- desc: "set custom hooks successfully",
- steps: steps{
- StartManager{},
- Begin{
- TransactionID: 1,
- RelativePath: relativePath,
- },
- Commit{
- TransactionID: 1,
- CustomHooksUpdate: &CustomHooksUpdate{
- CustomHooksTAR: validCustomHooks(t),
- },
- },
- Begin{
- TransactionID: 2,
- RelativePath: relativePath,
- ExpectedSnapshotLSN: 1,
- },
- Commit{
- TransactionID: 2,
- CustomHooksUpdate: &CustomHooksUpdate{},
- },
- },
- expectedState: StateAssertion{
- Database: DatabaseState{
- string(keyAppliedLSN(partitionID)): LSN(2).toProto(),
- },
- Directory: testhelper.DirectoryState{
- "/": {Mode: fs.ModeDir | perm.PrivateDir},
- "/wal": {Mode: fs.ModeDir | perm.PrivateDir},
- },
- Repositories: RepositoryStates{
- relativePath: {
- CustomHooks: testhelper.DirectoryState{
- "/": {Mode: fs.ModeDir | perm.PrivateDir},
- },
- },
- },
- },
- },
- {
- desc: "rejects invalid custom hooks",
- steps: steps{
- StartManager{},
- Begin{
- TransactionID: 1,
- RelativePath: relativePath,
- },
- Commit{
- TransactionID: 1,
- CustomHooksUpdate: &CustomHooksUpdate{
- CustomHooksTAR: []byte("corrupted tar"),
- },
- ExpectedError: func(tb testing.TB, actualErr error) {
- require.ErrorContains(tb, actualErr, "stage hooks: extract hooks: waiting for tar command completion: exit status")
- },
- },
- },
- },
- {
- desc: "reapplying custom hooks works",
- steps: steps{
- StartManager{
- Hooks: testTransactionHooks{
- BeforeStoreAppliedLSN: func(hookContext) {
- panic(errSimulatedCrash)
- },
- },
- ExpectedError: errSimulatedCrash,
- },
- Begin{
- TransactionID: 1,
- RelativePath: relativePath,
- },
- Commit{
- TransactionID: 1,
- CustomHooksUpdate: &CustomHooksUpdate{
- CustomHooksTAR: validCustomHooks(t),
- },
- ExpectedError: ErrTransactionProcessingStopped,
- },
- AssertManager{
- ExpectedError: errSimulatedCrash,
- },
- StartManager{},
- },
- expectedState: StateAssertion{
- Database: DatabaseState{
- string(keyAppliedLSN(partitionID)): LSN(1).toProto(),
- },
- Directory: testhelper.DirectoryState{
- "/": {Mode: fs.ModeDir | perm.PrivateDir},
- "/wal": {Mode: fs.ModeDir | perm.PrivateDir},
- },
- Repositories: RepositoryStates{
- relativePath: {
- CustomHooks: testhelper.DirectoryState{
- "/": {Mode: fs.ModeDir | perm.PrivateDir},
- "/pre-receive": {
- Mode: umask.Mask(fs.ModePerm),
- Content: []byte("hook content"),
- },
- "/private-dir": {Mode: fs.ModeDir | perm.PrivateDir},
- "/private-dir/private-file": {Mode: umask.Mask(perm.PrivateFile), Content: []byte("private content")},
- },
- },
- },
- },
- },
- {
- desc: "hook index is correctly determined from log and disk",
- steps: steps{
- StartManager{
- Hooks: testTransactionHooks{
- BeforeApplyLogEntry: func(hookContext) {
- panic(errSimulatedCrash)
- },
- },
- ExpectedError: errSimulatedCrash,
- },
- Begin{
- TransactionID: 1,
- RelativePath: relativePath,
- },
- Commit{
- TransactionID: 1,
- CustomHooksUpdate: &CustomHooksUpdate{
- CustomHooksTAR: validCustomHooks(t),
- },
- ExpectedError: ErrTransactionProcessingStopped,
- },
- AssertManager{
- ExpectedError: errSimulatedCrash,
- },
- StartManager{},
- Begin{
- TransactionID: 2,
- RelativePath: relativePath,
- ExpectedSnapshotLSN: 1,
- },
- Commit{
- TransactionID: 2,
- CustomHooksUpdate: &CustomHooksUpdate{},
- },
- Begin{
- TransactionID: 3,
- RelativePath: relativePath,
- ExpectedSnapshotLSN: 2,
- },
- CloseManager{},
- StartManager{},
- Begin{
- TransactionID: 4,
- RelativePath: relativePath,
- ExpectedSnapshotLSN: 2,
- },
- Rollback{
- TransactionID: 4,
- },
- },
- expectedState: StateAssertion{
- Database: DatabaseState{
- string(keyAppliedLSN(partitionID)): LSN(2).toProto(),
- },
- Directory: testhelper.DirectoryState{
- "/": {Mode: fs.ModeDir | perm.PrivateDir},
- "/wal": {Mode: fs.ModeDir | perm.PrivateDir},
- },
- Repositories: RepositoryStates{
- relativePath: {
- CustomHooks: testhelper.DirectoryState{
- "/": {Mode: fs.ModeDir | perm.PrivateDir},
- },
- },
- },
- },
- },
- {
- desc: "continues processing after reference verification failure",
- steps: steps{
- StartManager{},
- Begin{
- TransactionID: 1,
- RelativePath: relativePath,
- },
- Commit{
- TransactionID: 1,
- ReferenceUpdates: ReferenceUpdates{
- "refs/heads/main": {OldOID: setup.Commits.First.OID, NewOID: setup.Commits.Second.OID},
- },
- ExpectedError: ReferenceVerificationError{
- ReferenceName: "refs/heads/main",
- ExpectedOID: setup.Commits.First.OID,
- ActualOID: setup.ObjectHash.ZeroOID,
- },
- },
- Begin{
- TransactionID: 2,
- RelativePath: relativePath,
- },
- Commit{
- TransactionID: 2,
- ReferenceUpdates: ReferenceUpdates{
- "refs/heads/main": {OldOID: setup.ObjectHash.ZeroOID, NewOID: setup.Commits.Second.OID},
- },
- },
- },
- expectedState: StateAssertion{
- Database: DatabaseState{
- string(keyAppliedLSN(partitionID)): LSN(1).toProto(),
- },
- Repositories: RepositoryStates{
- relativePath: {
- DefaultBranch: "refs/heads/main",
- References: []git.Reference{{Name: "refs/heads/main", Target: setup.Commits.Second.OID.String()}},
- },
- },
- },
- },
- {
- desc: "continues processing after a restart",
- steps: steps{
- StartManager{},
- Begin{
- TransactionID: 1,
- RelativePath: relativePath,
- },
- Commit{
- TransactionID: 1,
- ReferenceUpdates: ReferenceUpdates{
- "refs/heads/main": {OldOID: setup.ObjectHash.ZeroOID, NewOID: setup.Commits.First.OID},
- },
- },
- AssertManager{},
- CloseManager{},
- StartManager{},
- Begin{
- TransactionID: 2,
- RelativePath: relativePath,
- ExpectedSnapshotLSN: 1,
- },
- Commit{
- TransactionID: 2,
- ReferenceUpdates: ReferenceUpdates{
- "refs/heads/main": {OldOID: setup.Commits.First.OID, NewOID: setup.Commits.Second.OID},
- },
- },
- },
- expectedState: StateAssertion{
- Database: DatabaseState{
- string(keyAppliedLSN(partitionID)): LSN(2).toProto(),
- },
- Repositories: RepositoryStates{
- relativePath: {
- DefaultBranch: "refs/heads/main",
- References: []git.Reference{{Name: "refs/heads/main", Target: setup.Commits.Second.OID.String()}},
- },
- },
- },
- },
- {
- desc: "continues processing after restarting after a reference verification failure",
- steps: steps{
- StartManager{},
- Begin{
- TransactionID: 1,
- RelativePath: relativePath,
- },
- Commit{
- TransactionID: 1,
- ReferenceUpdates: ReferenceUpdates{
- "refs/heads/main": {OldOID: setup.Commits.First.OID, NewOID: setup.Commits.Second.OID},
- },
- ExpectedError: ReferenceVerificationError{
- ReferenceName: "refs/heads/main",
- ExpectedOID: setup.Commits.First.OID,
- ActualOID: setup.ObjectHash.ZeroOID,
- },
- },
- CloseManager{},
- StartManager{},
- Begin{
- TransactionID: 2,
- RelativePath: relativePath,
- },
- Commit{
- TransactionID: 2,
- ReferenceUpdates: ReferenceUpdates{
- "refs/heads/main": {OldOID: setup.ObjectHash.ZeroOID, NewOID: setup.Commits.Second.OID},
- },
- },
- },
- expectedState: StateAssertion{
- Database: DatabaseState{
- string(keyAppliedLSN(partitionID)): LSN(1).toProto(),
- },
- Repositories: RepositoryStates{
- relativePath: {
- DefaultBranch: "refs/heads/main",
- References: []git.Reference{{Name: "refs/heads/main", Target: setup.Commits.Second.OID.String()}},
- },
- },
- },
- },
- {
- desc: "continues processing after failing to store log index",
- steps: steps{
- StartManager{
- Hooks: testTransactionHooks{
- BeforeStoreAppliedLSN: func(hookCtx hookContext) {
- panic(errSimulatedCrash)
- },
- },
- ExpectedError: errSimulatedCrash,
- },
- Begin{
- TransactionID: 1,
- RelativePath: relativePath,
- },
- Commit{
- TransactionID: 1,
- ReferenceUpdates: ReferenceUpdates{
- "refs/heads/main": {OldOID: setup.ObjectHash.ZeroOID, NewOID: setup.Commits.First.OID},
- },
- ExpectedError: ErrTransactionProcessingStopped,
- },
- AssertManager{
- ExpectedError: errSimulatedCrash,
- },
- StartManager{},
- Begin{
- TransactionID: 2,
- RelativePath: relativePath,
- ExpectedSnapshotLSN: 1,
- },
- Commit{
- TransactionID: 2,
- ReferenceUpdates: ReferenceUpdates{
- "refs/heads/main": {OldOID: setup.Commits.First.OID, NewOID: setup.Commits.Second.OID},
- },
- },
- },
- expectedState: StateAssertion{
- Database: DatabaseState{
- string(keyAppliedLSN(partitionID)): LSN(2).toProto(),
- },
- Repositories: RepositoryStates{
- relativePath: {
- DefaultBranch: "refs/heads/main",
- References: []git.Reference{{Name: "refs/heads/main", Target: setup.Commits.Second.OID.String()}},
- },
- },
- },
- },
- {
- desc: "recovers from the write-ahead log on start up",
- steps: steps{
- StartManager{
- Hooks: testTransactionHooks{
- BeforeApplyLogEntry: func(hookCtx hookContext) {
- hookCtx.closeManager()
- },
- },
- },
- Begin{
- TransactionID: 1,
- RelativePath: relativePath,
- },
- Commit{
- TransactionID: 1,
- ReferenceUpdates: ReferenceUpdates{
- "refs/heads/main": {OldOID: setup.ObjectHash.ZeroOID, NewOID: setup.Commits.First.OID},
- },
- ExpectedError: ErrTransactionProcessingStopped,
- },
- AssertManager{},
- StartManager{},
- Begin{
- TransactionID: 2,
- RelativePath: relativePath,
- ExpectedSnapshotLSN: 1,
- },
- Commit{
- TransactionID: 2,
- ReferenceUpdates: ReferenceUpdates{
- "refs/heads/main": {OldOID: setup.Commits.First.OID, NewOID: setup.Commits.Second.OID},
- },
- },
- },
- expectedState: StateAssertion{
- Database: DatabaseState{
- string(keyAppliedLSN(partitionID)): LSN(2).toProto(),
- },
- Repositories: RepositoryStates{
- relativePath: {
- DefaultBranch: "refs/heads/main",
- References: []git.Reference{{Name: "refs/heads/main", Target: setup.Commits.Second.OID.String()}},
- },
- },
- },
- },
- {
- desc: "reference verification fails after recovering logged writes",
- steps: steps{
- StartManager{
- Hooks: testTransactionHooks{
- BeforeApplyLogEntry: func(hookCtx hookContext) {
- hookCtx.closeManager()
- },
- },
- },
- Begin{
- TransactionID: 1,
- RelativePath: relativePath,
- },
- Commit{
- TransactionID: 1,
- ReferenceUpdates: ReferenceUpdates{
- "refs/heads/main": {OldOID: setup.ObjectHash.ZeroOID, NewOID: setup.Commits.First.OID},
- },
- ExpectedError: ErrTransactionProcessingStopped,
- },
- AssertManager{},
- StartManager{},
- Begin{
- TransactionID: 2,
- RelativePath: relativePath,
- ExpectedSnapshotLSN: 1,
- },
- Commit{
- TransactionID: 2,
- ReferenceUpdates: ReferenceUpdates{
- "refs/heads/main": {OldOID: setup.Commits.Second.OID, NewOID: setup.Commits.First.OID},
- },
- ExpectedError: ReferenceVerificationError{
- ReferenceName: "refs/heads/main",
- ExpectedOID: setup.Commits.Second.OID,
- ActualOID: setup.Commits.First.OID,
- },
- },
- },
- expectedState: StateAssertion{
- Database: DatabaseState{
- string(keyAppliedLSN(partitionID)): LSN(1).toProto(),
- },
- Repositories: RepositoryStates{
- relativePath: {
- DefaultBranch: "refs/heads/main",
- References: []git.Reference{{Name: "refs/heads/main", Target: setup.Commits.First.OID.String()}},
- },
- },
- },
- },
- {
desc: "begin returns if context is canceled before initialization",
steps: steps{
Begin{
@@ -2229,6 +1775,7 @@ func TestTransactionManager(t *testing.T) {
generateCreateRepositoryTests(t, setup),
generateDeleteRepositoryTests(t, setup),
generateAlternateTests(t, setup),
+ generateCustomHooksTests(t, setup),
}
for _, subCases := range subTests {
testCases = append(testCases, subCases...)