停止持久化 provider 原始响应、兼容响应快照、attempt/event/outbox 重复 JSON,并由标准任务结果动态生成 Kling/Keling/Volces 兼容响应。 增加事件去重与预算、极简 callback 投递、7/30 天分批清理、安全删除条件、并发迁移索引及可实际恢复的任务域排除备份。历史清理默认关闭,待兼容协议和异步恢复在线验证后单独启用。 验证:Go 全量测试与 go vet、PostgreSQL 18 集成与实际备份恢复、迁移安全测试、bash -n、ShellCheck、Compose 配置和人工发布脚本测试均通过。
103 lines
4.1 KiB
Go
103 lines
4.1 KiB
Go
package config
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestLoadIdentitySecretStoreUsesNewEnvironmentNamesAndIgnoresLegacyBusinessValues(t *testing.T) {
|
|
t.Setenv("IDENTITY_SECRET_STORE", "file")
|
|
t.Setenv("IDENTITY_SECRET_DIR", ".test-secrets/identity")
|
|
t.Setenv("OIDC_ISSUER", "https://legacy-sensitive.example/issuer")
|
|
t.Setenv("OIDC_INTROSPECTION_CLIENT_SECRET", "legacy-sensitive-secret")
|
|
t.Setenv("OIDC_SESSION_ENCRYPTION_KEY", "legacy-sensitive-session-key")
|
|
|
|
cfg := Load()
|
|
if cfg.IdentitySecretStore != "file" || cfg.IdentitySecretDir != ".test-secrets/identity" {
|
|
t.Fatalf("identity SecretStore = %q %q", cfg.IdentitySecretStore, cfg.IdentitySecretDir)
|
|
}
|
|
printed := fmt.Sprintf("%+v", cfg)
|
|
for _, legacyValue := range []string{"legacy-sensitive.example", "legacy-sensitive-secret", "legacy-sensitive-session-key"} {
|
|
if strings.Contains(printed, legacyValue) {
|
|
t.Fatalf("legacy identity business setting was loaded into Config: %q", legacyValue)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestValidateIdentityFileSecretStoreRequiresDirectory(t *testing.T) {
|
|
cfg := Config{IdentitySecretStore: "file", AsyncWorkerHardLimit: 2048, AsyncWorkerRefreshIntervalSeconds: 5}
|
|
if err := cfg.Validate(); err == nil || !strings.Contains(err.Error(), "IDENTITY_SECRET_DIR") {
|
|
t.Fatalf("Validate() error = %v, want missing identity secret directory", err)
|
|
}
|
|
cfg.IdentitySecretDir = ".test-secrets/identity"
|
|
if err := cfg.Validate(); err != nil {
|
|
t.Fatalf("valid file SecretStore was rejected: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestValidateIdentityKubernetesSecretStore(t *testing.T) {
|
|
cfg := Config{
|
|
IdentitySecretStore: "kubernetes",
|
|
IdentityKubernetesSecretName: "easyai-gateway-identity",
|
|
AsyncWorkerHardLimit: 2048,
|
|
AsyncWorkerRefreshIntervalSeconds: 5,
|
|
}
|
|
if err := cfg.Validate(); err == nil || !strings.Contains(err.Error(), "namespace") {
|
|
t.Fatalf("Validate() error = %v, want missing namespace", err)
|
|
}
|
|
cfg.IdentityKubernetesNamespace = "easyai"
|
|
if err := cfg.Validate(); err != nil {
|
|
t.Fatalf("valid Kubernetes SecretStore was rejected: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestValidateIdentitySecurityEventTiming(t *testing.T) {
|
|
cfg := Config{
|
|
IdentitySecurityEventHeartbeatIntervalSeconds: 60,
|
|
IdentitySecurityEventStaleAfterSeconds: 60,
|
|
IdentitySecurityEventClockSkewSeconds: 60,
|
|
AsyncWorkerHardLimit: 2048,
|
|
AsyncWorkerRefreshIntervalSeconds: 5,
|
|
}
|
|
if err := cfg.Validate(); err == nil || !strings.Contains(err.Error(), "heartbeat") {
|
|
t.Fatalf("Validate() error = %v, want invalid stale threshold", err)
|
|
}
|
|
}
|
|
|
|
func TestValidateAsyncWorkerSettings(t *testing.T) {
|
|
cfg := Config{AsyncWorkerHardLimit: 10001, AsyncWorkerRefreshIntervalSeconds: 5}
|
|
if err := cfg.Validate(); err == nil || !strings.Contains(err.Error(), "HARD_LIMIT") {
|
|
t.Fatalf("Validate() error = %v, want invalid hard limit", err)
|
|
}
|
|
cfg.AsyncWorkerHardLimit = 2048
|
|
cfg.AsyncWorkerRefreshIntervalSeconds = 0
|
|
if err := cfg.Validate(); err == nil || !strings.Contains(err.Error(), "REFRESH_INTERVAL") {
|
|
t.Fatalf("Validate() error = %v, want invalid refresh interval", err)
|
|
}
|
|
t.Setenv("AI_GATEWAY_ASYNC_WORKER_HARD_LIMIT", "not-an-integer")
|
|
loaded := Load()
|
|
if err := loaded.Validate(); err == nil || !strings.Contains(err.Error(), "HARD_LIMIT") {
|
|
t.Fatalf("Validate() error = %v, want invalid non-integer hard limit", err)
|
|
}
|
|
}
|
|
|
|
func TestValidateTaskHistorySettings(t *testing.T) {
|
|
cfg := Load()
|
|
cfg.TaskRetentionDays = 30
|
|
cfg.TaskAnalysisRetentionDays = 31
|
|
if err := cfg.Validate(); err == nil || !strings.Contains(err.Error(), "ANALYSIS_RETENTION") {
|
|
t.Fatalf("Validate() error = %v, want invalid analysis retention", err)
|
|
}
|
|
cfg.TaskAnalysisRetentionDays = 7
|
|
cfg.TaskCleanupIntervalSeconds = 59
|
|
if err := cfg.Validate(); err == nil || !strings.Contains(err.Error(), "CLEANUP_INTERVAL") {
|
|
t.Fatalf("Validate() error = %v, want invalid cleanup interval", err)
|
|
}
|
|
cfg.TaskCleanupIntervalSeconds = 300
|
|
cfg.TaskCleanupBatchSize = 5001
|
|
if err := cfg.Validate(); err == nil || !strings.Contains(err.Error(), "CLEANUP_BATCH") {
|
|
t.Fatalf("Validate() error = %v, want invalid cleanup batch", err)
|
|
}
|
|
}
|