github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/storage/badger/operation/modifiers_test.go (about) 1 package operation 2 3 import ( 4 "errors" 5 "fmt" 6 "testing" 7 8 "github.com/dgraph-io/badger/v2" 9 "github.com/stretchr/testify/assert" 10 "github.com/stretchr/testify/require" 11 "github.com/vmihailenco/msgpack/v4" 12 13 "github.com/onflow/flow-go/storage" 14 "github.com/onflow/flow-go/utils/unittest" 15 ) 16 17 func TestSkipDuplicates(t *testing.T) { 18 unittest.RunWithBadgerDB(t, func(db *badger.DB) { 19 e := Entity{ID: 1337} 20 key := []byte{0x01, 0x02, 0x03} 21 val, _ := msgpack.Marshal(e) 22 23 // persist first time 24 err := db.Update(insert(key, e)) 25 require.NoError(t, err) 26 27 e2 := Entity{ID: 1338} 28 29 // persist again 30 err = db.Update(SkipDuplicates(insert(key, e2))) 31 require.NoError(t, err) 32 33 // ensure old value is still used 34 var act []byte 35 _ = db.View(func(tx *badger.Txn) error { 36 item, err := tx.Get(key) 37 require.NoError(t, err) 38 act, err = item.ValueCopy(nil) 39 require.NoError(t, err) 40 return nil 41 }) 42 43 assert.Equal(t, val, act) 44 }) 45 } 46 47 func TestRetryOnConflict(t *testing.T) { 48 unittest.RunWithBadgerDB(t, func(db *badger.DB) { 49 t.Run("good op", func(t *testing.T) { 50 goodOp := func(*badger.Txn) error { 51 return nil 52 } 53 err := RetryOnConflict(db.Update, goodOp) 54 require.NoError(t, err) 55 }) 56 57 t.Run("conflict op should be retried", func(t *testing.T) { 58 n := 0 59 conflictOp := func(*badger.Txn) error { 60 n++ 61 if n > 3 { 62 return nil 63 } 64 return badger.ErrConflict 65 } 66 err := RetryOnConflict(db.Update, conflictOp) 67 require.NoError(t, err) 68 }) 69 70 t.Run("wrapped conflict op should be retried", func(t *testing.T) { 71 n := 0 72 conflictOp := func(*badger.Txn) error { 73 n++ 74 if n > 3 { 75 return nil 76 } 77 return fmt.Errorf("wrap error: %w", badger.ErrConflict) 78 } 79 err := RetryOnConflict(db.Update, conflictOp) 80 require.NoError(t, err) 81 }) 82 83 t.Run("other error should be returned", func(t *testing.T) { 84 otherError := errors.New("other error") 85 failOp := func(*badger.Txn) error { 86 return otherError 87 } 88 89 err := RetryOnConflict(db.Update, failOp) 90 require.Equal(t, otherError, err) 91 }) 92 }) 93 } 94 95 func TestSkipNonExists(t *testing.T) { 96 unittest.RunWithBadgerDB(t, func(db *badger.DB) { 97 t.Run("not found", func(t *testing.T) { 98 op := func(*badger.Txn) error { 99 return badger.ErrKeyNotFound 100 } 101 102 err := db.Update(SkipNonExist(op)) 103 require.NoError(t, err) 104 }) 105 106 t.Run("not exist", func(t *testing.T) { 107 op := func(*badger.Txn) error { 108 return storage.ErrNotFound 109 } 110 111 err := db.Update(SkipNonExist(op)) 112 require.NoError(t, err) 113 }) 114 115 t.Run("general error", func(t *testing.T) { 116 expectError := fmt.Errorf("random error") 117 op := func(*badger.Txn) error { 118 return expectError 119 } 120 121 err := db.Update(SkipNonExist(op)) 122 require.Equal(t, expectError, err) 123 }) 124 }) 125 }