289 lines
9.6 KiB
Go
289 lines
9.6 KiB
Go
package data
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
integrationbiz "kra/internal/biz/integration"
|
|
"kra/internal/config"
|
|
dataintegration "kra/internal/data/integration"
|
|
"kra/internal/integration/storage"
|
|
|
|
"gopkg.in/yaml.v3"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
func openIntegrationConfigTestDB(t *testing.T) *gorm.DB {
|
|
t.Helper()
|
|
db, err := openWithDriver("sqlite", "file:"+t.Name()+"?mode=memory&cache=shared", nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
sqlDB, err := db.DB()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
t.Cleanup(func() { _ = sqlDB.Close() })
|
|
if err = db.AutoMigrate(&dataintegration.ConfigPO{}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return db
|
|
}
|
|
|
|
func TestMigrateAllCreatesIntegrationConfigTable(t *testing.T) {
|
|
db, err := openWithDriver("sqlite", "file:"+t.Name()+"?mode=memory&cache=shared", nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
sqlDB, err := db.DB()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
t.Cleanup(func() { _ = sqlDB.Close() })
|
|
if err = migrateAll(db, testCatalog()); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !db.Migrator().HasTable(&dataintegration.ConfigPO{}) {
|
|
t.Fatal("migrateAll did not create sys_integration_configs")
|
|
}
|
|
}
|
|
|
|
func TestStorageIntegrationConfigRoundTrip(t *testing.T) {
|
|
db := openIntegrationConfigTestDB(t)
|
|
storage := &config.Storage{
|
|
Type: "aliyun-oss",
|
|
Qiniu: &config.Qiniu{
|
|
Zone: "ZoneHuadong", Bucket: "qiniu-bucket", AccessKey: "qiniu-key", SecretKey: "qiniu-secret",
|
|
},
|
|
AliyunOSS: &config.ObjectStore{
|
|
Endpoint: "oss-cn-hangzhou.aliyuncs.com", Region: "cn-hangzhou", Bucket: "assets",
|
|
AccessKey: "aliyun-key", SecretKey: "aliyun-secret", BaseURL: "https://cdn.example.com", PathPrefix: "uploads",
|
|
},
|
|
Minio: &config.ObjectStore{Endpoint: "127.0.0.1:9000", Bucket: "local", ForcePathStyle: true},
|
|
}
|
|
if err := saveStorageIntegrationConfig(db, storage); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
email := &config.Email{
|
|
To: "ops@example.com", From: "mailer@example.com", Host: "smtp.example.com",
|
|
Secret: "smtp-secret", Nickname: "Kra", Port: 465, IsSSL: true,
|
|
}
|
|
if err := saveEmailIntegrationConfig(db, email); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := db.Create(&dataintegration.ConfigPO{Kind: integrationbiz.IntegrationKindPayment, Provider: "wechat-pay", Config: `{"merchant_id":"123"}`}).Error; err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
loaded, found, err := loadStorageIntegrationConfig(db)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !found {
|
|
t.Fatal("storage integration configuration was not found")
|
|
}
|
|
if loaded.Type != "aliyun-oss" {
|
|
t.Fatalf("storage type = %q, want aliyun-oss", loaded.Type)
|
|
}
|
|
if loaded.AliyunOSS == nil || loaded.AliyunOSS.SecretKey != "aliyun-secret" || loaded.AliyunOSS.PathPrefix != "uploads" {
|
|
t.Fatalf("aliyun configuration = %#v", loaded.AliyunOSS)
|
|
}
|
|
if loaded.Qiniu == nil || loaded.Qiniu.SecretKey != "qiniu-secret" {
|
|
t.Fatalf("qiniu configuration = %#v", loaded.Qiniu)
|
|
}
|
|
|
|
loadedEmail, found, err := loadEmailIntegrationConfig(db)
|
|
if err != nil || !found {
|
|
t.Fatalf("email configuration found=%v, err=%v", found, err)
|
|
}
|
|
if loadedEmail.Host != "smtp.example.com" || loadedEmail.Secret != "smtp-secret" || loadedEmail.Port != 465 {
|
|
t.Fatalf("email configuration = %#v", loadedEmail)
|
|
}
|
|
|
|
var storageCount, emailCount, paymentCount int64
|
|
if err = db.Model(&dataintegration.ConfigPO{}).Where("kind = ?", integrationKindStorage).Count(&storageCount).Error; err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err = db.Model(&dataintegration.ConfigPO{}).Where("kind = ?", integrationbiz.IntegrationKindPayment).Count(&paymentCount).Error; err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err = db.Model(&dataintegration.ConfigPO{}).Where("kind = ?", integrationKindEmail).Count(&emailCount).Error; err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if storageCount != int64(len(storageProviderNames)) {
|
|
t.Fatalf("storage row count = %d, want %d", storageCount, len(storageProviderNames))
|
|
}
|
|
if paymentCount != 1 {
|
|
t.Fatalf("payment row count = %d, want 1", paymentCount)
|
|
}
|
|
if emailCount != 1 {
|
|
t.Fatalf("email row count = %d, want 1", emailCount)
|
|
}
|
|
}
|
|
|
|
func TestResolveStorageIntegrationConfigMigratesLegacyOnlyOnce(t *testing.T) {
|
|
db := openIntegrationConfigTestDB(t)
|
|
legacy := &config.Storage{
|
|
Type: "qiniu",
|
|
Qiniu: &config.Qiniu{Bucket: "legacy", SecretKey: "legacy-secret"},
|
|
}
|
|
loaded, err := resolveStorageIntegrationConfig(db, legacy)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if loaded.Type != "qiniu" || loaded.Qiniu.Bucket != "legacy" {
|
|
t.Fatalf("migrated storage = %#v", loaded)
|
|
}
|
|
|
|
other := &config.Storage{
|
|
Type: "minio",
|
|
Minio: &config.ObjectStore{Bucket: "must-not-replace-database"},
|
|
}
|
|
loaded, err = resolveStorageIntegrationConfig(db, other)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if loaded.Type != "qiniu" || loaded.Qiniu.SecretKey != "legacy-secret" {
|
|
t.Fatalf("database configuration was replaced by legacy config: %#v", loaded)
|
|
}
|
|
}
|
|
|
|
func TestMaskStorageSecretsLeavesUnconfiguredProvidersEmpty(t *testing.T) {
|
|
storage := &config.Storage{
|
|
Qiniu: &config.Qiniu{},
|
|
AliyunOSS: &config.ObjectStore{SecretKey: "configured-secret"},
|
|
Minio: &config.ObjectStore{},
|
|
}
|
|
maskStorageSecrets(storage)
|
|
if storage.Qiniu.SecretKey != "" || storage.Minio.SecretKey != "" {
|
|
t.Fatalf("empty provider secrets were masked: %#v", storage)
|
|
}
|
|
if storage.AliyunOSS.SecretKey != "******" {
|
|
t.Fatalf("configured secret was not masked: %q", storage.AliyunOSS.SecretKey)
|
|
}
|
|
}
|
|
|
|
func TestResolveEmailIntegrationConfigMigratesLegacyOnlyOnce(t *testing.T) {
|
|
db := openIntegrationConfigTestDB(t)
|
|
legacy := &config.Email{To: "ops@example.com", From: "old@example.com", Host: "smtp.old.example.com", Secret: "old-secret", Port: 465, IsSSL: true}
|
|
loaded, err := resolveEmailIntegrationConfig(db, legacy)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if loaded.Host != legacy.Host || loaded.Secret != legacy.Secret {
|
|
t.Fatalf("migrated email = %#v", loaded)
|
|
}
|
|
loaded, err = resolveEmailIntegrationConfig(db, &config.Email{Host: "must-not-replace.example.com"})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if loaded.Host != legacy.Host || loaded.Secret != legacy.Secret {
|
|
t.Fatalf("database email was replaced by legacy config: %#v", loaded)
|
|
}
|
|
}
|
|
|
|
func TestPersistConfigValuesRemovesStorageFromYAML(t *testing.T) {
|
|
path := filepath.Join(t.TempDir(), "config.yaml")
|
|
input := []byte("data: {}\nadmin:\n router_prefix: /old\n storage:\n type: qiniu\n qiniu:\n secret_key: legacy-secret\n email:\n host: smtp.legacy.example.com\n secret: legacy-email-secret\n extension_key: retained\n")
|
|
if err := os.WriteFile(path, input, 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
d := &Data{}
|
|
admin := &config.Admin{
|
|
ConfigPath: path,
|
|
RouterPrefix: "/api",
|
|
Storage: &config.Storage{
|
|
Type: "qiniu",
|
|
Qiniu: &config.Qiniu{SecretKey: "database-only-secret"},
|
|
},
|
|
Email: &config.Email{Host: "smtp.database.example.com", Secret: "database-only-email-secret"},
|
|
}
|
|
if err := d.persistConfigValues(&config.Data{}, admin); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
raw, err := os.ReadFile(path)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var document map[string]any
|
|
if err = yaml.Unmarshal(raw, &document); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
adminValue, ok := document["admin"].(map[string]any)
|
|
if !ok {
|
|
t.Fatalf("admin config = %#v", document["admin"])
|
|
}
|
|
if _, exists := adminValue["storage"]; exists {
|
|
t.Fatalf("storage remained in YAML: %s", raw)
|
|
}
|
|
if _, exists := adminValue["email"]; exists {
|
|
t.Fatalf("email remained in YAML: %s", raw)
|
|
}
|
|
if adminValue["extension_key"] != "retained" {
|
|
t.Fatalf("extension key was not retained: %#v", adminValue)
|
|
}
|
|
}
|
|
|
|
func TestPersistRuntimeConfigReplacesActiveStorage(t *testing.T) {
|
|
db := openIntegrationConfigTestDB(t)
|
|
configPath := filepath.Join(t.TempDir(), "config.yaml")
|
|
if err := os.WriteFile(configPath, []byte("data: {}\nadmin: {}\n"), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
oldRoot := filepath.Join(t.TempDir(), "old")
|
|
newRoot := filepath.Join(t.TempDir(), "new")
|
|
currentAdmin := &config.Admin{
|
|
ConfigPath: configPath,
|
|
Local: &config.Local{StorePath: oldRoot, PathPrefix: "old-files"},
|
|
Storage: &config.Storage{Type: "local"},
|
|
}
|
|
currentStorage, err := storage.NewReloadable(currentAdmin)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
reloadableDB := &reloadableDB{}
|
|
reloadableDB.current.Store(db)
|
|
d := &Data{
|
|
runtime: config.NewStore(&config.Config{Data: &config.Data{}, Admin: currentAdmin}),
|
|
gormDB: reloadableDB,
|
|
storage: currentStorage,
|
|
}
|
|
d.databaseReady.Store(true)
|
|
|
|
nextAdmin := cloneAdminConfig(currentAdmin)
|
|
nextAdmin.Local = &config.Local{StorePath: newRoot, PathPrefix: "new-files"}
|
|
nextAdmin.Email = &config.Email{
|
|
To: "ops@example.com", From: "mailer@example.com", Host: "smtp.example.com",
|
|
Secret: "runtime-secret", Port: 465, IsSSL: true,
|
|
}
|
|
if err = d.PersistRuntimeConfig(context.Background(), &config.Config{Data: &config.Data{}, Admin: nextAdmin}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
stored, err := d.storage.Put(context.Background(), "active.txt", strings.NewReader("active"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if stored.URL != "/new-files/active.txt" {
|
|
t.Fatalf("active storage URL = %q, want /new-files/active.txt", stored.URL)
|
|
}
|
|
if _, err = os.Stat(filepath.Join(newRoot, "active.txt")); err != nil {
|
|
t.Fatalf("active storage did not write to the new root: %v", err)
|
|
}
|
|
loaded, found, err := loadStorageIntegrationConfig(db)
|
|
if err != nil || !found || loaded.Type != "local" {
|
|
t.Fatalf("database storage config = %#v, found=%v, err=%v", loaded, found, err)
|
|
}
|
|
loadedEmail, found, err := loadEmailIntegrationConfig(db)
|
|
if err != nil || !found || loadedEmail.Secret != "runtime-secret" {
|
|
t.Fatalf("database email config = %#v, found=%v, err=%v", loadedEmail, found, err)
|
|
}
|
|
if runtimeEmail := d.runtime.Admin().Email; runtimeEmail == nil || runtimeEmail.Host != "smtp.example.com" {
|
|
t.Fatalf("runtime email config = %#v", runtimeEmail)
|
|
}
|
|
}
|