75 lines
2.3 KiB
Go
75 lines
2.3 KiB
Go
package testutil
|
||
|
||
import (
|
||
"bytes"
|
||
"database/sql"
|
||
"fmt"
|
||
"os"
|
||
"path/filepath"
|
||
"strings"
|
||
"testing"
|
||
"time"
|
||
|
||
"github.com/go-sql-driver/mysql"
|
||
"github.com/wmms/wmms/pkg/database"
|
||
)
|
||
|
||
// NewIsolationDB 在显式配置的 MySQL 服务器(TEST_DB_DSN 指向 company_isolation_test*)上
|
||
// 创建一个一次性的库,载入 scripts/init.sql 的空库结构,并把 database.DB 指向它;测试结束
|
||
// 自动删库并恢复。与 repository 侧的同名测试集共用同一台服务器与同一套空库结构,
|
||
// 让 Service 层的事务场景能直接跑真实 MySQL。未配置 TEST_DB_DSN 时跳过。
|
||
func NewIsolationDB(t *testing.T) *sql.DB {
|
||
t.Helper()
|
||
dsn := os.Getenv("TEST_DB_DSN")
|
||
if dsn == "" {
|
||
t.Skip("real MySQL integration requires TEST_DB_DSN")
|
||
}
|
||
cfg, err := mysql.ParseDSN(dsn)
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
if !strings.HasPrefix(cfg.DBName, "company_isolation_test") {
|
||
t.Fatal("TEST_DB_DSN must name a company_isolation_test schema")
|
||
}
|
||
cfg.DBName = ""
|
||
cfg.MultiStatements = true
|
||
cfg.ParseTime = true
|
||
// Match database.Init: a legitimate no-op update still matches its row.
|
||
cfg.ClientFoundRows = true
|
||
admin, err := sql.Open("mysql", cfg.FormatDSN())
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
name := fmt.Sprintf("company_isolation_test_%d", time.Now().UnixNano())
|
||
if _, err = admin.Exec("CREATE DATABASE `" + name + "` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci"); err != nil {
|
||
admin.Close()
|
||
t.Fatal(err)
|
||
}
|
||
cfg.DBName = name
|
||
db, err := sql.Open("mysql", cfg.FormatDSN())
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
original := database.DB
|
||
database.DB = db
|
||
t.Cleanup(func() { database.DB = original; db.Close(); admin.Exec("DROP DATABASE `" + name + "`"); admin.Close() })
|
||
|
||
content, err := os.ReadFile(filepath.Join("..", "..", "scripts", "init.sql"))
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
// init.sql 可能带 UTF-8 BOM,按字节剥掉,避免第一行 CREATE TABLE 解析失败。
|
||
content = bytes.TrimPrefix(content, []byte{0xEF, 0xBB, 0xBF})
|
||
var lines []string
|
||
for _, line := range strings.Split(string(content), "\n") {
|
||
if strings.HasPrefix(line, "CREATE DATABASE") || strings.HasPrefix(line, "USE ") {
|
||
continue
|
||
}
|
||
lines = append(lines, line)
|
||
}
|
||
if _, err = db.Exec(strings.Join(lines, "\n")); err != nil {
|
||
t.Fatalf("initialize scripts/init.sql: %v", err)
|
||
}
|
||
return db
|
||
}
|