Skip to content

Commit

Permalink
add separate test file to MoveBucket
Browse files Browse the repository at this point in the history
Signed-off-by: Mustafa Elbehery <[email protected]>
  • Loading branch information
Elbehery committed Dec 14, 2023
1 parent e5c4432 commit c6c5d86
Show file tree
Hide file tree
Showing 2 changed files with 185 additions and 172 deletions.
172 changes: 0 additions & 172 deletions bucket_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -464,178 +464,6 @@ func TestBucket_Delete_NonExisting(t *testing.T) {
}
}

func TestBucket_MoveBucket(t *testing.T) {
testCases := []struct {
name string
srcBucketPath []string
dstBucketPath []string
isInlined bool
expErr error
}{
{
name: "happy path",
srcBucketPath: []string{"x", "y", "z"},
dstBucketPath: []string{"a", "b"},
isInlined: false,
expErr: nil,
},
}

for _, tc := range testCases {
t.Run(tc.name, func(*testing.T) {
db := btesting.MustCreateDB(t)

// arrange
if err := db.Update(func(tx *bolt.Tx) error {
bk := createBucketIfNotExist(t, tx, tc.srcBucketPath...)
insertRandKeysValuesBucket(t, bk, rand.Intn(4096))
createBucketIfNotExist(t, tx, tc.dstBucketPath...)

return nil
}); err != nil {
t.Fatal(err)
}
db.MustCheck()

// act
//var tmpFile string
if err := db.Update(func(tx *bolt.Tx) error {
srcBucket := retrieveParentBucket(t, tx, tc.srcBucketPath...)
dstBucket := retrieveChildBucket(t, tx, tc.dstBucketPath...)
bucketToMove := tc.srcBucketPath[len(tc.srcBucketPath)-1]

//// dump bucketToMove to bbolt file for assertion
//bk := srcBucket.Bucket([]byte(bucketToMove))
//tmpFile = dumpBucketToFile(t, bk)

mErr := srcBucket.MoveBucket([]byte(bucketToMove), dstBucket)
require.Equal(t, tc.expErr, mErr)

return nil
}); err != nil {
t.Fatal(err)
}
db.MustCheck()

// assert
if err := db.View(func(tx *bolt.Tx) error {
srcBucket := retrieveParentBucket(t, tx, tc.srcBucketPath...)
bucketToMove := tc.srcBucketPath[len(tc.srcBucketPath)-1]

if bk := srcBucket.Bucket([]byte(bucketToMove)); bk != nil {
t.Fatalf("expected childBucket %v to be moved from srcBucket %v", bucketToMove, srcBucket)
}

dstBucket := retrieveChildBucket(t, tx, tc.dstBucketPath...)
if bk := dstBucket.Bucket([]byte(bucketToMove)); bk == nil {
t.Fatalf("expected childBucket %v to be child of dstBucket %v", bucketToMove, dstBucket)
}

childBucket := dstBucket.Bucket([]byte(bucketToMove))
if childBucket == nil {
t.Fatalf("expected subBucket %v to exist within dstBucket %v", bucketToMove, dstBucket)
}

//bucketOnDisk, err := os.ReadFile(tmpFile)
//if err != nil {
// t.Fatalf("error reading tmp file %v", tmpFile)
//}
//require.Equal(t, bucketOnDisk, childBucket.Write())

return nil
}); err != nil {
t.Fatal(err)
}
db.MustCheck()
})
}
}
func createBucketIfNotExist(t testing.TB, tx *bolt.Tx, paths ...string) *bolt.Bucket {
t.Helper()

bk, err := tx.CreateBucketIfNotExists([]byte(paths[0]))
if err != nil {
t.Fatalf("error creating bucket %v: %v", paths[0], err)
}

for _, key := range paths[1:] {
bk, err = bk.CreateBucketIfNotExists([]byte(key))
if err != nil {
t.Fatalf("error creating bucket %v: %v", key, err)
}
}

return bk
}

