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(&current)
    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  }