mirror of https://github.com/hak5/bolt.git
168 lines
3.3 KiB
Go
168 lines
3.3 KiB
Go
package bolt_test
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/boltdb/bolt"
|
|
)
|
|
|
|
// Ensure two functions can perform updates in a single batch.
|
|
func TestDB_Batch(t *testing.T) {
|
|
db := NewTestDB()
|
|
defer db.Close()
|
|
db.MustCreateBucket([]byte("widgets"))
|
|
|
|
// Iterate over multiple updates in separate goroutines.
|
|
n := 2
|
|
ch := make(chan error)
|
|
for i := 0; i < n; i++ {
|
|
go func(i int) {
|
|
ch <- db.Batch(func(tx *bolt.Tx) error {
|
|
return tx.Bucket([]byte("widgets")).Put(u64tob(uint64(i)), []byte{})
|
|
})
|
|
}(i)
|
|
}
|
|
|
|
// Check all responses to make sure there's no error.
|
|
for i := 0; i < n; i++ {
|
|
if err := <-ch; err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
// Ensure data is correct.
|
|
db.MustView(func(tx *bolt.Tx) error {
|
|
b := tx.Bucket([]byte("widgets"))
|
|
for i := 0; i < n; i++ {
|
|
if v := b.Get(u64tob(uint64(i))); v == nil {
|
|
t.Errorf("key not found: %d", i)
|
|
}
|
|
}
|
|
return nil
|
|
})
|
|
}
|
|
|
|
func TestDB_Batch_Panic(t *testing.T) {
|
|
db := NewTestDB()
|
|
defer db.Close()
|
|
|
|
var sentinel int
|
|
var bork = &sentinel
|
|
var problem interface{}
|
|
var err error
|
|
|
|
// Execute a function inside a batch that panics.
|
|
func() {
|
|
defer func() {
|
|
if p := recover(); p != nil {
|
|
problem = p
|
|
}
|
|
}()
|
|
err = db.Batch(func(tx *bolt.Tx) error {
|
|
panic(bork)
|
|
})
|
|
}()
|
|
|
|
// Verify there is no error.
|
|
if g, e := err, error(nil); g != e {
|
|
t.Fatalf("wrong error: %v != %v", g, e)
|
|
}
|
|
// Verify the panic was captured.
|
|
if g, e := problem, bork; g != e {
|
|
t.Fatalf("wrong error: %v != %v", g, e)
|
|
}
|
|
}
|
|
|
|
func TestDB_BatchFull(t *testing.T) {
|
|
db := NewTestDB()
|
|
defer db.Close()
|
|
db.MustCreateBucket([]byte("widgets"))
|
|
|
|
const size = 3
|
|
// buffered so we never leak goroutines
|
|
ch := make(chan error, size)
|
|
put := func(i int) {
|
|
ch <- db.Batch(func(tx *bolt.Tx) error {
|
|
return tx.Bucket([]byte("widgets")).Put(u64tob(uint64(i)), []byte{})
|
|
})
|
|
}
|
|
|
|
db.MaxBatchSize = size
|
|
// high enough to never trigger here
|
|
db.MaxBatchDelay = 1 * time.Hour
|
|
|
|
go put(1)
|
|
go put(2)
|
|
|
|
// Give the batch a chance to exhibit bugs.
|
|
time.Sleep(10 * time.Millisecond)
|
|
|
|
// not triggered yet
|
|
select {
|
|
case <-ch:
|
|
t.Fatalf("batch triggered too early")
|
|
default:
|
|
}
|
|
|
|
go put(3)
|
|
|
|
// Check all responses to make sure there's no error.
|
|
for i := 0; i < size; i++ {
|
|
if err := <-ch; err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
// Ensure data is correct.
|
|
db.MustView(func(tx *bolt.Tx) error {
|
|
b := tx.Bucket([]byte("widgets"))
|
|
for i := 1; i <= size; i++ {
|
|
if v := b.Get(u64tob(uint64(i))); v == nil {
|
|
t.Errorf("key not found: %d", i)
|
|
}
|
|
}
|
|
return nil
|
|
})
|
|
}
|
|
|
|
func TestDB_BatchTime(t *testing.T) {
|
|
db := NewTestDB()
|
|
defer db.Close()
|
|
db.MustCreateBucket([]byte("widgets"))
|
|
|
|
const size = 1
|
|
// buffered so we never leak goroutines
|
|
ch := make(chan error, size)
|
|
put := func(i int) {
|
|
ch <- db.Batch(func(tx *bolt.Tx) error {
|
|
return tx.Bucket([]byte("widgets")).Put(u64tob(uint64(i)), []byte{})
|
|
})
|
|
}
|
|
|
|
db.MaxBatchSize = 1000
|
|
db.MaxBatchDelay = 0
|
|
|
|
go put(1)
|
|
|
|
// Batch must trigger by time alone.
|
|
|
|
// Check all responses to make sure there's no error.
|
|
for i := 0; i < size; i++ {
|
|
if err := <-ch; err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
// Ensure data is correct.
|
|
db.MustView(func(tx *bolt.Tx) error {
|
|
b := tx.Bucket([]byte("widgets"))
|
|
for i := 1; i <= size; i++ {
|
|
if v := b.Get(u64tob(uint64(i))); v == nil {
|
|
t.Errorf("key not found: %d", i)
|
|
}
|
|
}
|
|
return nil
|
|
})
|
|
}
|