github.com/mendersoftware/go-lib-micro@v0.0.0-20240304135804-e8e39c59b148/mongo/migrate/migrator_simple_test.go (about) 1 // Copyright 2023 Northern.tech AS 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 package migrate_test 15 16 import ( 17 "context" 18 "errors" 19 "sort" 20 "testing" 21 "time" 22 23 "github.com/stretchr/testify/assert" 24 25 . "github.com/mendersoftware/go-lib-micro/mongo/migrate" 26 "github.com/mendersoftware/go-lib-micro/mongo/migrate/mocks" 27 "go.mongodb.org/mongo-driver/bson" 28 ) 29 30 func TestSimpleMigratorApply(t *testing.T) { 31 if testing.Short() { 32 t.Skip("skipping TestDummyMigratorApply in short mode.") 33 } 34 35 makeMigration := func(v Version, from Version, err error) Migration { 36 m := &mocks.Migration{} 37 m.On("Up", from).Return(err) 38 m.On("Version").Return(v) 39 return m 40 } 41 42 testCases := map[string]struct { 43 Automigrate bool 44 InputMigrations []MigrationEntry 45 InputVersion Version 46 47 Migrators []Migration 48 49 OutputVersion Version 50 OutputError error 51 }{ 52 "ok - empty state": { 53 Automigrate: true, 54 InputMigrations: nil, 55 InputVersion: MakeVersion(1, 0, 0), 56 57 OutputVersion: MakeVersion(1, 0, 0), 58 }, 59 60 "ok - already has version": { 61 Automigrate: true, 62 InputMigrations: []MigrationEntry{ 63 { 64 Version: MakeVersion(1, 0, 0), 65 Timestamp: time.Now(), 66 }, 67 }, 68 InputVersion: MakeVersion(1, 0, 0), 69 OutputVersion: MakeVersion(1, 0, 0), 70 }, 71 "ok - already has version, no automigrate": { 72 Automigrate: false, 73 InputMigrations: []MigrationEntry{ 74 { 75 Version: MakeVersion(1, 0, 0), 76 Timestamp: time.Now(), 77 }, 78 }, 79 InputVersion: MakeVersion(1, 0, 0), 80 OutputVersion: MakeVersion(1, 0, 0), 81 }, 82 "ok - add default target version": { 83 Automigrate: true, 84 InputMigrations: []MigrationEntry{ 85 { 86 Version: MakeVersion(1, 0, 0), 87 Timestamp: time.Now(), 88 }, 89 }, 90 InputVersion: MakeVersion(1, 1, 0), 91 OutputVersion: MakeVersion(1, 1, 0), 92 }, 93 "ok - add default target version, no automigrate": { 94 Automigrate: false, 95 InputMigrations: []MigrationEntry{ 96 { 97 Version: MakeVersion(1, 0, 0), 98 Timestamp: time.Now(), 99 }, 100 }, 101 InputVersion: MakeVersion(1, 1, 0), 102 OutputVersion: MakeVersion(1, 0, 0), 103 OutputError: errors.New("db needs migration: test has version 1.0.0, needs version 1.1.0"), 104 }, 105 "ok - ran migrations": { 106 Automigrate: true, 107 InputMigrations: []MigrationEntry{ 108 { 109 Version: MakeVersion(1, 0, 0), 110 Timestamp: time.Now(), 111 }, 112 { 113 Version: MakeVersion(1, 0, 1), 114 Timestamp: time.Now(), 115 }, 116 }, 117 InputVersion: MakeVersion(1, 1, 0), 118 OutputVersion: MakeVersion(1, 1, 0), 119 120 Migrators: []Migration{ 121 makeMigration(MakeVersion(1, 0, 1), MakeVersion(1, 0, 0), nil), 122 makeMigration(MakeVersion(1, 1, 0), MakeVersion(1, 0, 1), nil), 123 }, 124 }, 125 "ok - ran migrations, no automigrate": { 126 Automigrate: false, 127 InputMigrations: []MigrationEntry{ 128 { 129 Version: MakeVersion(1, 0, 0), 130 Timestamp: time.Now(), 131 }, 132 { 133 Version: MakeVersion(1, 0, 1), 134 Timestamp: time.Now(), 135 }, 136 }, 137 InputVersion: MakeVersion(1, 1, 0), 138 OutputVersion: MakeVersion(1, 0, 1), 139 140 Migrators: []Migration{ 141 makeMigration(MakeVersion(1, 0, 1), MakeVersion(1, 0, 0), nil), 142 makeMigration(MakeVersion(1, 1, 0), MakeVersion(1, 0, 1), nil), 143 }, 144 OutputError: errors.New("db needs migration: test has version 1.0.1, needs version 1.1.0"), 145 }, 146 "ok - migration to lower": { 147 Automigrate: true, 148 InputMigrations: nil, 149 InputVersion: MakeVersion(0, 1, 0), 150 OutputVersion: MakeVersion(0, 1, 0), 151 152 Migrators: []Migration{ 153 makeMigration(MakeVersion(1, 0, 1), MakeVersion(0, 0, 0), nil), 154 makeMigration(MakeVersion(1, 1, 0), MakeVersion(1, 0, 1), nil), 155 }, 156 }, 157 "err - failed migration": { 158 Automigrate: true, 159 InputMigrations: []MigrationEntry{ 160 { 161 Version: MakeVersion(1, 0, 0), 162 Timestamp: time.Now(), 163 }, 164 }, 165 InputVersion: MakeVersion(1, 1, 0), 166 // migration 1.0.3 fails, thus the output should remain at 1.0.2 167 OutputVersion: MakeVersion(1, 0, 2), 168 169 Migrators: []Migration{ 170 makeMigration(MakeVersion(1, 0, 1), MakeVersion(1, 0, 0), nil), 171 makeMigration(MakeVersion(1, 0, 3), MakeVersion(1, 0, 2), errors.New("failed")), 172 makeMigration(MakeVersion(1, 0, 2), MakeVersion(1, 0, 1), nil), 173 }, 174 175 OutputError: errors.New("failed to apply migration from 1.0.2 to 1.0.3: failed"), 176 }, 177 } 178 179 for name := range testCases { 180 tc := testCases[name] 181 t.Run(name, func(t *testing.T) { 182 183 //setup 184 db.Wipe() 185 client := db.Client() 186 for i := range tc.InputMigrations { 187 _, err := client.Database("test"). 188 Collection(DbMigrationsColl). 189 InsertOne(db.CTX(), tc.InputMigrations[i]) 190 assert.NoError(t, err) 191 } 192 193 //test 194 m := &SimpleMigrator{Client: client, Db: "test", Automigrate: tc.Automigrate} 195 err := m.Apply(context.Background(), tc.InputVersion, tc.Migrators) 196 if tc.OutputError != nil { 197 assert.Error(t, err) 198 assert.EqualError(t, err, tc.OutputError.Error()) 199 } else { 200 assert.NoError(t, err) 201 } 202 203 //verify 204 var out []MigrationEntry 205 cursor, _ := client.Database("test"). 206 Collection(DbMigrationsColl). 207 Find(db.CTX(), bson.M{}) 208 209 count := 0 210 for cursor.Next(db.CTX()) { 211 var res MigrationEntry 212 count++ 213 elem := &bson.D{} 214 err = cursor.Decode(elem) 215 bsonBytes, _ := bson.Marshal(elem) 216 bson.Unmarshal(bsonBytes, &res) 217 out = append(out, res) 218 } 219 220 // sort applied migrations 221 sort.Slice(out, func(i int, j int) bool { 222 return VersionIsLess(out[i].Version, out[j].Version) 223 }) 224 // applied migration should be last 225 assert.Equal(t, tc.OutputVersion, out[len(out)-1].Version) 226 }) 227 } 228 } 229 230 func TestErrNeedsMigration(t *testing.T) { 231 err := errors.New("db needs migration: mydbname has version 1.0.0, needs version 1.1.0") 232 233 assert.True(t, IsErrNeedsMigration(err)) 234 }