package config import ( "strings" "testing" ) func prodCfg() *Config { c := &Config{Env: "production"} c.JWT.Secret = "a-real-random-secret-not-the-default" c.Master = "0123456789abcdef0123456789abcdef" c.AdminPassword = "strong-enough-password" return c } func TestValidateProduction(t *testing.T) { if err := prodCfg().validate(); err != nil { t.Fatalf("配齐密钥应通过:%v", err) } cases := []struct { name string mutate func(*Config) want string }{ {"默认 jwt secret", func(c *Config) { c.JWT.Secret = "dev-only-secret-change-me" }, "OT_JWT_SECRET"}, {"空 jwt secret", func(c *Config) { c.JWT.Secret = "" }, "OT_JWT_SECRET"}, {"缺失 master key", func(c *Config) { c.Master = "" }, "OT_MASTER_KEY"}, {"过短 master key", func(c *Config) { c.Master = "short" }, "OT_MASTER_KEY"}, {"默认管理员密码", func(c *Config) { c.AdminPassword = "admin123" }, "OT_ADMIN_PASSWORD"}, {"未设管理员密码", func(c *Config) { c.AdminPassword = "" }, "OT_ADMIN_PASSWORD"}, } for _, tc := range cases { c := prodCfg() tc.mutate(c) err := c.validate() if err == nil { t.Fatalf("%s:应被拒绝", tc.name) } if !strings.Contains(err.Error(), tc.want) { t.Fatalf("%s:报错应点名 %s,实际 %v", tc.name, tc.want, err) } } // 多项同时缺失要一次全说清,别让人改一个试一个 c := prodCfg() c.JWT.Secret = "" c.Master = "" err := c.validate() if err == nil || !strings.Contains(err.Error(), "OT_JWT_SECRET") || !strings.Contains(err.Error(), "OT_MASTER_KEY") { t.Fatalf("应一次列出全部问题:%v", err) } // 开发环境不拦(本地跑默认值就是设计如此) dev := prodCfg() dev.Env = "development" dev.JWT.Secret = "dev-only-secret-change-me" dev.Master = "" dev.AdminPassword = "admin123" if err := dev.validate(); err != nil { t.Fatalf("development 不应拦截:%v", err) } } func TestSplitList(t *testing.T) { if got := splitList(""); got != nil { t.Fatalf("空串应为 nil,实际 %v", got) } if got := splitList(" , ,, "); got != nil { t.Fatalf("纯分隔符应为 nil,实际 %v", got) } got := splitList("https://a.com, https://b.com ,,http://c.com") if len(got) != 3 || got[0] != "https://a.com" || got[2] != "http://c.com" { t.Fatalf("解析错误:%v", got) } }