diff options
author | Ben Johnson <benbjohnson@yahoo.com> | 2014-07-11 09:54:10 -0600 |
---|---|---|
committer | Ben Johnson <benbjohnson@yahoo.com> | 2014-07-11 09:54:10 -0600 |
commit | ac4838472da343493c54c7649deb3b20669f8c3b (patch) | |
tree | a0da15376d9bd4b54877487e6f9c5d3614bd0d59 /db_test.go | |
parent | Merge pull request #219 from benbjohnson/freelist-overflow (diff) | |
download | dedo-ac4838472da343493c54c7649deb3b20669f8c3b.tar.gz dedo-ac4838472da343493c54c7649deb3b20669f8c3b.tar.xz |
Recover from panics appropriately.
This commit adds a defer handler to ensure that transactions are always closed out - even
in the event of a panic within user code. It's recommended that applications always fail
in the event of a panic but some packages such as net/http will automatically recover
which is a problem (IHMO).
Diffstat (limited to 'db_test.go')
-rw-r--r-- | db_test.go | 60 |
1 files changed, 60 insertions, 0 deletions
@@ -262,6 +262,37 @@ func TestDB_Update_ManualCommitAndRollback(t *testing.T) { }) } +// Ensure a write transaction that panics does not hold open locks. +func TestDB_Update_Panic(t *testing.T) { + withOpenDB(func(db *DB, path string) { + func() { + defer func() { + if r := recover(); r != nil { + warn("recover: update", r) + } + }() + db.Update(func(tx *Tx) error { + tx.CreateBucket([]byte("widgets")) + panic("omg") + return nil + }) + }() + + // Verify we can update again. + err := db.Update(func(tx *Tx) error { + _, err := tx.CreateBucket([]byte("widgets")) + return err + }) + assert.NoError(t, err) + + // Verify that our change persisted. + err = db.Update(func(tx *Tx) error { + assert.NotNil(t, tx.Bucket([]byte("widgets"))) + return nil + }) + }) +} + // Ensure a database can return an error through a read-only transactional block. func TestDB_View_Error(t *testing.T) { withOpenDB(func(db *DB, path string) { @@ -272,6 +303,35 @@ func TestDB_View_Error(t *testing.T) { }) } +// Ensure a read transaction that panics does not hold open locks. +func TestDB_View_Panic(t *testing.T) { + withOpenDB(func(db *DB, path string) { + db.Update(func(tx *Tx) error { + tx.CreateBucket([]byte("widgets")) + return nil + }) + + func() { + defer func() { + if r := recover(); r != nil { + warn("recover: view", r) + } + }() + db.View(func(tx *Tx) error { + assert.NotNil(t, tx.Bucket([]byte("widgets"))) + panic("omg") + return nil + }) + }() + + // Verify that we can still use read transactions. + db.View(func(tx *Tx) error { + assert.NotNil(t, tx.Bucket([]byte("widgets"))) + return nil + }) + }) +} + // Ensure that an error is returned when a database write fails. func TestDB_Commit_WriteFail(t *testing.T) { t.Skip("pending") // TODO(benbjohnson) |