feat: add tidb integration test cases (#6014)
* feat: support tidb integration test * feat: update the mysql driver version to test
This commit is contained in:
		
							parent
							
								
									878ac51e98
								
							
						
					
					
						commit
						02b7e26f6b
					
				
							
								
								
									
										33
									
								
								.github/workflows/tests.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										33
									
								
								.github/workflows/tests.yml
									
									
									
									
										vendored
									
									
								
							| @ -167,3 +167,36 @@ jobs: | |||||||
| 
 | 
 | ||||||
|     - name: Tests |     - name: Tests | ||||||
|       run: GITHUB_ACTION=true GORM_DIALECT=sqlserver GORM_DSN="sqlserver://gorm:LoremIpsum86@localhost:9930?database=gorm" ./tests/tests_all.sh |       run: GITHUB_ACTION=true GORM_DIALECT=sqlserver GORM_DSN="sqlserver://gorm:LoremIpsum86@localhost:9930?database=gorm" ./tests/tests_all.sh | ||||||
|  | 
 | ||||||
|  |   tidb: | ||||||
|  |     strategy: | ||||||
|  |       matrix: | ||||||
|  |         dbversion: [ 'v6.5.0' ] | ||||||
|  |         go: [ '1.19', '1.18' ] | ||||||
|  |         platform: [ ubuntu-latest ] | ||||||
|  |     runs-on: ${{ matrix.platform }} | ||||||
|  | 
 | ||||||
|  |     steps: | ||||||
|  |       - name: Setup TiDB | ||||||
|  |         uses: Icemap/tidb-action@main | ||||||
|  |         with: | ||||||
|  |           port: 9940 | ||||||
|  |           version: ${{matrix.dbversion}} | ||||||
|  | 
 | ||||||
|  |       - name: Set up Go 1.x | ||||||
|  |         uses: actions/setup-go@v3 | ||||||
|  |         with: | ||||||
|  |           go-version: ${{ matrix.go }} | ||||||
|  | 
 | ||||||
|  |       - name: Check out code into the Go module directory | ||||||
|  |         uses: actions/checkout@v3 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |       - name: go mod package cache | ||||||
|  |         uses: actions/cache@v3 | ||||||
|  |         with: | ||||||
|  |           path: ~/go/pkg/mod | ||||||
|  |           key: ${{ runner.os }}-go-${{ matrix.go }}-${{ hashFiles('tests/go.mod') }} | ||||||
|  | 
 | ||||||
|  |       - name: Tests | ||||||
|  |         run: GITHUB_ACTION=true GORM_DIALECT=tidb GORM_DSN="root:@tcp(localhost:9940)/test?charset=utf8&parseTime=True&loc=Local" ./tests/tests_all.sh | ||||||
|  | |||||||
| @ -138,6 +138,7 @@ func TestBelongsToAssociation(t *testing.T) { | |||||||
| 	unexistCompanyID := company.ID + 9999999 | 	unexistCompanyID := company.ID + 9999999 | ||||||
| 	user = User{Name: "invalid-user-with-invalid-belongs-to-foreign-key", CompanyID: &unexistCompanyID} | 	user = User{Name: "invalid-user-with-invalid-belongs-to-foreign-key", CompanyID: &unexistCompanyID} | ||||||
| 	if err := DB.Create(&user).Error; err == nil { | 	if err := DB.Create(&user).Error; err == nil { | ||||||
|  | 		tidbSkip(t, "not support the foreign key feature") | ||||||
| 		t.Errorf("should have gotten foreign key violation error") | 		t.Errorf("should have gotten foreign key violation error") | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | |||||||
| @ -95,6 +95,8 @@ func TestMany2ManyAssociation(t *testing.T) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestMany2ManyOmitAssociations(t *testing.T) { | func TestMany2ManyOmitAssociations(t *testing.T) { | ||||||
|  | 	tidbSkip(t, "not support the foreign key feature") | ||||||
|  | 
 | ||||||
| 	user := *GetUser("many2many_omit_associations", Config{Languages: 2}) | 	user := *GetUser("many2many_omit_associations", Config{Languages: 2}) | ||||||
| 
 | 
 | ||||||
| 	if err := DB.Omit("Languages.*").Create(&user).Error; err == nil { | 	if err := DB.Omit("Languages.*").Create(&user).Error; err == nil { | ||||||
|  | |||||||
| @ -71,6 +71,8 @@ func TestAssociationNotNullClear(t *testing.T) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestForeignKeyConstraints(t *testing.T) { | func TestForeignKeyConstraints(t *testing.T) { | ||||||
|  | 	tidbSkip(t, "not support the foreign key feature") | ||||||
|  | 
 | ||||||
| 	type Profile struct { | 	type Profile struct { | ||||||
| 		ID       uint | 		ID       uint | ||||||
| 		Name     string | 		Name     string | ||||||
| @ -126,6 +128,8 @@ func TestForeignKeyConstraints(t *testing.T) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestForeignKeyConstraintsBelongsTo(t *testing.T) { | func TestForeignKeyConstraintsBelongsTo(t *testing.T) { | ||||||
|  | 	tidbSkip(t, "not support the foreign key feature") | ||||||
|  | 
 | ||||||
| 	type Profile struct { | 	type Profile struct { | ||||||
| 		ID    uint | 		ID    uint | ||||||
| 		Name  string | 		Name  string | ||||||
|  | |||||||
| @ -29,3 +29,8 @@ services: | |||||||
|       - MSSQL_DB=gorm |       - MSSQL_DB=gorm | ||||||
|       - MSSQL_USER=gorm |       - MSSQL_USER=gorm | ||||||
|       - MSSQL_PASSWORD=LoremIpsum86 |       - MSSQL_PASSWORD=LoremIpsum86 | ||||||
|  |   tidb: | ||||||
|  |     image: 'pingcap/tidb:v6.5.0' | ||||||
|  |     ports: | ||||||
|  |       - 9940:4000 | ||||||
|  |     command: /tidb-server -store unistore -path "" -lease 0s > tidb.log 2>&1 & | ||||||
|  | |||||||
| @ -8,11 +8,11 @@ require ( | |||||||
| 	github.com/lib/pq v1.10.7 | 	github.com/lib/pq v1.10.7 | ||||||
| 	github.com/mattn/go-sqlite3 v1.14.16 // indirect | 	github.com/mattn/go-sqlite3 v1.14.16 // indirect | ||||||
| 	golang.org/x/crypto v0.5.0 // indirect | 	golang.org/x/crypto v0.5.0 // indirect | ||||||
| 	gorm.io/driver/mysql v1.4.5 | 	gorm.io/driver/mysql v1.4.6 | ||||||
| 	gorm.io/driver/postgres v1.4.6 | 	gorm.io/driver/postgres v1.4.6 | ||||||
| 	gorm.io/driver/sqlite v1.4.4 | 	gorm.io/driver/sqlite v1.4.4 | ||||||
| 	gorm.io/driver/sqlserver v1.4.2 | 	gorm.io/driver/sqlserver v1.4.2 | ||||||
| 	gorm.io/gorm v1.24.3 | 	gorm.io/gorm v1.24.5 | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| replace gorm.io/gorm => ../ | replace gorm.io/gorm => ../ | ||||||
|  | |||||||
| @ -1,6 +1,7 @@ | |||||||
| package tests_test | package tests_test | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
|  | 	"os" | ||||||
| 	"sort" | 	"sort" | ||||||
| 	"strconv" | 	"strconv" | ||||||
| 	"strings" | 	"strings" | ||||||
| @ -235,3 +236,13 @@ func CheckUser(t *testing.T, user User, expect User) { | |||||||
| 		} | 		} | ||||||
| 	}) | 	}) | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | func tidbSkip(t *testing.T, reason string) { | ||||||
|  | 	if isTiDB() { | ||||||
|  | 		t.Skipf("This test case skipped, because of TiDB '%s'", reason) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func isTiDB() bool { | ||||||
|  | 	return os.Getenv("GORM_DIALECT") == "tidb" | ||||||
|  | } | ||||||
|  | |||||||
| @ -374,7 +374,137 @@ func TestMigrateIndexes(t *testing.T) { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func TestTiDBMigrateColumns(t *testing.T) { | ||||||
|  | 	if !isTiDB() { | ||||||
|  | 		t.Skip() | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// TiDB can't change column constraint and has auto_random feature
 | ||||||
|  | 	type ColumnStruct struct { | ||||||
|  | 		ID    int `gorm:"primarykey;default:auto_random()"` | ||||||
|  | 		Name  string | ||||||
|  | 		Age   int    `gorm:"default:18;comment:my age"` | ||||||
|  | 		Code  string `gorm:"unique;comment:my code;"` | ||||||
|  | 		Code2 string | ||||||
|  | 		Code3 string `gorm:"unique"` | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	DB.Migrator().DropTable(&ColumnStruct{}) | ||||||
|  | 
 | ||||||
|  | 	if err := DB.AutoMigrate(&ColumnStruct{}); err != nil { | ||||||
|  | 		t.Errorf("Failed to migrate, got %v", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	type ColumnStruct2 struct { | ||||||
|  | 		ID    int    `gorm:"primarykey;default:auto_random()"` | ||||||
|  | 		Name  string `gorm:"size:100"` | ||||||
|  | 		Code  string `gorm:"unique;comment:my code2;default:hello"` | ||||||
|  | 		Code2 string `gorm:"comment:my code2;default:hello"` | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if err := DB.Table("column_structs").Migrator().AlterColumn(&ColumnStruct{}, "Name"); err != nil { | ||||||
|  | 		t.Fatalf("no error should happened when alter column, but got %v", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if err := DB.Table("column_structs").AutoMigrate(&ColumnStruct2{}); err != nil { | ||||||
|  | 		t.Fatalf("no error should happened when auto migrate 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 { | ||||||
|  | 			switch columnType.Name() { | ||||||
|  | 			case "id": | ||||||
|  | 				if v, ok := columnType.PrimaryKey(); !ok || !v { | ||||||
|  | 					t.Fatalf("column id primary key should be correct, name: %v, column: %#v", columnType.Name(), columnType) | ||||||
|  | 				} | ||||||
|  | 			case "name": | ||||||
|  | 				dataType := DB.Dialector.DataTypeOf(stmt.Schema.LookUpField(columnType.Name())) | ||||||
|  | 				if !strings.Contains(strings.ToUpper(dataType), strings.ToUpper(columnType.DatabaseTypeName())) { | ||||||
|  | 					t.Fatalf("column name type should be correct, name: %v, length: %v, expects: %v, column: %#v", columnType.Name(), columnType.DatabaseTypeName(), dataType, columnType) | ||||||
|  | 				} | ||||||
|  | 				if length, ok := columnType.Length(); !ok || length != 100 { | ||||||
|  | 					t.Fatalf("column name length should be correct, name: %v, length: %v, expects: %v, column: %#v", columnType.Name(), length, 100, columnType) | ||||||
|  | 				} | ||||||
|  | 			case "age": | ||||||
|  | 				if v, ok := columnType.DefaultValue(); !ok || v != "18" { | ||||||
|  | 					t.Fatalf("column age default value should be correct, name: %v, column: %#v", columnType.Name(), columnType) | ||||||
|  | 				} | ||||||
|  | 				if v, ok := columnType.Comment(); !ok || v != "my age" { | ||||||
|  | 					t.Fatalf("column age comment should be correct, name: %v, column: %#v", columnType.Name(), columnType) | ||||||
|  | 				} | ||||||
|  | 			case "code": | ||||||
|  | 				if v, ok := columnType.Unique(); !ok || !v { | ||||||
|  | 					t.Fatalf("column code unique should be correct, name: %v, column: %#v", columnType.Name(), columnType) | ||||||
|  | 				} | ||||||
|  | 				if v, ok := columnType.DefaultValue(); !ok || v != "hello" { | ||||||
|  | 					t.Fatalf("column code default value should be correct, name: %v, column: %#v, default value: %v", columnType.Name(), columnType, v) | ||||||
|  | 				} | ||||||
|  | 				if v, ok := columnType.Comment(); !ok || v != "my code2" { | ||||||
|  | 					t.Fatalf("column code comment should be correct, name: %v, column: %#v", columnType.Name(), columnType) | ||||||
|  | 				} | ||||||
|  | 			case "code2": | ||||||
|  | 				// Code2 string `gorm:"comment:my code2;default:hello"`
 | ||||||
|  | 				if v, ok := columnType.DefaultValue(); !ok || v != "hello" { | ||||||
|  | 					t.Fatalf("column code default value should be correct, name: %v, column: %#v, default value: %v", columnType.Name(), columnType, v) | ||||||
|  | 				} | ||||||
|  | 				if v, ok := columnType.Comment(); !ok || v != "my code2" { | ||||||
|  | 					t.Fatalf("column code comment should be correct, name: %v, column: %#v", columnType.Name(), columnType) | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	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 TestMigrateColumns(t *testing.T) { | func TestMigrateColumns(t *testing.T) { | ||||||
|  | 	tidbSkip(t, "use another test case") | ||||||
|  | 
 | ||||||
| 	sqlite := DB.Dialector.Name() == "sqlite" | 	sqlite := DB.Dialector.Name() == "sqlite" | ||||||
| 	sqlserver := DB.Dialector.Name() == "sqlserver" | 	sqlserver := DB.Dialector.Name() == "sqlserver" | ||||||
| 
 | 
 | ||||||
| @ -853,6 +983,8 @@ func TestUniqueColumn(t *testing.T) { | |||||||
| 	AssertEqual(t, "", value) | 	AssertEqual(t, "", value) | ||||||
| 	AssertEqual(t, false, ok) | 	AssertEqual(t, false, ok) | ||||||
| 
 | 
 | ||||||
|  | 	tidbSkip(t, "can't change column constraint") | ||||||
|  | 
 | ||||||
| 	// null -> empty string
 | 	// null -> empty string
 | ||||||
| 	err = DB.Table("unique_tests").AutoMigrate(&UniqueTest3{}) | 	err = DB.Table("unique_tests").AutoMigrate(&UniqueTest3{}) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
|  | |||||||
| @ -29,7 +29,7 @@ func TestRow(t *testing.T) { | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	table := "gorm.users" | 	table := "gorm.users" | ||||||
| 	if DB.Dialector.Name() != "mysql" { | 	if DB.Dialector.Name() != "mysql" || isTiDB() { | ||||||
| 		table = "users" // other databases doesn't support select with `database.table`
 | 		table = "users" // other databases doesn't support select with `database.table`
 | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| #!/bin/bash -e | #!/bin/bash -e | ||||||
| 
 | 
 | ||||||
| dialects=("sqlite" "mysql" "postgres" "sqlserver") | dialects=("sqlite" "mysql" "postgres" "sqlserver" "tidb") | ||||||
| 
 | 
 | ||||||
| if [[ $(pwd) == *"gorm/tests"* ]]; then | if [[ $(pwd) == *"gorm/tests"* ]]; then | ||||||
|   cd .. |   cd .. | ||||||
|  | |||||||
| @ -21,6 +21,7 @@ var ( | |||||||
| 	mysqlDSN     = "gorm:gorm@tcp(localhost:9910)/gorm?charset=utf8&parseTime=True&loc=Local" | 	mysqlDSN     = "gorm:gorm@tcp(localhost:9910)/gorm?charset=utf8&parseTime=True&loc=Local" | ||||||
| 	postgresDSN  = "user=gorm password=gorm dbname=gorm host=localhost port=9920 sslmode=disable TimeZone=Asia/Shanghai" | 	postgresDSN  = "user=gorm password=gorm dbname=gorm host=localhost port=9920 sslmode=disable TimeZone=Asia/Shanghai" | ||||||
| 	sqlserverDSN = "sqlserver://gorm:LoremIpsum86@localhost:9930?database=gorm" | 	sqlserverDSN = "sqlserver://gorm:LoremIpsum86@localhost:9930?database=gorm" | ||||||
|  | 	tidbDSN      = "root:@tcp(localhost:9940)/test?charset=utf8&parseTime=True&loc=Local" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func init() { | func init() { | ||||||
| @ -80,6 +81,12 @@ func OpenTestConnection() (db *gorm.DB, err error) { | |||||||
| 			dbDSN = sqlserverDSN | 			dbDSN = sqlserverDSN | ||||||
| 		} | 		} | ||||||
| 		db, err = gorm.Open(sqlserver.Open(dbDSN), &gorm.Config{}) | 		db, err = gorm.Open(sqlserver.Open(dbDSN), &gorm.Config{}) | ||||||
|  | 	case "tidb": | ||||||
|  | 		log.Println("testing tidb...") | ||||||
|  | 		if dbDSN == "" { | ||||||
|  | 			dbDSN = tidbDSN | ||||||
|  | 		} | ||||||
|  | 		db, err = gorm.Open(mysql.Open(dbDSN), &gorm.Config{}) | ||||||
| 	default: | 	default: | ||||||
| 		log.Println("testing sqlite3...") | 		log.Println("testing sqlite3...") | ||||||
| 		db, err = gorm.Open(sqlite.Open(filepath.Join(os.TempDir(), "gorm.db")), &gorm.Config{}) | 		db, err = gorm.Open(sqlite.Open(filepath.Join(os.TempDir(), "gorm.db")), &gorm.Config{}) | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Cheese
						Cheese