func TestTx_OnCommit_Rollback(t *testing.T) {
	var x int
	withOpenDB(func(db *DB, path string) {
		db.Update(func(tx *Tx) error {
			tx.OnCommit(func() { x += 1 })
			tx.OnCommit(func() { x += 2 })
			tx.CreateBucket([]byte("widgets"))
			return errors.New("rollback this commit")
		})
	})
	assert.Equal(t, 0, x)
}
Ensure that Tx commit handlers are NOT called after a transaction rolls back.
package bolt
import (
	"errors"
	"fmt"
	"os"
	"testing"
	"github.com/stretchr/testify/assert"
)
func TestTx_Commit_Closed(t *testing.T) {
	withOpenDB(func(db *DB, path string) {
		tx, _ := db.Begin(true)
		tx.CreateBucket([]byte("foo"))
		assert.NoError(t, tx.Commit())
		assert.Equal(t, tx.Commit(), ErrTxClosed)
	})
}
func TestTx_Rollback_Closed(t *testing.T) {
	withOpenDB(func(db *DB, path string) {
		tx, _ := db.Begin(true)
		assert.NoError(t, tx.Rollback())
		assert.Equal(t, tx.Rollback(), ErrTxClosed)
	})
}
func TestTx_Commit_ReadOnly(t *testing.T) {
	withOpenDB(func(db *DB, path string) {
		tx, _ := db.Begin(false)
		assert.Equal(t, tx.Commit(), ErrTxNotWritable)
	})
}
func TestTx_Cursor(t *testing.T) {
	withOpenDB(func(db *DB, path string) {
		db.Update(func(tx *Tx) error {
			tx.CreateBucket([]byte("widgets"))
			tx.CreateBucket([]byte("woojits"))
			c := tx.Cursor()
			k, v := c.First()
			assert.Equal(t, "widgets", string(k))
			assert.Nil(t, v)
			k, v = c.Next()
			assert.Equal(t, "woojits", string(k))
			assert.Nil(t, v)
			k, v = c.Next()
			assert.Nil(t, k)
			assert.Nil(t, v)
			return nil
		})
	})
}
func TestTx_CreateBucket_ReadOnly(t *testing.T) {
	withOpenDB(func(db *DB, path string) {
		db.View(func(tx *Tx) error {
			b, err := tx.CreateBucket([]byte("foo"))
			assert.Nil(t, b)
			assert.Equal(t, ErrTxNotWritable, err)
			return nil
		})
	})
}
func TestTx_CreateBucket_Closed(t *testing.T) {
	withOpenDB(func(db *DB, path string) {
		tx, _ := db.Begin(true)
		tx.Commit()
		b, err := tx.CreateBucket([]byte("foo"))
		assert.Nil(t, b)
		assert.Equal(t, ErrTxClosed, err)
	})
}
func TestTx_Bucket(t *testing.T) {
	withOpenDB(func(db *DB, path string) {
		db.Update(func(tx *Tx) error {
			tx.CreateBucket([]byte("widgets"))
			b := tx.Bucket([]byte("widgets"))
			assert.NotNil(t, b)
			return nil
		})
	})
}
func TestTx_Get_Missing(t *testing.T) {
	withOpenDB(func(db *DB, path string) {
		db.Update(func(tx *Tx) error {
			tx.CreateBucket([]byte("widgets"))
			tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte("bar"))
			value := tx.Bucket([]byte("widgets")).Get([]byte("no_such_key"))
			assert.Nil(t, value)
			return nil
		})
	})
}
func TestTx_CreateBucket(t *testing.T) {
	withOpenDB(func(db *DB, path string) {
		db.Update(func(tx *Tx) error {
			b, err := tx.CreateBucket([]byte("widgets"))
			assert.NotNil(t, b)
			assert.NoError(t, err)
			return nil
		})
		db.View(func(tx *Tx) error {
			b := tx.Bucket([]byte("widgets"))
			assert.NotNil(t, b)
			return nil
		})
	})
}
func TestTx_CreateBucketIfNotExists(t *testing.T) {
	withOpenDB(func(db *DB, path string) {
		db.Update(func(tx *Tx) error {
			b, err := tx.CreateBucketIfNotExists([]byte("widgets"))
			assert.NotNil(t, b)
			assert.NoError(t, err)
			b, err = tx.CreateBucketIfNotExists([]byte("widgets"))
			assert.NotNil(t, b)
			assert.NoError(t, err)
			b, err = tx.CreateBucketIfNotExists([]byte{})
			assert.Nil(t, b)
			assert.Equal(t, ErrBucketNameRequired, err)
			b, err = tx.CreateBucketIfNotExists(nil)
			assert.Nil(t, b)
			assert.Equal(t, ErrBucketNameRequired, err)
			return nil
		})
		db.View(func(tx *Tx) error {
			b := tx.Bucket([]byte("widgets"))
			assert.NotNil(t, b)
			return nil
		})
	})
}
func TestTx_CreateBucket_Exists(t *testing.T) {
	withOpenDB(func(db *DB, path string) {
		db.Update(func(tx *Tx) error {
			b, err := tx.CreateBucket([]byte("widgets"))
			assert.NotNil(t, b)
			assert.NoError(t, err)
			return nil
		})
		db.Update(func(tx *Tx) error {
			b, err := tx.CreateBucket([]byte("widgets"))
			assert.Nil(t, b)
			assert.Equal(t, ErrBucketExists, err)
			return nil
		})
	})
}
func TestTx_CreateBucket_NameRequired(t *testing.T) {
	withOpenDB(func(db *DB, path string) {
		db.Update(func(tx *Tx) error {
			b, err := tx.CreateBucket(nil)
			assert.Nil(t, b)
			assert.Equal(t, ErrBucketNameRequired, err)
			return nil
		})
	})
}
func TestTx_DeleteBucket(t *testing.T) {
	withOpenDB(func(db *DB, path string) {
		db.Update(func(tx *Tx) error {
			tx.CreateBucket([]byte("widgets"))
			tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte("bar"))
			return nil
		})
		var root pgid
		db.View(func(tx *Tx) error {
			root = tx.Bucket([]byte("widgets")).root
			return nil
		})
		db.Update(func(tx *Tx) error {
			assert.NoError(t, tx.DeleteBucket([]byte("widgets")))
			assert.Nil(t, tx.Bucket([]byte("widgets")))
			return nil
		})
		db.Update(func(tx *Tx) error {
			assert.Equal(t, []pgid{5, 4}, db.freelist.all())
			b, err := tx.CreateBucket([]byte("widgets"))
			assert.NotNil(t, b)
			assert.NoError(t, err)
			assert.Nil(t, tx.Bucket([]byte("widgets")).Get([]byte("foo")))
			return nil
		})
	})
}
func TestTx_DeleteBucket_Closed(t *testing.T) {
	withOpenDB(func(db *DB, path string) {
		tx, _ := db.Begin(true)
		tx.Commit()
		assert.Equal(t, tx.DeleteBucket([]byte("foo")), ErrTxClosed)
	})
}
func TestTx_DeleteBucket_ReadOnly(t *testing.T) {
	withOpenDB(func(db *DB, path string) {
		db.View(func(tx *Tx) error {
			assert.Equal(t, tx.DeleteBucket([]byte("foo")), ErrTxNotWritable)
			return nil
		})
	})
}
func TestTx_DeleteBucket_NotFound(t *testing.T) {
	withOpenDB(func(db *DB, path string) {
		db.Update(func(tx *Tx) error {
			assert.Equal(t, ErrBucketNotFound, tx.DeleteBucket([]byte("widgets")))
			return nil
		})
	})
}
func TestTx_OnCommit(t *testing.T) {
	var x int
	withOpenDB(func(db *DB, path string) {
		db.Update(func(tx *Tx) error {
			tx.OnCommit(func() { x += 1 })
			tx.OnCommit(func() { x += 2 })
			_, err := tx.CreateBucket([]byte("widgets"))
			return err
		})
	})
	assert.Equal(t, 3, x)
}