func retrieveParentBucket(t testing.TB, tx *bolt.Tx, paths ...string) *bolt.Bucket {
paths = paths[:len(paths)-1]
return retrieveChildBucket(t, tx, paths...)
}

func retrieveChildBucket(t testing.TB, tx *bolt.Tx, paths ...string) *bolt.Bucket {
t.Helper()

var bk *bolt.Bucket = nil
for _, path := range paths {
if bk == nil {
bk = tx.Bucket([]byte(path))
} else {
bk = bk.Bucket([]byte(path))
}
if bk == nil {
t.Fatalf("error retrieving bucket %v within paths %v", path, strings.TrimSuffix(strings.Join(paths, "->"), "->"))
}
}
return bk
}

func dumpBucketToFile(t testing.TB, bk *bolt.Bucket) string {
tmpFile := tempfile()
f, err := os.Create(tmpFile)
if err != nil {
t.Fatalf("error creating tmp file %v: %v", tmpFile, err)
}
defer f.Close()

data := bk.Write()
_, err = f.Write(data)
if err != nil {
t.Fatalf("error writing bucket %v to file %v tmpFile", bk, tmpFile)
}

return tmpFile
}

func insertRandKeysValuesBucket(t testing.TB, bk *bolt.Bucket, n int) {

var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
var min, max = 1, 1024

for i := 0; i < n; i++ {
// generate rand key/value length
keyLength := rand.Intn(max-min) + min
valLength := rand.Intn(max-min) + min

keyData := make([]rune, keyLength)
valData := make([]rune, valLength)

for j := range keyData {
keyData[j] = letters[rand.Intn(len(letters))]
}

for j := range valData {
valData[j] = letters[rand.Intn(len(letters))]
}

pErr := bk.Put([]byte(string(keyData)), []byte(string(valData)))
if pErr != nil {
t.Fatalf("error inserting key %v and value %v in bucket %v: %v", string(keyData), string(valData), bk.String(), pErr)
}
}

}

