All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 9m20s
116 lines
4.3 KiB
Go
116 lines
4.3 KiB
Go
package systemconfig_test
|
||
|
||
import (
|
||
"context"
|
||
stderrors "errors"
|
||
"sync"
|
||
"testing"
|
||
"time"
|
||
|
||
"github.com/break/junhong_cmp_fiber/internal/infrastructure/systemconfig"
|
||
"github.com/break/junhong_cmp_fiber/internal/model"
|
||
"github.com/break/junhong_cmp_fiber/internal/testutil"
|
||
"github.com/break/junhong_cmp_fiber/pkg/constants"
|
||
)
|
||
|
||
type unavailableCache struct{}
|
||
|
||
func (unavailableCache) Get(context.Context, string) (string, error) {
|
||
return "", stderrors.New("测试缓存不可用")
|
||
}
|
||
|
||
func (unavailableCache) Set(context.Context, string, string, time.Duration) error {
|
||
return stderrors.New("测试缓存不可用")
|
||
}
|
||
|
||
func (unavailableCache) Delete(context.Context, string) error {
|
||
return stderrors.New("测试缓存不可用")
|
||
}
|
||
|
||
type alertRecorder struct {
|
||
mu sync.Mutex
|
||
codes []string
|
||
}
|
||
|
||
func (r *alertRecorder) Warn(_ context.Context, code, _, _, _ string) {
|
||
r.mu.Lock()
|
||
defer r.mu.Unlock()
|
||
r.codes = append(r.codes, code)
|
||
}
|
||
|
||
func TestReaderUsesRedisHitAndFallsBackToPostgresOnMiss(t *testing.T) {
|
||
db := testutil.NewPostgresTransaction(t)
|
||
redisClient := testutil.NewRedisClient(t)
|
||
testutil.CreateTemporarySystemConfigTable(t, db)
|
||
registry := systemconfig.NewRegistry()
|
||
definition := systemconfig.Definition{
|
||
Key: "foundation.reader.limit", Module: "foundation", ValueType: constants.SystemConfigTypeInt,
|
||
DefaultValue: "10", Description: "读取器测试上限",
|
||
}
|
||
if err := registry.Register(definition); err != nil {
|
||
t.Fatalf("注册系统配置失败:%v", err)
|
||
}
|
||
if err := db.Create(&model.SystemConfig{
|
||
ConfigKey: definition.Key, ConfigValue: "20", ValueType: definition.ValueType,
|
||
Module: definition.Module, Description: definition.Description,
|
||
}).Error; err != nil {
|
||
t.Fatalf("准备数据库配置失败:%v", err)
|
||
}
|
||
cacheKey := constants.RedisSystemConfigKey(definition.Key)
|
||
t.Cleanup(func() { _ = redisClient.Del(context.Background(), cacheKey).Err() })
|
||
if err := redisClient.Set(context.Background(), cacheKey, "30", constants.SystemConfigCacheTTL).Err(); err != nil {
|
||
t.Fatalf("准备 Redis 缓存失败:%v", err)
|
||
}
|
||
reader := systemconfig.NewReader(db, registry, systemconfig.NewRedisCache(redisClient), nil)
|
||
|
||
value, err := reader.Get(context.Background(), definition.Key)
|
||
if err != nil || value != "30" {
|
||
t.Fatalf("Redis 命中结果错误:值=%q,错误=%v", value, err)
|
||
}
|
||
if err := redisClient.Del(context.Background(), cacheKey).Err(); err != nil {
|
||
t.Fatalf("清理 Redis 缓存失败:%v", err)
|
||
}
|
||
value, err = reader.Get(context.Background(), definition.Key)
|
||
if err != nil || value != "20" {
|
||
t.Fatalf("Redis 未命中时未回退 PostgreSQL:值=%q,错误=%v", value, err)
|
||
}
|
||
cached, err := redisClient.Get(context.Background(), cacheKey).Result()
|
||
if err != nil || cached != "20" {
|
||
t.Fatalf("PostgreSQL 结果未回填 Redis:值=%q,错误=%v", cached, err)
|
||
}
|
||
ttl, err := redisClient.TTL(context.Background(), cacheKey).Result()
|
||
if err != nil || ttl <= 0 || ttl > constants.SystemConfigCacheTTL {
|
||
t.Fatalf("Redis 回填 TTL 不符合公共常量:TTL=%s,错误=%v", ttl, err)
|
||
}
|
||
}
|
||
|
||
func TestReaderFallsBackToPostgresWhenCacheIsUnavailable(t *testing.T) {
|
||
db := testutil.NewPostgresTransaction(t)
|
||
testutil.CreateTemporarySystemConfigTable(t, db)
|
||
registry := systemconfig.NewRegistry()
|
||
definition := systemconfig.Definition{
|
||
Key: "foundation.reader.fallback", Module: "foundation", ValueType: constants.SystemConfigTypeString,
|
||
DefaultValue: "default", Description: "缓存故障回退测试值",
|
||
}
|
||
if err := registry.Register(definition); err != nil {
|
||
t.Fatalf("注册系统配置失败:%v", err)
|
||
}
|
||
if err := db.Create(&model.SystemConfig{
|
||
ConfigKey: definition.Key, ConfigValue: "database", ValueType: definition.ValueType,
|
||
Module: definition.Module, Description: definition.Description,
|
||
}).Error; err != nil {
|
||
t.Fatalf("准备数据库配置失败:%v", err)
|
||
}
|
||
alerts := &alertRecorder{}
|
||
reader := systemconfig.NewReader(db, registry, unavailableCache{}, alerts)
|
||
value, err := reader.Get(context.Background(), definition.Key)
|
||
if err != nil || value != "database" {
|
||
t.Fatalf("缓存不可用时未回退 PostgreSQL:值=%q,错误=%v", value, err)
|
||
}
|
||
alerts.mu.Lock()
|
||
defer alerts.mu.Unlock()
|
||
if len(alerts.codes) < 2 || alerts.codes[0] != "SYSTEM_CONFIG_CACHE_READ_FAILED" {
|
||
t.Fatalf("缓存读写故障未产生安全告警:%v", alerts.codes)
|
||
}
|
||
}
|