package migration import ( "strings" "testing" "github.com/glebarez/sqlite" "gorm.io/gorm" ) type existingSchema struct { ID uint `gorm:"primaryKey"` Name string } func (existingSchema) TableName() string { return "existing_schema" } func TestCreateMissingTablesDoesNotAlterExistingTables(t *testing.T) { db, err := gorm.Open(sqlite.Open("file:"+t.Name()+"?mode=memory&cache=shared"), &gorm.Config{}) if err != nil { t.Fatal(err) } if err = db.Exec("CREATE TABLE existing_schema (id integer primary key)").Error; err != nil { t.Fatal(err) } if err = CreateMissingTables(db, &existingSchema{}); err != nil { t.Fatal(err) } if db.Migrator().HasColumn(&existingSchema{}, "name") { t.Fatal("existing schema was altered") } } func TestCreateMissingTablesCreatesAbsentTables(t *testing.T) { db, err := gorm.Open(sqlite.Open("file:"+t.Name()+"?mode=memory&cache=shared"), &gorm.Config{}) if err != nil { t.Fatal(err) } if err = CreateMissingTables(db, &existingSchema{}); err != nil { t.Fatal(err) } if !db.Migrator().HasTable(&existingSchema{}) || !db.Migrator().HasColumn(&existingSchema{}, "name") { t.Fatal("missing schema was not created") } } func TestRunRepairsInvalidMigrationMetadataTable(t *testing.T) { db, err := gorm.Open(sqlite.Open("file:"+t.Name()+"?mode=memory&cache=shared"), &gorm.Config{}) if err != nil { t.Fatal(err) } if err = db.Exec("CREATE TABLE sys_schema_migrations (id integer primary key, title text)").Error; err != nil { t.Fatal(err) } called := false if err = Run(db, []Step{{ID: "202608200001_test", Migrate: func(*gorm.DB) error { called = true return nil }}}); err != nil { t.Fatal(err) } if !called { t.Fatal("migration was not rerun after metadata repair") } var dataType string if err = db.Raw("SELECT type FROM pragma_table_info(?) WHERE name = 'id'", TableName).Scan(&dataType).Error; err != nil { t.Fatal(err) } if !strings.Contains(strings.ToLower(dataType), "text") { t.Fatalf("migration id type = %q", dataType) } } func TestRunDoesNotLeakStatementState(t *testing.T) { db, err := gorm.Open(sqlite.Open("file:"+t.Name()+"?mode=memory&cache=shared"), &gorm.Config{}) if err != nil { t.Fatal(err) } if err = Run(db, []Step{{ID: "202608200001_test", Migrate: func(tx *gorm.DB) error { return CreateMissingTables(tx, &existingSchema{}) }}}); err != nil { t.Fatal(err) } var count int64 if err = db.Model(&existingSchema{}).Count(&count).Error; err != nil { t.Fatalf("shared database retained migration statement state: %v", err) } } func TestRunRejectsUnknownAppliedMigration(t *testing.T) { db, err := gorm.Open(sqlite.Open("file:"+t.Name()+"?mode=memory&cache=shared"), &gorm.Config{}) if err != nil { t.Fatal(err) } if err = db.Migrator().CreateTable(&record{}); err != nil { t.Fatal(err) } if err = db.Create(&record{ID: "unknown"}).Error; err != nil { t.Fatal(err) } if err = Run(db, []Step{{ID: "known", Migrate: func(*gorm.DB) error { return nil }}}); err == nil { t.Fatal("unknown migration was accepted") } }