Skip to content

Commit 2da5d75

Browse files
committed
feat: add configuration validation
Add validation to Config struct to ensure server name and version are provided: - Add Config.Validate() method that checks for empty Name and Version fields - Integrate validation into New() constructor with descriptive error messages - Add comprehensive tests for validation scenarios (valid, empty name, empty version) - Return clear error messages: "invalid config: server name cannot be empty" This prevents silent failures and improves developer experience by catching configuration errors early with actionable error messages.
1 parent 570b7f3 commit 2da5d75

File tree

2 files changed

+117
-0
lines changed

2 files changed

+117
-0
lines changed

server.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,23 @@ type Config struct {
3232
CacheConfig cache.Config
3333
}
3434

35+
// Validate checks if the configuration is valid
36+
func (c Config) Validate() error {
37+
if c.Name == "" {
38+
return fmt.Errorf("server name cannot be empty")
39+
}
40+
if c.Version == "" {
41+
return fmt.Errorf("server version cannot be empty")
42+
}
43+
return nil
44+
}
45+
3546
// New creates a new MCP server with common infrastructure
3647
func New(cfg Config, logger *zap.Logger) (*Server, error) {
48+
// Validate configuration
49+
if err := cfg.Validate(); err != nil {
50+
return nil, fmt.Errorf("invalid config: %w", err)
51+
}
3752
// Create shared HTTP client
3853
httpClient := httpx.New(logger)
3954

server_test.go

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,108 @@ import (
99
"go.uber.org/zap/zaptest"
1010
)
1111

12+
func TestConfig_Validate(t *testing.T) {
13+
tests := []struct {
14+
name string
15+
config Config
16+
wantErr bool
17+
errMsg string
18+
}{
19+
{
20+
name: "valid config",
21+
config: Config{
22+
Name: "test-server",
23+
Version: "1.0.0",
24+
CacheEnabled: true,
25+
},
26+
wantErr: false,
27+
},
28+
{
29+
name: "empty name",
30+
config: Config{
31+
Name: "",
32+
Version: "1.0.0",
33+
},
34+
wantErr: true,
35+
errMsg: "server name cannot be empty",
36+
},
37+
{
38+
name: "empty version",
39+
config: Config{
40+
Name: "test-server",
41+
Version: "",
42+
},
43+
wantErr: true,
44+
errMsg: "server version cannot be empty",
45+
},
46+
{
47+
name: "both empty",
48+
config: Config{
49+
Name: "",
50+
Version: "",
51+
},
52+
wantErr: true,
53+
errMsg: "server name cannot be empty",
54+
},
55+
}
56+
57+
for _, tt := range tests {
58+
t.Run(tt.name, func(t *testing.T) {
59+
err := tt.config.Validate()
60+
if tt.wantErr {
61+
if err == nil {
62+
t.Error("expected error but got nil")
63+
} else if err.Error() != tt.errMsg {
64+
t.Errorf("expected error %q, got %q", tt.errMsg, err.Error())
65+
}
66+
} else {
67+
if err != nil {
68+
t.Errorf("unexpected error: %v", err)
69+
}
70+
}
71+
})
72+
}
73+
}
74+
75+
func TestNew_ValidationError(t *testing.T) {
76+
logger := zaptest.NewLogger(t)
77+
78+
tests := []struct {
79+
name string
80+
config Config
81+
wantErr string
82+
}{
83+
{
84+
name: "empty name",
85+
config: Config{
86+
Name: "",
87+
Version: "1.0.0",
88+
},
89+
wantErr: "invalid config: server name cannot be empty",
90+
},
91+
{
92+
name: "empty version",
93+
config: Config{
94+
Name: "test-server",
95+
Version: "",
96+
},
97+
wantErr: "invalid config: server version cannot be empty",
98+
},
99+
}
100+
101+
for _, tt := range tests {
102+
t.Run(tt.name, func(t *testing.T) {
103+
_, err := New(tt.config, logger)
104+
if err == nil {
105+
t.Fatal("expected error but got nil")
106+
}
107+
if err.Error() != tt.wantErr {
108+
t.Errorf("expected error %q, got %q", tt.wantErr, err.Error())
109+
}
110+
})
111+
}
112+
}
113+
12114
func TestNew(t *testing.T) {
13115
logger := zaptest.NewLogger(t)
14116

0 commit comments

Comments
 (0)