Tests: Migrate from test DB to btesting.DB

Signed-off-by: Piotr Tabor <ptab@google.com>
pull/360/head
Piotr Tabor 2022-12-20 17:12:04 +01:00
parent f3e164d8dd
commit 26cc5e3e8b
7 changed files with 166 additions and 420 deletions

View File

@ -15,13 +15,14 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
bolt "go.etcd.io/bbolt" bolt "go.etcd.io/bbolt"
"go.etcd.io/bbolt/internal/btesting"
) )
// Ensure that a bucket that gets a non-existent key returns nil. // Ensure that a bucket that gets a non-existent key returns nil.
func TestBucket_Get_NonExistent(t *testing.T) { func TestBucket_Get_NonExistent(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
b, err := tx.CreateBucket([]byte("widgets")) b, err := tx.CreateBucket([]byte("widgets"))
@ -39,8 +40,7 @@ func TestBucket_Get_NonExistent(t *testing.T) {
// Ensure that a bucket can read a value that is not flushed yet. // Ensure that a bucket can read a value that is not flushed yet.
func TestBucket_Get_FromNode(t *testing.T) { func TestBucket_Get_FromNode(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
b, err := tx.CreateBucket([]byte("widgets")) b, err := tx.CreateBucket([]byte("widgets"))
@ -61,8 +61,7 @@ func TestBucket_Get_FromNode(t *testing.T) {
// Ensure that a bucket retrieved via Get() returns a nil. // Ensure that a bucket retrieved via Get() returns a nil.
func TestBucket_Get_IncompatibleValue(t *testing.T) { func TestBucket_Get_IncompatibleValue(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
_, err := tx.CreateBucket([]byte("widgets")) _, err := tx.CreateBucket([]byte("widgets"))
if err != nil { if err != nil {
@ -87,8 +86,7 @@ func TestBucket_Get_IncompatibleValue(t *testing.T) {
// //
// https://github.com/boltdb/bolt/issues/544 // https://github.com/boltdb/bolt/issues/544
func TestBucket_Get_Capacity(t *testing.T) { func TestBucket_Get_Capacity(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
// Write key to a bucket. // Write key to a bucket.
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
@ -125,8 +123,7 @@ func TestBucket_Get_Capacity(t *testing.T) {
// Ensure that a bucket can write a key/value. // Ensure that a bucket can write a key/value.
func TestBucket_Put(t *testing.T) { func TestBucket_Put(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
b, err := tx.CreateBucket([]byte("widgets")) b, err := tx.CreateBucket([]byte("widgets"))
if err != nil { if err != nil {
@ -148,8 +145,7 @@ func TestBucket_Put(t *testing.T) {
// Ensure that a bucket can rewrite a key in the same transaction. // Ensure that a bucket can rewrite a key in the same transaction.
func TestBucket_Put_Repeat(t *testing.T) { func TestBucket_Put_Repeat(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
b, err := tx.CreateBucket([]byte("widgets")) b, err := tx.CreateBucket([]byte("widgets"))
if err != nil { if err != nil {
@ -174,8 +170,7 @@ func TestBucket_Put_Repeat(t *testing.T) {
// Ensure that a bucket can write a bunch of large values. // Ensure that a bucket can write a bunch of large values.
func TestBucket_Put_Large(t *testing.T) { func TestBucket_Put_Large(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
count, factor := 100, 200 count, factor := 100, 200
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
@ -216,8 +211,7 @@ func TestDB_Put_VeryLarge(t *testing.T) {
n, batchN := 400000, 200000 n, batchN := 400000, 200000
ksize, vsize := 8, 500 ksize, vsize := 8, 500
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
for i := 0; i < n; i += batchN { for i := 0; i < n; i += batchN {
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
@ -241,8 +235,7 @@ func TestDB_Put_VeryLarge(t *testing.T) {
// Ensure that a setting a value on a key with a bucket value returns an error. // Ensure that a setting a value on a key with a bucket value returns an error.
func TestBucket_Put_IncompatibleValue(t *testing.T) { func TestBucket_Put_IncompatibleValue(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
b0, err := tx.CreateBucket([]byte("widgets")) b0, err := tx.CreateBucket([]byte("widgets"))
@ -264,8 +257,7 @@ func TestBucket_Put_IncompatibleValue(t *testing.T) {
// Ensure that a setting a value while the transaction is closed returns an error. // Ensure that a setting a value while the transaction is closed returns an error.
func TestBucket_Put_Closed(t *testing.T) { func TestBucket_Put_Closed(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
tx, err := db.Begin(true) tx, err := db.Begin(true)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -287,8 +279,7 @@ func TestBucket_Put_Closed(t *testing.T) {
// Ensure that setting a value on a read-only bucket returns an error. // Ensure that setting a value on a read-only bucket returns an error.
func TestBucket_Put_ReadOnly(t *testing.T) { func TestBucket_Put_ReadOnly(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
if _, err := tx.CreateBucket([]byte("widgets")); err != nil { if _, err := tx.CreateBucket([]byte("widgets")); err != nil {
@ -312,8 +303,7 @@ func TestBucket_Put_ReadOnly(t *testing.T) {
// Ensure that a bucket can delete an existing key. // Ensure that a bucket can delete an existing key.
func TestBucket_Delete(t *testing.T) { func TestBucket_Delete(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
b, err := tx.CreateBucket([]byte("widgets")) b, err := tx.CreateBucket([]byte("widgets"))
@ -337,8 +327,7 @@ func TestBucket_Delete(t *testing.T) {
// Ensure that deleting a large set of keys will work correctly. // Ensure that deleting a large set of keys will work correctly.
func TestBucket_Delete_Large(t *testing.T) { func TestBucket_Delete_Large(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
b, err := tx.CreateBucket([]byte("widgets")) b, err := tx.CreateBucket([]byte("widgets"))
@ -388,8 +377,7 @@ func TestBucket_Delete_FreelistOverflow(t *testing.T) {
t.Skip("skipping test in short mode.") t.Skip("skipping test in short mode.")
} }
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
k := make([]byte, 16) k := make([]byte, 16)
// The bigger the pages - the more values we need to write. // The bigger the pages - the more values we need to write.
@ -436,9 +424,7 @@ func TestBucket_Delete_FreelistOverflow(t *testing.T) {
} }
// Free page count should be preserved on reopen. // Free page count should be preserved on reopen.
if err := db.DB.Close(); err != nil { db.MustClose()
t.Fatal(err)
}
db.MustReopen() db.MustReopen()
if reopenFreePages := db.Stats().FreePageN; freePages != reopenFreePages { if reopenFreePages := db.Stats().FreePageN; freePages != reopenFreePages {
t.Fatalf("expected %d free pages, got %+v", freePages, db.Stats()) t.Fatalf("expected %d free pages, got %+v", freePages, db.Stats())
@ -447,8 +433,7 @@ func TestBucket_Delete_FreelistOverflow(t *testing.T) {
// Ensure that deleting of non-existing key is a no-op. // Ensure that deleting of non-existing key is a no-op.
func TestBucket_Delete_NonExisting(t *testing.T) { func TestBucket_Delete_NonExisting(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
b, err := tx.CreateBucket([]byte("widgets")) b, err := tx.CreateBucket([]byte("widgets"))
@ -480,8 +465,7 @@ func TestBucket_Delete_NonExisting(t *testing.T) {
// Ensure that accessing and updating nested buckets is ok across transactions. // Ensure that accessing and updating nested buckets is ok across transactions.
func TestBucket_Nested(t *testing.T) { func TestBucket_Nested(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
// Create a widgets bucket. // Create a widgets bucket.
@ -567,8 +551,7 @@ func TestBucket_Nested(t *testing.T) {
// Ensure that deleting a bucket using Delete() returns an error. // Ensure that deleting a bucket using Delete() returns an error.
func TestBucket_Delete_Bucket(t *testing.T) { func TestBucket_Delete_Bucket(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
b, err := tx.CreateBucket([]byte("widgets")) b, err := tx.CreateBucket([]byte("widgets"))
if err != nil { if err != nil {
@ -588,8 +571,7 @@ func TestBucket_Delete_Bucket(t *testing.T) {
// Ensure that deleting a key on a read-only bucket returns an error. // Ensure that deleting a key on a read-only bucket returns an error.
func TestBucket_Delete_ReadOnly(t *testing.T) { func TestBucket_Delete_ReadOnly(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
if _, err := tx.CreateBucket([]byte("widgets")); err != nil { if _, err := tx.CreateBucket([]byte("widgets")); err != nil {
@ -612,8 +594,7 @@ func TestBucket_Delete_ReadOnly(t *testing.T) {
// Ensure that a deleting value while the transaction is closed returns an error. // Ensure that a deleting value while the transaction is closed returns an error.
func TestBucket_Delete_Closed(t *testing.T) { func TestBucket_Delete_Closed(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
tx, err := db.Begin(true) tx, err := db.Begin(true)
if err != nil { if err != nil {
@ -635,8 +616,7 @@ func TestBucket_Delete_Closed(t *testing.T) {
// Ensure that deleting a bucket causes nested buckets to be deleted. // Ensure that deleting a bucket causes nested buckets to be deleted.
func TestBucket_DeleteBucket_Nested(t *testing.T) { func TestBucket_DeleteBucket_Nested(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
widgets, err := tx.CreateBucket([]byte("widgets")) widgets, err := tx.CreateBucket([]byte("widgets"))
@ -667,8 +647,7 @@ func TestBucket_DeleteBucket_Nested(t *testing.T) {
// Ensure that deleting a bucket causes nested buckets to be deleted after they have been committed. // Ensure that deleting a bucket causes nested buckets to be deleted after they have been committed.
func TestBucket_DeleteBucket_Nested2(t *testing.T) { func TestBucket_DeleteBucket_Nested2(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
widgets, err := tx.CreateBucket([]byte("widgets")) widgets, err := tx.CreateBucket([]byte("widgets"))
@ -734,8 +713,7 @@ func TestBucket_DeleteBucket_Nested2(t *testing.T) {
// Ensure that deleting a child bucket with multiple pages causes all pages to get collected. // Ensure that deleting a child bucket with multiple pages causes all pages to get collected.
// NOTE: Consistency check in bolt_test.DB.Close() will panic if pages not freed properly. // NOTE: Consistency check in bolt_test.DB.Close() will panic if pages not freed properly.
func TestBucket_DeleteBucket_Large(t *testing.T) { func TestBucket_DeleteBucket_Large(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
widgets, err := tx.CreateBucket([]byte("widgets")) widgets, err := tx.CreateBucket([]byte("widgets"))
@ -770,8 +748,7 @@ func TestBucket_DeleteBucket_Large(t *testing.T) {
// Ensure that a simple value retrieved via Bucket() returns a nil. // Ensure that a simple value retrieved via Bucket() returns a nil.
func TestBucket_Bucket_IncompatibleValue(t *testing.T) { func TestBucket_Bucket_IncompatibleValue(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
widgets, err := tx.CreateBucket([]byte("widgets")) widgets, err := tx.CreateBucket([]byte("widgets"))
@ -793,8 +770,7 @@ func TestBucket_Bucket_IncompatibleValue(t *testing.T) {
// Ensure that creating a bucket on an existing non-bucket key returns an error. // Ensure that creating a bucket on an existing non-bucket key returns an error.
func TestBucket_CreateBucket_IncompatibleValue(t *testing.T) { func TestBucket_CreateBucket_IncompatibleValue(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
widgets, err := tx.CreateBucket([]byte("widgets")) widgets, err := tx.CreateBucket([]byte("widgets"))
if err != nil { if err != nil {
@ -815,8 +791,7 @@ func TestBucket_CreateBucket_IncompatibleValue(t *testing.T) {
// Ensure that deleting a bucket on an existing non-bucket key returns an error. // Ensure that deleting a bucket on an existing non-bucket key returns an error.
func TestBucket_DeleteBucket_IncompatibleValue(t *testing.T) { func TestBucket_DeleteBucket_IncompatibleValue(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
widgets, err := tx.CreateBucket([]byte("widgets")) widgets, err := tx.CreateBucket([]byte("widgets"))
@ -837,8 +812,7 @@ func TestBucket_DeleteBucket_IncompatibleValue(t *testing.T) {
// Ensure bucket can set and update its sequence number. // Ensure bucket can set and update its sequence number.
func TestBucket_Sequence(t *testing.T) { func TestBucket_Sequence(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
bkt, err := tx.CreateBucket([]byte("0")) bkt, err := tx.CreateBucket([]byte("0"))
@ -879,8 +853,7 @@ func TestBucket_Sequence(t *testing.T) {
// Ensure that a bucket can return an autoincrementing sequence. // Ensure that a bucket can return an autoincrementing sequence.
func TestBucket_NextSequence(t *testing.T) { func TestBucket_NextSequence(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
widgets, err := tx.CreateBucket([]byte("widgets")) widgets, err := tx.CreateBucket([]byte("widgets"))
@ -922,8 +895,7 @@ func TestBucket_NextSequence(t *testing.T) {
// the only thing updated on the bucket. // the only thing updated on the bucket.
// https://github.com/boltdb/bolt/issues/296 // https://github.com/boltdb/bolt/issues/296
func TestBucket_NextSequence_Persist(t *testing.T) { func TestBucket_NextSequence_Persist(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
if _, err := tx.CreateBucket([]byte("widgets")); err != nil { if _, err := tx.CreateBucket([]byte("widgets")); err != nil {
@ -958,8 +930,7 @@ func TestBucket_NextSequence_Persist(t *testing.T) {
// Ensure that retrieving the next sequence on a read-only bucket returns an error. // Ensure that retrieving the next sequence on a read-only bucket returns an error.
func TestBucket_NextSequence_ReadOnly(t *testing.T) { func TestBucket_NextSequence_ReadOnly(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
if _, err := tx.CreateBucket([]byte("widgets")); err != nil { if _, err := tx.CreateBucket([]byte("widgets")); err != nil {
@ -983,8 +954,7 @@ func TestBucket_NextSequence_ReadOnly(t *testing.T) {
// Ensure that retrieving the next sequence for a bucket on a closed database return an error. // Ensure that retrieving the next sequence for a bucket on a closed database return an error.
func TestBucket_NextSequence_Closed(t *testing.T) { func TestBucket_NextSequence_Closed(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
tx, err := db.Begin(true) tx, err := db.Begin(true)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -1003,8 +973,7 @@ func TestBucket_NextSequence_Closed(t *testing.T) {
// Ensure a user can loop over all key/value pairs in a bucket. // Ensure a user can loop over all key/value pairs in a bucket.
func TestBucket_ForEach(t *testing.T) { func TestBucket_ForEach(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
type kv struct { type kv struct {
k []byte k []byte
@ -1053,8 +1022,7 @@ func TestBucket_ForEach(t *testing.T) {
} }
func TestBucket_ForEachBucket(t *testing.T) { func TestBucket_ForEachBucket(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
expectedItems := [][]byte{ expectedItems := [][]byte{
[]byte("csubbucket"), []byte("csubbucket"),
@ -1098,8 +1066,7 @@ func TestBucket_ForEachBucket(t *testing.T) {
} }
func TestBucket_ForEachBucket_NoBuckets(t *testing.T) { func TestBucket_ForEachBucket_NoBuckets(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
verifyReads := func(b *bolt.Bucket) { verifyReads := func(b *bolt.Bucket) {
var items [][]byte var items [][]byte
@ -1137,8 +1104,7 @@ func TestBucket_ForEachBucket_NoBuckets(t *testing.T) {
// Ensure a database can stop iteration early. // Ensure a database can stop iteration early.
func TestBucket_ForEach_ShortCircuit(t *testing.T) { func TestBucket_ForEach_ShortCircuit(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
b, err := tx.CreateBucket([]byte("widgets")) b, err := tx.CreateBucket([]byte("widgets"))
if err != nil { if err != nil {
@ -1176,8 +1142,7 @@ func TestBucket_ForEach_ShortCircuit(t *testing.T) {
// Ensure that looping over a bucket on a closed database returns an error. // Ensure that looping over a bucket on a closed database returns an error.
func TestBucket_ForEach_Closed(t *testing.T) { func TestBucket_ForEach_Closed(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
tx, err := db.Begin(true) tx, err := db.Begin(true)
if err != nil { if err != nil {
@ -1200,8 +1165,7 @@ func TestBucket_ForEach_Closed(t *testing.T) {
// Ensure that an error is returned when inserting with an empty key. // Ensure that an error is returned when inserting with an empty key.
func TestBucket_Put_EmptyKey(t *testing.T) { func TestBucket_Put_EmptyKey(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
b, err := tx.CreateBucket([]byte("widgets")) b, err := tx.CreateBucket([]byte("widgets"))
@ -1222,8 +1186,7 @@ func TestBucket_Put_EmptyKey(t *testing.T) {
// Ensure that an error is returned when inserting with a key that's too large. // Ensure that an error is returned when inserting with a key that's too large.
func TestBucket_Put_KeyTooLarge(t *testing.T) { func TestBucket_Put_KeyTooLarge(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
b, err := tx.CreateBucket([]byte("widgets")) b, err := tx.CreateBucket([]byte("widgets"))
if err != nil { if err != nil {
@ -1245,8 +1208,7 @@ func TestBucket_Put_ValueTooLarge(t *testing.T) {
t.Skip("not enough RAM for test") t.Skip("not enough RAM for test")
} }
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
b, err := tx.CreateBucket([]byte("widgets")) b, err := tx.CreateBucket([]byte("widgets"))
@ -1268,8 +1230,7 @@ func TestBucket_Stats(t *testing.T) {
t.Skip("skipping test in short mode") t.Skip("skipping test in short mode")
} }
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
// Add bucket with fewer keys but one big value. // Add bucket with fewer keys but one big value.
bigKey := []byte("really-big-value") bigKey := []byte("really-big-value")
@ -1361,8 +1322,7 @@ func TestBucket_Stats_RandomFill(t *testing.T) {
t.Skip("invalid page size for test") t.Skip("invalid page size for test")
} }
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
// Add a set of values in random order. It will be the same random // Add a set of values in random order. It will be the same random
// order so we can maintain consistency between test runs. // order so we can maintain consistency between test runs.
@ -1423,8 +1383,7 @@ func TestBucket_Stats_RandomFill(t *testing.T) {
// Ensure a bucket can calculate stats. // Ensure a bucket can calculate stats.
func TestBucket_Stats_Small(t *testing.T) { func TestBucket_Stats_Small(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
// Add a bucket that fits on a single root leaf. // Add a bucket that fits on a single root leaf.
@ -1487,8 +1446,7 @@ func TestBucket_Stats_Small(t *testing.T) {
} }
func TestBucket_Stats_EmptyBucket(t *testing.T) { func TestBucket_Stats_EmptyBucket(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
// Add a bucket that fits on a single root leaf. // Add a bucket that fits on a single root leaf.
@ -1547,8 +1505,7 @@ func TestBucket_Stats_EmptyBucket(t *testing.T) {
// Ensure a bucket can calculate stats. // Ensure a bucket can calculate stats.
func TestBucket_Stats_Nested(t *testing.T) { func TestBucket_Stats_Nested(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
b, err := tx.CreateBucket([]byte("foo")) b, err := tx.CreateBucket([]byte("foo"))
@ -1653,8 +1610,7 @@ func TestBucket_Stats_Large(t *testing.T) {
t.Skip("skipping test in short mode.") t.Skip("skipping test in short mode.")
} }
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
var index int var index int
for i := 0; i < 100; i++ { for i := 0; i < 100; i++ {
@ -1731,7 +1687,7 @@ func TestBucket_Put_Single(t *testing.T) {
index := 0 index := 0
if err := quick.Check(func(items testdata) bool { if err := quick.Check(func(items testdata) bool {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose() defer db.MustClose()
m := make(map[string][]byte) m := make(map[string][]byte)
@ -1788,7 +1744,7 @@ func TestBucket_Put_Multiple(t *testing.T) {
} }
if err := quick.Check(func(items testdata) bool { if err := quick.Check(func(items testdata) bool {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose() defer db.MustClose()
// Bulk insert all values. // Bulk insert all values.
@ -1841,7 +1797,7 @@ func TestBucket_Delete_Quick(t *testing.T) {
} }
if err := quick.Check(func(items testdata) bool { if err := quick.Check(func(items testdata) bool {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose() defer db.MustClose()
// Bulk insert all values. // Bulk insert all values.

View File

@ -4,6 +4,7 @@ import (
"bytes" "bytes"
"encoding/binary" "encoding/binary"
"fmt" "fmt"
"go.etcd.io/bbolt/internal/btesting"
"log" "log"
"os" "os"
"reflect" "reflect"
@ -16,8 +17,7 @@ import (
// Ensure that a cursor can return a reference to the bucket that created it. // Ensure that a cursor can return a reference to the bucket that created it.
func TestCursor_Bucket(t *testing.T) { func TestCursor_Bucket(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
b, err := tx.CreateBucket([]byte("widgets")) b, err := tx.CreateBucket([]byte("widgets"))
if err != nil { if err != nil {
@ -34,8 +34,7 @@ func TestCursor_Bucket(t *testing.T) {
// Ensure that a Tx cursor can seek to the appropriate keys. // Ensure that a Tx cursor can seek to the appropriate keys.
func TestCursor_Seek(t *testing.T) { func TestCursor_Seek(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
b, err := tx.CreateBucket([]byte("widgets")) b, err := tx.CreateBucket([]byte("widgets"))
if err != nil { if err != nil {
@ -104,8 +103,7 @@ func TestCursor_Seek(t *testing.T) {
} }
func TestCursor_Delete(t *testing.T) { func TestCursor_Delete(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
const count = 1000 const count = 1000
@ -167,8 +165,7 @@ func TestCursor_Delete(t *testing.T) {
// //
// Related: https://github.com/boltdb/bolt/pull/187 // Related: https://github.com/boltdb/bolt/pull/187
func TestCursor_Seek_Large(t *testing.T) { func TestCursor_Seek_Large(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
var count = 10000 var count = 10000
@ -231,8 +228,7 @@ func TestCursor_Seek_Large(t *testing.T) {
// Ensure that a cursor can iterate over an empty bucket without error. // Ensure that a cursor can iterate over an empty bucket without error.
func TestCursor_EmptyBucket(t *testing.T) { func TestCursor_EmptyBucket(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
_, err := tx.CreateBucket([]byte("widgets")) _, err := tx.CreateBucket([]byte("widgets"))
return err return err
@ -256,8 +252,7 @@ func TestCursor_EmptyBucket(t *testing.T) {
// Ensure that a Tx cursor can reverse iterate over an empty bucket without error. // Ensure that a Tx cursor can reverse iterate over an empty bucket without error.
func TestCursor_EmptyBucketReverse(t *testing.T) { func TestCursor_EmptyBucketReverse(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
_, err := tx.CreateBucket([]byte("widgets")) _, err := tx.CreateBucket([]byte("widgets"))
@ -281,8 +276,7 @@ func TestCursor_EmptyBucketReverse(t *testing.T) {
// Ensure that a Tx cursor can iterate over a single root with a couple elements. // Ensure that a Tx cursor can iterate over a single root with a couple elements.
func TestCursor_Iterate_Leaf(t *testing.T) { func TestCursor_Iterate_Leaf(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
b, err := tx.CreateBucket([]byte("widgets")) b, err := tx.CreateBucket([]byte("widgets"))
@ -352,8 +346,7 @@ func TestCursor_Iterate_Leaf(t *testing.T) {
// Ensure that a Tx cursor can iterate in reverse over a single root with a couple elements. // Ensure that a Tx cursor can iterate in reverse over a single root with a couple elements.
func TestCursor_LeafRootReverse(t *testing.T) { func TestCursor_LeafRootReverse(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
b, err := tx.CreateBucket([]byte("widgets")) b, err := tx.CreateBucket([]byte("widgets"))
@ -416,8 +409,7 @@ func TestCursor_LeafRootReverse(t *testing.T) {
// Ensure that a Tx cursor can restart from the beginning. // Ensure that a Tx cursor can restart from the beginning.
func TestCursor_Restart(t *testing.T) { func TestCursor_Restart(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
b, err := tx.CreateBucket([]byte("widgets")) b, err := tx.CreateBucket([]byte("widgets"))
@ -462,8 +454,7 @@ func TestCursor_Restart(t *testing.T) {
// Ensure that a cursor can skip over empty pages that have been deleted. // Ensure that a cursor can skip over empty pages that have been deleted.
func TestCursor_First_EmptyPages(t *testing.T) { func TestCursor_First_EmptyPages(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
// Create 1000 keys in the "widgets" bucket. // Create 1000 keys in the "widgets" bucket.
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
@ -509,8 +500,7 @@ func TestCursor_First_EmptyPages(t *testing.T) {
// Ensure that a cursor can skip over empty pages that have been deleted. // Ensure that a cursor can skip over empty pages that have been deleted.
func TestCursor_Last_EmptyPages(t *testing.T) { func TestCursor_Last_EmptyPages(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
// Create 1000 keys in the "widgets" bucket. // Create 1000 keys in the "widgets" bucket.
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
@ -557,7 +547,7 @@ func TestCursor_Last_EmptyPages(t *testing.T) {
// Ensure that a Tx can iterate over all elements in a bucket. // Ensure that a Tx can iterate over all elements in a bucket.
func TestCursor_QuickCheck(t *testing.T) { func TestCursor_QuickCheck(t *testing.T) {
f := func(items testdata) bool { f := func(items testdata) bool {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose() defer db.MustClose()
// Bulk insert all values. // Bulk insert all values.
@ -615,7 +605,7 @@ func TestCursor_QuickCheck(t *testing.T) {
// Ensure that a transaction can iterate over all elements in a bucket in reverse. // Ensure that a transaction can iterate over all elements in a bucket in reverse.
func TestCursor_QuickCheck_Reverse(t *testing.T) { func TestCursor_QuickCheck_Reverse(t *testing.T) {
f := func(items testdata) bool { f := func(items testdata) bool {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose() defer db.MustClose()
// Bulk insert all values. // Bulk insert all values.
@ -671,8 +661,7 @@ func TestCursor_QuickCheck_Reverse(t *testing.T) {
// Ensure that a Tx cursor can iterate over subbuckets. // Ensure that a Tx cursor can iterate over subbuckets.
func TestCursor_QuickCheck_BucketsOnly(t *testing.T) { func TestCursor_QuickCheck_BucketsOnly(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
b, err := tx.CreateBucket([]byte("widgets")) b, err := tx.CreateBucket([]byte("widgets"))
@ -713,8 +702,7 @@ func TestCursor_QuickCheck_BucketsOnly(t *testing.T) {
// Ensure that a Tx cursor can reverse iterate over subbuckets. // Ensure that a Tx cursor can reverse iterate over subbuckets.
func TestCursor_QuickCheck_BucketsOnly_Reverse(t *testing.T) { func TestCursor_QuickCheck_BucketsOnly_Reverse(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
b, err := tx.CreateBucket([]byte("widgets")) b, err := tx.CreateBucket([]byte("widgets"))

View File

@ -4,24 +4,22 @@ import (
"bytes" "bytes"
"encoding/binary" "encoding/binary"
"errors" "errors"
"flag"
"fmt" "fmt"
"go.etcd.io/bbolt/internal/btesting"
"hash/fnv" "hash/fnv"
"log" "log"
"math/rand" "math/rand"
"os" "os"
"path/filepath" "path/filepath"
"regexp"
"sync" "sync"
"testing" "testing"
"time" "time"
"unsafe" "unsafe"
bolt "go.etcd.io/bbolt" "github.com/stretchr/testify/require"
)
var statsFlag = flag.Bool("stats", false, "show performance stats") bolt "go.etcd.io/bbolt"
"go.etcd.io/bbolt/internal/btesting"
)
// pageSize is the size of one page in the data file. // pageSize is the size of one page in the data file.
const pageSize = 4096 const pageSize = 4096
@ -148,12 +146,11 @@ func TestOpen_ErrVersionMismatch(t *testing.T) {
} }
// Create empty database. // Create empty database.
db := MustOpenDB() db := btesting.MustCreateDB(t)
path := db.Path() path := db.Path()
defer db.MustClose()
// Close database. // Close database.
if err := db.DB.Close(); err != nil { if err := db.Close(); err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -185,12 +182,11 @@ func TestOpen_ErrChecksum(t *testing.T) {
} }
// Create empty database. // Create empty database.
db := MustOpenDB() db := btesting.MustCreateDB(t)
path := db.Path() path := db.Path()
defer db.MustClose()
// Close database. // Close database.
if err := db.DB.Close(); err != nil { if err := db.Close(); err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -272,9 +268,8 @@ func TestOpen_Size_Large(t *testing.T) {
} }
// Open a data file. // Open a data file.
db := MustOpenDB() db := btesting.MustCreateDB(t)
path := db.Path() path := db.Path()
defer db.MustClose()
pagesize := db.Info().PageSize pagesize := db.Info().PageSize
@ -454,8 +449,7 @@ func TestDB_Open_InitialMmapSize(t *testing.T) {
// TestDB_Open_ReadOnly checks a database in read only mode can read but not write. // TestDB_Open_ReadOnly checks a database in read only mode can read but not write.
func TestDB_Open_ReadOnly(t *testing.T) { func TestDB_Open_ReadOnly(t *testing.T) {
// Create a writable db, write k-v and close it. // Create a writable db, write k-v and close it.
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
b, err := tx.CreateBucket([]byte("widgets")) b, err := tx.CreateBucket([]byte("widgets"))
@ -473,7 +467,7 @@ func TestDB_Open_ReadOnly(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
f := db.f f := db.Path()
o := &bolt.Options{ReadOnly: true} o := &bolt.Options{ReadOnly: true}
readOnlyDB, err := bolt.Open(f, 0666, o) readOnlyDB, err := bolt.Open(f, 0666, o)
if err != nil { if err != nil {
@ -510,13 +504,11 @@ func TestDB_Open_ReadOnly(t *testing.T) {
func TestOpen_BigPage(t *testing.T) { func TestOpen_BigPage(t *testing.T) {
pageSize := os.Getpagesize() pageSize := os.Getpagesize()
db1 := MustOpenWithOption(&bolt.Options{PageSize: pageSize * 2}) db1 := btesting.MustCreateDBWithOption(t, &bolt.Options{PageSize: pageSize * 2})
defer db1.MustClose()
db2 := MustOpenWithOption(&bolt.Options{PageSize: pageSize * 4}) db2 := btesting.MustCreateDBWithOption(t, &bolt.Options{PageSize: pageSize * 4})
defer db2.MustClose()
if db1sz, db2sz := fileSize(db1.f), fileSize(db2.f); db1sz >= db2sz { if db1sz, db2sz := fileSize(db1.Path()), fileSize(db2.Path()); db1sz >= db2sz {
t.Errorf("expected %d < %d", db1sz, db2sz) t.Errorf("expected %d < %d", db1sz, db2sz)
} }
} }
@ -525,8 +517,7 @@ func TestOpen_BigPage(t *testing.T) {
// write-out after no free list sync will recover the free list // write-out after no free list sync will recover the free list
// and write it out. // and write it out.
func TestOpen_RecoverFreeList(t *testing.T) { func TestOpen_RecoverFreeList(t *testing.T) {
db := MustOpenWithOption(&bolt.Options{NoFreelistSync: true}) db := btesting.MustCreateDBWithOption(t, &bolt.Options{NoFreelistSync: true})
defer db.MustClose()
// Write some pages. // Write some pages.
tx, err := db.Begin(true) tx, err := db.Begin(true)
@ -568,6 +559,7 @@ func TestOpen_RecoverFreeList(t *testing.T) {
if err := db.DB.Close(); err != nil { if err := db.DB.Close(); err != nil {
t.Fatal(err) t.Fatal(err)
} }
db.MustClose()
// Record freelist count from opening with NoFreelistSync. // Record freelist count from opening with NoFreelistSync.
db.MustReopen() db.MustReopen()
@ -578,9 +570,10 @@ func TestOpen_RecoverFreeList(t *testing.T) {
if err := db.DB.Close(); err != nil { if err := db.DB.Close(); err != nil {
t.Fatal(err) t.Fatal(err)
} }
db.MustClose()
// Check free page count is reconstructed when opened with freelist sync. // Check free page count is reconstructed when opened with freelist sync.
db.o = &bolt.Options{} db.SetOptions(&bolt.Options{})
db.MustReopen() db.MustReopen()
// One less free page for syncing the free list on open. // One less free page for syncing the free list on open.
freepages-- freepages--
@ -599,33 +592,22 @@ func TestDB_Begin_ErrDatabaseNotOpen(t *testing.T) {
// Ensure that a read-write transaction can be retrieved. // Ensure that a read-write transaction can be retrieved.
func TestDB_BeginRW(t *testing.T) { func TestDB_BeginRW(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
tx, err := db.Begin(true) tx, err := db.Begin(true)
if err != nil { require.NoError(t, err)
t.Fatal(err) require.NotNil(t, tx, "expected tx")
} else if tx == nil { defer func() { require.NoError(t, tx.Commit()) }()
t.Fatal("expected tx")
}
if tx.DB() != db.DB { require.True(t, tx.Writable(), "expected writable tx")
t.Fatal("unexpected tx database") require.Same(t, db.DB, tx.DB())
} else if !tx.Writable() {
t.Fatal("expected writable tx")
}
if err := tx.Commit(); err != nil {
t.Fatal(err)
}
} }
// TestDB_Concurrent_WriteTo checks that issuing WriteTo operations concurrently // TestDB_Concurrent_WriteTo checks that issuing WriteTo operations concurrently
// with commits does not produce corrupted db files. // with commits does not produce corrupted db files.
func TestDB_Concurrent_WriteTo(t *testing.T) { func TestDB_Concurrent_WriteTo(t *testing.T) {
o := &bolt.Options{NoFreelistSync: false} o := &bolt.Options{NoFreelistSync: false}
db := MustOpenWithOption(o) db := btesting.MustCreateDBWithOption(t, o)
defer db.MustClose()
var wg sync.WaitGroup var wg sync.WaitGroup
wtxs, rtxs := 5, 5 wtxs, rtxs := 5, 5
@ -646,8 +628,7 @@ func TestDB_Concurrent_WriteTo(t *testing.T) {
panic(err) panic(err)
} }
f.Close() f.Close()
snap := &DB{nil, f.Name(), o} snap := btesting.MustOpenDBWithOption(t, f.Name(), o)
snap.MustReopen()
defer snap.MustClose() defer snap.MustClose()
snap.MustCheck() snap.MustCheck()
} }
@ -698,7 +679,7 @@ func TestDB_Close_PendingTx_RO(t *testing.T) { testDB_Close_PendingTx(t, false)
// Ensure that a database cannot close while transactions are open. // Ensure that a database cannot close while transactions are open.
func testDB_Close_PendingTx(t *testing.T, writable bool) { func testDB_Close_PendingTx(t *testing.T, writable bool) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
// Start transaction. // Start transaction.
tx, err := db.Begin(writable) tx, err := db.Begin(writable)
@ -748,8 +729,7 @@ func testDB_Close_PendingTx(t *testing.T, writable bool) {
// Ensure a database can provide a transactional block. // Ensure a database can provide a transactional block.
func TestDB_Update(t *testing.T) { func TestDB_Update(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
b, err := tx.CreateBucket([]byte("widgets")) b, err := tx.CreateBucket([]byte("widgets"))
if err != nil { if err != nil {
@ -797,8 +777,7 @@ func TestDB_Update_Closed(t *testing.T) {
// Ensure a panic occurs while trying to commit a managed transaction. // Ensure a panic occurs while trying to commit a managed transaction.
func TestDB_Update_ManualCommit(t *testing.T) { func TestDB_Update_ManualCommit(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
var panicked bool var panicked bool
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
@ -823,8 +802,7 @@ func TestDB_Update_ManualCommit(t *testing.T) {
// Ensure a panic occurs while trying to rollback a managed transaction. // Ensure a panic occurs while trying to rollback a managed transaction.
func TestDB_Update_ManualRollback(t *testing.T) { func TestDB_Update_ManualRollback(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
var panicked bool var panicked bool
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
@ -849,8 +827,7 @@ func TestDB_Update_ManualRollback(t *testing.T) {
// Ensure a panic occurs while trying to commit a managed transaction. // Ensure a panic occurs while trying to commit a managed transaction.
func TestDB_View_ManualCommit(t *testing.T) { func TestDB_View_ManualCommit(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
var panicked bool var panicked bool
if err := db.View(func(tx *bolt.Tx) error { if err := db.View(func(tx *bolt.Tx) error {
@ -875,8 +852,7 @@ func TestDB_View_ManualCommit(t *testing.T) {
// Ensure a panic occurs while trying to rollback a managed transaction. // Ensure a panic occurs while trying to rollback a managed transaction.
func TestDB_View_ManualRollback(t *testing.T) { func TestDB_View_ManualRollback(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
var panicked bool var panicked bool
if err := db.View(func(tx *bolt.Tx) error { if err := db.View(func(tx *bolt.Tx) error {
@ -901,8 +877,7 @@ func TestDB_View_ManualRollback(t *testing.T) {
// Ensure a write transaction that panics does not hold open locks. // Ensure a write transaction that panics does not hold open locks.
func TestDB_Update_Panic(t *testing.T) { func TestDB_Update_Panic(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
// Panic during update but recover. // Panic during update but recover.
func() { func() {
@ -945,8 +920,7 @@ func TestDB_Update_Panic(t *testing.T) {
// Ensure a database can return an error through a read-only transactional block. // Ensure a database can return an error through a read-only transactional block.
func TestDB_View_Error(t *testing.T) { func TestDB_View_Error(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
if err := db.View(func(tx *bolt.Tx) error { if err := db.View(func(tx *bolt.Tx) error {
return errors.New("xxx") return errors.New("xxx")
@ -957,8 +931,7 @@ func TestDB_View_Error(t *testing.T) {
// Ensure a read transaction that panics does not hold open locks. // Ensure a read transaction that panics does not hold open locks.
func TestDB_View_Panic(t *testing.T) { func TestDB_View_Panic(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
if _, err := tx.CreateBucket([]byte("widgets")); err != nil { if _, err := tx.CreateBucket([]byte("widgets")); err != nil {
@ -1000,8 +973,7 @@ func TestDB_View_Panic(t *testing.T) {
// Ensure that DB stats can be returned. // Ensure that DB stats can be returned.
func TestDB_Stats(t *testing.T) { func TestDB_Stats(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
_, err := tx.CreateBucket([]byte("widgets")) _, err := tx.CreateBucket([]byte("widgets"))
return err return err
@ -1021,8 +993,7 @@ func TestDB_Stats(t *testing.T) {
// Ensure that database pages are in expected order and type. // Ensure that database pages are in expected order and type.
func TestDB_Consistency(t *testing.T) { func TestDB_Consistency(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
_, err := tx.CreateBucket([]byte("widgets")) _, err := tx.CreateBucket([]byte("widgets"))
return err return err
@ -1107,8 +1078,7 @@ func TestDBStats_Sub(t *testing.T) {
// Ensure two functions can perform updates in a single batch. // Ensure two functions can perform updates in a single batch.
func TestDB_Batch(t *testing.T) { func TestDB_Batch(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
if _, err := tx.CreateBucket([]byte("widgets")); err != nil { if _, err := tx.CreateBucket([]byte("widgets")); err != nil {
@ -1152,8 +1122,7 @@ func TestDB_Batch(t *testing.T) {
} }
func TestDB_Batch_Panic(t *testing.T) { func TestDB_Batch_Panic(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
var sentinel int var sentinel int
var bork = &sentinel var bork = &sentinel
@ -1183,8 +1152,7 @@ func TestDB_Batch_Panic(t *testing.T) {
} }
func TestDB_BatchFull(t *testing.T) { func TestDB_BatchFull(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
_, err := tx.CreateBucket([]byte("widgets")) _, err := tx.CreateBucket([]byte("widgets"))
return err return err
@ -1242,8 +1210,7 @@ func TestDB_BatchFull(t *testing.T) {
} }
func TestDB_BatchTime(t *testing.T) { func TestDB_BatchTime(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
_, err := tx.CreateBucket([]byte("widgets")) _, err := tx.CreateBucket([]byte("widgets"))
return err return err
@ -1431,8 +1398,8 @@ func ExampleDB_Begin() {
} }
func BenchmarkDBBatchAutomatic(b *testing.B) { func BenchmarkDBBatchAutomatic(b *testing.B) {
db := MustOpenDB() db := btesting.MustCreateDB(b)
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
_, err := tx.CreateBucket([]byte("bench")) _, err := tx.CreateBucket([]byte("bench"))
return err return err
@ -1476,8 +1443,7 @@ func BenchmarkDBBatchAutomatic(b *testing.B) {
} }
func BenchmarkDBBatchSingle(b *testing.B) { func BenchmarkDBBatchSingle(b *testing.B) {
db := MustOpenDB() db := btesting.MustCreateDB(b)
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
_, err := tx.CreateBucket([]byte("bench")) _, err := tx.CreateBucket([]byte("bench"))
return err return err
@ -1520,8 +1486,7 @@ func BenchmarkDBBatchSingle(b *testing.B) {
} }
func BenchmarkDBBatchManual10x100(b *testing.B) { func BenchmarkDBBatchManual10x100(b *testing.B) {
db := MustOpenDB() db := btesting.MustCreateDB(b)
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
_, err := tx.CreateBucket([]byte("bench")) _, err := tx.CreateBucket([]byte("bench"))
return err return err
@ -1574,7 +1539,7 @@ func BenchmarkDBBatchManual10x100(b *testing.B) {
validateBatchBench(b, db) validateBatchBench(b, db)
} }
func validateBatchBench(b *testing.B, db *DB) { func validateBatchBench(b *testing.B, db *btesting.DB) {
var rollback = errors.New("sentinel error to cause rollback") var rollback = errors.New("sentinel error to cause rollback")
validate := func(tx *bolt.Tx) error { validate := func(tx *bolt.Tx) error {
bucket := tx.Bucket([]byte("bench")) bucket := tx.Bucket([]byte("bench"))
@ -1609,149 +1574,6 @@ func validateBatchBench(b *testing.B, db *DB) {
} }
} }
// DB is a test wrapper for bolt.DB.
type DB struct {
*bolt.DB
f string
o *bolt.Options
}
// MustOpenDB returns a new, open DB at a temporary location.
// Deprecated: Please use btesting.MustCreateDB(...).
func MustOpenDB() *DB {
return MustOpenWithOption(nil)
}
// MustOpenDBWithOption returns a new, open DB at a temporary location with given options.
// Deprecated: Please use btesting.MustCreateWithOption(...).
func MustOpenWithOption(o *bolt.Options) *DB {
f := tempfile()
if o == nil {
o = bolt.DefaultOptions
}
freelistType := bolt.FreelistArrayType
if env := os.Getenv(bolt.TestFreelistType); env == string(bolt.FreelistMapType) {
freelistType = bolt.FreelistMapType
}
o.FreelistType = freelistType
db, err := bolt.Open(f, 0666, o)
if err != nil {
panic(err)
}
return &DB{
DB: db,
f: f,
o: o,
}
}
// Closes the DB without removing the file.
// Allows for Reopen().
func (db *DB) CloseTemporarily() error {
if err := db.DB.Close(); err != nil {
return err
}
db.DB = nil
return nil
}
// Close closes the database and deletes the underlying file.
func (db *DB) Close() error {
// Log statistics.
if *statsFlag {
db.PrintStats()
}
// Check database consistency after every test.
db.MustCheck()
// Close database and remove file.
defer os.Remove(db.Path())
return db.DB.Close()
}
// MustClose closes the database and deletes the underlying file. Panic on error.
func (db *DB) MustClose() {
if err := db.Close(); err != nil {
panic(err)
}
}
// MustReopen reopen the database. Panic on error.
func (db *DB) MustReopen() {
indb, err := bolt.Open(db.f, 0666, db.o)
if err != nil {
panic(err)
}
db.DB = indb
}
// PrintStats prints the database stats
func (db *DB) PrintStats() {
var stats = db.Stats()
fmt.Printf("[db] %-20s %-20s %-20s\n",
fmt.Sprintf("pg(%d/%d)", stats.TxStats.PageCount, stats.TxStats.PageAlloc),
fmt.Sprintf("cur(%d)", stats.TxStats.CursorCount),
fmt.Sprintf("node(%d/%d)", stats.TxStats.NodeCount, stats.TxStats.NodeDeref),
)
fmt.Printf(" %-20s %-20s %-20s\n",
fmt.Sprintf("rebal(%d/%v)", stats.TxStats.Rebalance, truncDuration(stats.TxStats.RebalanceTime)),
fmt.Sprintf("spill(%d/%v)", stats.TxStats.Spill, truncDuration(stats.TxStats.SpillTime)),
fmt.Sprintf("w(%d/%v)", stats.TxStats.Write, truncDuration(stats.TxStats.WriteTime)),
)
}
// MustCheck runs a consistency check on the database and panics if any errors are found.
func (db *DB) MustCheck() {
if err := db.Update(func(tx *bolt.Tx) error {
// Collect all the errors.
var errors []error
for err := range tx.Check() {
errors = append(errors, err)
if len(errors) > 10 {
break
}
}
// If errors occurred, copy the DB and print the errors.
if len(errors) > 0 {
var path = tempfile()
if err := tx.CopyFile(path, 0600); err != nil {
panic(err)
}
// Print errors.
fmt.Print("\n\n")
fmt.Printf("consistency check failed (%d errors)\n", len(errors))
for _, err := range errors {
fmt.Println(err)
}
fmt.Println("")
fmt.Println("db saved to:")
fmt.Println(path)
fmt.Print("\n\n")
os.Exit(-1)
}
return nil
}); err != nil && err != bolt.ErrDatabaseNotOpen {
panic(err)
}
}
// CopyTempFile copies a database to a temporary file.
func (db *DB) CopyTempFile() {
path := tempfile()
if err := db.View(func(tx *bolt.Tx) error {
return tx.CopyFile(path, 0600)
}); err != nil {
panic(err)
}
fmt.Println("db copied to: ", path)
}
// tempfile returns a temporary file path. // tempfile returns a temporary file path.
func tempfile() string { func tempfile() string {
f, err := os.CreateTemp("", "bolt-") f, err := os.CreateTemp("", "bolt-")
@ -1774,10 +1596,6 @@ func trunc(b []byte, length int) []byte {
return b return b
} }
func truncDuration(d time.Duration) string {
return regexp.MustCompile(`^(\d+)(\.\d+)`).ReplaceAllString(d.String(), "$1")
}
func fileSize(path string) int64 { func fileSize(path string) int64 {
fi, err := os.Stat(path) fi, err := os.Stat(path)
if err != nil { if err != nil {

View File

@ -3,6 +3,7 @@ package btesting
import ( import (
"flag" "flag"
"fmt" "fmt"
"github.com/stretchr/testify/require"
bolt "go.etcd.io/bbolt" bolt "go.etcd.io/bbolt"
"os" "os"
"path/filepath" "path/filepath"
@ -36,15 +37,15 @@ func MustCreateDBWithOption(t testing.TB, o *bolt.Options) *DB {
} }
func MustOpenDBWithOption(t testing.TB, f string, o *bolt.Options) *DB { func MustOpenDBWithOption(t testing.TB, f string, o *bolt.Options) *DB {
t.Logf("Opening bbolt DB at: %s", f)
if o == nil { if o == nil {
o = bolt.DefaultOptions o = bolt.DefaultOptions
} }
freelistType := bolt.FreelistMapType freelistType := bolt.FreelistArrayType
if env := os.Getenv(TestFreelistType); env == string(bolt.FreelistArrayType) { if env := os.Getenv(TestFreelistType); env == string(bolt.FreelistMapType) {
freelistType = bolt.FreelistArrayType freelistType = bolt.FreelistMapType
} }
o.FreelistType = freelistType
o.FreelistType = freelistType o.FreelistType = freelistType
@ -77,7 +78,7 @@ func (db *DB) Close() error {
if *statsFlag { if *statsFlag {
db.PrintStats() db.PrintStats()
} }
db.t.Logf("Closing bbolt DB at: %s", db.f)
err := db.DB.Close() err := db.DB.Close()
if err != nil { if err != nil {
return err return err
@ -87,13 +88,18 @@ func (db *DB) Close() error {
return nil return nil
} }
// MustClose closes the database and deletes the underlying file. Panic on error. // MustClose closes the database but does NOT delete the underlying file.
func (db *DB) MustClose() { func (db *DB) MustClose() {
if err := db.Close(); err != nil { if err := db.Close(); err != nil {
panic(err) panic(err)
} }
} }
func (db *DB) MustDeleteFile() {
err := os.Remove(db.Path())
require.NoError(db.t, err)
}
func (db *DB) SetOptions(o *bolt.Options) { func (db *DB) SetOptions(o *bolt.Options) {
db.o = o db.o = o
} }
@ -103,6 +109,7 @@ func (db *DB) MustReopen() {
if db.DB != nil { if db.DB != nil {
panic("Please call Close() before MustReopen()") panic("Please call Close() before MustReopen()")
} }
db.t.Logf("Reopening bbolt DB at: %s", db.f)
indb, err := bolt.Open(db.Path(), 0666, db.o) indb, err := bolt.Open(db.Path(), 0666, db.o)
if err != nil { if err != nil {
panic(err) panic(err)

View File

@ -3,6 +3,7 @@ package bbolt_test
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"go.etcd.io/bbolt/internal/btesting"
"math/rand" "math/rand"
"sync" "sync"
"sync/atomic" "sync/atomic"
@ -43,8 +44,7 @@ func testSimulate(t *testing.T, openOption *bolt.Options, round, threadCount, pa
var versions = make(map[int]*QuickDB) var versions = make(map[int]*QuickDB)
versions[1] = NewQuickDB() versions[1] = NewQuickDB()
db := MustOpenWithOption(openOption) db := btesting.MustCreateDBWithOption(t, openOption)
defer db.MustClose()
var mutex sync.Mutex var mutex sync.Mutex
@ -146,6 +146,9 @@ func testSimulate(t *testing.T, openOption *bolt.Options, round, threadCount, pa
} }
db.MustClose() db.MustClose()
// I have doubts the DB drop is indented here (as 'versions' is not being reset).
// But I'm preserving for now the original behavior.
db.MustDeleteFile()
db.MustReopen() db.MustReopen()
} }

View File

@ -4,6 +4,7 @@ import (
"bytes" "bytes"
"errors" "errors"
"fmt" "fmt"
"go.etcd.io/bbolt/internal/btesting"
"log" "log"
"os" "os"
"testing" "testing"
@ -13,7 +14,7 @@ import (
// TestTx_Check_ReadOnly tests consistency checking on a ReadOnly database. // TestTx_Check_ReadOnly tests consistency checking on a ReadOnly database.
func TestTx_Check_ReadOnly(t *testing.T) { func TestTx_Check_ReadOnly(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.Close() defer db.Close()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
b, err := tx.CreateBucket([]byte("widgets")) b, err := tx.CreateBucket([]byte("widgets"))
@ -27,11 +28,11 @@ func TestTx_Check_ReadOnly(t *testing.T) {
}); err != nil { }); err != nil {
t.Fatal(err) t.Fatal(err)
} }
if err := db.DB.Close(); err != nil { if err := db.Close(); err != nil {
t.Fatal(err) t.Fatal(err)
} }
readOnlyDB, err := bolt.Open(db.f, 0666, &bolt.Options{ReadOnly: true}) readOnlyDB, err := bolt.Open(db.Path(), 0666, &bolt.Options{ReadOnly: true})
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -65,8 +66,7 @@ func TestTx_Check_ReadOnly(t *testing.T) {
// Ensure that committing a closed transaction returns an error. // Ensure that committing a closed transaction returns an error.
func TestTx_Commit_ErrTxClosed(t *testing.T) { func TestTx_Commit_ErrTxClosed(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
tx, err := db.Begin(true) tx, err := db.Begin(true)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -87,8 +87,7 @@ func TestTx_Commit_ErrTxClosed(t *testing.T) {
// Ensure that rolling back a closed transaction returns an error. // Ensure that rolling back a closed transaction returns an error.
func TestTx_Rollback_ErrTxClosed(t *testing.T) { func TestTx_Rollback_ErrTxClosed(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
tx, err := db.Begin(true) tx, err := db.Begin(true)
if err != nil { if err != nil {
@ -105,8 +104,7 @@ func TestTx_Rollback_ErrTxClosed(t *testing.T) {
// Ensure that committing a read-only transaction returns an error. // Ensure that committing a read-only transaction returns an error.
func TestTx_Commit_ErrTxNotWritable(t *testing.T) { func TestTx_Commit_ErrTxNotWritable(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
tx, err := db.Begin(false) tx, err := db.Begin(false)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -123,8 +121,7 @@ func TestTx_Commit_ErrTxNotWritable(t *testing.T) {
// Ensure that a transaction can retrieve a cursor on the root bucket. // Ensure that a transaction can retrieve a cursor on the root bucket.
func TestTx_Cursor(t *testing.T) { func TestTx_Cursor(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
if _, err := tx.CreateBucket([]byte("widgets")); err != nil { if _, err := tx.CreateBucket([]byte("widgets")); err != nil {
t.Fatal(err) t.Fatal(err)
@ -161,8 +158,7 @@ func TestTx_Cursor(t *testing.T) {
// Ensure that creating a bucket with a read-only transaction returns an error. // Ensure that creating a bucket with a read-only transaction returns an error.
func TestTx_CreateBucket_ErrTxNotWritable(t *testing.T) { func TestTx_CreateBucket_ErrTxNotWritable(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
if err := db.View(func(tx *bolt.Tx) error { if err := db.View(func(tx *bolt.Tx) error {
_, err := tx.CreateBucket([]byte("foo")) _, err := tx.CreateBucket([]byte("foo"))
if err != bolt.ErrTxNotWritable { if err != bolt.ErrTxNotWritable {
@ -176,8 +172,7 @@ func TestTx_CreateBucket_ErrTxNotWritable(t *testing.T) {
// Ensure that creating a bucket on a closed transaction returns an error. // Ensure that creating a bucket on a closed transaction returns an error.
func TestTx_CreateBucket_ErrTxClosed(t *testing.T) { func TestTx_CreateBucket_ErrTxClosed(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
tx, err := db.Begin(true) tx, err := db.Begin(true)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -193,8 +188,7 @@ func TestTx_CreateBucket_ErrTxClosed(t *testing.T) {
// Ensure that a Tx can retrieve a bucket. // Ensure that a Tx can retrieve a bucket.
func TestTx_Bucket(t *testing.T) { func TestTx_Bucket(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
if _, err := tx.CreateBucket([]byte("widgets")); err != nil { if _, err := tx.CreateBucket([]byte("widgets")); err != nil {
t.Fatal(err) t.Fatal(err)
@ -210,8 +204,7 @@ func TestTx_Bucket(t *testing.T) {
// Ensure that a Tx retrieving a non-existent key returns nil. // Ensure that a Tx retrieving a non-existent key returns nil.
func TestTx_Get_NotFound(t *testing.T) { func TestTx_Get_NotFound(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
b, err := tx.CreateBucket([]byte("widgets")) b, err := tx.CreateBucket([]byte("widgets"))
if err != nil { if err != nil {
@ -232,8 +225,7 @@ func TestTx_Get_NotFound(t *testing.T) {
// Ensure that a bucket can be created and retrieved. // Ensure that a bucket can be created and retrieved.
func TestTx_CreateBucket(t *testing.T) { func TestTx_CreateBucket(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
// Create a bucket. // Create a bucket.
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
@ -261,8 +253,7 @@ func TestTx_CreateBucket(t *testing.T) {
// Ensure that a bucket can be created if it doesn't already exist. // Ensure that a bucket can be created if it doesn't already exist.
func TestTx_CreateBucketIfNotExists(t *testing.T) { func TestTx_CreateBucketIfNotExists(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
// Create bucket. // Create bucket.
if b, err := tx.CreateBucketIfNotExists([]byte("widgets")); err != nil { if b, err := tx.CreateBucketIfNotExists([]byte("widgets")); err != nil {
@ -296,8 +287,7 @@ func TestTx_CreateBucketIfNotExists(t *testing.T) {
// Ensure transaction returns an error if creating an unnamed bucket. // Ensure transaction returns an error if creating an unnamed bucket.
func TestTx_CreateBucketIfNotExists_ErrBucketNameRequired(t *testing.T) { func TestTx_CreateBucketIfNotExists_ErrBucketNameRequired(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
if _, err := tx.CreateBucketIfNotExists([]byte{}); err != bolt.ErrBucketNameRequired { if _, err := tx.CreateBucketIfNotExists([]byte{}); err != bolt.ErrBucketNameRequired {
t.Fatalf("unexpected error: %s", err) t.Fatalf("unexpected error: %s", err)
@ -315,8 +305,7 @@ func TestTx_CreateBucketIfNotExists_ErrBucketNameRequired(t *testing.T) {
// Ensure that a bucket cannot be created twice. // Ensure that a bucket cannot be created twice.
func TestTx_CreateBucket_ErrBucketExists(t *testing.T) { func TestTx_CreateBucket_ErrBucketExists(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
// Create a bucket. // Create a bucket.
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
@ -341,8 +330,7 @@ func TestTx_CreateBucket_ErrBucketExists(t *testing.T) {
// Ensure that a bucket is created with a non-blank name. // Ensure that a bucket is created with a non-blank name.
func TestTx_CreateBucket_ErrBucketNameRequired(t *testing.T) { func TestTx_CreateBucket_ErrBucketNameRequired(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
if _, err := tx.CreateBucket(nil); err != bolt.ErrBucketNameRequired { if _, err := tx.CreateBucket(nil); err != bolt.ErrBucketNameRequired {
t.Fatalf("unexpected error: %s", err) t.Fatalf("unexpected error: %s", err)
@ -355,8 +343,7 @@ func TestTx_CreateBucket_ErrBucketNameRequired(t *testing.T) {
// Ensure that a bucket can be deleted. // Ensure that a bucket can be deleted.
func TestTx_DeleteBucket(t *testing.T) { func TestTx_DeleteBucket(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
// Create a bucket and add a value. // Create a bucket and add a value.
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
@ -402,8 +389,7 @@ func TestTx_DeleteBucket(t *testing.T) {
// Ensure that deleting a bucket on a closed transaction returns an error. // Ensure that deleting a bucket on a closed transaction returns an error.
func TestTx_DeleteBucket_ErrTxClosed(t *testing.T) { func TestTx_DeleteBucket_ErrTxClosed(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
tx, err := db.Begin(true) tx, err := db.Begin(true)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -418,8 +404,7 @@ func TestTx_DeleteBucket_ErrTxClosed(t *testing.T) {
// Ensure that deleting a bucket with a read-only transaction returns an error. // Ensure that deleting a bucket with a read-only transaction returns an error.
func TestTx_DeleteBucket_ReadOnly(t *testing.T) { func TestTx_DeleteBucket_ReadOnly(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
if err := db.View(func(tx *bolt.Tx) error { if err := db.View(func(tx *bolt.Tx) error {
if err := tx.DeleteBucket([]byte("foo")); err != bolt.ErrTxNotWritable { if err := tx.DeleteBucket([]byte("foo")); err != bolt.ErrTxNotWritable {
t.Fatalf("unexpected error: %s", err) t.Fatalf("unexpected error: %s", err)
@ -432,8 +417,7 @@ func TestTx_DeleteBucket_ReadOnly(t *testing.T) {
// Ensure that nothing happens when deleting a bucket that doesn't exist. // Ensure that nothing happens when deleting a bucket that doesn't exist.
func TestTx_DeleteBucket_NotFound(t *testing.T) { func TestTx_DeleteBucket_NotFound(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
if err := tx.DeleteBucket([]byte("widgets")); err != bolt.ErrBucketNotFound { if err := tx.DeleteBucket([]byte("widgets")); err != bolt.ErrBucketNotFound {
t.Fatalf("unexpected error: %s", err) t.Fatalf("unexpected error: %s", err)
@ -447,8 +431,7 @@ func TestTx_DeleteBucket_NotFound(t *testing.T) {
// Ensure that no error is returned when a tx.ForEach function does not return // Ensure that no error is returned when a tx.ForEach function does not return
// an error. // an error.
func TestTx_ForEach_NoError(t *testing.T) { func TestTx_ForEach_NoError(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
b, err := tx.CreateBucket([]byte("widgets")) b, err := tx.CreateBucket([]byte("widgets"))
if err != nil { if err != nil {
@ -471,8 +454,7 @@ func TestTx_ForEach_NoError(t *testing.T) {
// Ensure that an error is returned when a tx.ForEach function returns an error. // Ensure that an error is returned when a tx.ForEach function returns an error.
func TestTx_ForEach_WithError(t *testing.T) { func TestTx_ForEach_WithError(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
b, err := tx.CreateBucket([]byte("widgets")) b, err := tx.CreateBucket([]byte("widgets"))
if err != nil { if err != nil {
@ -496,8 +478,7 @@ func TestTx_ForEach_WithError(t *testing.T) {
// Ensure that Tx commit handlers are called after a transaction successfully commits. // Ensure that Tx commit handlers are called after a transaction successfully commits.
func TestTx_OnCommit(t *testing.T) { func TestTx_OnCommit(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
var x int var x int
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
@ -516,8 +497,7 @@ func TestTx_OnCommit(t *testing.T) {
// Ensure that Tx commit handlers are NOT called after a transaction rolls back. // Ensure that Tx commit handlers are NOT called after a transaction rolls back.
func TestTx_OnCommit_Rollback(t *testing.T) { func TestTx_OnCommit_Rollback(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
var x int var x int
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
@ -536,8 +516,7 @@ func TestTx_OnCommit_Rollback(t *testing.T) {
// Ensure that the database can be copied to a file path. // Ensure that the database can be copied to a file path.
func TestTx_CopyFile(t *testing.T) { func TestTx_CopyFile(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
path := tempfile() path := tempfile()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
@ -607,8 +586,7 @@ func (f *failWriter) Write(p []byte) (n int, err error) {
// Ensure that Copy handles write errors right. // Ensure that Copy handles write errors right.
func TestTx_CopyFile_Error_Meta(t *testing.T) { func TestTx_CopyFile_Error_Meta(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
b, err := tx.CreateBucket([]byte("widgets")) b, err := tx.CreateBucket([]byte("widgets"))
if err != nil { if err != nil {
@ -634,8 +612,7 @@ func TestTx_CopyFile_Error_Meta(t *testing.T) {
// Ensure that Copy handles write errors right. // Ensure that Copy handles write errors right.
func TestTx_CopyFile_Error_Normal(t *testing.T) { func TestTx_CopyFile_Error_Normal(t *testing.T) {
db := MustOpenDB() db := btesting.MustCreateDB(t)
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
b, err := tx.CreateBucket([]byte("widgets")) b, err := tx.CreateBucket([]byte("widgets"))
if err != nil { if err != nil {
@ -719,8 +696,7 @@ func TestTx_releaseRange(t *testing.T) {
// Set initial mmap size well beyond the limit we will hit in this // Set initial mmap size well beyond the limit we will hit in this
// test, since we are testing with long running read transactions // test, since we are testing with long running read transactions
// and will deadlock if db.grow is triggered. // and will deadlock if db.grow is triggered.
db := MustOpenWithOption(&bolt.Options{InitialMmapSize: os.Getpagesize() * 100}) db := btesting.MustCreateDBWithOption(t, &bolt.Options{InitialMmapSize: os.Getpagesize() * 100})
defer db.MustClose()
bucket := "bucket" bucket := "bucket"

View File

@ -5,6 +5,7 @@ package bbolt_test
import ( import (
"fmt" "fmt"
"go.etcd.io/bbolt/internal/btesting"
"testing" "testing"
bolt "go.etcd.io/bbolt" bolt "go.etcd.io/bbolt"
@ -15,8 +16,7 @@ func TestMlock_DbOpen(t *testing.T) {
// 32KB // 32KB
skipOnMemlockLimitBelow(t, 32*1024) skipOnMemlockLimitBelow(t, 32*1024)
db := MustOpenWithOption(&bolt.Options{Mlock: true}) btesting.MustCreateDBWithOption(t, &bolt.Options{Mlock: true})
defer db.MustClose()
} }
// Test change between "empty" (16KB) and "non-empty" db // Test change between "empty" (16KB) and "non-empty" db
@ -24,8 +24,7 @@ func TestMlock_DbCanGrow_Small(t *testing.T) {
// 32KB // 32KB
skipOnMemlockLimitBelow(t, 32*1024) skipOnMemlockLimitBelow(t, 32*1024)
db := MustOpenWithOption(&bolt.Options{Mlock: true}) db := btesting.MustCreateDBWithOption(t, &bolt.Options{Mlock: true})
defer db.MustClose()
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {
b, err := tx.CreateBucketIfNotExists([]byte("bucket")) b, err := tx.CreateBucketIfNotExists([]byte("bucket"))
@ -58,25 +57,24 @@ func TestMlock_DbCanGrow_Big(t *testing.T) {
chunksBefore := 64 chunksBefore := 64
chunksAfter := 64 chunksAfter := 64
db := MustOpenWithOption(&bolt.Options{Mlock: true}) db := btesting.MustCreateDBWithOption(t, &bolt.Options{Mlock: true})
defer db.MustClose()
for chunk := 0; chunk < chunksBefore; chunk++ { for chunk := 0; chunk < chunksBefore; chunk++ {
insertChunk(t, db, chunk) insertChunk(t, db, chunk)
} }
dbSize := fileSize(db.f) dbSize := fileSize(db.Path())
for chunk := 0; chunk < chunksAfter; chunk++ { for chunk := 0; chunk < chunksAfter; chunk++ {
insertChunk(t, db, chunksBefore+chunk) insertChunk(t, db, chunksBefore+chunk)
} }
newDbSize := fileSize(db.f) newDbSize := fileSize(db.Path())
if newDbSize <= dbSize { if newDbSize <= dbSize {
t.Errorf("db didn't grow: %v <= %v", newDbSize, dbSize) t.Errorf("db didn't grow: %v <= %v", newDbSize, dbSize)
} }
} }
func insertChunk(t *testing.T, db *DB, chunkId int) { func insertChunk(t *testing.T, db *btesting.DB, chunkId int) {
chunkSize := 1024 chunkSize := 1024
if err := db.Update(func(tx *bolt.Tx) error { if err := db.Update(func(tx *bolt.Tx) error {