feat: 迁移 Admin Repository 到 MySQL 8 (#79)
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
// Package testutil 为 Admin 测试创建彼此隔离的 MySQL 8 数据库。
|
||||
package testutil
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"database/sql"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"cmautobuy/admin/config"
|
||||
"cmautobuy/admin/repository"
|
||||
)
|
||||
|
||||
// TestingT 是本包需要的 testing.T 最小接口,避免生产包依赖 testing。
|
||||
type TestingT interface {
|
||||
Helper()
|
||||
Cleanup(func())
|
||||
Fatalf(format string, args ...any)
|
||||
Errorf(format string, args ...any)
|
||||
Skipf(format string, args ...any)
|
||||
}
|
||||
|
||||
// OpenMySQL 为一个测试创建独立数据库,测试结束后只删除该数据库。
|
||||
func OpenMySQL(t TestingT) *sql.DB {
|
||||
t.Helper()
|
||||
if os.Getenv("CMAUTOBUY_MYSQL_TEST") != "1" {
|
||||
t.Skipf("未设置 CMAUTOBUY_MYSQL_TEST=1,跳过真实 MySQL 8 测试")
|
||||
}
|
||||
baseConfig, err := config.LoadDatabaseFromEnv()
|
||||
if err != nil {
|
||||
t.Fatalf("读取 MySQL 测试配置失败: %v", err)
|
||||
}
|
||||
if !strings.HasSuffix(baseConfig.Name, "_test") {
|
||||
t.Fatalf("MySQL 测试基础库名必须以 _test 结尾,实际 %q", baseConfig.Name)
|
||||
}
|
||||
adminDB, err := repository.OpenMySQL(baseConfig)
|
||||
if err != nil {
|
||||
t.Fatalf("连接 MySQL 测试基础库失败: %v", err)
|
||||
}
|
||||
|
||||
databaseName := testDatabaseName(baseConfig.Name)
|
||||
quotedName := quoteIdentifier(databaseName)
|
||||
if _, err := adminDB.Exec("CREATE DATABASE " + quotedName +
|
||||
" CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci"); err != nil {
|
||||
adminDB.Close()
|
||||
t.Fatalf("创建隔离 MySQL 测试库失败: %v", err)
|
||||
}
|
||||
|
||||
testConfig := baseConfig
|
||||
testConfig.Name = databaseName
|
||||
db, err := repository.OpenMySQL(testConfig)
|
||||
if err != nil {
|
||||
adminDB.Exec("DROP DATABASE " + quotedName)
|
||||
adminDB.Close()
|
||||
t.Fatalf("连接隔离 MySQL 测试库失败: %v", err)
|
||||
}
|
||||
if err := repository.MigrateMySQL(db); err != nil {
|
||||
db.Close()
|
||||
adminDB.Exec("DROP DATABASE " + quotedName)
|
||||
adminDB.Close()
|
||||
t.Fatalf("初始化隔离 MySQL 测试库失败: %v", err)
|
||||
}
|
||||
t.Cleanup(func() {
|
||||
db.Close()
|
||||
if _, err := adminDB.Exec("DROP DATABASE " + quotedName); err != nil {
|
||||
t.Errorf("清理隔离 MySQL 测试库 %s 失败: %v", databaseName, err)
|
||||
}
|
||||
adminDB.Close()
|
||||
})
|
||||
return db
|
||||
}
|
||||
|
||||
func testDatabaseName(base string) string {
|
||||
random := make([]byte, 8)
|
||||
if _, err := rand.Read(random); err != nil {
|
||||
panic(fmt.Sprintf("生成 MySQL 测试库随机名失败: %v", err))
|
||||
}
|
||||
if len(base) > 40 {
|
||||
base = base[:40]
|
||||
}
|
||||
return base + "_" + hex.EncodeToString(random)
|
||||
}
|
||||
|
||||
func quoteIdentifier(name string) string {
|
||||
return "`" + strings.ReplaceAll(name, "`", "``") + "`"
|
||||
}
|
||||
Reference in New Issue
Block a user