初始提交:OCI 面板后端(含 GenAI 网关一期)

This commit is contained in:
Wang Defa
2026-07-09 15:31:04 +08:00
commit b9a3e97e84
168 changed files with 31794 additions and 0 deletions
+121
View File
@@ -0,0 +1,121 @@
package service
import (
"context"
"errors"
"testing"
)
func TestSecurityReadWrite(t *testing.T) {
tests := []struct {
name string
setup func(t *testing.T, svc *SettingService)
want SecuritySettings
}{
{
name: "键全部缺省回退默认",
setup: func(t *testing.T, svc *SettingService) {},
want: securityDefaults,
},
{
name: "写入后读回",
setup: func(t *testing.T, svc *SettingService) {
in := SecuritySettings{LoginFailLimit: 10, LoginLockMinutes: 30, IPRateRPS: 20, IPRateBurst: 60, RealIPHeader: "X-Client-IP", AppURL: "https://demo.example.com/"}
if err := svc.UpdateSecurity(context.Background(), in); err != nil {
t.Fatalf("UpdateSecurity: %v", err)
}
},
want: SecuritySettings{LoginFailLimit: 10, LoginLockMinutes: 30, IPRateRPS: 20, IPRateBurst: 60, RealIPHeader: "X-Client-IP", AppURL: "https://demo.example.com"},
},
{
name: "脏数据按字段回退默认",
setup: func(t *testing.T, svc *SettingService) {
for k, v := range map[string]string{
settingSecLoginFailLimit: "abc",
settingSecIPRateRPS: "9999",
settingSecRealIPHeader: "X Evil Header\r\n",
} {
if err := svc.set(context.Background(), k, v); err != nil {
t.Fatalf("set: %v", err)
}
}
},
want: securityDefaults,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
svc, _ := newSettingEnv(t)
tt.setup(t, svc)
got, err := svc.Security(context.Background())
if err != nil {
t.Fatalf("Security: %v", err)
}
if got != tt.want {
t.Errorf("settings = %+v, want %+v", got, tt.want)
}
})
}
}
func TestUpdateSecurityRejectsInvalid(t *testing.T) {
base := securityDefaults
tests := []struct {
name string
mutate func(*SecuritySettings)
}{
{name: "失败阈值越界", mutate: func(s *SecuritySettings) { s.LoginFailLimit = 0 }},
{name: "锁定时长越界", mutate: func(s *SecuritySettings) { s.LoginLockMinutes = 1441 }},
{name: "限速越界", mutate: func(s *SecuritySettings) { s.IPRateRPS = 101 }},
{name: "突发越界", mutate: func(s *SecuritySettings) { s.IPRateBurst = 0 }},
{name: "请求头含非法字符", mutate: func(s *SecuritySettings) { s.RealIPHeader = "X Custom;" }},
{name: "面板地址缺协议", mutate: func(s *SecuritySettings) { s.AppURL = "demo.example.com" }},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
svc, _ := newSettingEnv(t)
in := base
tt.mutate(&in)
if err := svc.UpdateSecurity(context.Background(), in); !errors.Is(err, ErrInvalidSecurity) {
t.Fatalf("err = %v, want ErrInvalidSecurity", err)
}
})
}
}
func TestSecurityCachedSnapshot(t *testing.T) {
svc, _ := newSettingEnv(t)
// 未初始化时返回默认,不触库
if got := svc.SecurityCached(); got != securityDefaults {
t.Errorf("cold cache = %+v, want defaults", got)
}
in := securityDefaults
in.LoginFailLimit = 8
if err := svc.UpdateSecurity(context.Background(), in); err != nil {
t.Fatalf("UpdateSecurity: %v", err)
}
// Update 即刷新快照
if got := svc.SecurityCached(); got.LoginFailLimit != 8 {
t.Errorf("cached limit = %d, want 8", got.LoginFailLimit)
}
// nil 容忍
if got := securityOf(nil); got != securityDefaults {
t.Errorf("securityOf(nil) = %+v, want defaults", got)
}
}
func TestEffectiveAppURL(t *testing.T) {
svc, _ := newSettingEnv(t)
svc.SetEnvPublicURL("https://env.example.com/")
if got := svc.EffectiveAppURL(); got != "https://env.example.com" {
t.Errorf("env fallback = %q", got)
}
in := securityDefaults
in.AppURL = "https://app.example.com"
if err := svc.UpdateSecurity(context.Background(), in); err != nil {
t.Fatalf("UpdateSecurity: %v", err)
}
if got := svc.EffectiveAppURL(); got != "https://app.example.com" {
t.Errorf("app_url 应优先, got %q", got)
}
}