mirror of https://github.com/hak5/bolt.git
247 lines
6.2 KiB
Go
247 lines
6.2 KiB
Go
package bolt
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"sort"
|
|
"testing"
|
|
"testing/quick"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
// Ensure that the database can retrieve a list of buckets.
|
|
func TestTransactionBuckets(t *testing.T) {
|
|
withOpenDB(func(db *DB, path string) {
|
|
db.CreateBucket("foo")
|
|
db.CreateBucket("bar")
|
|
db.CreateBucket("baz")
|
|
buckets, err := db.Buckets()
|
|
if assert.NoError(t, err) && assert.Equal(t, len(buckets), 3) {
|
|
assert.Equal(t, buckets[0].Name(), "bar")
|
|
assert.Equal(t, buckets[1].Name(), "baz")
|
|
assert.Equal(t, buckets[2].Name(), "foo")
|
|
}
|
|
})
|
|
}
|
|
|
|
// Ensure that a Transaction can retrieve a bucket.
|
|
func TestTransactionBucketMissing(t *testing.T) {
|
|
withOpenDB(func(db *DB, path string) {
|
|
db.CreateBucket("widgets")
|
|
b, err := db.Bucket("widgets")
|
|
assert.NoError(t, err)
|
|
if assert.NotNil(t, b) {
|
|
assert.Equal(t, "widgets", b.Name())
|
|
}
|
|
})
|
|
}
|
|
|
|
// Ensure that a Transaction retrieving a non-existent key returns nil.
|
|
func TestTransactionGetMissing(t *testing.T) {
|
|
withOpenDB(func(db *DB, path string) {
|
|
db.CreateBucket("widgets")
|
|
db.Put("widgets", []byte("foo"), []byte("bar"))
|
|
value, err := db.Get("widgets", []byte("no_such_key"))
|
|
assert.NoError(t, err)
|
|
assert.Nil(t, value)
|
|
})
|
|
}
|
|
|
|
// Ensure that a Transaction cursor can iterate over an empty bucket without error.
|
|
func TestTransactionCursorEmptyBucket(t *testing.T) {
|
|
withOpenDB(func(db *DB, path string) {
|
|
db.CreateBucket("widgets")
|
|
txn, _ := db.Transaction()
|
|
c, err := txn.Cursor("widgets")
|
|
assert.NoError(t, err)
|
|
k, v := c.First()
|
|
assert.Nil(t, k)
|
|
assert.Nil(t, v)
|
|
txn.Close()
|
|
})
|
|
}
|
|
|
|
// Ensure that a Transaction returns a nil when a bucket doesn't exist.
|
|
func TestTransactionCursorMissingBucket(t *testing.T) {
|
|
withOpenDB(func(db *DB, path string) {
|
|
db.CreateBucket("widgets")
|
|
txn, _ := db.Transaction()
|
|
c, err := txn.Cursor("woojits")
|
|
assert.Nil(t, c)
|
|
assert.Equal(t, err, ErrBucketNotFound)
|
|
txn.Close()
|
|
})
|
|
}
|
|
|
|
// Ensure that a Transaction cursor can iterate over a single root with a couple elements.
|
|
func TestTransactionCursorLeafRoot(t *testing.T) {
|
|
withOpenDB(func(db *DB, path string) {
|
|
db.CreateBucket("widgets")
|
|
db.Put("widgets", []byte("baz"), []byte{})
|
|
db.Put("widgets", []byte("foo"), []byte{0})
|
|
db.Put("widgets", []byte("bar"), []byte{1})
|
|
txn, _ := db.Transaction()
|
|
c, err := txn.Cursor("widgets")
|
|
assert.NoError(t, err)
|
|
|
|
k, v := c.First()
|
|
assert.Equal(t, string(k), "bar")
|
|
assert.Equal(t, v, []byte{1})
|
|
|
|
k, v = c.Next()
|
|
assert.Equal(t, string(k), "baz")
|
|
assert.Equal(t, v, []byte{})
|
|
|
|
k, v = c.Next()
|
|
assert.Equal(t, string(k), "foo")
|
|
assert.Equal(t, v, []byte{0})
|
|
|
|
k, v = c.Next()
|
|
assert.Nil(t, k)
|
|
assert.Nil(t, v)
|
|
|
|
k, v = c.Next()
|
|
assert.Nil(t, k)
|
|
assert.Nil(t, v)
|
|
|
|
txn.Close()
|
|
})
|
|
}
|
|
|
|
// Ensure that a Transaction cursor can iterate in reverse over a single root with a couple elements.
|
|
func TestTransactionCursorLeafRootReverse(t *testing.T) {
|
|
withOpenDB(func(db *DB, path string) {
|
|
db.CreateBucket("widgets")
|
|
db.Put("widgets", []byte("baz"), []byte{})
|
|
db.Put("widgets", []byte("foo"), []byte{0})
|
|
db.Put("widgets", []byte("bar"), []byte{1})
|
|
txn, _ := db.Transaction()
|
|
c, err := txn.Cursor("widgets")
|
|
assert.NoError(t, err)
|
|
|
|
k, v := c.Last()
|
|
assert.Equal(t, string(k), "foo")
|
|
assert.Equal(t, v, []byte{0})
|
|
|
|
k, v = c.Prev()
|
|
assert.Equal(t, string(k), "baz")
|
|
assert.Equal(t, v, []byte{})
|
|
|
|
k, v = c.Prev()
|
|
assert.Equal(t, string(k), "bar")
|
|
assert.Equal(t, v, []byte{1})
|
|
|
|
k, v = c.Prev()
|
|
assert.Nil(t, k)
|
|
assert.Nil(t, v)
|
|
|
|
k, v = c.Prev()
|
|
assert.Nil(t, k)
|
|
assert.Nil(t, v)
|
|
|
|
txn.Close()
|
|
})
|
|
}
|
|
|
|
// Ensure that a Transaction cursor can restart from the beginning.
|
|
func TestTransactionCursorRestart(t *testing.T) {
|
|
withOpenDB(func(db *DB, path string) {
|
|
db.CreateBucket("widgets")
|
|
db.Put("widgets", []byte("bar"), []byte{})
|
|
db.Put("widgets", []byte("foo"), []byte{})
|
|
|
|
txn, _ := db.Transaction()
|
|
c, err := txn.Cursor("widgets")
|
|
assert.NoError(t, err)
|
|
|
|
k, _ := c.First()
|
|
assert.Equal(t, string(k), "bar")
|
|
|
|
k, _ = c.Next()
|
|
assert.Equal(t, string(k), "foo")
|
|
|
|
k, _ = c.First()
|
|
assert.Equal(t, string(k), "bar")
|
|
|
|
k, _ = c.Next()
|
|
assert.Equal(t, string(k), "foo")
|
|
|
|
txn.Close()
|
|
})
|
|
}
|
|
|
|
// Ensure that a transaction can iterate over all elements in a bucket.
|
|
func TestTransactionCursorIterate(t *testing.T) {
|
|
f := func(items testdata) bool {
|
|
withOpenDB(func(db *DB, path string) {
|
|
// Bulk insert all values.
|
|
db.CreateBucket("widgets")
|
|
rwtxn, _ := db.RWTransaction()
|
|
for _, item := range items {
|
|
assert.NoError(t, rwtxn.Put("widgets", item.Key, item.Value))
|
|
}
|
|
assert.NoError(t, rwtxn.Commit())
|
|
|
|
// Sort test data.
|
|
sort.Sort(items)
|
|
|
|
// Iterate over all items and check consistency.
|
|
var index = 0
|
|
txn, _ := db.Transaction()
|
|
c, err := txn.Cursor("widgets")
|
|
assert.NoError(t, err)
|
|
for k, v := c.First(); k != nil && index < len(items); k, v = c.Next() {
|
|
assert.Equal(t, k, items[index].Key)
|
|
assert.Equal(t, v, items[index].Value)
|
|
index++
|
|
}
|
|
assert.Equal(t, len(items), index)
|
|
txn.Close()
|
|
})
|
|
fmt.Fprint(os.Stderr, ".")
|
|
return true
|
|
}
|
|
if err := quick.Check(f, qconfig()); err != nil {
|
|
t.Error(err)
|
|
}
|
|
fmt.Fprint(os.Stderr, "\n")
|
|
}
|
|
|
|
// Ensure that a transaction can iterate over all elements in a bucket in reverse.
|
|
func TestTransactionCursorIterateReverse(t *testing.T) {
|
|
f := func(items testdata) bool {
|
|
withOpenDB(func(db *DB, path string) {
|
|
// Bulk insert all values.
|
|
db.CreateBucket("widgets")
|
|
rwtxn, _ := db.RWTransaction()
|
|
for _, item := range items {
|
|
assert.NoError(t, rwtxn.Put("widgets", item.Key, item.Value))
|
|
}
|
|
assert.NoError(t, rwtxn.Commit())
|
|
|
|
// Sort test data.
|
|
sort.Sort(revtestdata(items))
|
|
|
|
// Iterate over all items and check consistency.
|
|
var index = 0
|
|
txn, _ := db.Transaction()
|
|
c, err := txn.Cursor("widgets")
|
|
assert.NoError(t, err)
|
|
for k, v := c.Last(); k != nil && index < len(items); k, v = c.Prev() {
|
|
assert.Equal(t, k, items[index].Key)
|
|
assert.Equal(t, v, items[index].Value)
|
|
index++
|
|
}
|
|
assert.Equal(t, len(items), index)
|
|
txn.Close()
|
|
})
|
|
fmt.Fprint(os.Stderr, ".")
|
|
return true
|
|
}
|
|
if err := quick.Check(f, qconfig()); err != nil {
|
|
t.Error(err)
|
|
}
|
|
fmt.Fprint(os.Stderr, "\n")
|
|
}
|