Improve test coverage.

pull/34/head
Ben Johnson 2014-02-15 23:38:03 -07:00
parent 72b799480f
commit d1952237ed
7 changed files with 128 additions and 41 deletions

View File

@ -154,9 +154,7 @@ func (c *Cursor) keyValue() ([]byte, []byte) {
// node returns the node that the cursor is currently positioned on. // node returns the node that the cursor is currently positioned on.
func (c *Cursor) node(t *RWTransaction) *node { func (c *Cursor) node(t *RWTransaction) *node {
if len(c.stack) == 0 { _assert(len(c.stack) > 0, "accessing a node with a zero-length cursor stack")
return nil
}
// Start from root and traverse down the hierarchy. // Start from root and traverse down the hierarchy.
n := t.node(c.stack[0].page.id, nil) n := t.node(c.stack[0].page.id, nil)

15
db.go
View File

@ -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 // A reader transaction is maintained during the copy so it is safe to continue
// using the database while a copy is in progress. // using the database while a copy is in progress.
func (db *DB) Copy(w io.Writer) error { func (db *DB) Copy(w io.Writer) error {
if !db.opened {
return DatabaseNotOpenError
}
// Maintain a reader transaction so pages don't get reclaimed. // Maintain a reader transaction so pages don't get reclaimed.
t, err := db.Transaction() t, err := db.Transaction()
if err != nil { if err != nil {
@ -514,14 +510,3 @@ func (db *DB) allocate(count int) (*page, error) {
return p, nil 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. // Ensure a database can provide a transactional block.
func TestDBTransactionBlock(t *testing.T) { func TestDBTransactionBlock(t *testing.T) {
withOpenDB(func(db *DB, path string) { 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. // Ensure a closed database returns an error while running a transaction block
func TestDBCopy(t *testing.T) { func TestDBTransactionBlockWhileClosed(t *testing.T) {
t.Skip("pending") // TODO(benbjohnson) 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. // Ensure that the database can be copied to a file path.
func TestDBCopyFile(t *testing.T) { 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. var db2 DB
func TestDBSync(t *testing.T) { assert.NoError(t, db2.Open("/tmp/bolt.copyfile.db", 0666))
t.Skip("pending") // TODO(benbjohnson) 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. // Ensure that an error is returned when a database write fails.

View File

@ -47,7 +47,10 @@ func TestParallelTransactions(t *testing.T) {
local := current local := current
txn, err := db.Transaction() txn, err := db.Transaction()
mutex.RUnlock() mutex.RUnlock()
if !assert.NoError(t, err) { if err == DatabaseNotOpenError {
wg.Done()
return
} else if !assert.NoError(t, err) {
t.FailNow() t.FailNow()
} }

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. // Ensure that a bucket can be created and retrieved.
func TestRWTransactionCreateBucket(t *testing.T) { func TestRWTransactionCreateBucket(t *testing.T) {
withOpenDB(func(db *DB, path string) { withOpenDB(func(db *DB, path string) {
@ -69,7 +78,23 @@ func TestRWTransactionCreateBucketWithLongName(t *testing.T) {
// Ensure that a bucket can be deleted. // Ensure that a bucket can be deleted.
func TestRWTransactionDeleteBucket(t *testing.T) { 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. // 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. // Ensure that an error is returned when inserting into a bucket that doesn't exist.
func TestRWTransactionPutBucketNotFound(t *testing.T) { 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. // Ensure that an error is returned when inserting with an empty key.
func TestRWTransactionPutEmptyKey(t *testing.T) { 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. // Ensure that an error is returned when inserting with a key that's too large.
func TestRWTransactionPutKeyTooLarge(t *testing.T) { func TestRWTransactionPutKeyTooLarge(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"))
// Ensure that an error is returned when inserting with data that's too large. assert.Equal(t, err, KeyTooLargeError)
func TestRWTransactionPutDataTooLarge(t *testing.T) { })
t.Skip("pending") // TODO(benbjohnson)
} }
// Ensure that an error is returned when deleting from a bucket that doesn't exist. // Ensure that an error is returned when deleting from a bucket that doesn't exist.
func TestRWTransactionDeleteBucketNotFound(t *testing.T) { 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. // 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. // Buckets retrieves a list of all buckets.
func (t *Transaction) Buckets() []*Bucket { func (t *Transaction) Buckets() []*Bucket {
warn("[pending] Transaction.Buckets()") // TODO buckets := make([]*Bucket, 0, len(t.buckets.items))
return nil 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. // 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. // Ensure that the database can retrieve a list of buckets.
func TestTransactionBuckets(t *testing.T) { 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. // Ensure that a Transaction can retrieve a bucket.