mirror of https://github.com/hak5/bolt.git
Improve test coverage.
parent
72b799480f
commit
d1952237ed
|
@ -154,9 +154,7 @@ func (c *Cursor) keyValue() ([]byte, []byte) {
|
|||
|
||||
// node returns the node that the cursor is currently positioned on.
|
||||
func (c *Cursor) node(t *RWTransaction) *node {
|
||||
if len(c.stack) == 0 {
|
||||
return nil
|
||||
}
|
||||
_assert(len(c.stack) > 0, "accessing a node with a zero-length cursor stack")
|
||||
|
||||
// Start from root and traverse down the hierarchy.
|
||||
n := t.node(c.stack[0].page.id, nil)
|
||||
|
|
17
db.go
17
db.go
|
@ -240,7 +240,7 @@ func (db *DB) Close() {
|
|||
|
||||
func (db *DB) close() {
|
||||
db.opened = false
|
||||
|
||||
|
||||
// TODO(benbjohnson): Undo everything in Open().
|
||||
db.freelist = nil
|
||||
db.path = ""
|
||||
|
@ -432,10 +432,6 @@ func (db *DB) Delete(name string, key []byte) error {
|
|||
// A reader transaction is maintained during the copy so it is safe to continue
|
||||
// using the database while a copy is in progress.
|
||||
func (db *DB) Copy(w io.Writer) error {
|
||||
if !db.opened {
|
||||
return DatabaseNotOpenError
|
||||
}
|
||||
|
||||
// Maintain a reader transaction so pages don't get reclaimed.
|
||||
t, err := db.Transaction()
|
||||
if err != nil {
|
||||
|
@ -514,14 +510,3 @@ func (db *DB) allocate(count int) (*page, error) {
|
|||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// sync flushes the file descriptor to disk.
|
||||
func (db *DB) sync(force bool) error {
|
||||
if db.opened {
|
||||
return DatabaseNotOpenError
|
||||
}
|
||||
if err := syscall.Fsync(int(db.file.Fd())); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
67
db_test.go
67
db_test.go
|
@ -178,6 +178,14 @@ func TestDBDelete(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
// Ensure that a delete on a missing bucket returns an error.
|
||||
func TestDBDeleteFromMissingBucket(t *testing.T) {
|
||||
withOpenDB(func(db *DB, path string) {
|
||||
err := db.Delete("widgets", []byte("foo"))
|
||||
assert.Equal(t, err, BucketNotFoundError)
|
||||
})
|
||||
}
|
||||
|
||||
// Ensure a database can provide a transactional block.
|
||||
func TestDBTransactionBlock(t *testing.T) {
|
||||
withOpenDB(func(db *DB, path string) {
|
||||
|
@ -196,19 +204,62 @@ func TestDBTransactionBlock(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
// Ensure that the database can be copied to a writer.
|
||||
func TestDBCopy(t *testing.T) {
|
||||
t.Skip("pending") // TODO(benbjohnson)
|
||||
// Ensure a closed database returns an error while running a transaction block
|
||||
func TestDBTransactionBlockWhileClosed(t *testing.T) {
|
||||
withDB(func(db *DB, path string) {
|
||||
err := db.Do(func(txn *RWTransaction) error {
|
||||
txn.CreateBucket("widgets")
|
||||
return nil
|
||||
})
|
||||
assert.Equal(t, err, DatabaseNotOpenError)
|
||||
})
|
||||
}
|
||||
|
||||
// Ensure a closed database returns an error when finding a bucket.
|
||||
func TestDBBucketWhileClosed(t *testing.T) {
|
||||
withDB(func(db *DB, path string) {
|
||||
b, err := db.Bucket("widgets")
|
||||
assert.Equal(t, err, DatabaseNotOpenError)
|
||||
assert.Nil(t, b)
|
||||
})
|
||||
}
|
||||
|
||||
// Ensure a closed database returns an error when finding all buckets.
|
||||
func TestDBBucketsWhileClosed(t *testing.T) {
|
||||
withDB(func(db *DB, path string) {
|
||||
b, err := db.Buckets()
|
||||
assert.Equal(t, err, DatabaseNotOpenError)
|
||||
assert.Nil(t, b)
|
||||
})
|
||||
}
|
||||
|
||||
// Ensure a closed database returns an error when getting a key.
|
||||
func TestDBGetWhileClosed(t *testing.T) {
|
||||
withDB(func(db *DB, path string) {
|
||||
value, err := db.Get("widgets", []byte("foo"))
|
||||
assert.Equal(t, err, DatabaseNotOpenError)
|
||||
assert.Nil(t, value)
|
||||
})
|
||||
}
|
||||
|
||||
// Ensure that the database can be copied to a file path.
|
||||
func TestDBCopyFile(t *testing.T) {
|
||||
t.Skip("pending") // TODO(benbjohnson)
|
||||
}
|
||||
withOpenDB(func(db *DB, path string) {
|
||||
db.CreateBucket("widgets")
|
||||
db.Put("widgets", []byte("foo"), []byte("bar"))
|
||||
db.Put("widgets", []byte("baz"), []byte("bat"))
|
||||
assert.NoError(t, os.RemoveAll("/tmp/bolt.copyfile.db"))
|
||||
assert.NoError(t, db.CopyFile("/tmp/bolt.copyfile.db", 0666))
|
||||
|
||||
// Ensure that the database can sync to the file system.
|
||||
func TestDBSync(t *testing.T) {
|
||||
t.Skip("pending") // TODO(benbjohnson)
|
||||
var db2 DB
|
||||
assert.NoError(t, db2.Open("/tmp/bolt.copyfile.db", 0666))
|
||||
defer db2.Close()
|
||||
|
||||
value, _ := db2.Get("widgets", []byte("foo"))
|
||||
assert.Equal(t, value, []byte("bar"))
|
||||
value, _ = db2.Get("widgets", []byte("baz"))
|
||||
assert.Equal(t, value, []byte("bat"))
|
||||
})
|
||||
}
|
||||
|
||||
// Ensure that an error is returned when a database write fails.
|
||||
|
|
|
@ -47,7 +47,10 @@ func TestParallelTransactions(t *testing.T) {
|
|||
local := current
|
||||
txn, err := db.Transaction()
|
||||
mutex.RUnlock()
|
||||
if !assert.NoError(t, err) {
|
||||
if err == DatabaseNotOpenError {
|
||||
wg.Done()
|
||||
return
|
||||
} else if !assert.NoError(t, err) {
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,15 @@ func TestRWTransaction(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
// Ensure that opening a RWTransaction while the DB is closed returns an error.
|
||||
func TestRWTransactionOpenWithClosedDB(t *testing.T) {
|
||||
withDB(func(db *DB, path string) {
|
||||
txn, err := db.RWTransaction()
|
||||
assert.Equal(t, err, DatabaseNotOpenError)
|
||||
assert.Nil(t, txn)
|
||||
})
|
||||
}
|
||||
|
||||
// Ensure that a bucket can be created and retrieved.
|
||||
func TestRWTransactionCreateBucket(t *testing.T) {
|
||||
withOpenDB(func(db *DB, path string) {
|
||||
|
@ -69,7 +78,23 @@ func TestRWTransactionCreateBucketWithLongName(t *testing.T) {
|
|||
|
||||
// Ensure that a bucket can be deleted.
|
||||
func TestRWTransactionDeleteBucket(t *testing.T) {
|
||||
t.Skip("pending") // TODO(benbjohnson)
|
||||
withOpenDB(func(db *DB, path string) {
|
||||
// Create a bucket and add a value.
|
||||
db.CreateBucket("widgets")
|
||||
db.Put("widgets", []byte("foo"), []byte("bar"))
|
||||
|
||||
// Delete the bucket and make sure we can't get the value.
|
||||
assert.NoError(t, db.DeleteBucket("widgets"))
|
||||
value, err := db.Get("widgets", []byte("foo"))
|
||||
assert.Equal(t, err, BucketNotFoundError)
|
||||
assert.Nil(t, value)
|
||||
|
||||
// Create the bucket again and make sure there's not a phantom value.
|
||||
assert.NoError(t, db.CreateBucket("widgets"))
|
||||
value, err = db.Get("widgets", []byte("foo"))
|
||||
assert.NoError(t, err)
|
||||
assert.Nil(t, value)
|
||||
})
|
||||
}
|
||||
|
||||
// Ensure that a bucket can return an autoincrementing sequence.
|
||||
|
@ -100,27 +125,38 @@ func TestRWTransactionNextSequence(t *testing.T) {
|
|||
|
||||
// Ensure that an error is returned when inserting into a bucket that doesn't exist.
|
||||
func TestRWTransactionPutBucketNotFound(t *testing.T) {
|
||||
t.Skip("pending") // TODO(benbjohnson)
|
||||
withOpenDB(func(db *DB, path string) {
|
||||
err := db.Put("widgets", []byte("foo"), []byte("bar"))
|
||||
assert.Equal(t, err, BucketNotFoundError)
|
||||
})
|
||||
}
|
||||
|
||||
// Ensure that an error is returned when inserting with an empty key.
|
||||
func TestRWTransactionPutEmptyKey(t *testing.T) {
|
||||
t.Skip("pending") // TODO(benbjohnson)
|
||||
withOpenDB(func(db *DB, path string) {
|
||||
db.CreateBucket("widgets")
|
||||
err := db.Put("widgets", []byte(""), []byte("bar"))
|
||||
assert.Equal(t, err, KeyRequiredError)
|
||||
err = db.Put("widgets", nil, []byte("bar"))
|
||||
assert.Equal(t, err, KeyRequiredError)
|
||||
})
|
||||
}
|
||||
|
||||
// Ensure that an error is returned when inserting with a key that's too large.
|
||||
func TestRWTransactionPutKeyTooLarge(t *testing.T) {
|
||||
t.Skip("pending") // TODO(benbjohnson)
|
||||
}
|
||||
|
||||
// Ensure that an error is returned when inserting with data that's too large.
|
||||
func TestRWTransactionPutDataTooLarge(t *testing.T) {
|
||||
t.Skip("pending") // TODO(benbjohnson)
|
||||
withOpenDB(func(db *DB, path string) {
|
||||
db.CreateBucket("widgets")
|
||||
err := db.Put("widgets", make([]byte, 32769), []byte("bar"))
|
||||
assert.Equal(t, err, KeyTooLargeError)
|
||||
})
|
||||
}
|
||||
|
||||
// Ensure that an error is returned when deleting from a bucket that doesn't exist.
|
||||
func TestRWTransactionDeleteBucketNotFound(t *testing.T) {
|
||||
t.Skip("pending") // TODO(benbjohnson)
|
||||
withOpenDB(func(db *DB, path string) {
|
||||
err := db.DeleteBucket("widgets")
|
||||
assert.Equal(t, err, BucketNotFoundError)
|
||||
})
|
||||
}
|
||||
|
||||
// Ensure that a bucket can write random keys and values across multiple txns.
|
||||
|
|
|
@ -63,8 +63,12 @@ func (t *Transaction) Bucket(name string) *Bucket {
|
|||
|
||||
// Buckets retrieves a list of all buckets.
|
||||
func (t *Transaction) Buckets() []*Bucket {
|
||||
warn("[pending] Transaction.Buckets()") // TODO
|
||||
return nil
|
||||
buckets := make([]*Bucket, 0, len(t.buckets.items))
|
||||
for name, b := range t.buckets.items {
|
||||
bucket := &Bucket{bucket: b, transaction: t, name: name}
|
||||
buckets = append(buckets, bucket)
|
||||
}
|
||||
return buckets
|
||||
}
|
||||
|
||||
// Cursor creates a cursor associated with a given bucket.
|
||||
|
|
|
@ -12,7 +12,17 @@ import (
|
|||
|
||||
// Ensure that the database can retrieve a list of buckets.
|
||||
func TestTransactionBuckets(t *testing.T) {
|
||||
t.Skip("pending") // TODO(benbjohnson)
|
||||
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.
|
||||
|
|
Loading…
Reference in New Issue