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 }