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 = "sk_testing" |
28 ) | 26 ) |
29 | 27 |
30 // Creates an SQLite test database and runs migration tests against it using the | |
31 // given migration steps. | |
32 func SQLiteVersioningTests(t *testing.T, migrationSteps []database.MigrationStep
) { | |
33 // Initialize without argument to test against SQLite3 | |
34 conf := &database.DatabaseConfig{ | |
35 SQLiteFilePath: SQLITE_DB_PATH, | |
36 MigrationSteps: migrationSteps, | |
37 } | |
38 | |
39 vdb := database.NewVersionedDB(conf) | |
40 assert.False(t, vdb.IsMySQL) | |
41 testDBVersioning(t, vdb) | |
42 } | |
43 | |
44 // Creates an MySQL test database and runs migration tests against it using the | 28 // Creates an MySQL test database and runs migration tests against it using the |
45 // given migration steps. See Get for required credentials. | 29 // given migration steps. See Get for required credentials. |
46 // The test assumes that the database is empty and that the readwrite user is | 30 // The test assumes that the database is empty and that the readwrite user is |
47 // not allowed to create/drop/alter tables. | 31 // not allowed to create/drop/alter tables. |
48 func MySQLVersioningTests(t *testing.T, dbName string, migrationSteps []database
.MigrationStep) { | 32 func MySQLVersioningTests(t *testing.T, dbName string, migrationSteps []database
.MigrationStep) { |
49 // OpenDB as root user and remove all tables. | 33 // OpenDB as root user and remove all tables. |
50 » rootConf := &database.DatabaseConfig{ | 34 » rootConf := database.LocalTestRootDatabaseConfig(TEST_DB, migrationSteps
) |
51 » » MySQLString: GetTestMySQLConnStr(t, "root", dbName), | |
52 » » MigrationSteps: migrationSteps, | |
53 » } | |
54 lockVdb := GetMySQlLock(t, rootConf) | 35 lockVdb := GetMySQlLock(t, rootConf) |
55 defer func() { | 36 defer func() { |
56 ReleaseMySQLLock(t, lockVdb) | 37 ReleaseMySQLLock(t, lockVdb) |
57 lockVdb.Close() | 38 lockVdb.Close() |
58 }() | 39 }() |
59 | 40 |
60 rootVdb := database.NewVersionedDB(rootConf) | 41 rootVdb := database.NewVersionedDB(rootConf) |
61 assert.True(t, rootVdb.IsMySQL) | |
62 ClearMySQLTables(t, rootVdb) | 42 ClearMySQLTables(t, rootVdb) |
63 assert.Nil(t, rootVdb.Close()) | 43 assert.Nil(t, rootVdb.Close()) |
64 | 44 |
65 // Configuration for the readwrite user without DDL privileges. | 45 // Configuration for the readwrite user without DDL privileges. |
66 » readWriteConf := &database.DatabaseConfig{ | 46 » readWriteConf := database.LocalTestDatabaseConfig(TEST_DB, migrationStep
s) |
67 » » MySQLString: GetTestMySQLConnStr(t, "readwrite", dbName), | |
68 » » MigrationSteps: migrationSteps, | |
69 » } | |
70 | 47 |
71 // Open DB as readwrite user and make sure it fails because of a missing | 48 // Open DB as readwrite user and make sure it fails because of a missing |
72 // version table. | 49 // version table. |
73 // Note: This requires the database to be empty. | 50 // Note: This requires the database to be empty. |
74 assert.Panics(t, func() { | 51 assert.Panics(t, func() { |
75 database.NewVersionedDB(readWriteConf) | 52 database.NewVersionedDB(readWriteConf) |
76 }) | 53 }) |
77 | 54 |
78 rootVdb = database.NewVersionedDB(rootConf) | 55 rootVdb = database.NewVersionedDB(rootConf) |
79 testDBVersioning(t, rootVdb) | 56 testDBVersioning(t, rootVdb) |
80 | 57 |
81 // Make sure it doesn't panic for readwrite user after the migration | 58 // Make sure it doesn't panic for readwrite user after the migration |
82 assert.NotPanics(t, func() { | 59 assert.NotPanics(t, func() { |
83 database.NewVersionedDB(readWriteConf) | 60 database.NewVersionedDB(readWriteConf) |
84 }) | 61 }) |
85 } | 62 } |
86 | 63 |
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. | 64 // Get a lock from MySQL to serialize DB tests. |
110 func GetMySQlLock(t *testing.T, conf *database.DatabaseConfig) *database.Version
edDB { | 65 func GetMySQlLock(t *testing.T, conf *database.DatabaseConfig) *database.Version
edDB { |
111 vdb := database.NewVersionedDB(conf) | 66 vdb := database.NewVersionedDB(conf) |
112 _, err := vdb.DB.Exec("SELECT GET_LOCK(?,30)", SQL_LOCK) | 67 _, err := vdb.DB.Exec("SELECT GET_LOCK(?,30)", SQL_LOCK) |
113 assert.Nil(t, err) | 68 assert.Nil(t, err) |
114 return vdb | 69 return vdb |
115 } | 70 } |
116 | 71 |
117 // Release the MySQL lock. | 72 // Release the MySQL lock. |
118 func ReleaseMySQLLock(t *testing.T, vdb *database.VersionedDB) { | 73 func ReleaseMySQLLock(t *testing.T, vdb *database.VersionedDB) { |
(...skipping 15 matching lines...) Expand all Loading... |
134 names = append(names, tableName) | 89 names = append(names, tableName) |
135 } | 90 } |
136 | 91 |
137 if len(names) > 0 { | 92 if len(names) > 0 { |
138 stmt = "DROP TABLE " + strings.Join(names, ",") | 93 stmt = "DROP TABLE " + strings.Join(names, ",") |
139 _, err = vdb.DB.Exec(stmt) | 94 _, err = vdb.DB.Exec(stmt) |
140 assert.Nil(t, err) | 95 assert.Nil(t, err) |
141 } | 96 } |
142 } | 97 } |
143 | 98 |
| 99 // MySQLTestDatabase is a convenience struct for using a test database which |
| 100 // starts in a clean state. |
| 101 type MySQLTestDatabase struct { |
| 102 rootVdb *database.VersionedDB |
| 103 t *testing.T |
| 104 } |
| 105 |
| 106 // SetupMySQLTestDatabase returns a MySQLTestDatabase in a clean state. It must |
| 107 // be closed after use. |
| 108 // |
| 109 // Example usage: |
| 110 // |
| 111 // db := SetupMySQLTestDatabase(t, migrationSteps) |
| 112 // defer db.Close() |
| 113 // ... Tests here ... |
| 114 func SetupMySQLTestDatabase(t *testing.T, migrationSteps []database.MigrationSte
p) *MySQLTestDatabase { |
| 115 conf := database.LocalTestRootDatabaseConfig(TEST_DB, migrationSteps) |
| 116 lockVdb := GetMySQlLock(t, conf) |
| 117 rootVdb := database.NewVersionedDB(conf) |
| 118 ClearMySQLTables(t, rootVdb) |
| 119 if err := rootVdb.Close(); err != nil { |
| 120 t.Fatal(err) |
| 121 } |
| 122 rootVdb = database.NewVersionedDB(conf) |
| 123 if err := rootVdb.Migrate(rootVdb.MaxDBVersion()); err != nil { |
| 124 t.Fatal(err) |
| 125 } |
| 126 if err := rootVdb.Close(); err != nil { |
| 127 t.Fatal(err) |
| 128 } |
| 129 return &MySQLTestDatabase{lockVdb, t} |
| 130 } |
| 131 |
| 132 func (d *MySQLTestDatabase) Close() { |
| 133 if err := d.rootVdb.Migrate(0); err != nil { |
| 134 d.t.Fatal(err) |
| 135 } |
| 136 ReleaseMySQLLock(d.t, d.rootVdb) |
| 137 d.rootVdb.Close() |
| 138 } |
| 139 |
144 // Test wether the migration steps execute correctly. | 140 // Test wether the migration steps execute correctly. |
145 func testDBVersioning(t *testing.T, vdb *database.VersionedDB) { | 141 func testDBVersioning(t *testing.T, vdb *database.VersionedDB) { |
146 // get the DB version | 142 // get the DB version |
147 dbVersion, err := vdb.DBVersion() | 143 dbVersion, err := vdb.DBVersion() |
148 assert.Nil(t, err) | 144 assert.Nil(t, err) |
149 maxVersion := vdb.MaxDBVersion() | 145 maxVersion := vdb.MaxDBVersion() |
150 | 146 |
151 // downgrade to 0 | 147 // downgrade to 0 |
152 err = vdb.Migrate(0) | 148 err = vdb.Migrate(0) |
153 assert.Nil(t, err) | 149 assert.Nil(t, err) |
154 dbVersion, err = vdb.DBVersion() | 150 dbVersion, err = vdb.DBVersion() |
155 assert.Nil(t, err) | 151 assert.Nil(t, err) |
156 assert.Equal(t, 0, dbVersion) | 152 assert.Equal(t, 0, dbVersion) |
157 | 153 |
158 // upgrade the the latest version | 154 // upgrade the the latest version |
159 err = vdb.Migrate(maxVersion) | 155 err = vdb.Migrate(maxVersion) |
160 assert.Nil(t, err) | 156 assert.Nil(t, err) |
161 dbVersion, err = vdb.DBVersion() | 157 dbVersion, err = vdb.DBVersion() |
162 assert.Nil(t, err) | 158 assert.Nil(t, err) |
163 assert.Equal(t, maxVersion, dbVersion) | 159 assert.Equal(t, maxVersion, dbVersion) |
164 } | 160 } |
OLD | NEW |