2016-11-22 23:50:27 +03:00
|
|
|
package channeldb
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
2018-08-03 04:17:25 +03:00
|
|
|
"io/ioutil"
|
2016-11-23 00:57:26 +03:00
|
|
|
"testing"
|
|
|
|
|
2018-03-11 06:00:57 +03:00
|
|
|
"github.com/coreos/bbolt"
|
2016-11-22 23:50:27 +03:00
|
|
|
"github.com/go-errors/errors"
|
|
|
|
)
|
|
|
|
|
|
|
|
// TestVersionFetchPut checks the propernces of fetch/put methods
|
|
|
|
// and also initialization of meta data in case if don't have any in
|
|
|
|
// database.
|
|
|
|
func TestVersionFetchPut(t *testing.T) {
|
2017-06-17 01:59:20 +03:00
|
|
|
t.Parallel()
|
|
|
|
|
2016-11-22 23:50:27 +03:00
|
|
|
db, cleanUp, err := makeTestDB()
|
2016-12-22 23:04:41 +03:00
|
|
|
defer cleanUp()
|
2016-11-22 23:50:27 +03:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
meta, err := db.FetchMeta(nil)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2016-11-23 00:57:26 +03:00
|
|
|
if meta.DbVersionNumber != getLatestDBVersion(dbVersions) {
|
2016-11-22 23:50:27 +03:00
|
|
|
t.Fatal("initialization of meta information wasn't performed")
|
|
|
|
}
|
|
|
|
|
2017-02-23 22:56:47 +03:00
|
|
|
newVersion := getLatestDBVersion(dbVersions) + 1
|
2016-11-23 00:57:26 +03:00
|
|
|
meta.DbVersionNumber = newVersion
|
2016-11-22 23:50:27 +03:00
|
|
|
|
2016-11-28 05:44:14 +03:00
|
|
|
if err := db.PutMeta(meta); err != nil {
|
2016-11-22 23:50:27 +03:00
|
|
|
t.Fatalf("update of meta failed %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
meta, err = db.FetchMeta(nil)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2016-11-23 00:57:26 +03:00
|
|
|
if meta.DbVersionNumber != newVersion {
|
2016-11-22 23:50:27 +03:00
|
|
|
t.Fatal("update of meta information wasn't performed")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// TestOrderOfMigrations checks that migrations are applied in proper order.
|
|
|
|
func TestOrderOfMigrations(t *testing.T) {
|
2017-06-17 01:59:20 +03:00
|
|
|
t.Parallel()
|
|
|
|
|
2016-11-22 23:50:27 +03:00
|
|
|
appliedMigration := -1
|
|
|
|
versions := []version{
|
|
|
|
{0, nil},
|
|
|
|
{1, nil},
|
|
|
|
{2, func(tx *bolt.Tx) error {
|
|
|
|
appliedMigration = 2
|
|
|
|
return nil
|
|
|
|
}},
|
|
|
|
{3, func(tx *bolt.Tx) error {
|
|
|
|
appliedMigration = 3
|
|
|
|
return nil
|
|
|
|
}},
|
|
|
|
}
|
|
|
|
|
|
|
|
// Retrieve the migration that should be applied to db, as far as
|
|
|
|
// current version is 1, we skip zero and first versions.
|
2017-02-08 23:56:37 +03:00
|
|
|
migrations, _ := getMigrationsToApply(versions, 1)
|
2016-11-22 23:50:27 +03:00
|
|
|
|
|
|
|
if len(migrations) != 2 {
|
|
|
|
t.Fatal("incorrect number of migrations to apply")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Apply first migration.
|
|
|
|
migrations[0](nil)
|
|
|
|
|
|
|
|
// Check that first migration corresponds to the second version.
|
|
|
|
if appliedMigration != 2 {
|
|
|
|
t.Fatal("incorrect order of applying migrations")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Apply second migration.
|
|
|
|
migrations[1](nil)
|
|
|
|
|
|
|
|
// Check that second migration corresponds to the third version.
|
|
|
|
if appliedMigration != 3 {
|
|
|
|
t.Fatal("incorrect order of applying migrations")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// TestGlobalVersionList checks that there is no mistake in global version list
|
|
|
|
// in terms of version ordering.
|
|
|
|
func TestGlobalVersionList(t *testing.T) {
|
2017-06-17 01:59:20 +03:00
|
|
|
t.Parallel()
|
|
|
|
|
2016-11-23 00:57:26 +03:00
|
|
|
if dbVersions == nil {
|
2016-11-22 23:50:27 +03:00
|
|
|
t.Fatal("can't find versions list")
|
|
|
|
}
|
|
|
|
|
2016-11-23 00:57:26 +03:00
|
|
|
if len(dbVersions) == 0 {
|
2016-11-22 23:50:27 +03:00
|
|
|
t.Fatal("db versions list is empty")
|
|
|
|
}
|
|
|
|
|
2016-11-23 00:57:26 +03:00
|
|
|
prev := dbVersions[0].number
|
|
|
|
for i := 1; i < len(dbVersions); i++ {
|
|
|
|
version := dbVersions[i].number
|
2016-11-22 23:50:27 +03:00
|
|
|
|
|
|
|
if version == prev {
|
|
|
|
t.Fatal("duplicates db versions")
|
|
|
|
}
|
|
|
|
if version < prev {
|
|
|
|
t.Fatal("order of db versions is wrong")
|
|
|
|
}
|
|
|
|
|
|
|
|
prev = version
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestMigrationWithPanic(t *testing.T) {
|
2017-06-17 01:59:20 +03:00
|
|
|
t.Parallel()
|
|
|
|
|
2016-11-22 23:50:27 +03:00
|
|
|
bucketPrefix := []byte("somebucket")
|
|
|
|
keyPrefix := []byte("someprefix")
|
|
|
|
beforeMigration := []byte("beforemigration")
|
|
|
|
afterMigration := []byte("aftermigration")
|
|
|
|
|
|
|
|
beforeMigrationFunc := func(d *DB) {
|
|
|
|
// Insert data in database and in order then make sure that the
|
|
|
|
// key isn't changes in case of panic or fail.
|
2016-11-28 05:32:45 +03:00
|
|
|
d.Update(func(tx *bolt.Tx) error {
|
2016-11-22 23:50:27 +03:00
|
|
|
bucket, err := tx.CreateBucketIfNotExists(bucketPrefix)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
bucket.Put(keyPrefix, beforeMigration)
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2018-02-07 06:11:11 +03:00
|
|
|
// Create migration function which changes the initially created data and
|
2016-11-22 23:50:27 +03:00
|
|
|
// throw the panic, in this case we pretending that something goes.
|
|
|
|
migrationWithPanic := func(tx *bolt.Tx) error {
|
|
|
|
bucket, err := tx.CreateBucketIfNotExists(bucketPrefix)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
bucket.Put(keyPrefix, afterMigration)
|
|
|
|
panic("panic!")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check that version of database and data wasn't changed.
|
|
|
|
afterMigrationFunc := func(d *DB) {
|
|
|
|
meta, err := d.FetchMeta(nil)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2016-11-23 00:57:26 +03:00
|
|
|
if meta.DbVersionNumber != 0 {
|
2018-02-07 06:11:11 +03:00
|
|
|
t.Fatal("migration panicked but version is changed")
|
2016-11-22 23:50:27 +03:00
|
|
|
}
|
|
|
|
|
2016-11-28 05:32:45 +03:00
|
|
|
err = d.Update(func(tx *bolt.Tx) error {
|
2016-11-22 23:50:27 +03:00
|
|
|
bucket, err := tx.CreateBucketIfNotExists(bucketPrefix)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
value := bucket.Get(keyPrefix)
|
|
|
|
if !bytes.Equal(value, beforeMigration) {
|
|
|
|
return errors.New("migration failed but data is " +
|
|
|
|
"changed")
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
applyMigration(t,
|
|
|
|
beforeMigrationFunc,
|
|
|
|
afterMigrationFunc,
|
|
|
|
migrationWithPanic,
|
|
|
|
true)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestMigrationWithFatal(t *testing.T) {
|
2017-06-17 01:59:20 +03:00
|
|
|
t.Parallel()
|
|
|
|
|
2016-11-22 23:50:27 +03:00
|
|
|
bucketPrefix := []byte("somebucket")
|
|
|
|
keyPrefix := []byte("someprefix")
|
|
|
|
beforeMigration := []byte("beforemigration")
|
|
|
|
afterMigration := []byte("aftermigration")
|
|
|
|
|
|
|
|
beforeMigrationFunc := func(d *DB) {
|
2016-11-28 05:32:45 +03:00
|
|
|
d.Update(func(tx *bolt.Tx) error {
|
2016-11-22 23:50:27 +03:00
|
|
|
bucket, err := tx.CreateBucketIfNotExists(bucketPrefix)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
bucket.Put(keyPrefix, beforeMigration)
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2018-02-07 06:11:11 +03:00
|
|
|
// Create migration function which changes the initially created data and
|
|
|
|
// return the error, in this case we pretending that something goes
|
2016-11-22 23:50:27 +03:00
|
|
|
// wrong.
|
|
|
|
migrationWithFatal := func(tx *bolt.Tx) error {
|
|
|
|
bucket, err := tx.CreateBucketIfNotExists(bucketPrefix)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
bucket.Put(keyPrefix, afterMigration)
|
2017-02-23 22:56:47 +03:00
|
|
|
return errors.New("some error")
|
2016-11-22 23:50:27 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// Check that version of database and initial data wasn't changed.
|
|
|
|
afterMigrationFunc := func(d *DB) {
|
|
|
|
meta, err := d.FetchMeta(nil)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2016-11-23 00:57:26 +03:00
|
|
|
if meta.DbVersionNumber != 0 {
|
2016-11-22 23:50:27 +03:00
|
|
|
t.Fatal("migration failed but version is changed")
|
|
|
|
}
|
|
|
|
|
2016-11-28 05:32:45 +03:00
|
|
|
err = d.Update(func(tx *bolt.Tx) error {
|
2016-11-22 23:50:27 +03:00
|
|
|
bucket, err := tx.CreateBucketIfNotExists(bucketPrefix)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
value := bucket.Get(keyPrefix)
|
|
|
|
if !bytes.Equal(value, beforeMigration) {
|
|
|
|
return errors.New("migration failed but data is " +
|
|
|
|
"changed")
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
applyMigration(t,
|
|
|
|
beforeMigrationFunc,
|
|
|
|
afterMigrationFunc,
|
|
|
|
migrationWithFatal,
|
|
|
|
true)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestMigrationWithoutErrors(t *testing.T) {
|
2017-06-17 01:59:20 +03:00
|
|
|
t.Parallel()
|
|
|
|
|
2016-11-22 23:50:27 +03:00
|
|
|
bucketPrefix := []byte("somebucket")
|
|
|
|
keyPrefix := []byte("someprefix")
|
|
|
|
beforeMigration := []byte("beforemigration")
|
|
|
|
afterMigration := []byte("aftermigration")
|
|
|
|
|
|
|
|
// Populate database with initial data.
|
|
|
|
beforeMigrationFunc := func(d *DB) {
|
2016-11-28 05:32:45 +03:00
|
|
|
d.Update(func(tx *bolt.Tx) error {
|
2016-11-22 23:50:27 +03:00
|
|
|
bucket, err := tx.CreateBucketIfNotExists(bucketPrefix)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
bucket.Put(keyPrefix, beforeMigration)
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2018-02-07 06:11:11 +03:00
|
|
|
// Create migration function which changes the initially created data.
|
2016-11-22 23:50:27 +03:00
|
|
|
migrationWithoutErrors := func(tx *bolt.Tx) error {
|
|
|
|
bucket, err := tx.CreateBucketIfNotExists(bucketPrefix)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
bucket.Put(keyPrefix, afterMigration)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check that version of database and data was properly changed.
|
|
|
|
afterMigrationFunc := func(d *DB) {
|
|
|
|
meta, err := d.FetchMeta(nil)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2016-11-23 00:57:26 +03:00
|
|
|
if meta.DbVersionNumber != 1 {
|
2016-11-22 23:50:27 +03:00
|
|
|
t.Fatal("version number isn't changed after " +
|
2018-02-07 06:11:11 +03:00
|
|
|
"successfully applied migration")
|
2016-11-22 23:50:27 +03:00
|
|
|
}
|
|
|
|
|
2016-11-28 05:32:45 +03:00
|
|
|
err = d.Update(func(tx *bolt.Tx) error {
|
2016-11-22 23:50:27 +03:00
|
|
|
bucket, err := tx.CreateBucketIfNotExists(bucketPrefix)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
value := bucket.Get(keyPrefix)
|
|
|
|
if !bytes.Equal(value, afterMigration) {
|
2018-02-07 06:11:11 +03:00
|
|
|
return errors.New("migration wasn't applied " +
|
2016-11-22 23:50:27 +03:00
|
|
|
"properly")
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
applyMigration(t,
|
|
|
|
beforeMigrationFunc,
|
|
|
|
afterMigrationFunc,
|
|
|
|
migrationWithoutErrors,
|
|
|
|
false)
|
|
|
|
}
|
2018-08-03 04:17:25 +03:00
|
|
|
|
|
|
|
// TestMigrationReversion tests after performing a migration to a higher
|
|
|
|
// database version, opening the database with a lower latest db version returns
|
|
|
|
// ErrDBReversion.
|
|
|
|
func TestMigrationReversion(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
tempDirName, err := ioutil.TempDir("", "channeldb")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to create temp dir: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
cdb, err := Open(tempDirName)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to open channeldb: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update the database metadata to point to one more than the highest
|
|
|
|
// known version.
|
|
|
|
err = cdb.Update(func(tx *bolt.Tx) error {
|
|
|
|
newMeta := &Meta{
|
|
|
|
DbVersionNumber: getLatestDBVersion(dbVersions) + 1,
|
|
|
|
}
|
|
|
|
|
|
|
|
return putMeta(newMeta, tx)
|
|
|
|
})
|
|
|
|
|
|
|
|
// Close the database. Even if we succeeded, our next step is to reopen.
|
|
|
|
cdb.Close()
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to increase db version: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err = Open(tempDirName)
|
|
|
|
if err != ErrDBReversion {
|
|
|
|
t.Fatalf("unexpected error when opening channeldb, "+
|
|
|
|
"want: %v, got: %v", ErrDBReversion, err)
|
|
|
|
}
|
|
|
|
}
|