Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 package testutil | 1 package testutil |
| 2 | 2 |
| 3 import ( | 3 import ( |
| 4 "fmt" | |
| 5 "os" | |
| 6 "strings" | 4 "strings" |
| 7 "testing" | 5 "testing" |
| 8 ) | 6 ) |
| 9 | 7 |
| 10 import ( | 8 import ( |
| 11 // Using 'require' which is like using 'assert' but causes tests to fail . | 9 // Using 'require' which is like using 'assert' but causes tests to fail . |
| 12 assert "github.com/stretchr/testify/require" | 10 assert "github.com/stretchr/testify/require" |
| 13 | 11 |
| 14 "skia.googlesource.com/buildbot.git/go/database" | 12 "skia.googlesource.com/buildbot.git/go/database" |
| 15 ) | 13 ) |
| 16 | 14 |
| 17 // Connection string to the local MySQL database for testing. | 15 // Connection string to the local MySQL database for testing. |
| 18 const ( | 16 const ( |
| 19 // String to open a local database for testing. The string formatting | 17 // String to open a local database for testing. The string formatting |
| 20 // parameters are: username, password, database. | 18 // parameters are: username, password, database. |
| 21 MYSQL_DB_OPEN = "%s:%s@tcp(localhost:3306)/%s?parseTime=true" | 19 MYSQL_DB_OPEN = "%s:%s@tcp(localhost:3306)/%s?parseTime=true" |
| 22 | 20 |
| 23 // File path to the local SQLite testing databse. | |
| 24 SQLITE_DB_PATH = "./testing.db" | |
| 25 | |
| 26 // Name of the MySQL lock | 21 // Name of the MySQL lock |
| 27 SQL_LOCK = "mysql_testlock" | 22 SQL_LOCK = "mysql_testlock" |
| 23 | |
| 24 // Name of the shared test database. | |
| 25 TEST_DB_HOST = "localhost" | |
| 26 TEST_DB_PORT = 3306 | |
| 27 TEST_DB_NAME = "sk_testing" | |
| 28 | |
| 29 // Names of test users. These users should have no password and be | |
| 30 // limited to accessing the sk_testing database. | |
| 31 USER_ROOT = "test_root" | |
| 32 USER_RW = "test_rw" | |
| 33 | |
| 34 // Empty password for testing. | |
| 35 TEST_PASSWORD = "" | |
| 28 ) | 36 ) |
| 29 | 37 |
| 30 // Creates an SQLite test database and runs migration tests against it using the | 38 // LocalTestDatabaseConfig returns a DatabaseConfig appropriate for local |
| 31 // given migration steps. | 39 // testing. |
| 32 func SQLiteVersioningTests(t *testing.T, migrationSteps []database.MigrationStep ) { | 40 func LocalTestDatabaseConfig(m []database.MigrationStep) *database.DatabaseConfi g { |
| 33 » // Initialize without argument to test against SQLite3 | 41 » return database.NewDatabaseConfig(USER_RW, "", TEST_DB_HOST, TEST_DB_POR T, TEST_DB_NAME, m) |
| 34 » conf := &database.DatabaseConfig{ | 42 } |
| 35 » » SQLiteFilePath: SQLITE_DB_PATH, | |
| 36 » » MigrationSteps: migrationSteps, | |
| 37 » } | |
| 38 | 43 |
| 39 » vdb := database.NewVersionedDB(conf) | 44 // LocalTestDatabaseConfig returns a DatabaseConfig appropriate for local |
|
jcgregorio
2014/12/19 20:27:06
LocalTestRootDatabaseConfig
borenet
2014/12/19 20:39:15
Done.
| |
| 40 » assert.False(t, vdb.IsMySQL) | 45 // testing, with root access. |
| 41 » testDBVersioning(t, vdb) | 46 func LocalTestRootDatabaseConfig(m []database.MigrationStep) *database.DatabaseC onfig { |
| 47 » return database.NewDatabaseConfig(USER_ROOT, "", TEST_DB_HOST, TEST_DB_P ORT, TEST_DB_NAME, m) | |
| 42 } | 48 } |
| 43 | 49 |
| 44 // Creates an MySQL test database and runs migration tests against it using the | 50 // Creates an MySQL test database and runs migration tests against it using the |
| 45 // given migration steps. See Get for required credentials. | 51 // given migration steps. See Get for required credentials. |
| 46 // The test assumes that the database is empty and that the readwrite user is | 52 // The test assumes that the database is empty and that the readwrite user is |
| 47 // not allowed to create/drop/alter tables. | 53 // not allowed to create/drop/alter tables. |
| 48 func MySQLVersioningTests(t *testing.T, dbName string, migrationSteps []database .MigrationStep) { | 54 func MySQLVersioningTests(t *testing.T, dbName string, migrationSteps []database .MigrationStep) { |
| 49 // OpenDB as root user and remove all tables. | 55 // OpenDB as root user and remove all tables. |
| 50 » rootConf := &database.DatabaseConfig{ | 56 » rootConf := LocalTestRootDatabaseConfig(migrationSteps) |
| 51 » » MySQLString: GetTestMySQLConnStr(t, "root", dbName), | |
| 52 » » MigrationSteps: migrationSteps, | |
| 53 » } | |
| 54 lockVdb := GetMySQlLock(t, rootConf) | 57 lockVdb := GetMySQlLock(t, rootConf) |
| 55 defer func() { | 58 defer func() { |
| 56 ReleaseMySQLLock(t, lockVdb) | 59 ReleaseMySQLLock(t, lockVdb) |
| 57 lockVdb.Close() | 60 lockVdb.Close() |
| 58 }() | 61 }() |
| 59 | 62 |
| 60 rootVdb := database.NewVersionedDB(rootConf) | 63 rootVdb := database.NewVersionedDB(rootConf) |
| 61 assert.True(t, rootVdb.IsMySQL) | |
| 62 ClearMySQLTables(t, rootVdb) | 64 ClearMySQLTables(t, rootVdb) |
| 63 assert.Nil(t, rootVdb.Close()) | 65 assert.Nil(t, rootVdb.Close()) |
| 64 | 66 |
| 65 // Configuration for the readwrite user without DDL privileges. | 67 // Configuration for the readwrite user without DDL privileges. |
| 66 » readWriteConf := &database.DatabaseConfig{ | 68 » readWriteConf := LocalTestDatabaseConfig(migrationSteps) |
| 67 » » MySQLString: GetTestMySQLConnStr(t, "readwrite", dbName), | |
| 68 » » MigrationSteps: migrationSteps, | |
| 69 » } | |
| 70 | 69 |
| 71 // Open DB as readwrite user and make sure it fails because of a missing | 70 // Open DB as readwrite user and make sure it fails because of a missing |
| 72 // version table. | 71 // version table. |
| 73 // Note: This requires the database to be empty. | 72 // Note: This requires the database to be empty. |
| 74 assert.Panics(t, func() { | 73 assert.Panics(t, func() { |
| 75 database.NewVersionedDB(readWriteConf) | 74 database.NewVersionedDB(readWriteConf) |
| 76 }) | 75 }) |
| 77 | 76 |
| 78 rootVdb = database.NewVersionedDB(rootConf) | 77 rootVdb = database.NewVersionedDB(rootConf) |
| 79 testDBVersioning(t, rootVdb) | 78 testDBVersioning(t, rootVdb) |
| 80 | 79 |
| 81 // Make sure it doesn't panic for readwrite user after the migration | 80 // Make sure it doesn't panic for readwrite user after the migration |
| 82 assert.NotPanics(t, func() { | 81 assert.NotPanics(t, func() { |
| 83 database.NewVersionedDB(readWriteConf) | 82 database.NewVersionedDB(readWriteConf) |
| 84 }) | 83 }) |
| 85 } | 84 } |
| 86 | 85 |
| 87 // Returns a connection string to the local MySQL server and the given database. | |
| 88 // The test will be skipped if these environement variables are not set: | |
| 89 // MYSQL_TESTING_RWPW (password of readwrite user) | |
| 90 // MYSQL_TESTING_ROOTPW (password of the db root user) | |
| 91 func GetTestMySQLConnStr(t *testing.T, user string, dbName string) string { | |
| 92 rwUserPw, rootPw := os.Getenv("MYSQL_TESTING_RWPW"), os.Getenv("MYSQL_TE STING_ROOTPW") | |
| 93 if testing.Short() { | |
| 94 t.Skip("Skipping test against MySQL in short mode.") | |
| 95 } | |
| 96 | |
| 97 // Skip this test unless there are environment variables with the rwuser and | |
| 98 // root password for the local MySQL instance. | |
| 99 if (rwUserPw == "") || (rootPw == "") { | |
| 100 t.Skip("Skipping test against MySQL. Set 'MYSQL_TESTING_ROOTPW' and 'MYSQL_TESTING_RWPW' to enable tests.") | |
| 101 } | |
| 102 pw := rwUserPw | |
| 103 if user == "root" { | |
| 104 pw = rootPw | |
| 105 } | |
| 106 return fmt.Sprintf(MYSQL_DB_OPEN, user, pw, dbName) | |
| 107 } | |
| 108 | |
| 109 // Get a lock from MySQL to serialize DB tests. | 86 // Get a lock from MySQL to serialize DB tests. |
| 110 func GetMySQlLock(t *testing.T, conf *database.DatabaseConfig) *database.Version edDB { | 87 func GetMySQlLock(t *testing.T, conf *database.DatabaseConfig) *database.Version edDB { |
| 111 vdb := database.NewVersionedDB(conf) | 88 vdb := database.NewVersionedDB(conf) |
| 112 _, err := vdb.DB.Exec("SELECT GET_LOCK(?,30)", SQL_LOCK) | 89 _, err := vdb.DB.Exec("SELECT GET_LOCK(?,30)", SQL_LOCK) |
| 113 assert.Nil(t, err) | 90 assert.Nil(t, err) |
| 114 return vdb | 91 return vdb |
| 115 } | 92 } |
| 116 | 93 |
| 117 // Release the MySQL lock. | 94 // Release the MySQL lock. |
| 118 func ReleaseMySQLLock(t *testing.T, vdb *database.VersionedDB) { | 95 func ReleaseMySQLLock(t *testing.T, vdb *database.VersionedDB) { |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 134 names = append(names, tableName) | 111 names = append(names, tableName) |
| 135 } | 112 } |
| 136 | 113 |
| 137 if len(names) > 0 { | 114 if len(names) > 0 { |
| 138 stmt = "DROP TABLE " + strings.Join(names, ",") | 115 stmt = "DROP TABLE " + strings.Join(names, ",") |
| 139 _, err = vdb.DB.Exec(stmt) | 116 _, err = vdb.DB.Exec(stmt) |
| 140 assert.Nil(t, err) | 117 assert.Nil(t, err) |
| 141 } | 118 } |
| 142 } | 119 } |
| 143 | 120 |
| 121 // MySQLTestDatabase is a convenience struct for using a test database which | |
| 122 // starts in a clean state. | |
| 123 type MySQLTestDatabase struct { | |
| 124 rootVdb *database.VersionedDB | |
| 125 t *testing.T | |
| 126 } | |
| 127 | |
| 128 // SetupMySQLTestDatabase returns a MySQLTestDatabase in a clean state. It must | |
| 129 // be closed after use. | |
| 130 // | |
| 131 // Example usage: | |
| 132 // | |
| 133 // db := SetupMySQLTestDatabase(t, migrationSteps) | |
| 134 // defer db.Close() | |
| 135 // ... Tests here ... | |
| 136 func SetupMySQLTestDatabase(t *testing.T, migrationSteps []database.MigrationSte p) *MySQLTestDatabase { | |
| 137 conf := LocalTestRootDatabaseConfig(migrationSteps) | |
| 138 lockVdb := GetMySQlLock(t, conf) | |
| 139 rootVdb := database.NewVersionedDB(conf) | |
| 140 ClearMySQLTables(t, rootVdb) | |
| 141 if err := rootVdb.Close(); err != nil { | |
| 142 t.Fatal(err) | |
| 143 } | |
| 144 rootVdb = database.NewVersionedDB(conf) | |
| 145 if err := rootVdb.Migrate(rootVdb.MaxDBVersion()); err != nil { | |
| 146 t.Fatal(err) | |
| 147 } | |
| 148 if err := rootVdb.Close(); err != nil { | |
| 149 t.Fatal(err) | |
| 150 } | |
| 151 return &MySQLTestDatabase{lockVdb, t} | |
| 152 } | |
| 153 | |
| 154 func (d *MySQLTestDatabase) Close() { | |
| 155 if err := d.rootVdb.Migrate(0); err != nil { | |
| 156 d.t.Fatal(err) | |
| 157 } | |
| 158 ReleaseMySQLLock(d.t, d.rootVdb) | |
| 159 d.rootVdb.Close() | |
| 160 } | |
| 161 | |
| 144 // Test wether the migration steps execute correctly. | 162 // Test wether the migration steps execute correctly. |
| 145 func testDBVersioning(t *testing.T, vdb *database.VersionedDB) { | 163 func testDBVersioning(t *testing.T, vdb *database.VersionedDB) { |
| 146 // get the DB version | 164 // get the DB version |
| 147 dbVersion, err := vdb.DBVersion() | 165 dbVersion, err := vdb.DBVersion() |
| 148 assert.Nil(t, err) | 166 assert.Nil(t, err) |
| 149 maxVersion := vdb.MaxDBVersion() | 167 maxVersion := vdb.MaxDBVersion() |
| 150 | 168 |
| 151 // downgrade to 0 | 169 // downgrade to 0 |
| 152 err = vdb.Migrate(0) | 170 err = vdb.Migrate(0) |
| 153 assert.Nil(t, err) | 171 assert.Nil(t, err) |
| 154 dbVersion, err = vdb.DBVersion() | 172 dbVersion, err = vdb.DBVersion() |
| 155 assert.Nil(t, err) | 173 assert.Nil(t, err) |
| 156 assert.Equal(t, 0, dbVersion) | 174 assert.Equal(t, 0, dbVersion) |
| 157 | 175 |
| 158 // upgrade the the latest version | 176 // upgrade the the latest version |
| 159 err = vdb.Migrate(maxVersion) | 177 err = vdb.Migrate(maxVersion) |
| 160 assert.Nil(t, err) | 178 assert.Nil(t, err) |
| 161 dbVersion, err = vdb.DBVersion() | 179 dbVersion, err = vdb.DBVersion() |
| 162 assert.Nil(t, err) | 180 assert.Nil(t, err) |
| 163 assert.Equal(t, maxVersion, dbVersion) | 181 assert.Equal(t, maxVersion, dbVersion) |
| 164 } | 182 } |
| OLD | NEW |