增加短信渠道
This commit is contained in:
@@ -179,6 +179,21 @@ func openWithDriverConfig(driver, dsn string, config *config.Database, appLogger
|
||||
return db, nil
|
||||
}
|
||||
|
||||
func bootstrapDatabaseDSN(c *config.Database) (string, error) {
|
||||
bootstrap := *c
|
||||
// An empty name passed to databaseDSN falls back to the configured name.
|
||||
// Clear both fields so MySQL can connect before the target database exists.
|
||||
bootstrap.Name = ""
|
||||
bootstrap.Source = ""
|
||||
switch normalizedDriver(c.Driver) {
|
||||
case "pgsql":
|
||||
bootstrap.Name = "postgres"
|
||||
case "mssql":
|
||||
bootstrap.Name = "master"
|
||||
}
|
||||
return databaseDSN(&bootstrap, "")
|
||||
}
|
||||
|
||||
func openDatabase(c *config.Database, create bool, template string, appLogger *slog.Logger) (*gorm.DB, error) {
|
||||
driver := normalizedDriver(c.Driver)
|
||||
if driver == "" {
|
||||
@@ -198,14 +213,7 @@ func openDatabase(c *config.Database, create bool, template string, appLogger *s
|
||||
if !databaseNamePattern.MatchString(c.Name) {
|
||||
return nil, fmt.Errorf("invalid database name %q", c.Name)
|
||||
}
|
||||
bootstrap := ""
|
||||
switch driver {
|
||||
case "pgsql":
|
||||
bootstrap = "postgres"
|
||||
case "mssql":
|
||||
bootstrap = "master"
|
||||
}
|
||||
dsn, err := databaseDSN(c, bootstrap)
|
||||
dsn, err := bootstrapDatabaseDSN(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -4,9 +4,44 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
mysqldriver "github.com/go-sql-driver/mysql"
|
||||
"kra/internal/config"
|
||||
)
|
||||
|
||||
func TestMySQLBootstrapConnectsWithoutTargetDatabase(t *testing.T) {
|
||||
for _, host := range []string{"", "mysql"} {
|
||||
t.Run("host="+host, func(t *testing.T) {
|
||||
cfg := &config.Database{Driver: "mysql", Host: host, Name: "kra_new", Source: "root@tcp(localhost:3306)/kra_new"}
|
||||
original := *cfg
|
||||
dsn, err := bootstrapDatabaseDSN(cfg)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
parsed, err := mysqldriver.ParseDSN(dsn)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if parsed.DBName != "" {
|
||||
t.Fatalf("bootstrap selected database %q before creating it", parsed.DBName)
|
||||
}
|
||||
if *cfg != original {
|
||||
t.Fatal("bootstrap changed the target configuration")
|
||||
}
|
||||
target, err := databaseDSN(cfg, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
parsed, err = mysqldriver.ParseDSN(target)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if parsed.DBName != "kra_new" {
|
||||
t.Fatalf("target connection selected database %q", parsed.DBName)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMySQLDatabaseDSNIncludesNetworkTimeouts(t *testing.T) {
|
||||
dsn, err := databaseDSN(&config.Database{
|
||||
Driver: "mysql",
|
||||
|
||||
@@ -16,7 +16,7 @@ func ReadRuntime(db *gorm.DB) ([]runtimeconfig.Config, error) {
|
||||
}
|
||||
var rows []ConfigPO
|
||||
if err := db.Session(&gorm.Session{NewDB: true}).
|
||||
Where("kind IN ?", []string{"mq", "websocket"}).
|
||||
Where("kind IN ?", []string{"mq", "websocket", "sms"}).
|
||||
Order("kind ASC, provider ASC").
|
||||
Find(&rows).Error; err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, err
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
package integration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
biz "kra/internal/biz/integration"
|
||||
"kra/internal/integration/runtimeconfig"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSMSSecretsSurviveMaskedSaveAndRuntimeReload(t *testing.T) {
|
||||
db, err := openWithDriver("sqlite", "file:"+t.Name()+"?mode=memory&cache=shared")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err = db.AutoMigrate(&ConfigPO{}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
p := &integrationRuntimeTestProvider{Data: &Data{gormDB: newReloadableDB(db)}, store: runtimeconfig.NewStore()}
|
||||
repo := NewIntegrationConfigRepo(p)
|
||||
for _, provider := range []string{"aliyun", "tencent"} {
|
||||
values := biz.DefaultIntegrationConfig("sms", provider)
|
||||
for k, v := range values {
|
||||
if v == "" {
|
||||
values[k] = "test-" + k
|
||||
}
|
||||
}
|
||||
raw, _ := json.Marshal(values)
|
||||
if err = repo.SaveIntegrationConfig(context.Background(), &biz.IntegrationConfig{Kind: "sms", Provider: provider, Enabled: true, Values: raw}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
masked, err := repo.FindIntegrationConfig(context.Background(), "sms", provider)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var public map[string]string
|
||||
_ = json.Unmarshal(masked.Values, &public)
|
||||
for k := range values {
|
||||
if biz.IsIntegrationSecretKey(k) && public[k] != "******" {
|
||||
t.Fatalf("unmasked key %s", k)
|
||||
}
|
||||
}
|
||||
if err = repo.SaveIntegrationConfig(context.Background(), masked); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
rows, err := ReadRuntime(db)
|
||||
if err != nil || len(rows) != 2 {
|
||||
t.Fatalf("runtime rows=%d error=%v", len(rows), err)
|
||||
}
|
||||
for _, row := range rows {
|
||||
var values map[string]string
|
||||
_ = json.Unmarshal(row.Values, &values)
|
||||
key := "access_key_secret"
|
||||
if row.Provider == "tencent" {
|
||||
key = "secret_key"
|
||||
}
|
||||
if values[key] != "test-"+key {
|
||||
t.Fatal("saved secret did not survive runtime reload")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -34,8 +34,8 @@ func TestMigrateAllRunsModuleSchemasWithoutBootstrapSeed(t *testing.T) {
|
||||
if err = db.Table(migration.TableName).Count(&versions).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if versions != 13 {
|
||||
t.Fatalf("migration versions = %d, want 13", versions)
|
||||
if versions != 14 {
|
||||
t.Fatalf("migration versions = %d, want 14", versions)
|
||||
}
|
||||
var communicationRows []dataintegration.ConfigPO
|
||||
if err = db.Where("kind IN ?", []string{"mq", "websocket"}).Order("kind, provider").Find(&communicationRows).Error; err != nil {
|
||||
|
||||
Reference in New Issue
Block a user