test(config): add coverage for validateUsersConfig, cloneStringMap, cloneAgentConfig

- TestValidateUsersConfig: nil users, empty roles, empty user_ids,
  duplicate users across roles, multiple wildcards, invalid default_role
- TestCloneStringMap: nil input, empty map, populated map, deep copy
- TestPickAgentTemplateForNewProject: clone from project, fallback to
  first project, default codex agent, explicit agent type
- TestCloneAgentConfig: with and without providers, deep copy of
  Options and Provider.Env

config package coverage: 74.1% → 80.0%

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Claude committed 2026-03-22 01:09:49 +08:00
1 parent 5409f8aece
commit 079249dc77
1 file changed
+305
+305
View File
@@ -846,3 +846,308 @@ app_id = "old_app" # keep inline comment
app_secret = "old_secret"
custom_option = "still_here"
`
// --- validateUsersConfig tests ---
func TestValidateUsersConfig(t *testing.T) {
tests := []struct {
name string
cfg Config
wantErr string
}{
{
name: "nil users is valid",
cfg: Config{
Projects: []ProjectConfig{{
Name: "p1",
Agent: AgentConfig{Type: "codex"},
Platforms: []PlatformConfig{{Type: "telegram", Options: map[string]any{"token": "x"}}},
Users: nil,
}},
},
wantErr: "",
},
{
name: "empty roles",
cfg: Config{
Projects: []ProjectConfig{{
Name: "p1",
Agent: AgentConfig{Type: "codex"},
Platforms: []PlatformConfig{{Type: "telegram", Options: map[string]any{"token": "x"}}},
Users: &UsersConfig{Roles: map[string]RoleConfig{}},
}},
},
wantErr: `no roles defined`,
},
{
name: "empty user_ids in role",
cfg: Config{
Projects: []ProjectConfig{{
Name: "p1",
Agent: AgentConfig{Type: "codex"},
Platforms: []PlatformConfig{{Type: "telegram", Options: map[string]any{"token": "x"}}},
Users: &UsersConfig{
Roles: map[string]RoleConfig{
"admin": {UserIDs: []string{}},
},
},
}},
},
wantErr: `empty user_ids`,
},
{
name: "duplicate user in different roles",
cfg: Config{
Projects: []ProjectConfig{{
Name: "p1",
Agent: AgentConfig{Type: "codex"},
Platforms: []PlatformConfig{{Type: "telegram", Options: map[string]any{"token": "x"}}},
Users: &UsersConfig{
Roles: map[string]RoleConfig{
"admin": {UserIDs: []string{"user1"}},
"member": {UserIDs: []string{"user1"}},
},
},
}},
},
wantErr: `appears in both role`,
},
{
name: "wildcard in multiple roles",
cfg: Config{
Projects: []ProjectConfig{{
Name: "p1",
Agent: AgentConfig{Type: "codex"},
Platforms: []PlatformConfig{{Type: "telegram", Options: map[string]any{"token": "x"}}},
Users: &UsersConfig{
Roles: map[string]RoleConfig{
"admin": {UserIDs: []string{"*"}},
"member": {UserIDs: []string{"*"}},
},
},
}},
},
wantErr: `wildcard`,
},
{
name: "default_role not matching any role",
cfg: Config{
Projects: []ProjectConfig{{
Name: "p1",
Agent: AgentConfig{Type: "codex"},
Platforms: []PlatformConfig{{Type: "telegram", Options: map[string]any{"token": "x"}}},
Users: &UsersConfig{
DefaultRole: "superadmin",
Roles: map[string]RoleConfig{
"admin": {UserIDs: []string{"u1"}},
},
},
}},
},
wantErr: `default_role`,
},
{
name: "valid users config",
cfg: Config{
Projects: []ProjectConfig{{
Name: "p1",
Agent: AgentConfig{Type: "codex"},
Platforms: []PlatformConfig{{Type: "telegram", Options: map[string]any{"token": "x"}}},
Users: &UsersConfig{
DefaultRole: "member",
Roles: map[string]RoleConfig{
"admin": {UserIDs: []string{"admin1"}},
"member": {UserIDs: []string{"*"}},
},
},
}},
},
wantErr: "",
},
{
name: "valid with wildcard in one role only",
cfg: Config{
Projects: []ProjectConfig{{
Name: "p1",
Agent: AgentConfig{Type: "codex"},
Platforms: []PlatformConfig{{Type: "telegram", Options: map[string]any{"token": "x"}}},
Users: &UsersConfig{
Roles: map[string]RoleConfig{
"admin": {UserIDs: []string{"u1"}},
"member": {UserIDs: []string{"*", "u2"}},
},
},
}},
},
wantErr: "",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := validateUsersConfig("projects[0]", tt.cfg.Projects[0].Users)
if tt.wantErr == "" {
if err != nil {
t.Errorf("unexpected error: %v", err)
}
} else {
if err == nil {
t.Error("expected error, got nil")
} else if !strings.Contains(err.Error(), tt.wantErr) {
t.Errorf("error = %q, want substring %q", err.Error(), tt.wantErr)
}
}
})
}
}
// --- cloneStringMap tests ---
func TestCloneStringMap(t *testing.T) {
// nil map
if got := cloneStringMap(nil); got != nil {
t.Errorf("cloneStringMap(nil) = %v, want nil", got)
}
// empty map
empty := cloneStringMap(map[string]string{})
if got := cloneStringMap(empty); got == nil || len(got) != 0 {
t.Errorf("cloneStringMap(empty) = %v, want empty non-nil map", got)
}
// populated map
orig := map[string]string{"key1": "val1", "key2": "val2"}
cloned := cloneStringMap(orig)
if len(cloned) != len(orig) {
t.Errorf("length mismatch: got %d, want %d", len(cloned), len(orig))
}
for k, v := range orig {
if cloned[k] != v {
t.Errorf("cloneStringMap[%q] = %q, want %q", k, cloned[k], v)
}
}
// verify it's a deep copy
delete(cloned, "key1")
if _, ok := orig["key1"]; !ok {
t.Error("cloneStringMap returned same map reference, not a copy")
}
}
// --- pickAgentTemplateForNewProject tests ---
func TestPickAgentTemplateForNewProject(t *testing.T) {
baseProj := ProjectConfig{
Name: "base",
Agent: AgentConfig{
Type: "claudecode",
Options: map[string]any{"mode": "yolo"},
Providers: []ProviderConfig{{
Name: "openai",
APIKey: "sk-test",
Model: "gpt-4",
}},
},
Platforms: []PlatformConfig{{Type: "telegram", Options: map[string]any{"token": "x"}}},
}
t.Run("clone from existing project", func(t *testing.T) {
cfg := &Config{Projects: []ProjectConfig{baseProj}}
opts := EnsureProjectWithFeishuOptions{CloneFromProject: "base"}
got := pickAgentTemplateForNewProject(cfg, opts)
if got.Type != "claudecode" {
t.Errorf("Type = %q, want claudecode", got.Type)
}
if len(got.Providers) != 1 || got.Providers[0].APIKey != "sk-test" {
t.Errorf("Providers not cloned correctly")
}
})
t.Run("no clone but has projects", func(t *testing.T) {
cfg := &Config{Projects: []ProjectConfig{baseProj}}
opts := EnsureProjectWithFeishuOptions{}
got := pickAgentTemplateForNewProject(cfg, opts)
if got.Type != "claudecode" {
t.Errorf("Type = %q, want claudecode", got.Type)
}
})
t.Run("no projects uses default codex", func(t *testing.T) {
cfg := &Config{Projects: []ProjectConfig{}}
opts := EnsureProjectWithFeishuOptions{}
got := pickAgentTemplateForNewProject(cfg, opts)
if got.Type != "codex" {
t.Errorf("Type = %q, want codex", got.Type)
}
if got.Options == nil {
t.Error("Options should not be nil")
}
})
t.Run("no projects with explicit agent type", func(t *testing.T) {
cfg := &Config{Projects: []ProjectConfig{}}
opts := EnsureProjectWithFeishuOptions{AgentType: "gemini"}
got := pickAgentTemplateForNewProject(cfg, opts)
if got.Type != "gemini" {
t.Errorf("Type = %q, want gemini", got.Type)
}
})
}
// --- cloneAgentConfig tests ---
func TestCloneAgentConfig(t *testing.T) {
t.Run("without providers", func(t *testing.T) {
in := AgentConfig{
Type: "codex",
Options: map[string]any{"mode": "default"},
}
got := cloneAgentConfig(in)
if got.Type != "codex" {
t.Errorf("Type = %q, want codex", got.Type)
}
if got.Options["mode"] != "default" {
t.Errorf("Options not cloned")
}
if len(got.Providers) != 0 {
t.Errorf("Providers length = %d, want 0", len(got.Providers))
}
})
t.Run("with providers", func(t *testing.T) {
in := AgentConfig{
Type: "claudecode",
Options: map[string]any{"work_dir": "/tmp/test"},
Providers: []ProviderConfig{
{
Name: "openai",
APIKey: "sk-test",
BaseURL: "https://api.openai.com",
Model: "gpt-4",
Thinking: "on",
Env: map[string]string{"DEBUG": "1"},
},
},
}
got := cloneAgentConfig(in)
if len(got.Providers) != 1 {
t.Fatalf("Providers length = %d, want 1", len(got.Providers))
}
p := got.Providers[0]
if p.Name != "openai" || p.APIKey != "sk-test" || p.BaseURL != "https://api.openai.com" || p.Model != "gpt-4" {
t.Errorf("Provider fields not cloned correctly: %+v", p)
}
if p.Env["DEBUG"] != "1" {
t.Errorf("Provider Env not cloned correctly")
}
// Verify deep copy of Options
got.Options["mode"] = "changed"
if in.Options["mode"] == "changed" {
t.Error("Options is same reference, not a deep copy")
}
// Verify deep copy of Provider Env
delete(got.Providers[0].Env, "DEBUG")
if in.Providers[0].Env["DEBUG"] == "" {
t.Error("Provider Env is same reference, not a deep copy")
}
})
}