github.com/btcsuite/btcwallet/walletdb@v1.4.2/migration/manager_test.go (about)

     1  package migration_test
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"reflect"
     7  	"testing"
     8  
     9  	"github.com/btcsuite/btcwallet/walletdb"
    10  	"github.com/btcsuite/btcwallet/walletdb/migration"
    11  	"github.com/davecgh/go-spew/spew"
    12  )
    13  
    14  type mockMigrationManager struct {
    15  	currentVersion uint32
    16  	versions       []migration.Version
    17  }
    18  
    19  var _ migration.Manager = (*mockMigrationManager)(nil)
    20  
    21  func (m *mockMigrationManager) Name() string {
    22  	return "mock"
    23  }
    24  
    25  func (m *mockMigrationManager) Namespace() walletdb.ReadWriteBucket {
    26  	return nil
    27  }
    28  
    29  func (m *mockMigrationManager) CurrentVersion(_ walletdb.ReadBucket) (uint32, error) {
    30  	return m.currentVersion, nil
    31  }
    32  
    33  func (m *mockMigrationManager) SetVersion(_ walletdb.ReadWriteBucket, version uint32) error {
    34  	m.currentVersion = version
    35  	return nil
    36  }
    37  
    38  func (m *mockMigrationManager) Versions() []migration.Version {
    39  	return m.versions
    40  }
    41  
    42  // TestGetLatestVersion ensures that we can properly retrieve the latest version
    43  // from a slice of versions.
    44  func TestGetLatestVersion(t *testing.T) {
    45  	t.Parallel()
    46  
    47  	tests := []struct {
    48  		versions      []migration.Version
    49  		latestVersion uint32
    50  	}{
    51  		{
    52  			versions:      []migration.Version{},
    53  			latestVersion: 0,
    54  		},
    55  		{
    56  			versions: []migration.Version{
    57  				{
    58  					Number:    1,
    59  					Migration: nil,
    60  				},
    61  			},
    62  			latestVersion: 1,
    63  		},
    64  		{
    65  			versions: []migration.Version{
    66  				{
    67  					Number:    1,
    68  					Migration: nil,
    69  				},
    70  				{
    71  					Number:    2,
    72  					Migration: nil,
    73  				},
    74  			},
    75  			latestVersion: 2,
    76  		},
    77  		{
    78  			versions: []migration.Version{
    79  				{
    80  					Number:    2,
    81  					Migration: nil,
    82  				},
    83  				{
    84  					Number:    0,
    85  					Migration: nil,
    86  				},
    87  				{
    88  					Number:    1,
    89  					Migration: nil,
    90  				},
    91  			},
    92  			latestVersion: 2,
    93  		},
    94  	}
    95  
    96  	for i, test := range tests {
    97  		latestVersion := migration.GetLatestVersion(test.versions)
    98  		if latestVersion != test.latestVersion {
    99  			t.Fatalf("test %d: expected latest version %d, got %d",
   100  				i, test.latestVersion, latestVersion)
   101  		}
   102  	}
   103  }
   104  
   105  // TestVersionsToApply ensures that the proper versions that needs to be applied
   106  // are returned given the current version.
   107  func TestVersionsToApply(t *testing.T) {
   108  	t.Parallel()
   109  
   110  	tests := []struct {
   111  		currentVersion  uint32
   112  		versions        []migration.Version
   113  		versionsToApply []migration.Version
   114  	}{
   115  		{
   116  			currentVersion: 0,
   117  			versions: []migration.Version{
   118  				{
   119  					Number:    0,
   120  					Migration: nil,
   121  				},
   122  			},
   123  			versionsToApply: nil,
   124  		},
   125  		{
   126  			currentVersion: 1,
   127  			versions: []migration.Version{
   128  				{
   129  					Number:    0,
   130  					Migration: nil,
   131  				},
   132  			},
   133  			versionsToApply: nil,
   134  		},
   135  		{
   136  			currentVersion: 0,
   137  			versions: []migration.Version{
   138  				{
   139  					Number:    0,
   140  					Migration: nil,
   141  				},
   142  				{
   143  					Number:    1,
   144  					Migration: nil,
   145  				},
   146  				{
   147  					Number:    2,
   148  					Migration: nil,
   149  				},
   150  			},
   151  			versionsToApply: []migration.Version{
   152  				{
   153  					Number:    1,
   154  					Migration: nil,
   155  				},
   156  				{
   157  					Number:    2,
   158  					Migration: nil,
   159  				},
   160  			},
   161  		},
   162  		{
   163  			currentVersion: 0,
   164  			versions: []migration.Version{
   165  				{
   166  					Number:    2,
   167  					Migration: nil,
   168  				},
   169  				{
   170  					Number:    0,
   171  					Migration: nil,
   172  				},
   173  				{
   174  					Number:    1,
   175  					Migration: nil,
   176  				},
   177  			},
   178  			versionsToApply: []migration.Version{
   179  				{
   180  					Number:    1,
   181  					Migration: nil,
   182  				},
   183  				{
   184  					Number:    2,
   185  					Migration: nil,
   186  				},
   187  			},
   188  		},
   189  	}
   190  
   191  	for i, test := range tests {
   192  		versionsToApply := migration.VersionsToApply(
   193  			test.currentVersion, test.versions,
   194  		)
   195  
   196  		if !reflect.DeepEqual(versionsToApply, test.versionsToApply) {
   197  			t.Fatalf("test %d: versions to apply mismatch\n"+
   198  				"expected: %v\ngot: %v", i,
   199  				spew.Sdump(test.versionsToApply),
   200  				spew.Sdump(versionsToApply))
   201  		}
   202  	}
   203  }
   204  
   205  // TestUpgradeRevert ensures that we are not able to revert to a previous
   206  // version.
   207  func TestUpgradeRevert(t *testing.T) {
   208  	t.Parallel()
   209  
   210  	m := &mockMigrationManager{
   211  		currentVersion: 1,
   212  		versions: []migration.Version{
   213  			{
   214  				Number:    0,
   215  				Migration: nil,
   216  			},
   217  		},
   218  	}
   219  
   220  	if err := migration.Upgrade(m); err != migration.ErrReversion {
   221  		t.Fatalf("expected Upgrade to fail with ErrReversion, got %v",
   222  			err)
   223  	}
   224  }
   225  
   226  // TestUpgradeSameVersion ensures that no upgrades happen if the current version
   227  // matches the latest.
   228  func TestUpgradeSameVersion(t *testing.T) {
   229  	t.Parallel()
   230  
   231  	m := &mockMigrationManager{
   232  		currentVersion: 1,
   233  		versions: []migration.Version{
   234  			{
   235  				Number:    0,
   236  				Migration: nil,
   237  			},
   238  			{
   239  				Number: 1,
   240  				Migration: func(walletdb.ReadWriteBucket) error {
   241  					return errors.New("migration should " +
   242  						"not happen due to already " +
   243  						"being on the latest version")
   244  				},
   245  			},
   246  		},
   247  	}
   248  
   249  	if err := migration.Upgrade(m); err != nil {
   250  		t.Fatalf("unable to upgrade: %v", err)
   251  	}
   252  }
   253  
   254  // TestUpgradeNewVersion ensures that we can properly upgrade to a newer version
   255  // if available.
   256  func TestUpgradeNewVersion(t *testing.T) {
   257  	t.Parallel()
   258  
   259  	versions := []migration.Version{
   260  		{
   261  			Number:    0,
   262  			Migration: nil,
   263  		},
   264  		{
   265  			Number: 1,
   266  			Migration: func(walletdb.ReadWriteBucket) error {
   267  				return nil
   268  			},
   269  		},
   270  	}
   271  
   272  	m := &mockMigrationManager{
   273  		currentVersion: 0,
   274  		versions:       versions,
   275  	}
   276  
   277  	if err := migration.Upgrade(m); err != nil {
   278  		t.Fatalf("unable to upgrade: %v", err)
   279  	}
   280  
   281  	latestVersion := migration.GetLatestVersion(versions)
   282  	if m.currentVersion != latestVersion {
   283  		t.Fatalf("expected current version to match latest: "+
   284  			"current=%d vs latest=%d", m.currentVersion,
   285  			latestVersion)
   286  	}
   287  }
   288  
   289  // TestUpgradeMultipleVersions ensures that we can go through multiple upgrades
   290  // in-order to reach the latest version.
   291  func TestUpgradeMultipleVersions(t *testing.T) {
   292  	t.Parallel()
   293  
   294  	previousVersion := uint32(0)
   295  	versions := []migration.Version{
   296  		{
   297  			Number:    previousVersion,
   298  			Migration: nil,
   299  		},
   300  		{
   301  			Number: 1,
   302  			Migration: func(walletdb.ReadWriteBucket) error {
   303  				if previousVersion != 0 {
   304  					return fmt.Errorf("expected previous "+
   305  						"version to be %d, got %d", 0,
   306  						previousVersion)
   307  				}
   308  
   309  				previousVersion = 1
   310  				return nil
   311  			},
   312  		},
   313  		{
   314  			Number: 2,
   315  			Migration: func(walletdb.ReadWriteBucket) error {
   316  				if previousVersion != 1 {
   317  					return fmt.Errorf("expected previous "+
   318  						"version to be %d, got %d", 1,
   319  						previousVersion)
   320  				}
   321  
   322  				previousVersion = 2
   323  				return nil
   324  			},
   325  		},
   326  	}
   327  
   328  	m := &mockMigrationManager{
   329  		currentVersion: 0,
   330  		versions:       versions,
   331  	}
   332  
   333  	if err := migration.Upgrade(m); err != nil {
   334  		t.Fatalf("unable to upgrade: %v", err)
   335  	}
   336  
   337  	latestVersion := migration.GetLatestVersion(versions)
   338  	if m.currentVersion != latestVersion {
   339  		t.Fatalf("expected current version to match latest: "+
   340  			"current=%d vs latest=%d", m.currentVersion,
   341  			latestVersion)
   342  	}
   343  }