lbcwallet/walletdb/migration/manager_test.go
Wilmer Paulino 541ad708c7
walletdb/migration: add new migration package with Manager interface
In this commit, we add a new sub-package to the walletdb package:
migration. In this package, we define a new interface, Manager, which
will expose all of the necessary functions required to abstract the
migration logic of different sub-services within the wallet, like the
address and transaction managers. The implementations of this interface
will then be able to use the migration logic within the Upgrade
function with no additional complexity.
2018-11-05 17:58:16 -08:00

344 lines
6.5 KiB
Go

package migration_test
import (
"errors"
"fmt"
"reflect"
"testing"
"github.com/btcsuite/btcwallet/walletdb"
"github.com/btcsuite/btcwallet/walletdb/migration"
"github.com/davecgh/go-spew/spew"
)
type mockMigrationManager struct {
currentVersion uint32
versions []migration.Version
}
var _ migration.Manager = (*mockMigrationManager)(nil)
func (m *mockMigrationManager) Name() string {
return "mock"
}
func (m *mockMigrationManager) Namespace() walletdb.ReadWriteBucket {
return nil
}
func (m *mockMigrationManager) CurrentVersion(_ walletdb.ReadBucket) (uint32, error) {
return m.currentVersion, nil
}
func (m *mockMigrationManager) SetVersion(_ walletdb.ReadWriteBucket, version uint32) error {
m.currentVersion = version
return nil
}
func (m *mockMigrationManager) Versions() []migration.Version {
return m.versions
}
// TestGetLatestVersion ensures that we can properly retrieve the latest version
// from a slice of versions.
func TestGetLatestVersion(t *testing.T) {
t.Parallel()
tests := []struct {
versions []migration.Version
latestVersion uint32
}{
{
versions: []migration.Version{},
latestVersion: 0,
},
{
versions: []migration.Version{
{
Number: 1,
Migration: nil,
},
},
latestVersion: 1,
},
{
versions: []migration.Version{
{
Number: 1,
Migration: nil,
},
{
Number: 2,
Migration: nil,
},
},
latestVersion: 2,
},
{
versions: []migration.Version{
{
Number: 2,
Migration: nil,
},
{
Number: 0,
Migration: nil,
},
{
Number: 1,
Migration: nil,
},
},
latestVersion: 2,
},
}
for i, test := range tests {
latestVersion := migration.GetLatestVersion(test.versions)
if latestVersion != test.latestVersion {
t.Fatalf("test %d: expected latest version %d, got %d",
i, test.latestVersion, latestVersion)
}
}
}
// TestVersionsToApply ensures that the proper versions that needs to be applied
// are returned given the current version.
func TestVersionsToApply(t *testing.T) {
t.Parallel()
tests := []struct {
currentVersion uint32
versions []migration.Version
versionsToApply []migration.Version
}{
{
currentVersion: 0,
versions: []migration.Version{
{
Number: 0,
Migration: nil,
},
},
versionsToApply: nil,
},
{
currentVersion: 1,
versions: []migration.Version{
{
Number: 0,
Migration: nil,
},
},
versionsToApply: nil,
},
{
currentVersion: 0,
versions: []migration.Version{
{
Number: 0,
Migration: nil,
},
{
Number: 1,
Migration: nil,
},
{
Number: 2,
Migration: nil,
},
},
versionsToApply: []migration.Version{
{
Number: 1,
Migration: nil,
},
{
Number: 2,
Migration: nil,
},
},
},
{
currentVersion: 0,
versions: []migration.Version{
{
Number: 2,
Migration: nil,
},
{
Number: 0,
Migration: nil,
},
{
Number: 1,
Migration: nil,
},
},
versionsToApply: []migration.Version{
{
Number: 1,
Migration: nil,
},
{
Number: 2,
Migration: nil,
},
},
},
}
for i, test := range tests {
versionsToApply := migration.VersionsToApply(
test.currentVersion, test.versions,
)
if !reflect.DeepEqual(versionsToApply, test.versionsToApply) {
t.Fatalf("test %d: versions to apply mismatch\n"+
"expected: %v\ngot: %v", i,
spew.Sdump(test.versionsToApply),
spew.Sdump(versionsToApply))
}
}
}
// TestUpgradeRevert ensures that we are not able to revert to a previous
// version.
func TestUpgradeRevert(t *testing.T) {
t.Parallel()
m := &mockMigrationManager{
currentVersion: 1,
versions: []migration.Version{
{
Number: 0,
Migration: nil,
},
},
}
if err := migration.Upgrade(m); err != migration.ErrReversion {
t.Fatalf("expected Upgrade to fail with ErrReversion, got %v",
err)
}
}
// TestUpgradeSameVersion ensures that no upgrades happen if the current version
// matches the latest.
func TestUpgradeSameVersion(t *testing.T) {
t.Parallel()
m := &mockMigrationManager{
currentVersion: 1,
versions: []migration.Version{
{
Number: 0,
Migration: nil,
},
{
Number: 1,
Migration: func(walletdb.ReadWriteBucket) error {
return errors.New("migration should " +
"not happen due to already " +
"being on the latest version")
},
},
},
}
if err := migration.Upgrade(m); err != nil {
t.Fatalf("unable to upgrade: %v", err)
}
}
// TestUpgradeNewVersion ensures that we can properly upgrade to a newer version
// if available.
func TestUpgradeNewVersion(t *testing.T) {
t.Parallel()
versions := []migration.Version{
{
Number: 0,
Migration: nil,
},
{
Number: 1,
Migration: func(walletdb.ReadWriteBucket) error {
return nil
},
},
}
m := &mockMigrationManager{
currentVersion: 0,
versions: versions,
}
if err := migration.Upgrade(m); err != nil {
t.Fatalf("unable to upgrade: %v", err)
}
latestVersion := migration.GetLatestVersion(versions)
if m.currentVersion != latestVersion {
t.Fatalf("expected current version to match latest: "+
"current=%d vs latest=%d", m.currentVersion,
latestVersion)
}
}
// TestUpgradeMultipleVersions ensures that we can go through multiple upgrades
// in-order to reach the latest version.
func TestUpgradeMultipleVersions(t *testing.T) {
t.Parallel()
previousVersion := uint32(0)
versions := []migration.Version{
{
Number: previousVersion,
Migration: nil,
},
{
Number: 1,
Migration: func(walletdb.ReadWriteBucket) error {
if previousVersion != 0 {
return fmt.Errorf("expected previous "+
"version to be %d, got %d", 0,
previousVersion)
}
previousVersion = 1
return nil
},
},
{
Number: 2,
Migration: func(walletdb.ReadWriteBucket) error {
if previousVersion != 1 {
return fmt.Errorf("expected previous "+
"version to be %d, got %d", 1,
previousVersion)
}
previousVersion = 2
return nil
},
},
}
m := &mockMigrationManager{
currentVersion: 0,
versions: versions,
}
if err := migration.Upgrade(m); err != nil {
t.Fatalf("unable to upgrade: %v", err)
}
latestVersion := migration.GetLatestVersion(versions)
if m.currentVersion != latestVersion {
t.Fatalf("expected current version to match latest: "+
"current=%d vs latest=%d", m.currentVersion,
latestVersion)
}
}