github.com/CloudCom/goose@v0.0.0-20151110184009-e03c3249c21b/lib/goose/migrate_test.go (about) 1 package goose 2 3 import ( 4 "io/ioutil" 5 "os" 6 "path/filepath" 7 "testing" 8 9 _ "github.com/go-sql-driver/mysql" 10 _ "github.com/lib/pq" 11 _ "github.com/mattn/go-sqlite3" 12 13 "github.com/stretchr/testify/assert" 14 "github.com/stretchr/testify/require" 15 ) 16 17 func getSqlite3Driver(t *testing.T) DBDriver { 18 return DBDriver{ 19 Name: "sqlite3", 20 Dialect: Sqlite3Dialect{}, 21 OpenStr: ":memory:", 22 } 23 } 24 25 func getMysqlDriver(t *testing.T) DBDriver { 26 dsn := os.Getenv("MYSQL_DATABASE_DSN") 27 if dsn == "" { 28 t.SkipNow() 29 } 30 return DBDriver{ 31 Name: "mysql", 32 Dialect: MySqlDialect{}, 33 OpenStr: dsn, 34 } 35 } 36 37 func getPostgresDriver(t *testing.T) DBDriver { 38 dsn := os.Getenv("POSTGRES_DATABASE_DSN") 39 if dsn == "" { 40 t.SkipNow() 41 } 42 return DBDriver{ 43 Name: "postgres", 44 Dialect: PostgresDialect{}, 45 OpenStr: dsn, 46 } 47 } 48 49 func getRedshiftDriver(t *testing.T) DBDriver { 50 dsn := os.Getenv("REDSHIFT_DATABASE_DSN") 51 if dsn == "" { 52 t.SkipNow() 53 } 54 return DBDriver{ 55 Name: "postgres", 56 Dialect: RedshiftDialect{}, 57 OpenStr: dsn, 58 } 59 } 60 61 func TestMigrationSorterLen(t *testing.T) { 62 ms := migrationSorter{ 63 {Version: 1}, 64 {Version: 2}, 65 {Version: 4}, 66 {Version: 3}, 67 } 68 l := ms.Len() 69 if l != 4 { 70 t.Errorf("expected ms.Len() == 4, but got %d\n", l) 71 } 72 } 73 74 func TestMigrationSorterSwap(t *testing.T) { 75 ms := migrationSorter{ 76 {Version: 1}, 77 {Version: 2}, 78 {Version: 4}, 79 {Version: 3}, 80 } 81 ms.Swap(1, 2) 82 if ms[1].Version != 4 { 83 t.Errorf("expected ms[1].Version == 4, but got %d\n", ms[1].Version) 84 } 85 if ms[2].Version != 2 { 86 t.Errorf("expected ms[2].Version == 2, but got %d\n", ms[1].Version) 87 } 88 } 89 90 func TestMigrationSorterLess(t *testing.T) { 91 ms := migrationSorter{ 92 {Version: 1}, 93 {Version: 2}, 94 {Version: 4}, 95 {Version: 3}, 96 } 97 v := ms.Less(2, 3) 98 if v != false { 99 t.Errorf("expected ms.Less(2,3) == false, but got %v\n", v) 100 } 101 v = ms.Less(3, 2) 102 if v != true { 103 t.Errorf("expected ms.Less(3,2) == true, but got %v\n", v) 104 } 105 } 106 107 func setupMigrationsDir(migrationMap map[string][2]string) (string, func()) { 108 td, err := ioutil.TempDir("", "goose-test-") 109 if err != nil { 110 panic(err) 111 } 112 113 dbPath := filepath.Join(td, "db") 114 migrationsPath := filepath.Join(dbPath, "migrations") 115 os.MkdirAll(migrationsPath, 0700) 116 117 for name, migrations := range migrationMap { 118 migStr := `-- +goose Up 119 ` + migrations[0] + ` 120 121 -- +goose Down 122 ` + migrations[1] + ` 123 ` 124 if err := ioutil.WriteFile(filepath.Join(migrationsPath, name), []byte(migStr), 0600); err != nil { 125 panic(err) 126 } 127 } 128 129 return migrationsPath, func() { os.RemoveAll(td) } 130 } 131 132 func TestCollectMigrations(t *testing.T) { 133 md, mdCleanup := setupMigrationsDir(map[string][2]string{ 134 "20010203040506_first.sql": [2]string{"SELECT 1;", "SELECT 1;"}, 135 "20010203040507_second.sql": [2]string{"SELECT 2;", "SELECT 2;"}, 136 "20010203040508_third.sql": [2]string{"SELECT 3;", "SELECT 3;"}, 137 }) 138 defer mdCleanup() 139 140 migs, err := CollectMigrations(md) 141 require.NoError(t, err) 142 143 assert.Len(t, migs, 3) 144 assert.Contains(t, migs, &Migration{ 145 Version: 20010203040506, 146 IsApplied: false, 147 Source: filepath.Join(md, "20010203040506_first.sql"), 148 }) 149 assert.Contains(t, migs, &Migration{ 150 Version: 20010203040507, 151 IsApplied: false, 152 Source: filepath.Join(md, "20010203040507_second.sql"), 153 }) 154 assert.Contains(t, migs, &Migration{ 155 Version: 20010203040508, 156 IsApplied: false, 157 Source: filepath.Join(md, "20010203040508_third.sql"), 158 }) 159 } 160 161 func testRunMigrationsOnDb(t *testing.T, driver DBDriver) { 162 md, mdCleanup := setupMigrationsDir(map[string][2]string{ 163 "20010203040506_setup.sql": [2]string{"CREATE TABLE test(value VARCHAR(20));", "DROP TABLE test;"}, 164 "20010203040507_one.sql": [2]string{"INSERT INTO test(value) VALUES('one');", "DELETE FROM test WHERE value = 'one';"}, 165 "20010203040508_two.sql": [2]string{"INSERT INTO test(value) VALUES('two');", "DELETE FROM test WHERE value = 'two';"}, 166 }) 167 defer mdCleanup() 168 conf := &DBConf{ 169 Driver: driver, 170 MigrationsDir: md, 171 } 172 173 db, err := OpenDBFromDBConf(conf) 174 require.NoError(t, err) 175 176 db.Exec("DROP TABLE goose_db_version") 177 db.Exec("DROP TABLE test") 178 179 err = RunMigrationsOnDb(conf, conf.MigrationsDir, 20010203040508, db) 180 require.NoError(t, err) 181 182 rows, err := db.Query("SELECT value FROM test") 183 require.NoError(t, err) 184 defer rows.Close() 185 var values []string 186 for rows.Next() { 187 var value string 188 err := rows.Scan(&value) 189 require.NoError(t, err) 190 values = append(values, value) 191 } 192 193 assert.Len(t, values, 2) 194 assert.Contains(t, values, "one") 195 assert.Contains(t, values, "two") 196 } 197 func TestRunMigrationsOnDb_sqlite3(t *testing.T) { 198 testRunMigrationsOnDb(t, getSqlite3Driver(t)) 199 } 200 func TestRunMigrationsOnDb_mysql(t *testing.T) { 201 testRunMigrationsOnDb(t, getMysqlDriver(t)) 202 } 203 func TestRunMigrationsOnDb_postgres(t *testing.T) { 204 testRunMigrationsOnDb(t, getPostgresDriver(t)) 205 } 206 func TestRunMigrationsOnDb_redshift(t *testing.T) { 207 testRunMigrationsOnDb(t, getRedshiftDriver(t)) 208 } 209 210 func testRunMigrationsOnDb_missingMiddle(t *testing.T, driver DBDriver) { 211 md, mdCleanup := setupMigrationsDir(map[string][2]string{ 212 "20010203040506_setup.sql": [2]string{"CREATE TABLE test(value VARCHAR(20));", "DROP TABLE test;"}, 213 "20010203040507_one.sql": [2]string{"INSERT INTO test(value) VALUES('one');", "DELETE FROM test WHERE value = 'one';"}, 214 "20010203040508_two.sql": [2]string{"INSERT INTO test(value) VALUES('two');", "DELETE FROM test WHERE value = 'two';"}, 215 }) 216 defer mdCleanup() 217 conf := &DBConf{ 218 Driver: driver, 219 MigrationsDir: md, 220 } 221 222 db, err := OpenDBFromDBConf(conf) 223 require.NoError(t, err) 224 225 db.Exec("DROP TABLE goose_db_version") 226 db.Exec("DROP TABLE test") 227 228 // make the middle migration disappear for a moment 229 err = os.Rename(filepath.Join(md, "20010203040507_one.sql"), filepath.Join(md, "20010203040507_one.sql_")) 230 require.NoError(t, err) 231 232 err = RunMigrationsOnDb(conf, conf.MigrationsDir, 20010203040508, db) 233 require.NoError(t, err) 234 235 rows, err := db.Query("SELECT value FROM test") 236 require.NoError(t, err) 237 defer rows.Close() 238 var values []string 239 for rows.Next() { 240 var value string 241 err := rows.Scan(&value) 242 require.NoError(t, err) 243 values = append(values, value) 244 } 245 246 assert.Len(t, values, 1) 247 assert.Contains(t, values, "two") 248 249 // now put it back 250 err = os.Rename(filepath.Join(md, "20010203040507_one.sql_"), filepath.Join(md, "20010203040507_one.sql")) 251 require.NoError(t, err) 252 253 err = RunMigrationsOnDb(conf, conf.MigrationsDir, 20010203040508, db) 254 require.NoError(t, err) 255 256 rows, err = db.Query("SELECT value FROM test") 257 require.NoError(t, err) 258 defer rows.Close() 259 values = []string{} 260 for rows.Next() { 261 var value string 262 err := rows.Scan(&value) 263 require.NoError(t, err) 264 values = append(values, value) 265 } 266 267 assert.Len(t, values, 2) 268 assert.Contains(t, values, "one") 269 assert.Contains(t, values, "two") 270 } 271 func TestRunMigrationsOnDb_missingMiddle_sqlite3(t *testing.T) { 272 testRunMigrationsOnDb_missingMiddle(t, getSqlite3Driver(t)) 273 } 274 func TestRunMigrationsOnDb_missingMiddle_mysql(t *testing.T) { 275 testRunMigrationsOnDb_missingMiddle(t, getMysqlDriver(t)) 276 } 277 func TestRunMigrationsOnDb_missingMiddle_postgres(t *testing.T) { 278 testRunMigrationsOnDb_missingMiddle(t, getPostgresDriver(t)) 279 } 280 func TestRunMigrationsOnDb_missingMiddle_redshift(t *testing.T) { 281 testRunMigrationsOnDb_missingMiddle(t, getRedshiftDriver(t)) 282 } 283 284 func testRunMigrationsOnDb_down(t *testing.T, driver DBDriver) { 285 md, mdCleanup := setupMigrationsDir(map[string][2]string{ 286 "20010203040506_setup.sql": [2]string{"CREATE TABLE test(value VARCHAR(20));", "DROP TABLE test;"}, 287 "20010203040507_one.sql": [2]string{"INSERT INTO test(value) VALUES('one');", "DELETE FROM test WHERE value = 'one';"}, 288 "20010203040508_two.sql": [2]string{"INSERT INTO test(value) VALUES('two');", "DELETE FROM test WHERE value = 'two';"}, 289 }) 290 defer mdCleanup() 291 conf := &DBConf{ 292 Driver: driver, 293 MigrationsDir: md, 294 } 295 296 db, err := OpenDBFromDBConf(conf) 297 require.NoError(t, err) 298 299 db.Exec("DROP TABLE goose_db_version") 300 db.Exec("DROP TABLE test") 301 302 // up 303 err = RunMigrationsOnDb(conf, conf.MigrationsDir, 20010203040508, db) 304 require.NoError(t, err) 305 306 // down 307 err = RunMigrationsOnDb(conf, conf.MigrationsDir, 20010203040507, db) 308 require.NoError(t, err) 309 310 rows, err := db.Query("SELECT value FROM test") 311 require.NoError(t, err) 312 defer rows.Close() 313 var values []string 314 for rows.Next() { 315 var value string 316 err := rows.Scan(&value) 317 require.NoError(t, err) 318 values = append(values, value) 319 } 320 321 assert.Len(t, values, 1) 322 assert.Contains(t, values, "one") 323 } 324 func TestRunMigrationsOnDb_down_sqlite3(t *testing.T) { 325 testRunMigrationsOnDb_down(t, getSqlite3Driver(t)) 326 } 327 func TestRunMigrationsOnDb_down_mysql(t *testing.T) { 328 testRunMigrationsOnDb_down(t, getMysqlDriver(t)) 329 } 330 func TestRunMigrationsOnDb_down_postgres(t *testing.T) { 331 testRunMigrationsOnDb_down(t, getPostgresDriver(t)) 332 } 333 func TestRunMigrationsOnDb_down_redshift(t *testing.T) { 334 testRunMigrationsOnDb_down(t, getRedshiftDriver(t)) 335 } 336 337 func testRunMigrationsOnDb_upDownUp(t *testing.T, driver DBDriver) { 338 md, mdCleanup := setupMigrationsDir(map[string][2]string{ 339 "20010203040506_setup.sql": [2]string{"CREATE TABLE test(value VARCHAR(20));", "DROP TABLE test;"}, 340 "20010203040507_one.sql": [2]string{"INSERT INTO test(value) VALUES('one');", "DELETE FROM test WHERE value = 'one';"}, 341 "20010203040508_two.sql": [2]string{"INSERT INTO test(value) VALUES('two');", "DELETE FROM test WHERE value = 'two';"}, 342 }) 343 defer mdCleanup() 344 conf := &DBConf{ 345 Driver: driver, 346 MigrationsDir: md, 347 } 348 349 db, err := OpenDBFromDBConf(conf) 350 require.NoError(t, err) 351 352 db.Exec("DROP TABLE goose_db_version") 353 db.Exec("DROP TABLE test") 354 355 // up 356 err = RunMigrationsOnDb(conf, conf.MigrationsDir, 20010203040508, db) 357 require.NoError(t, err) 358 359 // down 360 err = RunMigrationsOnDb(conf, conf.MigrationsDir, 0, db) 361 require.NoError(t, err) 362 363 rows, err := db.Query("SELECT value FROM test") 364 require.Error(t, err) // table won't exist 365 366 // up 367 err = RunMigrationsOnDb(conf, conf.MigrationsDir, 20010203040508, db) 368 require.NoError(t, err) 369 370 rows, err = db.Query("SELECT value FROM test") 371 require.NoError(t, err) 372 defer rows.Close() 373 var values []string 374 for rows.Next() { 375 var value string 376 err := rows.Scan(&value) 377 require.NoError(t, err) 378 values = append(values, value) 379 } 380 381 assert.Len(t, values, 2) 382 assert.Contains(t, values, "one") 383 assert.Contains(t, values, "two") 384 } 385 func TestRunMigrationsOnDb_upDownUp_sqlite3(t *testing.T) { 386 testRunMigrationsOnDb_upDownUp(t, getSqlite3Driver(t)) 387 } 388 func TestRunMigrationsOnDb_upDownUp_mysql(t *testing.T) { 389 testRunMigrationsOnDb_upDownUp(t, getMysqlDriver(t)) 390 } 391 func TestRunMigrationsOnDb_upDownUp_postgres(t *testing.T) { 392 testRunMigrationsOnDb_upDownUp(t, getPostgresDriver(t)) 393 } 394 func TestRunMigrationsOnDb_upDownUp_redshift(t *testing.T) { 395 testRunMigrationsOnDb_upDownUp(t, getRedshiftDriver(t)) 396 }