// Package testdb 準備整合測試專用的測試資料庫(與開發資料庫 // alterminal 隔離),供需要完整資料表(users、sessions、 // signing_keys、applications、authorization_codes、refresh_tokens、 // consents)的套件測試使用。go test 以套件為單位並行執行,各套件 // 取得各自的資料庫(alterminal_test_<套件名>),避免並行測試相互 // TRUNCATE。oidc 套件的測試須以外部測試套件(package oidc_test) // 匯入本套件——store 為遷移而匯入 oidc 模型,內部測試套件匯入本 // 套件會形成循環。 package testdb import ( "fmt" "path/filepath" "runtime" "strings" "testing" "gorm.io/driver/postgres" "gorm.io/gorm" "alterminal/internal/store" ) // New 連線本機 PostgreSQL,建立(若不存在)並遷移呼叫方套件專屬的 // 測試資料庫、清空所有資料表後回傳連線;本機 PostgreSQL 不可用時 // 跳過測試。 func New(t *testing.T) *gorm.DB { t.Helper() // 以呼叫方(測試檔)所在目錄為套件識別,各套件一個資料庫。 _, file, _, ok := runtime.Caller(1) dbName := "alterminal_test" if ok { dbName += "_" + filepath.Base(filepath.Dir(file)) } admin, err := gorm.Open(postgres.Open(fmt.Sprintf( "host=%s port=%s user=%s password=%s dbname=postgres sslmode=disable TimeZone=UTC", store.EnvOr("DB_HOST", "localhost"), store.EnvOr("DB_PORT", "5432"), store.EnvOr("DB_USER", "postgres"), store.EnvOr("DB_PASSWORD", "postgres"), )), &gorm.Config{}) if err != nil { t.Skipf("本機 PostgreSQL 不可用,跳過整合測試:%v", err) } if err := admin.Exec(fmt.Sprintf("CREATE DATABASE %s", dbName)).Error; err != nil && !strings.Contains(err.Error(), "already exists") { t.Skipf("無法建立測試資料庫:%v", err) } t.Setenv("DB_NAME", dbName) db, err := store.Open() if err != nil { t.Skipf("連線測試資料庫失敗:%v", err) } t.Cleanup(func() { if sqlDB, err := db.DB(); err == nil { sqlDB.Close() } }) if err := db.Exec("TRUNCATE users, sessions, signing_keys, applications, authorization_codes, refresh_tokens, consents RESTART IDENTITY CASCADE").Error; err != nil { t.Fatalf("清空測試資料失敗:%v", err) } return db }