github.com/0xPolygon/supernets2-node@v0.0.0-20230711153321-2fe574524eaa/db/migrations/state/utils_test.go (about) 1 package migrations_test 2 3 import ( 4 "database/sql" 5 "fmt" 6 "testing" 7 8 "github.com/0xPolygon/supernets2-node/db" 9 "github.com/0xPolygon/supernets2-node/log" 10 "github.com/0xPolygon/supernets2-node/test/dbutils" 11 "github.com/gobuffalo/packr/v2" 12 "github.com/jackc/pgx/v4" 13 "github.com/jackc/pgx/v4/stdlib" 14 migrate "github.com/rubenv/sql-migrate" 15 "github.com/stretchr/testify/require" 16 ) 17 18 /* 19 Considerations tricks and tips for migration file testing: 20 21 - Functionality of the DB is tested by the rest of the packages, migration tests only have to check persistence across migrations (both UP and DOWN) 22 - It's recommended to use real data (from testnet/mainnet), but modifying NULL fields to check that those are migrated properly 23 - It's recommended to use some SQL tool (such as DBeaver) that generates insert queries from existing rows 24 - Any new migration file could be tested using the existing `migrationTester` interface. Check `0002_test.go` for an example 25 */ 26 27 func init() { 28 log.Init(log.Config{ 29 Level: "debug", 30 Outputs: []string{"stderr"}, 31 }) 32 } 33 34 type migrationTester interface { 35 // InsertData used to insert data in the affected tables of the migration that is being tested 36 // data will be inserted with the schema as it was previous the migration that is being tested 37 InsertData(*sql.DB) error 38 // RunAssertsAfterMigrationUp this function will be called after running the migration is being tested 39 // and should assert that the data inserted in the function InsertData is persisted properly 40 RunAssertsAfterMigrationUp(*testing.T, *sql.DB) 41 // RunAssertsAfterMigrationDown this function will be called after reverting the migration that is being tested 42 // and should assert that the data inserted in the function InsertData is persisted properly 43 RunAssertsAfterMigrationDown(*testing.T, *sql.DB) 44 } 45 46 var ( 47 stateDBCfg = dbutils.NewStateConfigFromEnv() 48 packrMigrations = map[string]*packr.Box{ 49 db.StateMigrationName: packr.New(db.StateMigrationName, "./migrations/state"), 50 db.PoolMigrationName: packr.New(db.PoolMigrationName, "./migrations/pool"), 51 } 52 ) 53 54 func runMigrationTest(t *testing.T, migrationNumber int, miter migrationTester) { 55 // Initialize an empty DB 56 d, err := initCleanSQLDB() 57 require.NoError(t, err) 58 require.NoError(t, runMigrationsDown(d, 0, db.StateMigrationName)) 59 // Run migrations until migration to test 60 require.NoError(t, runMigrationsUp(d, migrationNumber-1, db.StateMigrationName)) 61 // Insert data into table(s) affected by migration 62 require.NoError(t, miter.InsertData(d)) 63 // Run migration that is being tested 64 require.NoError(t, runMigrationsUp(d, 1, db.StateMigrationName)) 65 // Check that data is persisted properly after migration up 66 miter.RunAssertsAfterMigrationUp(t, d) 67 // Revert migration to test 68 require.NoError(t, runMigrationsDown(d, 1, db.StateMigrationName)) 69 // Check that data is persisted properly after migration down 70 miter.RunAssertsAfterMigrationDown(t, d) 71 } 72 73 func initCleanSQLDB() (*sql.DB, error) { 74 // run migrations 75 if err := db.RunMigrationsDown(stateDBCfg, db.StateMigrationName); err != nil { 76 return nil, err 77 } 78 c, err := pgx.ParseConfig(fmt.Sprintf("postgres://%s:%s@%s:%s/%s", stateDBCfg.User, stateDBCfg.Password, stateDBCfg.Host, stateDBCfg.Port, stateDBCfg.Name)) 79 if err != nil { 80 return nil, err 81 } 82 sqlDB := stdlib.OpenDB(*c) 83 return sqlDB, nil 84 } 85 86 func runMigrationsUp(d *sql.DB, n int, packrName string) error { 87 box, ok := packrMigrations[packrName] 88 if !ok { 89 return fmt.Errorf("packr box not found with name: %v", packrName) 90 } 91 92 var migrations = &migrate.PackrMigrationSource{Box: box} 93 nMigrations, err := migrate.ExecMax(d, "postgres", migrations, migrate.Up, n) 94 if err != nil { 95 return err 96 } 97 if nMigrations != n { 98 return fmt.Errorf("Unexpected amount of migrations: expected: %d, actual: %d", n, nMigrations) 99 } 100 return nil 101 } 102 103 func runMigrationsDown(d *sql.DB, n int, packrName string) error { 104 box, ok := packrMigrations[packrName] 105 if !ok { 106 return fmt.Errorf("packr box not found with name: %v", packrName) 107 } 108 109 var migrations = &migrate.PackrMigrationSource{Box: box} 110 nMigrations, err := migrate.ExecMax(d, "postgres", migrations, migrate.Down, n) 111 if err != nil { 112 return err 113 } 114 if nMigrations != n { 115 return fmt.Errorf("Unexpected amount of migrations: expected: %d, actual: %d", n, nMigrations) 116 } 117 return nil 118 }