备份一下
This commit is contained in:
615
pkg/config/config_test.go
Normal file
615
pkg/config/config_test.go
Normal file
@@ -0,0 +1,615 @@
|
||||
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")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user