Improve test coverage.

master
Ben Johnson 2014-02-15 23:38:03 -07:00
parent 72b799480f
commit 0bf796c9de
6 changed files with 124 additions and 40 deletions

View File

@ -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
View File

@ -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
}

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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.