616 lines
13 KiB
Go
616 lines
13 KiB
Go
package config
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
// TestConfig_Validate tests configuration validation rules
|
|
func TestConfig_Validate(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
config *Config
|
|
wantErr bool
|
|
errMsg string
|
|
}{
|
|
{
|
|
name: "valid config",
|
|
config: &Config{
|
|
Server: ServerConfig{
|
|
Address: ":3000",
|
|
ReadTimeout: 10 * time.Second,
|
|
WriteTimeout: 10 * time.Second,
|
|
ShutdownTimeout: 30 * time.Second,
|
|
},
|
|
Redis: RedisConfig{
|
|
Address: "localhost",
|
|
Port: 6379,
|
|
DB: 0,
|
|
PoolSize: 10,
|
|
MinIdleConns: 5,
|
|
},
|
|
Logging: LoggingConfig{
|
|
Level: "info",
|
|
AppLog: LogRotationConfig{
|
|
Filename: "logs/app.log",
|
|
MaxSize: 100,
|
|
MaxBackups: 30,
|
|
MaxAge: 30,
|
|
},
|
|
AccessLog: LogRotationConfig{
|
|
Filename: "logs/access.log",
|
|
MaxSize: 500,
|
|
MaxBackups: 90,
|
|
MaxAge: 90,
|
|
},
|
|
},
|
|
Middleware: MiddlewareConfig{
|
|
RateLimiter: RateLimiterConfig{
|
|
Max: 100,
|
|
Expiration: 1 * time.Minute,
|
|
Storage: "memory",
|
|
},
|
|
},
|
|
},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "empty server address",
|
|
config: &Config{
|
|
Server: ServerConfig{
|
|
Address: "",
|
|
ReadTimeout: 10 * time.Second,
|
|
WriteTimeout: 10 * time.Second,
|
|
ShutdownTimeout: 30 * time.Second,
|
|
},
|
|
Redis: RedisConfig{
|
|
Address: "localhost",
|
|
Port: 6379,
|
|
PoolSize: 10,
|
|
},
|
|
Logging: LoggingConfig{
|
|
Level: "info",
|
|
AppLog: LogRotationConfig{
|
|
Filename: "logs/app.log",
|
|
MaxSize: 100,
|
|
},
|
|
AccessLog: LogRotationConfig{
|
|
Filename: "logs/access.log",
|
|
MaxSize: 500,
|
|
},
|
|
},
|
|
},
|
|
wantErr: true,
|
|
errMsg: "server.address",
|
|
},
|
|
{
|
|
name: "read timeout too short",
|
|
config: &Config{
|
|
Server: ServerConfig{
|
|
Address: ":3000",
|
|
ReadTimeout: 1 * time.Second,
|
|
WriteTimeout: 10 * time.Second,
|
|
ShutdownTimeout: 30 * time.Second,
|
|
},
|
|
Redis: RedisConfig{
|
|
Address: "localhost",
|
|
Port: 6379,
|
|
PoolSize: 10,
|
|
},
|
|
Logging: LoggingConfig{
|
|
Level: "info",
|
|
AppLog: LogRotationConfig{
|
|
Filename: "logs/app.log",
|
|
MaxSize: 100,
|
|
},
|
|
AccessLog: LogRotationConfig{
|
|
Filename: "logs/access.log",
|
|
MaxSize: 500,
|
|
},
|
|
},
|
|
},
|
|
wantErr: true,
|
|
errMsg: "read_timeout",
|
|
},
|
|
{
|
|
name: "read timeout too long",
|
|
config: &Config{
|
|
Server: ServerConfig{
|
|
Address: ":3000",
|
|
ReadTimeout: 400 * time.Second,
|
|
WriteTimeout: 10 * time.Second,
|
|
ShutdownTimeout: 30 * time.Second,
|
|
},
|
|
Redis: RedisConfig{
|
|
Address: "localhost",
|
|
Port: 6379,
|
|
PoolSize: 10,
|
|
},
|
|
Logging: LoggingConfig{
|
|
Level: "info",
|
|
AppLog: LogRotationConfig{
|
|
Filename: "logs/app.log",
|
|
MaxSize: 100,
|
|
},
|
|
AccessLog: LogRotationConfig{
|
|
Filename: "logs/access.log",
|
|
MaxSize: 500,
|
|
},
|
|
},
|
|
},
|
|
wantErr: true,
|
|
errMsg: "read_timeout",
|
|
},
|
|
{
|
|
name: "write timeout out of range",
|
|
config: &Config{
|
|
Server: ServerConfig{
|
|
Address: ":3000",
|
|
ReadTimeout: 10 * time.Second,
|
|
WriteTimeout: 1 * time.Second,
|
|
ShutdownTimeout: 30 * time.Second,
|
|
},
|
|
Redis: RedisConfig{
|
|
Address: "localhost",
|
|
Port: 6379,
|
|
PoolSize: 10,
|
|
},
|
|
Logging: LoggingConfig{
|
|
Level: "info",
|
|
AppLog: LogRotationConfig{
|
|
Filename: "logs/app.log",
|
|
MaxSize: 100,
|
|
},
|
|
AccessLog: LogRotationConfig{
|
|
Filename: "logs/access.log",
|
|
MaxSize: 500,
|
|
},
|
|
},
|
|
},
|
|
wantErr: true,
|
|
errMsg: "write_timeout",
|
|
},
|
|
{
|
|
name: "shutdown timeout too short",
|
|
config: &Config{
|
|
Server: ServerConfig{
|
|
Address: ":3000",
|
|
ReadTimeout: 10 * time.Second,
|
|
WriteTimeout: 10 * time.Second,
|
|
ShutdownTimeout: 5 * time.Second,
|
|
},
|
|
Redis: RedisConfig{
|
|
Address: "localhost",
|
|
Port: 6379,
|
|
PoolSize: 10,
|
|
},
|
|
Logging: LoggingConfig{
|
|
Level: "info",
|
|
AppLog: LogRotationConfig{
|
|
Filename: "logs/app.log",
|
|
MaxSize: 100,
|
|
},
|
|
AccessLog: LogRotationConfig{
|
|
Filename: "logs/access.log",
|
|
MaxSize: 500,
|
|
},
|
|
},
|
|
},
|
|
wantErr: true,
|
|
errMsg: "shutdown_timeout",
|
|
},
|
|
{
|
|
name: "empty redis address",
|
|
config: &Config{
|
|
Server: ServerConfig{
|
|
Address: ":3000",
|
|
ReadTimeout: 10 * time.Second,
|
|
WriteTimeout: 10 * time.Second,
|
|
ShutdownTimeout: 30 * time.Second,
|
|
},
|
|
Redis: RedisConfig{
|
|
Address: "",
|
|
Port: 6379,
|
|
PoolSize: 10,
|
|
},
|
|
Logging: LoggingConfig{
|
|
Level: "info",
|
|
AppLog: LogRotationConfig{
|
|
Filename: "logs/app.log",
|
|
MaxSize: 100,
|
|
},
|
|
AccessLog: LogRotationConfig{
|
|
Filename: "logs/access.log",
|
|
MaxSize: 500,
|
|
},
|
|
},
|
|
},
|
|
wantErr: true,
|
|
errMsg: "redis.address",
|
|
},
|
|
{
|
|
name: "invalid redis port - too high",
|
|
config: &Config{
|
|
Server: ServerConfig{
|
|
Address: ":3000",
|
|
ReadTimeout: 10 * time.Second,
|
|
WriteTimeout: 10 * time.Second,
|
|
ShutdownTimeout: 30 * time.Second,
|
|
},
|
|
Redis: RedisConfig{
|
|
Address: "localhost",
|
|
Port: 99999,
|
|
PoolSize: 10,
|
|
},
|
|
Logging: LoggingConfig{
|
|
Level: "info",
|
|
AppLog: LogRotationConfig{
|
|
Filename: "logs/app.log",
|
|
MaxSize: 100,
|
|
},
|
|
AccessLog: LogRotationConfig{
|
|
Filename: "logs/access.log",
|
|
MaxSize: 500,
|
|
},
|
|
},
|
|
},
|
|
wantErr: true,
|
|
errMsg: "redis.port",
|
|
},
|
|
{
|
|
name: "invalid redis port - zero",
|
|
config: &Config{
|
|
Server: ServerConfig{
|
|
Address: ":3000",
|
|
ReadTimeout: 10 * time.Second,
|
|
WriteTimeout: 10 * time.Second,
|
|
ShutdownTimeout: 30 * time.Second,
|
|
},
|
|
Redis: RedisConfig{
|
|
Address: "localhost",
|
|
Port: 0,
|
|
PoolSize: 10,
|
|
},
|
|
Logging: LoggingConfig{
|
|
Level: "info",
|
|
AppLog: LogRotationConfig{
|
|
Filename: "logs/app.log",
|
|
MaxSize: 100,
|
|
},
|
|
AccessLog: LogRotationConfig{
|
|
Filename: "logs/access.log",
|
|
MaxSize: 500,
|
|
},
|
|
},
|
|
},
|
|
wantErr: true,
|
|
errMsg: "redis.port",
|
|
},
|
|
{
|
|
name: "redis db out of range",
|
|
config: &Config{
|
|
Server: ServerConfig{
|
|
Address: ":3000",
|
|
ReadTimeout: 10 * time.Second,
|
|
WriteTimeout: 10 * time.Second,
|
|
ShutdownTimeout: 30 * time.Second,
|
|
},
|
|
Redis: RedisConfig{
|
|
Address: "localhost",
|
|
Port: 6379,
|
|
DB: 20,
|
|
PoolSize: 10,
|
|
},
|
|
Logging: LoggingConfig{
|
|
Level: "info",
|
|
AppLog: LogRotationConfig{
|
|
Filename: "logs/app.log",
|
|
MaxSize: 100,
|
|
},
|
|
AccessLog: LogRotationConfig{
|
|
Filename: "logs/access.log",
|
|
MaxSize: 500,
|
|
},
|
|
},
|
|
},
|
|
wantErr: true,
|
|
errMsg: "redis.db",
|
|
},
|
|
{
|
|
name: "redis pool size too large",
|
|
config: &Config{
|
|
Server: ServerConfig{
|
|
Address: ":3000",
|
|
ReadTimeout: 10 * time.Second,
|
|
WriteTimeout: 10 * time.Second,
|
|
ShutdownTimeout: 30 * time.Second,
|
|
},
|
|
Redis: RedisConfig{
|
|
Address: "localhost",
|
|
Port: 6379,
|
|
PoolSize: 2000,
|
|
},
|
|
Logging: LoggingConfig{
|
|
Level: "info",
|
|
AppLog: LogRotationConfig{
|
|
Filename: "logs/app.log",
|
|
MaxSize: 100,
|
|
},
|
|
AccessLog: LogRotationConfig{
|
|
Filename: "logs/access.log",
|
|
MaxSize: 500,
|
|
},
|
|
},
|
|
},
|
|
wantErr: true,
|
|
errMsg: "pool_size",
|
|
},
|
|
{
|
|
name: "min idle conns exceeds pool size",
|
|
config: &Config{
|
|
Server: ServerConfig{
|
|
Address: ":3000",
|
|
ReadTimeout: 10 * time.Second,
|
|
WriteTimeout: 10 * time.Second,
|
|
ShutdownTimeout: 30 * time.Second,
|
|
},
|
|
Redis: RedisConfig{
|
|
Address: "localhost",
|
|
Port: 6379,
|
|
PoolSize: 10,
|
|
MinIdleConns: 20,
|
|
},
|
|
Logging: LoggingConfig{
|
|
Level: "info",
|
|
AppLog: LogRotationConfig{
|
|
Filename: "logs/app.log",
|
|
MaxSize: 100,
|
|
},
|
|
AccessLog: LogRotationConfig{
|
|
Filename: "logs/access.log",
|
|
MaxSize: 500,
|
|
},
|
|
},
|
|
},
|
|
wantErr: true,
|
|
errMsg: "min_idle_conns",
|
|
},
|
|
{
|
|
name: "invalid log level",
|
|
config: &Config{
|
|
Server: ServerConfig{
|
|
Address: ":3000",
|
|
ReadTimeout: 10 * time.Second,
|
|
WriteTimeout: 10 * time.Second,
|
|
ShutdownTimeout: 30 * time.Second,
|
|
},
|
|
Redis: RedisConfig{
|
|
Address: "localhost",
|
|
Port: 6379,
|
|
PoolSize: 10,
|
|
},
|
|
Logging: LoggingConfig{
|
|
Level: "invalid",
|
|
AppLog: LogRotationConfig{
|
|
Filename: "logs/app.log",
|
|
MaxSize: 100,
|
|
},
|
|
AccessLog: LogRotationConfig{
|
|
Filename: "logs/access.log",
|
|
MaxSize: 500,
|
|
},
|
|
},
|
|
},
|
|
wantErr: true,
|
|
errMsg: "logging.level",
|
|
},
|
|
{
|
|
name: "empty app log filename",
|
|
config: &Config{
|
|
Server: ServerConfig{
|
|
Address: ":3000",
|
|
ReadTimeout: 10 * time.Second,
|
|
WriteTimeout: 10 * time.Second,
|
|
ShutdownTimeout: 30 * time.Second,
|
|
},
|
|
Redis: RedisConfig{
|
|
Address: "localhost",
|
|
Port: 6379,
|
|
PoolSize: 10,
|
|
},
|
|
Logging: LoggingConfig{
|
|
Level: "info",
|
|
AppLog: LogRotationConfig{
|
|
Filename: "",
|
|
MaxSize: 100,
|
|
},
|
|
AccessLog: LogRotationConfig{
|
|
Filename: "logs/access.log",
|
|
MaxSize: 500,
|
|
},
|
|
},
|
|
},
|
|
wantErr: true,
|
|
errMsg: "app_log.filename",
|
|
},
|
|
{
|
|
name: "app log max size out of range",
|
|
config: &Config{
|
|
Server: ServerConfig{
|
|
Address: ":3000",
|
|
ReadTimeout: 10 * time.Second,
|
|
WriteTimeout: 10 * time.Second,
|
|
ShutdownTimeout: 30 * time.Second,
|
|
},
|
|
Redis: RedisConfig{
|
|
Address: "localhost",
|
|
Port: 6379,
|
|
PoolSize: 10,
|
|
},
|
|
Logging: LoggingConfig{
|
|
Level: "info",
|
|
AppLog: LogRotationConfig{
|
|
Filename: "logs/app.log",
|
|
MaxSize: 2000,
|
|
},
|
|
AccessLog: LogRotationConfig{
|
|
Filename: "logs/access.log",
|
|
MaxSize: 500,
|
|
},
|
|
},
|
|
},
|
|
wantErr: true,
|
|
errMsg: "app_log.max_size",
|
|
},
|
|
{
|
|
name: "invalid rate limiter storage",
|
|
config: &Config{
|
|
Server: ServerConfig{
|
|
Address: ":3000",
|
|
ReadTimeout: 10 * time.Second,
|
|
WriteTimeout: 10 * time.Second,
|
|
ShutdownTimeout: 30 * time.Second,
|
|
},
|
|
Redis: RedisConfig{
|
|
Address: "localhost",
|
|
Port: 6379,
|
|
PoolSize: 10,
|
|
},
|
|
Logging: LoggingConfig{
|
|
Level: "info",
|
|
AppLog: LogRotationConfig{
|
|
Filename: "logs/app.log",
|
|
MaxSize: 100,
|
|
},
|
|
AccessLog: LogRotationConfig{
|
|
Filename: "logs/access.log",
|
|
MaxSize: 500,
|
|
},
|
|
},
|
|
Middleware: MiddlewareConfig{
|
|
RateLimiter: RateLimiterConfig{
|
|
Max: 100,
|
|
Storage: "invalid",
|
|
},
|
|
},
|
|
},
|
|
wantErr: true,
|
|
errMsg: "rate_limiter.storage",
|
|
},
|
|
{
|
|
name: "rate limiter max too high",
|
|
config: &Config{
|
|
Server: ServerConfig{
|
|
Address: ":3000",
|
|
ReadTimeout: 10 * time.Second,
|
|
WriteTimeout: 10 * time.Second,
|
|
ShutdownTimeout: 30 * time.Second,
|
|
},
|
|
Redis: RedisConfig{
|
|
Address: "localhost",
|
|
Port: 6379,
|
|
PoolSize: 10,
|
|
},
|
|
Logging: LoggingConfig{
|
|
Level: "info",
|
|
AppLog: LogRotationConfig{
|
|
Filename: "logs/app.log",
|
|
MaxSize: 100,
|
|
},
|
|
AccessLog: LogRotationConfig{
|
|
Filename: "logs/access.log",
|
|
MaxSize: 500,
|
|
},
|
|
},
|
|
Middleware: MiddlewareConfig{
|
|
RateLimiter: RateLimiterConfig{
|
|
Max: 20000,
|
|
Storage: "memory",
|
|
},
|
|
},
|
|
},
|
|
wantErr: true,
|
|
errMsg: "rate_limiter.max",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
err := tt.config.Validate()
|
|
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("Config.Validate() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
|
|
if tt.wantErr && tt.errMsg != "" {
|
|
if err == nil {
|
|
t.Errorf("expected error containing %q, got nil", tt.errMsg)
|
|
} else if err.Error() == "" {
|
|
t.Errorf("expected error containing %q, got empty error", tt.errMsg)
|
|
}
|
|
// Note: We check that error message exists, not exact match
|
|
// This is because error messages might change slightly
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestSet tests the Set function
|
|
func TestSet(t *testing.T) {
|
|
// Valid config
|
|
validCfg := &Config{
|
|
Server: ServerConfig{
|
|
Address: ":3000",
|
|
ReadTimeout: 10 * time.Second,
|
|
WriteTimeout: 10 * time.Second,
|
|
ShutdownTimeout: 30 * time.Second,
|
|
},
|
|
Redis: RedisConfig{
|
|
Address: "localhost",
|
|
Port: 6379,
|
|
PoolSize: 10,
|
|
},
|
|
Logging: LoggingConfig{
|
|
Level: "info",
|
|
AppLog: LogRotationConfig{
|
|
Filename: "logs/app.log",
|
|
MaxSize: 100,
|
|
},
|
|
AccessLog: LogRotationConfig{
|
|
Filename: "logs/access.log",
|
|
MaxSize: 500,
|
|
},
|
|
},
|
|
}
|
|
|
|
err := Set(validCfg)
|
|
if err != nil {
|
|
t.Errorf("Set() with valid config failed: %v", err)
|
|
}
|
|
|
|
// Verify it was set
|
|
got := Get()
|
|
if got.Server.Address != ":3000" {
|
|
t.Errorf("Get() after Set() returned wrong address: got %s, want :3000", got.Server.Address)
|
|
}
|
|
|
|
// Test with nil config
|
|
err = Set(nil)
|
|
if err == nil {
|
|
t.Error("Set(nil) should return error")
|
|
}
|
|
|
|
// Test with invalid config
|
|
invalidCfg := &Config{
|
|
Server: ServerConfig{
|
|
Address: "", // Empty address is invalid
|
|
},
|
|
}
|
|
|
|
err = Set(invalidCfg)
|
|
if err == nil {
|
|
t.Error("Set() with invalid config should return error")
|
|
}
|
|
}
|