github.com/marinho/drone@v0.2.1-0.20140504195434-d3ba962e89a7/pkg/database/migrate/testing/migrate_test.go (about) 1 package migrate 2 3 import ( 4 "database/sql" 5 "fmt" 6 "log" 7 "os" 8 "strings" 9 "testing" 10 11 . "github.com/drone/drone/pkg/database/migrate" 12 13 _ "github.com/go-sql-driver/mysql" 14 _ "github.com/mattn/go-sqlite3" 15 "github.com/russross/meddler" 16 ) 17 18 var ( 19 db *sql.DB 20 driver, dsn string 21 22 dbname = "drone_test" 23 ) 24 25 var sqliteTestSchema = ` 26 CREATE TABLE samples ( 27 id INTEGER PRIMARY KEY AUTOINCREMENT, 28 imel VARCHAR(255) UNIQUE, 29 name VARCHAR(255) 30 ); 31 ` 32 33 var mysqlTestSchema = ` 34 CREATE TABLE samples ( 35 id INTEGER PRIMARY KEY AUTO_INCREMENT, 36 imel VARCHAR(255) UNIQUE, 37 name VARCHAR(255) 38 ) 39 ` 40 41 var dataDump = []string{ 42 `INSERT INTO samples (imel, name) VALUES ('test@example.com', 'Test Tester');`, 43 `INSERT INTO samples (imel, name) VALUES ('foo@bar.com', 'Foo Bar');`, 44 `INSERT INTO samples (imel, name) VALUES ('crash@bandicoot.io', 'Crash Bandicoot');`, 45 } 46 47 func TestMigrateCreateTable(t *testing.T) { 48 defer tearDown() 49 if err := setUp(); err != nil { 50 t.Fatalf("Error preparing database: %q", err) 51 } 52 53 mgr := New(db) 54 if err := mgr.Add(&revision1{}).Migrate(); err != nil { 55 t.Fatalf("Can not migrate: %q", err) 56 } 57 58 sample := Sample{ 59 ID: 1, 60 Imel: "test@example.com", 61 Name: "Test Tester", 62 } 63 if err := meddler.Save(db, "samples", &sample); err != nil { 64 t.Fatalf("Can not save data: %q", err) 65 } 66 } 67 68 func TestMigrateExistingCreateTable(t *testing.T) { 69 defer tearDown() 70 if err := setUp(); err != nil { 71 t.Fatalf("Error preparing database: %q", err) 72 } 73 74 var testSchema string 75 if driver == "mysql" { 76 testSchema = mysqlTestSchema 77 } else { 78 testSchema = sqliteTestSchema 79 } 80 81 if _, err := db.Exec(testSchema); err != nil { 82 t.Fatalf("Can not create database: %q", err) 83 } 84 85 mgr := New(db) 86 rev := &revision1{} 87 if err := mgr.Add(rev).Migrate(); err != nil { 88 t.Fatalf("Can not migrate: %q", err) 89 } 90 91 var current int64 92 db.QueryRow("SELECT max(revision) FROM migration").Scan(¤t) 93 if current != rev.Revision() { 94 t.Fatalf("Did not successfully migrate") 95 } 96 } 97 98 func TestMigrateRenameTable(t *testing.T) { 99 defer tearDown() 100 if err := setUp(); err != nil { 101 t.Fatalf("Error preparing database: %q", err) 102 } 103 104 mgr := New(db) 105 if err := mgr.Add(&revision1{}).Migrate(); err != nil { 106 t.Fatalf("Can not migrate: %q", err) 107 } 108 109 loadFixture(t) 110 111 if err := mgr.Add(&revision2{}).Migrate(); err != nil { 112 t.Fatalf("Can not migrate: %q", err) 113 } 114 115 sample := Sample{} 116 if err := meddler.QueryRow(db, &sample, `SELECT * FROM examples WHERE id = ?`, 2); err != nil { 117 t.Fatalf("Can not fetch data: %q", err) 118 } 119 120 if sample.Imel != "foo@bar.com" { 121 t.Errorf("Column doesn't match. Expect: %s, got: %s", "foo@bar.com", sample.Imel) 122 } 123 } 124 125 type TableInfo struct { 126 CID int64 `meddler:"cid,pk"` 127 Name string `meddler:"name"` 128 Type string `meddler:"type"` 129 Notnull bool `meddler:"notnull"` 130 DfltValue interface{} `meddler:"dflt_value"` 131 PK bool `meddler:"pk"` 132 } 133 134 type MysqlTableInfo struct { 135 Field string `meddler:"Field"` 136 Type string `meddler:"Type"` 137 Null string `meddler:"Null"` 138 Key interface{} `meddler:"Key"` 139 Default interface{} `meddler:"Default"` 140 Extra interface{} `meddler:"Extra"` 141 } 142 143 func TestMigrateAddRemoveColumns(t *testing.T) { 144 defer tearDown() 145 if err := setUp(); err != nil { 146 t.Fatalf("Error preparing database: %q", err) 147 } 148 149 mgr := New(db) 150 if err := mgr.Add(&revision1{}, &revision3{}).Migrate(); err != nil { 151 t.Fatalf("Can not migrate: %q", err) 152 } 153 154 switch driver { 155 case "mysql": 156 var columns []*MysqlTableInfo 157 if err := meddler.QueryAll(db, &columns, `SHOW COLUMNS FROM samples`); err != nil { 158 t.Fatalf("Can not access table infor: %q", err) 159 } 160 161 if len(columns) < 5 { 162 t.Errorf("Expect length columns: %d\nGot: %d", 5, len(columns)) 163 } 164 default: 165 var columns []*TableInfo 166 if err := meddler.QueryAll(db, &columns, `PRAGMA table_info(samples);`); err != nil { 167 t.Fatalf("Can not access table info: %q", err) 168 } 169 170 if len(columns) < 5 { 171 t.Errorf("Expect length columns: %d\nGot: %d", 5, len(columns)) 172 } 173 } 174 175 var row = AddColumnSample{ 176 ID: 33, 177 Name: "Foo", 178 Imel: "foo@bar.com", 179 Url: "http://example.com", 180 Num: 42, 181 } 182 if err := meddler.Save(db, "samples", &row); err != nil { 183 t.Fatalf("Can not save into database: %q", err) 184 } 185 186 if err := mgr.MigrateTo(1); err != nil { 187 t.Fatalf("Can not migrate: %q", err) 188 } 189 190 switch driver { 191 case "mysql": 192 var columns []*MysqlTableInfo 193 if err := meddler.QueryAll(db, &columns, `SHOW COLUMNS FROM samples`); err != nil { 194 t.Fatalf("Can not access table infor: %q", err) 195 } 196 197 if len(columns) != 3 { 198 t.Errorf("Expect length columns: %d\nGot: %d", 3, len(columns)) 199 } 200 default: 201 var columns []*TableInfo 202 if err := meddler.QueryAll(db, &columns, `PRAGMA table_info(samples);`); err != nil { 203 t.Fatalf("Can not access table info: %q", err) 204 } 205 206 if len(columns) != 3 { 207 t.Errorf("Expect length columns: %d\nGot: %d", 3, len(columns)) 208 } 209 } 210 211 } 212 213 func TestRenameColumn(t *testing.T) { 214 defer tearDown() 215 if err := setUp(); err != nil { 216 t.Fatalf("Error preparing database: %q", err) 217 } 218 219 mgr := New(db) 220 if err := mgr.Add(&revision1{}, &revision4{}).MigrateTo(1); err != nil { 221 t.Fatalf("Can not migrate: %q", err) 222 } 223 224 loadFixture(t) 225 226 if err := mgr.MigrateTo(4); err != nil { 227 t.Fatalf("Can not migrate: %q", err) 228 } 229 230 row := RenameSample{} 231 if err := meddler.QueryRow(db, &row, `SELECT * FROM samples WHERE id = 3;`); err != nil { 232 t.Fatalf("Can not query database: %q", err) 233 } 234 235 if row.Email != "crash@bandicoot.io" { 236 t.Errorf("Expect %s, got %s", "crash@bandicoot.io", row.Email) 237 } 238 } 239 240 func TestMigrateExistingTable(t *testing.T) { 241 defer tearDown() 242 if err := setUp(); err != nil { 243 t.Fatalf("Error preparing database: %q", err) 244 } 245 246 var testSchema string 247 if driver == "mysql" { 248 testSchema = mysqlTestSchema 249 } else { 250 testSchema = sqliteTestSchema 251 } 252 253 if _, err := db.Exec(testSchema); err != nil { 254 t.Fatalf("Can not create database: %q", err) 255 } 256 257 loadFixture(t) 258 259 mgr := New(db) 260 if err := mgr.Add(&revision4{}).Migrate(); err != nil { 261 t.Fatalf("Can not migrate: %q", err) 262 } 263 264 var rows []*RenameSample 265 if err := meddler.QueryAll(db, &rows, `SELECT * from samples;`); err != nil { 266 t.Fatalf("Can not query database: %q", err) 267 } 268 269 if len(rows) != 3 { 270 t.Errorf("Expect rows length = %d, got %d", 3, len(rows)) 271 } 272 273 if rows[1].Email != "foo@bar.com" { 274 t.Errorf("Expect email = %s, got %s", "foo@bar.com", rows[1].Email) 275 } 276 } 277 278 type sqliteMaster struct { 279 Sql interface{} `meddler:"sql"` 280 } 281 282 func TestIndexOperations(t *testing.T) { 283 defer tearDown() 284 if err := setUp(); err != nil { 285 t.Fatalf("Error preparing database: %q", err) 286 } 287 288 mgr := New(db) 289 290 // Migrate, create index 291 if err := mgr.Add(&revision1{}, &revision3{}, &revision5{}).Migrate(); err != nil { 292 t.Fatalf("Can not migrate: %q", err) 293 } 294 295 var esquel []*sqliteMaster 296 var mysquel struct { 297 Table string `meddler:"Table"` 298 CreateTable string `meddler:"Create Table"` 299 } 300 switch driver { 301 case "mysql": 302 query := `SHOW CREATE TABLE samples` 303 if err := meddler.QueryRow(db, &mysquel, query); err != nil { 304 t.Fatalf("Can not fetch table definition: %q", err) 305 } 306 307 if !strings.Contains(mysquel.CreateTable, "KEY `idx_samples_on_url_and_name` (`url`,`name`)") { 308 t.Errorf("Can not find index, got: %q", mysquel.CreateTable) 309 } 310 311 if err := mgr.Add(&revision6{}).Migrate(); err != nil { 312 t.Fatalf("Can not migrate: %q", err) 313 } 314 315 if err := meddler.QueryRow(db, &mysquel, query); err != nil { 316 t.Fatalf("Can not find index: %q", err) 317 } 318 319 if !strings.Contains(mysquel.CreateTable, "KEY `idx_samples_on_url_and_name` (`host`,`name`)") { 320 t.Errorf("Can not find index, got: %q", mysquel.CreateTable) 321 } 322 323 if err := mgr.Add(&revision7{}).Migrate(); err != nil { 324 t.Fatalf("Can not migrate: %q", err) 325 } 326 327 if err := meddler.QueryRow(db, &mysquel, query); err != nil { 328 t.Fatalf("Can not find index: %q", err) 329 } 330 331 if strings.Contains(mysquel.CreateTable, "KEY `idx_samples_on_url_and_name` (`host`,`name`)") { 332 t.Errorf("Expect index to be deleted.") 333 } 334 335 default: 336 // Query sqlite_master, check if index is exists. 337 query := `SELECT sql FROM sqlite_master WHERE type='index' and tbl_name='samples'` 338 if err := meddler.QueryAll(db, &esquel, query); err != nil { 339 t.Fatalf("Can not find index: %q", err) 340 } 341 342 indexStatement := `CREATE INDEX idx_samples_on_url_and_name ON samples (url, name)` 343 if string(esquel[1].Sql.([]byte)) != indexStatement { 344 t.Errorf("Can not find index, got: %q", esquel[1]) 345 } 346 347 // Migrate, rename indexed columns 348 if err := mgr.Add(&revision6{}).Migrate(); err != nil { 349 t.Fatalf("Can not migrate: %q", err) 350 } 351 352 var esquel1 []*sqliteMaster 353 if err := meddler.QueryAll(db, &esquel1, query); err != nil { 354 t.Fatalf("Can not find index: %q", err) 355 } 356 357 indexStatement = `CREATE INDEX idx_samples_on_host_and_name ON samples (host, name)` 358 if string(esquel1[1].Sql.([]byte)) != indexStatement { 359 t.Errorf("Can not find index, got: %q", esquel1[1]) 360 } 361 362 if err := mgr.Add(&revision7{}).Migrate(); err != nil { 363 t.Fatalf("Can not migrate: %q", err) 364 } 365 366 var esquel2 []*sqliteMaster 367 if err := meddler.QueryAll(db, &esquel2, query); err != nil { 368 t.Fatalf("Can not find index: %q", err) 369 } 370 371 if len(esquel2) != 1 { 372 t.Errorf("Expect row length equal to %d, got %d", 1, len(esquel2)) 373 } 374 } 375 } 376 377 func TestColumnRedundancy(t *testing.T) { 378 defer tearDown() 379 if err := setUp(); err != nil { 380 t.Fatalf("Error preparing database: %q", err) 381 } 382 383 migr := New(db) 384 if err := migr.Add(&revision1{}, &revision8{}, &revision9{}).Migrate(); err != nil { 385 t.Fatalf("Can not migrate: %q", err) 386 } 387 388 var dummy, query, tableSql string 389 switch driver { 390 case "mysql": 391 query = `SHOW CREATE TABLE samples` 392 if err := db.QueryRow(query).Scan(&dummy, &tableSql); err != nil { 393 t.Fatalf("Can not query table's definition: %q", err) 394 } 395 if !strings.Contains(tableSql, "`repository`") { 396 t.Errorf("Expect column with name repository") 397 } 398 default: 399 query = `SELECT sql FROM sqlite_master where type='table' and name='samples'` 400 if err := db.QueryRow(query).Scan(&tableSql); err != nil { 401 t.Fatalf("Can not query sqlite_master: %q", err) 402 } 403 if !strings.Contains(tableSql, "repository ") { 404 t.Errorf("Expect column with name repository") 405 } 406 } 407 } 408 409 func TestChangeColumnType(t *testing.T) { 410 defer tearDown() 411 if err := setUp(); err != nil { 412 t.Fatalf("Error preparing database: %q", err) 413 } 414 415 migr := New(db) 416 if err := migr.Add(&revision1{}, &revision4{}, &revision10{}).Migrate(); err != nil { 417 t.Fatalf("Can not migrate: %q", err) 418 } 419 420 var dummy, tableSql, query string 421 switch driver { 422 case "mysql": 423 query = `SHOW CREATE TABLE samples` 424 if err := db.QueryRow(query).Scan(&dummy, &tableSql); err != nil { 425 t.Fatalf("Can not query table's definition: %q", err) 426 } 427 if !strings.Contains(tableSql, "`email` varchar(512)") { 428 t.Errorf("Expect email type to changed: %q", tableSql) 429 } 430 default: 431 query = `SELECT sql FROM sqlite_master where type='table' and name='samples'` 432 if err := db.QueryRow(query).Scan(&tableSql); err != nil { 433 t.Fatalf("Can not query sqlite_master: %q", err) 434 } 435 if !strings.Contains(tableSql, "email varchar(512) UNIQUE") { 436 t.Errorf("Expect email type to changed: %q", tableSql) 437 } 438 } 439 } 440 441 func init() { 442 if driver = os.Getenv("DB_ENV"); len(driver) == 0 { 443 driver = "sqlite3" 444 } 445 if dsn = os.Getenv("MYSQL_LOGIN"); len(dsn) == 0 { 446 dsn = ":memory:" 447 } else { 448 dsn = fmt.Sprintf("%s@/?parseTime=true", dsn) 449 } 450 } 451 452 func setUp() error { 453 var err error 454 Driver = SQLite 455 if db, err = sql.Open(driver, dsn); err != nil { 456 log.Fatalf("Can't connect to database: %q", err) 457 } 458 if driver == "mysql" { 459 Driver = MySQL 460 if _, err := db.Exec(fmt.Sprintf("CREATE DATABASE %s", dbname)); err != nil { 461 log.Fatalf("Can't create database: %q", err) 462 } 463 if _, err := db.Exec(fmt.Sprintf("USE %s", dbname)); err != nil { 464 log.Fatalf("Can't use database: %q", dbname) 465 } 466 } 467 return err 468 } 469 470 func tearDown() { 471 if driver == "mysql" { 472 db.Exec(fmt.Sprintf("DROP DATABASE %s", dbname)) 473 } 474 db.Close() 475 } 476 477 func loadFixture(t *testing.T) { 478 for _, sql := range dataDump { 479 if _, err := db.Exec(sql); err != nil { 480 t.Fatalf("Can not insert into database: %q", err) 481 } 482 } 483 }