@@ -19,7 +19,6 @@ import (
19
19
20
20
"github.com/github/gh-ost/go/base"
21
21
"github.com/github/gh-ost/go/binlog"
22
- "github.com/github/gh-ost/go/mysql"
23
22
"github.com/github/gh-ost/go/sql"
24
23
)
25
24
@@ -198,6 +197,7 @@ type ApplierTestSuite struct {
198
197
suite.Suite
199
198
200
199
mysqlContainer testcontainers.Container
200
+ db * gosql.DB
201
201
}
202
202
203
203
func (suite * ApplierTestSuite ) SetupSuite () {
@@ -216,49 +216,50 @@ func (suite *ApplierTestSuite) SetupSuite() {
216
216
suite .Require ().NoError (err )
217
217
218
218
suite .mysqlContainer = mysqlContainer
219
+
220
+ dsn , err := GetDSN (ctx , mysqlContainer )
221
+ suite .Require ().NoError (err )
222
+
223
+ db , err := gosql .Open ("mysql" , dsn )
224
+ suite .Require ().NoError (err )
225
+
226
+ suite .db = db
219
227
}
220
228
221
229
func (suite * ApplierTestSuite ) TeardownSuite () {
222
230
ctx := context .Background ()
223
231
224
- suite .Require ().NoError (suite .mysqlContainer .Terminate (ctx ))
232
+ suite .Assert ().NoError (suite .db .Close ())
233
+ suite .Assert ().NoError (suite .mysqlContainer .Terminate (ctx ))
225
234
}
226
235
227
236
func (suite * ApplierTestSuite ) SetupTest () {
228
237
ctx := context .Background ()
229
238
230
- rc , _ , err := suite .mysqlContainer .Exec (ctx , []string {"mysql" , "-uroot" , "-proot-password" , "-e" , "CREATE DATABASE test;" })
231
- suite .Require ().NoError (err )
232
- suite .Require ().Equalf (0 , rc , "failed to created database: expected exit code 0, got %d" , rc )
233
-
234
- rc , _ , err = suite .mysqlContainer .Exec (ctx , []string {"mysql" , "-uroot" , "-proot-password" , "-e" , "CREATE TABLE test.testing (id INT, item_id INT);" })
239
+ _ , err := suite .db .ExecContext (ctx , "CREATE DATABASE test" )
235
240
suite .Require ().NoError (err )
236
- suite .Require ().Equalf (0 , rc , "failed to created table: expected exit code 0, got %d" , rc )
237
241
}
238
242
239
243
func (suite * ApplierTestSuite ) TearDownTest () {
240
244
ctx := context .Background ()
241
245
242
- rc , _ , err := suite .mysqlContainer . Exec (ctx , [] string { "mysql" , "-uroot" , "-proot-password" , "-e" , " DROP DATABASE test;" } )
246
+ _ , err := suite .db . ExecContext (ctx , " DROP DATABASE test" )
243
247
suite .Require ().NoError (err )
244
- suite .Require ().Equalf (0 , rc , "failed to created database: expected exit code 0, got %d" , rc )
245
248
}
246
249
247
250
func (suite * ApplierTestSuite ) TestInitDBConnections () {
248
251
ctx := context .Background ()
249
252
250
- host , err := suite .mysqlContainer .Host (ctx )
253
+ var err error
254
+
255
+ _ , err = suite .db .ExecContext (ctx , "CREATE TABLE test.testing (id INT, item_id INT);" )
251
256
suite .Require ().NoError (err )
252
257
253
- port , err := suite . mysqlContainer . MappedPort (ctx , "3306" )
258
+ connectionConfig , err := GetConnectionConfig (ctx , suite . mysqlContainer )
254
259
suite .Require ().NoError (err )
255
260
256
261
migrationContext := base .NewMigrationContext ()
257
- migrationContext .ApplierConnectionConfig = mysql .NewConnectionConfig ()
258
- migrationContext .ApplierConnectionConfig .Key .Hostname = host
259
- migrationContext .ApplierConnectionConfig .Key .Port = port .Int ()
260
- migrationContext .ApplierConnectionConfig .User = "root"
261
- migrationContext .ApplierConnectionConfig .Password = "root-password"
262
+ migrationContext .ApplierConnectionConfig = connectionConfig
262
263
migrationContext .DatabaseName = "test"
263
264
migrationContext .SkipPortValidation = true
264
265
migrationContext .OriginalTableName = "testing"
@@ -280,18 +281,19 @@ func (suite *ApplierTestSuite) TestInitDBConnections() {
280
281
func (suite * ApplierTestSuite ) TestApplyDMLEventQueries () {
281
282
ctx := context .Background ()
282
283
283
- host , err := suite .mysqlContainer .Host (ctx )
284
+ var err error
285
+
286
+ _ , err = suite .db .ExecContext (ctx , "CREATE TABLE test.testing (id INT, item_id INT);" )
287
+ suite .Require ().NoError (err )
288
+
289
+ _ , err = suite .db .ExecContext (ctx , "CREATE TABLE test._testing_gho (id INT, item_id INT);" )
284
290
suite .Require ().NoError (err )
285
291
286
- port , err := suite . mysqlContainer . MappedPort (ctx , "3306" )
292
+ connectionConfig , err := GetConnectionConfig (ctx , suite . mysqlContainer )
287
293
suite .Require ().NoError (err )
288
294
289
295
migrationContext := base .NewMigrationContext ()
290
- migrationContext .ApplierConnectionConfig = mysql .NewConnectionConfig ()
291
- migrationContext .ApplierConnectionConfig .Key .Hostname = host
292
- migrationContext .ApplierConnectionConfig .Key .Port = port .Int ()
293
- migrationContext .ApplierConnectionConfig .User = "root"
294
- migrationContext .ApplierConnectionConfig .Password = "root-password"
296
+ migrationContext .ApplierConnectionConfig = connectionConfig
295
297
migrationContext .DatabaseName = "test"
296
298
migrationContext .SkipPortValidation = true
297
299
migrationContext .OriginalTableName = "testing"
@@ -307,10 +309,6 @@ func (suite *ApplierTestSuite) TestApplyDMLEventQueries() {
307
309
err = applier .InitDBConnections ()
308
310
suite .Require ().NoError (err )
309
311
310
- rc , _ , err := suite .mysqlContainer .Exec (ctx , []string {"mysql" , "-uroot" , "-proot-password" , "-e" , "CREATE TABLE test._testing_gho (id INT, item_id INT);" })
311
- suite .Require ().NoError (err )
312
- suite .Require ().Equalf (0 , rc , "failed to created table: expected exit code 0, got %d" , rc )
313
-
314
312
dmlEvents := []* binlog.BinlogDMLEvent {
315
313
{
316
314
DatabaseName : "test" ,
@@ -323,11 +321,7 @@ func (suite *ApplierTestSuite) TestApplyDMLEventQueries() {
323
321
suite .Require ().NoError (err )
324
322
325
323
// Check that the row was inserted
326
- db , err := gosql .Open ("mysql" , "root:root-password@tcp(" + host + ":3306)/test" )
327
- suite .Require ().NoError (err )
328
- defer db .Close ()
329
-
330
- rows , err := db .Query ("SELECT * FROM test._testing_gho" )
324
+ rows , err := suite .db .Query ("SELECT * FROM test._testing_gho" )
331
325
suite .Require ().NoError (err )
332
326
defer rows .Close ()
333
327
@@ -350,18 +344,16 @@ func (suite *ApplierTestSuite) TestApplyDMLEventQueries() {
350
344
func (suite * ApplierTestSuite ) TestValidateOrDropExistingTables () {
351
345
ctx := context .Background ()
352
346
353
- host , err := suite .mysqlContainer .Host (ctx )
347
+ var err error
348
+
349
+ _ , err = suite .db .ExecContext (ctx , "CREATE TABLE test.testing (id INT, item_id INT);" )
354
350
suite .Require ().NoError (err )
355
351
356
- port , err := suite . mysqlContainer . MappedPort (ctx , "3306" )
352
+ connectionConfig , err := GetConnectionConfig (ctx , suite . mysqlContainer )
357
353
suite .Require ().NoError (err )
358
354
359
355
migrationContext := base .NewMigrationContext ()
360
- migrationContext .ApplierConnectionConfig = mysql .NewConnectionConfig ()
361
- migrationContext .ApplierConnectionConfig .Key .Hostname = host
362
- migrationContext .ApplierConnectionConfig .Key .Port = port .Int ()
363
- migrationContext .ApplierConnectionConfig .User = "root"
364
- migrationContext .ApplierConnectionConfig .Password = "root-password"
356
+ migrationContext .ApplierConnectionConfig = connectionConfig
365
357
migrationContext .DatabaseName = "test"
366
358
migrationContext .SkipPortValidation = true
367
359
migrationContext .OriginalTableName = "testing"
@@ -381,6 +373,127 @@ func (suite *ApplierTestSuite) TestValidateOrDropExistingTables() {
381
373
suite .Require ().NoError (err )
382
374
}
383
375
376
+ func (suite * ApplierTestSuite ) TestValidateOrDropExistingTablesWithGhostTableExisting () {
377
+ ctx := context .Background ()
378
+
379
+ var err error
380
+
381
+ _ , err = suite .db .ExecContext (ctx , "CREATE TABLE test.testing (id INT, item_id INT);" )
382
+ suite .Require ().NoError (err )
383
+
384
+ _ , err = suite .db .ExecContext (ctx , "CREATE TABLE test._testing_gho (id INT, item_id INT);" )
385
+ suite .Require ().NoError (err )
386
+
387
+ connectionConfig , err := GetConnectionConfig (ctx , suite .mysqlContainer )
388
+ suite .Require ().NoError (err )
389
+
390
+ migrationContext := base .NewMigrationContext ()
391
+ migrationContext .ApplierConnectionConfig = connectionConfig
392
+ migrationContext .DatabaseName = "test"
393
+ migrationContext .SkipPortValidation = true
394
+ migrationContext .OriginalTableName = "testing"
395
+ migrationContext .SetConnectionConfig ("innodb" )
396
+
397
+ migrationContext .OriginalTableColumns = sql .NewColumnList ([]string {"id" , "item_id" })
398
+ migrationContext .SharedColumns = sql .NewColumnList ([]string {"id" , "item_id" })
399
+ migrationContext .MappedSharedColumns = sql .NewColumnList ([]string {"id" , "item_id" })
400
+
401
+ applier := NewApplier (migrationContext )
402
+ defer applier .Teardown ()
403
+
404
+ err = applier .InitDBConnections ()
405
+ suite .Require ().NoError (err )
406
+
407
+ err = applier .ValidateOrDropExistingTables ()
408
+ suite .Require ().Error (err )
409
+ suite .Require ().EqualError (err , "Table `_testing_gho` already exists. Panicking. Use --initially-drop-ghost-table to force dropping it, though I really prefer that you drop it or rename it away" )
410
+ }
411
+
412
+ func (suite * ApplierTestSuite ) TestValidateOrDropExistingTablesWithGhostTableExistingAndInitiallyDropGhostTableSet () {
413
+ ctx := context .Background ()
414
+
415
+ var err error
416
+
417
+ _ , err = suite .db .ExecContext (ctx , "CREATE TABLE test.testing (id INT, item_id INT);" )
418
+ suite .Require ().NoError (err )
419
+
420
+ _ , err = suite .db .ExecContext (ctx , "CREATE TABLE test._testing_gho (id INT, item_id INT);" )
421
+ suite .Require ().NoError (err )
422
+
423
+ connectionConfig , err := GetConnectionConfig (ctx , suite .mysqlContainer )
424
+ suite .Require ().NoError (err )
425
+
426
+ migrationContext := base .NewMigrationContext ()
427
+ migrationContext .ApplierConnectionConfig = connectionConfig
428
+ migrationContext .DatabaseName = "test"
429
+ migrationContext .SkipPortValidation = true
430
+ migrationContext .OriginalTableName = "testing"
431
+ migrationContext .SetConnectionConfig ("innodb" )
432
+
433
+ migrationContext .InitiallyDropGhostTable = true
434
+
435
+ applier := NewApplier (migrationContext )
436
+ defer applier .Teardown ()
437
+
438
+ err = applier .InitDBConnections ()
439
+ suite .Require ().NoError (err )
440
+
441
+ err = applier .ValidateOrDropExistingTables ()
442
+ suite .Require ().NoError (err )
443
+
444
+ // Check that the ghost table was dropped
445
+ var tableName string
446
+ err = suite .db .QueryRow ("SHOW TABLES IN test LIKE '_testing_gho'" ).Scan (& tableName )
447
+ suite .Require ().Error (err )
448
+ suite .Require ().Equal (gosql .ErrNoRows , err )
449
+ }
450
+
451
+ func (suite * ApplierTestSuite ) TestCreateGhostTable () {
452
+ ctx := context .Background ()
453
+
454
+ var err error
455
+
456
+ _ , err = suite .db .ExecContext (ctx , "CREATE TABLE test.testing (id INT, item_id INT);" )
457
+ suite .Require ().NoError (err )
458
+
459
+ connectionConfig , err := GetConnectionConfig (ctx , suite .mysqlContainer )
460
+ suite .Require ().NoError (err )
461
+
462
+ migrationContext := base .NewMigrationContext ()
463
+ migrationContext .ApplierConnectionConfig = connectionConfig
464
+ migrationContext .DatabaseName = "test"
465
+ migrationContext .SkipPortValidation = true
466
+ migrationContext .OriginalTableName = "testing"
467
+ migrationContext .SetConnectionConfig ("innodb" )
468
+
469
+ migrationContext .OriginalTableColumns = sql .NewColumnList ([]string {"id" , "item_id" })
470
+ migrationContext .SharedColumns = sql .NewColumnList ([]string {"id" , "item_id" })
471
+ migrationContext .MappedSharedColumns = sql .NewColumnList ([]string {"id" , "item_id" })
472
+
473
+ migrationContext .InitiallyDropGhostTable = true
474
+
475
+ applier := NewApplier (migrationContext )
476
+ defer applier .Teardown ()
477
+
478
+ err = applier .InitDBConnections ()
479
+ suite .Require ().NoError (err )
480
+
481
+ err = applier .CreateGhostTable ()
482
+ suite .Require ().NoError (err )
483
+
484
+ // Check that the ghost table was created
485
+ var tableName string
486
+ err = suite .db .QueryRow ("SHOW TABLES IN test LIKE '_testing_gho'" ).Scan (& tableName )
487
+ suite .Require ().NoError (err )
488
+ suite .Require ().Equal ("_testing_gho" , tableName )
489
+
490
+ // Check that the ghost table has the same columns as the original table
491
+ var createDDL string
492
+ err = suite .db .QueryRow ("SHOW CREATE TABLE test._testing_gho" ).Scan (& tableName , & createDDL )
493
+ suite .Require ().NoError (err )
494
+ suite .Require ().Equal ("CREATE TABLE `_testing_gho` (\n `id` int DEFAULT NULL,\n `item_id` int DEFAULT NULL\n ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci" , createDDL )
495
+ }
496
+
384
497
func TestApplier (t * testing.T ) {
385
498
suite .Run (t , new (ApplierTestSuite ))
386
499
}
0 commit comments