
use golangci/golangci-lint-action instead of reviewdog/action-golangci-lint as the second was not reporting any failures even if there was some. Report code coverage with codecov/codecov-action I have set some flags per dialect and go version Several linters has been fixed, some disabled so the build can pass
457 lines
13 KiB
Go
457 lines
13 KiB
Go
package tests_test
|
|
|
|
import (
|
|
"math/rand"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"gorm.io/gorm"
|
|
. "gorm.io/gorm/utils/tests"
|
|
)
|
|
|
|
func TestMigrate(t *testing.T) {
|
|
allModels := []interface{}{&User{}, &Account{}, &Pet{}, &Company{}, &Toy{}, &Language{}}
|
|
rand.Seed(time.Now().UnixNano())
|
|
rand.Shuffle(len(allModels), func(i, j int) { allModels[i], allModels[j] = allModels[j], allModels[i] })
|
|
DB.Migrator().DropTable("user_speaks", "user_friends", "ccc")
|
|
|
|
if err := DB.Migrator().DropTable(allModels...); err != nil {
|
|
t.Fatalf("Failed to drop table, got error %v", err)
|
|
}
|
|
|
|
if err := DB.AutoMigrate(allModels...); err != nil {
|
|
t.Fatalf("Failed to auto migrate, but got error %v", err)
|
|
}
|
|
|
|
if tables, err := DB.Migrator().GetTables(); err != nil {
|
|
t.Fatalf("Failed to get database all tables, but got error %v", err)
|
|
} else {
|
|
for _, t1 := range []string{"users", "accounts", "pets", "companies", "toys", "languages"} {
|
|
hasTable := false
|
|
for _, t2 := range tables {
|
|
if t2 == t1 {
|
|
hasTable = true
|
|
break
|
|
}
|
|
}
|
|
if !hasTable {
|
|
t.Fatalf("Failed to get table %v when GetTables", t1)
|
|
}
|
|
}
|
|
}
|
|
|
|
for _, m := range allModels {
|
|
if !DB.Migrator().HasTable(m) {
|
|
t.Fatalf("Failed to create table for %#v---", m)
|
|
}
|
|
}
|
|
|
|
DB.Scopes(func(db *gorm.DB) *gorm.DB {
|
|
return db.Table("ccc")
|
|
}).Migrator().CreateTable(&Company{})
|
|
|
|
if !DB.Migrator().HasTable("ccc") {
|
|
t.Errorf("failed to create table ccc")
|
|
}
|
|
|
|
for _, indexes := range [][2]string{
|
|
{"user_speaks", "fk_user_speaks_user"},
|
|
{"user_speaks", "fk_user_speaks_language"},
|
|
{"user_friends", "fk_user_friends_user"},
|
|
{"user_friends", "fk_user_friends_friends"},
|
|
{"accounts", "fk_users_account"},
|
|
{"users", "fk_users_team"},
|
|
{"users", "fk_users_company"},
|
|
} {
|
|
if !DB.Migrator().HasConstraint(indexes[0], indexes[1]) {
|
|
t.Fatalf("Failed to find index for many2many for %v %v", indexes[0], indexes[1])
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestAutoMigrateSelfReferential(t *testing.T) {
|
|
type MigratePerson struct {
|
|
ID uint
|
|
Name string
|
|
ManagerID *uint
|
|
Manager *MigratePerson
|
|
}
|
|
|
|
DB.Migrator().DropTable(&MigratePerson{})
|
|
|
|
if err := DB.AutoMigrate(&MigratePerson{}); err != nil {
|
|
t.Fatalf("Failed to auto migrate, but got error %v", err)
|
|
}
|
|
|
|
if !DB.Migrator().HasConstraint("migrate_people", "fk_migrate_people_manager") {
|
|
t.Fatalf("Failed to find has one constraint between people and managers")
|
|
}
|
|
}
|
|
|
|
func TestSmartMigrateColumn(t *testing.T) {
|
|
fullSupported := map[string]bool{"mysql": true}[DB.Dialector.Name()]
|
|
|
|
type UserMigrateColumn struct {
|
|
ID uint
|
|
Name string
|
|
Salary float64
|
|
Birthday time.Time `gorm:"precision:4"`
|
|
}
|
|
|
|
DB.Migrator().DropTable(&UserMigrateColumn{})
|
|
|
|
DB.AutoMigrate(&UserMigrateColumn{})
|
|
|
|
type UserMigrateColumn2 struct {
|
|
ID uint
|
|
Name string `gorm:"size:128"`
|
|
Salary float64 `gorm:"precision:2"`
|
|
Birthday time.Time `gorm:"precision:2"`
|
|
NameIgnoreMigration string `gorm:"size:100"`
|
|
}
|
|
|
|
if err := DB.Table("user_migrate_columns").AutoMigrate(&UserMigrateColumn2{}); err != nil {
|
|
t.Fatalf("failed to auto migrate, got error: %v", err)
|
|
}
|
|
|
|
columnTypes, err := DB.Table("user_migrate_columns").Migrator().ColumnTypes(&UserMigrateColumn{})
|
|
if err != nil {
|
|
t.Fatalf("failed to get column types, got error: %v", err)
|
|
}
|
|
|
|
for _, columnType := range columnTypes {
|
|
switch columnType.Name() {
|
|
case "name":
|
|
if length, _ := columnType.Length(); (fullSupported || length != 0) && length != 128 {
|
|
t.Fatalf("name's length should be 128, but got %v", length)
|
|
}
|
|
case "salary":
|
|
if precision, o, _ := columnType.DecimalSize(); (fullSupported || precision != 0) && precision != 2 {
|
|
t.Fatalf("salary's precision should be 2, but got %v %v", precision, o)
|
|
}
|
|
case "birthday":
|
|
if precision, _, _ := columnType.DecimalSize(); (fullSupported || precision != 0) && precision != 2 {
|
|
t.Fatalf("birthday's precision should be 2, but got %v", precision)
|
|
}
|
|
}
|
|
}
|
|
|
|
type UserMigrateColumn3 struct {
|
|
ID uint
|
|
Name string `gorm:"size:256"`
|
|
Salary float64 `gorm:"precision:3"`
|
|
Birthday time.Time `gorm:"precision:3"`
|
|
NameIgnoreMigration string `gorm:"size:128;-:migration"`
|
|
}
|
|
|
|
if err := DB.Table("user_migrate_columns").AutoMigrate(&UserMigrateColumn3{}); err != nil {
|
|
t.Fatalf("failed to auto migrate, got error: %v", err)
|
|
}
|
|
|
|
columnTypes, err = DB.Table("user_migrate_columns").Migrator().ColumnTypes(&UserMigrateColumn{})
|
|
if err != nil {
|
|
t.Fatalf("failed to get column types, got error: %v", err)
|
|
}
|
|
|
|
for _, columnType := range columnTypes {
|
|
switch columnType.Name() {
|
|
case "name":
|
|
if length, _ := columnType.Length(); (fullSupported || length != 0) && length != 256 {
|
|
t.Fatalf("name's length should be 128, but got %v", length)
|
|
}
|
|
case "salary":
|
|
if precision, _, _ := columnType.DecimalSize(); (fullSupported || precision != 0) && precision != 3 {
|
|
t.Fatalf("salary's precision should be 2, but got %v", precision)
|
|
}
|
|
case "birthday":
|
|
if precision, _, _ := columnType.DecimalSize(); (fullSupported || precision != 0) && precision != 3 {
|
|
t.Fatalf("birthday's precision should be 2, but got %v", precision)
|
|
}
|
|
case "name_ignore_migration":
|
|
if length, _ := columnType.Length(); (fullSupported || length != 0) && length != 100 {
|
|
t.Fatalf("name_ignore_migration's length should still be 100 but got %v", length)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestMigrateWithColumnComment(t *testing.T) {
|
|
type UserWithColumnComment struct {
|
|
gorm.Model
|
|
Name string `gorm:"size:111;comment:this is a 字段"`
|
|
}
|
|
|
|
if err := DB.Migrator().DropTable(&UserWithColumnComment{}); err != nil {
|
|
t.Fatalf("Failed to drop table, got error %v", err)
|
|
}
|
|
|
|
if err := DB.AutoMigrate(&UserWithColumnComment{}); err != nil {
|
|
t.Fatalf("Failed to auto migrate, but got error %v", err)
|
|
}
|
|
}
|
|
|
|
func TestMigrateWithIndexComment(t *testing.T) {
|
|
if DB.Dialector.Name() != "mysql" {
|
|
t.Skip()
|
|
}
|
|
|
|
type UserWithIndexComment struct {
|
|
gorm.Model
|
|
Name string `gorm:"size:111;index:,comment:这是一个index"`
|
|
}
|
|
|
|
if err := DB.Migrator().DropTable(&UserWithIndexComment{}); err != nil {
|
|
t.Fatalf("Failed to drop table, got error %v", err)
|
|
}
|
|
|
|
if err := DB.AutoMigrate(&UserWithIndexComment{}); err != nil {
|
|
t.Fatalf("Failed to auto migrate, but got error %v", err)
|
|
}
|
|
}
|
|
|
|
func TestMigrateWithUniqueIndex(t *testing.T) {
|
|
type UserWithUniqueIndex struct {
|
|
ID int
|
|
Name string `gorm:"size:20;index:idx_name,unique"`
|
|
Date time.Time `gorm:"index:idx_name,unique"`
|
|
}
|
|
|
|
DB.Migrator().DropTable(&UserWithUniqueIndex{})
|
|
if err := DB.AutoMigrate(&UserWithUniqueIndex{}); err != nil {
|
|
t.Fatalf("failed to migrate, got %v", err)
|
|
}
|
|
|
|
if !DB.Migrator().HasIndex(&UserWithUniqueIndex{}, "idx_name") {
|
|
t.Errorf("Failed to find created index")
|
|
}
|
|
}
|
|
|
|
func TestMigrateTable(t *testing.T) {
|
|
type TableStruct struct {
|
|
gorm.Model
|
|
Name string
|
|
}
|
|
|
|
DB.Migrator().DropTable(&TableStruct{})
|
|
DB.AutoMigrate(&TableStruct{})
|
|
|
|
if !DB.Migrator().HasTable(&TableStruct{}) {
|
|
t.Fatalf("should found created table")
|
|
}
|
|
|
|
type NewTableStruct struct {
|
|
gorm.Model
|
|
Name string
|
|
}
|
|
|
|
if err := DB.Migrator().RenameTable(&TableStruct{}, &NewTableStruct{}); err != nil {
|
|
t.Fatalf("Failed to rename table, got error %v", err)
|
|
}
|
|
|
|
if !DB.Migrator().HasTable("new_table_structs") {
|
|
t.Fatal("should found renamed table")
|
|
}
|
|
|
|
DB.Migrator().DropTable("new_table_structs")
|
|
|
|
if DB.Migrator().HasTable(&NewTableStruct{}) {
|
|
t.Fatal("should not found droped table")
|
|
}
|
|
}
|
|
|
|
func TestMigrateIndexes(t *testing.T) {
|
|
type IndexStruct struct {
|
|
gorm.Model
|
|
Name string `gorm:"size:255;index"`
|
|
}
|
|
|
|
DB.Migrator().DropTable(&IndexStruct{})
|
|
DB.AutoMigrate(&IndexStruct{})
|
|
|
|
if err := DB.Migrator().DropIndex(&IndexStruct{}, "Name"); err != nil {
|
|
t.Fatalf("Failed to drop index for user's name, got err %v", err)
|
|
}
|
|
|
|
if err := DB.Migrator().CreateIndex(&IndexStruct{}, "Name"); err != nil {
|
|
t.Fatalf("Got error when tried to create index: %+v", err)
|
|
}
|
|
|
|
if !DB.Migrator().HasIndex(&IndexStruct{}, "Name") {
|
|
t.Fatalf("Failed to find index for user's name")
|
|
}
|
|
|
|
if err := DB.Migrator().DropIndex(&IndexStruct{}, "Name"); err != nil {
|
|
t.Fatalf("Failed to drop index for user's name, got err %v", err)
|
|
}
|
|
|
|
if DB.Migrator().HasIndex(&IndexStruct{}, "Name") {
|
|
t.Fatalf("Should not find index for user's name after delete")
|
|
}
|
|
|
|
if err := DB.Migrator().CreateIndex(&IndexStruct{}, "Name"); err != nil {
|
|
t.Fatalf("Got error when tried to create index: %+v", err)
|
|
}
|
|
|
|
if err := DB.Migrator().RenameIndex(&IndexStruct{}, "idx_index_structs_name", "idx_users_name_1"); err != nil {
|
|
t.Fatalf("no error should happen when rename index, but got %v", err)
|
|
}
|
|
|
|
if !DB.Migrator().HasIndex(&IndexStruct{}, "idx_users_name_1") {
|
|
t.Fatalf("Should find index for user's name after rename")
|
|
}
|
|
|
|
if err := DB.Migrator().DropIndex(&IndexStruct{}, "idx_users_name_1"); err != nil {
|
|
t.Fatalf("Failed to drop index for user's name, got err %v", err)
|
|
}
|
|
|
|
if DB.Migrator().HasIndex(&IndexStruct{}, "idx_users_name_1") {
|
|
t.Fatalf("Should not find index for user's name after delete")
|
|
}
|
|
}
|
|
|
|
func TestMigrateColumns(t *testing.T) {
|
|
type ColumnStruct struct {
|
|
gorm.Model
|
|
Name string
|
|
}
|
|
|
|
DB.Migrator().DropTable(&ColumnStruct{})
|
|
|
|
if err := DB.AutoMigrate(&ColumnStruct{}); err != nil {
|
|
t.Errorf("Failed to migrate, got %v", err)
|
|
}
|
|
|
|
type ColumnStruct2 struct {
|
|
gorm.Model
|
|
Name string `gorm:"size:100"`
|
|
}
|
|
|
|
if err := DB.Table("column_structs").Migrator().AlterColumn(&ColumnStruct2{}, "Name"); err != nil {
|
|
t.Fatalf("no error should happened when alter column, but got %v", err)
|
|
}
|
|
|
|
if columnTypes, err := DB.Migrator().ColumnTypes(&ColumnStruct{}); err != nil {
|
|
t.Fatalf("no error should returns for ColumnTypes")
|
|
} else {
|
|
stmt := &gorm.Statement{DB: DB}
|
|
stmt.Parse(&ColumnStruct2{})
|
|
|
|
for _, columnType := range columnTypes {
|
|
if columnType.Name() == "name" {
|
|
dataType := DB.Dialector.DataTypeOf(stmt.Schema.LookUpField(columnType.Name()))
|
|
if !strings.Contains(strings.ToUpper(dataType), strings.ToUpper(columnType.DatabaseTypeName())) {
|
|
t.Errorf("column type should be correct, name: %v, length: %v, expects: %v", columnType.Name(), columnType.DatabaseTypeName(), dataType)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
type NewColumnStruct struct {
|
|
gorm.Model
|
|
Name string
|
|
NewName string
|
|
}
|
|
|
|
if err := DB.Table("column_structs").Migrator().AddColumn(&NewColumnStruct{}, "NewName"); err != nil {
|
|
t.Fatalf("Failed to add column, got %v", err)
|
|
}
|
|
|
|
if !DB.Table("column_structs").Migrator().HasColumn(&NewColumnStruct{}, "NewName") {
|
|
t.Fatalf("Failed to find added column")
|
|
}
|
|
|
|
if err := DB.Table("column_structs").Migrator().DropColumn(&NewColumnStruct{}, "NewName"); err != nil {
|
|
t.Fatalf("Failed to add column, got %v", err)
|
|
}
|
|
|
|
if DB.Table("column_structs").Migrator().HasColumn(&NewColumnStruct{}, "NewName") {
|
|
t.Fatalf("Found deleted column")
|
|
}
|
|
|
|
if err := DB.Table("column_structs").Migrator().AddColumn(&NewColumnStruct{}, "NewName"); err != nil {
|
|
t.Fatalf("Failed to add column, got %v", err)
|
|
}
|
|
|
|
if err := DB.Table("column_structs").Migrator().RenameColumn(&NewColumnStruct{}, "NewName", "new_new_name"); err != nil {
|
|
t.Fatalf("Failed to add column, got %v", err)
|
|
}
|
|
|
|
if !DB.Table("column_structs").Migrator().HasColumn(&NewColumnStruct{}, "new_new_name") {
|
|
t.Fatalf("Failed to found renamed column")
|
|
}
|
|
|
|
if err := DB.Table("column_structs").Migrator().DropColumn(&NewColumnStruct{}, "new_new_name"); err != nil {
|
|
t.Fatalf("Failed to add column, got %v", err)
|
|
}
|
|
|
|
if DB.Table("column_structs").Migrator().HasColumn(&NewColumnStruct{}, "new_new_name") {
|
|
t.Fatalf("Found deleted column")
|
|
}
|
|
}
|
|
|
|
func TestMigrateConstraint(t *testing.T) {
|
|
names := []string{"Account", "fk_users_account", "Pets", "fk_users_pets", "Company", "fk_users_company", "Team", "fk_users_team", "Languages", "fk_users_languages"}
|
|
|
|
for _, name := range names {
|
|
if !DB.Migrator().HasConstraint(&User{}, name) {
|
|
DB.Migrator().CreateConstraint(&User{}, name)
|
|
}
|
|
|
|
if err := DB.Migrator().DropConstraint(&User{}, name); err != nil {
|
|
t.Fatalf("failed to drop constraint %v, got error %v", name, err)
|
|
}
|
|
|
|
if DB.Migrator().HasConstraint(&User{}, name) {
|
|
t.Fatalf("constraint %v should been deleted", name)
|
|
}
|
|
|
|
if err := DB.Migrator().CreateConstraint(&User{}, name); err != nil {
|
|
t.Fatalf("failed to create constraint %v, got error %v", name, err)
|
|
}
|
|
|
|
if !DB.Migrator().HasConstraint(&User{}, name) {
|
|
t.Fatalf("failed to found constraint %v", name)
|
|
}
|
|
}
|
|
}
|
|
|
|
type DynamicUser struct {
|
|
gorm.Model
|
|
Name string
|
|
CompanyID string `gorm:"index"`
|
|
}
|
|
|
|
// To test auto migrate crate indexes for dynamic table name
|
|
// https://github.com/go-gorm/gorm/issues/4752
|
|
func TestMigrateIndexesWithDynamicTableName(t *testing.T) {
|
|
// Create primary table
|
|
if err := DB.AutoMigrate(&DynamicUser{}); err != nil {
|
|
t.Fatalf("AutoMigrate create table error: %#v", err)
|
|
}
|
|
|
|
// Create sub tables
|
|
for _, v := range []string{"01", "02", "03"} {
|
|
tableName := "dynamic_users_" + v
|
|
m := DB.Scopes(func(db *gorm.DB) *gorm.DB {
|
|
return db.Table(tableName)
|
|
}).Migrator()
|
|
|
|
if err := m.AutoMigrate(&DynamicUser{}); err != nil {
|
|
t.Fatalf("AutoMigrate create table error: %#v", err)
|
|
}
|
|
|
|
if !m.HasTable(tableName) {
|
|
t.Fatalf("AutoMigrate expected %#v exist, but not.", tableName)
|
|
}
|
|
|
|
if !m.HasIndex(&DynamicUser{}, "CompanyID") {
|
|
t.Fatalf("Should have index on %s", "CompanyI.")
|
|
}
|
|
|
|
if !m.HasIndex(&DynamicUser{}, "DeletedAt") {
|
|
t.Fatalf("Should have index on deleted_at.")
|
|
}
|
|
}
|
|
}
|