// Ensure that accessing and updating nested buckets is ok across transactions.
func TestBucket_Nested(t *testing.T) {
db := btesting.MustCreateDB(t)
Expand Down
185 changes: 185 additions & 0 deletions movebucket_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
package bbolt_test

import (
"math/rand"
"os"
"strings"
"testing"

"github.com/stretchr/testify/require"

bolt "go.etcd.io/bbolt"
"go.etcd.io/bbolt/internal/btesting"
)

func TestBucket_MoveBucket(t *testing.T) {
testCases := []struct {
name string
srcBucketPath []string
dstBucketPath []string
isInlined bool
expErr error
}{
{
name: "happy path",
srcBucketPath: []string{"x", "y", "z"},
dstBucketPath: []string{"a", "b"},
isInlined: false,
expErr: nil,
},
}

for _, tc := range testCases {
t.Run(tc.name, func(*testing.T) {
db := btesting.MustCreateDB(t)

// arrange
if err := db.Update(func(tx *bolt.Tx) error {
bk := createBucketIfNotExist(t, tx, tc.srcBucketPath...)
insertRandKeysValuesBucket(t, bk, rand.Intn(4096))
createBucketIfNotExist(t, tx, tc.dstBucketPath...)

return nil
}); err != nil {
t.Fatal(err)
}
db.MustCheck()

// act
//var tmpFile string
if err := db.Update(func(tx *bolt.Tx) error {
srcBucket := retrieveParentBucket(t, tx, tc.srcBucketPath...)
dstBucket := retrieveChildBucket(t, tx, tc.dstBucketPath...)
bucketToMove := tc.srcBucketPath[len(tc.srcBucketPath)-1]

//// dump bucketToMove to bbolt file for assertion
//bk := srcBucket.Bucket([]byte(bucketToMove))
//tmpFile = dumpBucketToFile(t, bk)

mErr := srcBucket.MoveBucket([]byte(bucketToMove), dstBucket)
require.Equal(t, tc.expErr, mErr)

return nil
}); err != nil {
t.Fatal(err)
}
db.MustCheck()

// assert
if err := db.View(func(tx *bolt.Tx) error {
srcBucket := retrieveParentBucket(t, tx, tc.srcBucketPath...)
bucketToMove := tc.srcBucketPath[len(tc.srcBucketPath)-1]

if bk := srcBucket.Bucket([]byte(bucketToMove)); bk != nil {
t.Fatalf("expected childBucket %v to be moved from srcBucket %v", bucketToMove, srcBucket)
}

dstBucket := retrieveChildBucket(t, tx, tc.dstBucketPath...)
if bk := dstBucket.Bucket([]byte(bucketToMove)); bk == nil {
t.Fatalf("expected childBucket %v to be child of dstBucket %v", bucketToMove, dstBucket)
}

childBucket := dstBucket.Bucket([]byte(bucketToMove))
if childBucket == nil {
t.Fatalf("expected subBucket %v to exist within dstBucket %v", bucketToMove, dstBucket)
}

//bucketOnDisk, err := os.ReadFile(tmpFile)
//if err != nil {
// t.Fatalf("error reading tmp file %v", tmpFile)
//}
//require.Equal(t, bucketOnDisk, childBucket.Write())

return nil
}); err != nil {
t.Fatal(err)
}
db.MustCheck()
})
}
}
func createBucketIfNotExist(t testing.TB, tx *bolt.Tx, paths ...string) *bolt.Bucket {
t.Helper()

bk, err := tx.CreateBucketIfNotExists([]byte(paths[0]))
if err != nil {
t.Fatalf("error creating bucket %v: %v", paths[0], err)
}

for _, key := range paths[1:] {
bk, err = bk.CreateBucketIfNotExists([]byte(key))
if err != nil {
t.Fatalf("error creating bucket %v: %v", key, err)
}
}

return bk
}

func retrieveParentBucket(t testing.TB, tx *bolt.Tx, paths ...string) *bolt.Bucket {
paths = paths[:len(paths)-1]
return retrieveChildBucket(t, tx, paths...)
}

func retrieveChildBucket(t testing.TB, tx *bolt.Tx, paths ...string) *bolt.Bucket {
t.Helper()

var bk *bolt.Bucket = nil
for _, path := range paths {
if bk == nil {
bk = tx.Bucket([]byte(path))
} else {
bk = bk.Bucket([]byte(path))
}
if bk == nil {
t.Fatalf("error retrieving bucket %v within paths %v", path, strings.TrimSuffix(strings.Join(paths, "->"), "->"))
}
}
return bk
}

func dumpBucketToFile(t testing.TB, bk *bolt.Bucket) string {
tmpFile := tempfile()
f, err := os.Create(tmpFile)
if err != nil {
t.Fatalf("error creating tmp file %v: %v", tmpFile, err)
}
defer f.Close()

data := bk.Write()
_, err = f.Write(data)
if err != nil {
t.Fatalf("error writing bucket %v to file %v tmpFile", bk, tmpFile)
}

return tmpFile
}

func insertRandKeysValuesBucket(t testing.TB, bk *bolt.Bucket, n int) {

var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
var min, max = 1, 1024

for i := 0; i < n; i++ {
// generate rand key/value length
keyLength := rand.Intn(max-min) + min
valLength := rand.Intn(max-min) + min

keyData := make([]rune, keyLength)
valData := make([]rune, valLength)

for j := range keyData {
keyData[j] = letters[rand.Intn(len(letters))]
}

for j := range valData {
valData[j] = letters[rand.Intn(len(letters))]
}

pErr := bk.Put([]byte(string(keyData)), []byte(string(valData)))
if pErr != nil {
t.Fatalf("error inserting key %v and value %v in bucket %v: %v", string(keyData), string(valData), bk.String(), pErr)
}
}

}

0 comments on commit c6c5d86

Please sign in to comment.