feat: 实现分层架构,包含 domain、service、repository 和 pkg 层
- 新增 domain 层:model、provider、route、stats 实体 - 新增 service 层:models、providers、routing、stats 业务逻辑 - 新增 repository 层:models、providers、stats 数据访问 - 新增 pkg 工具包:errors、logger、validator - 新增中间件:CORS、logging、recovery、request ID - 新增数据库迁移:初始 schema 和索引 - 新增单元测试和集成测试 - 新增规范文档:config-management、database-migration、error-handling、layered-architecture、middleware-system、request-validation、structured-logging、test-coverage - 移除 config 子包和 model_router(已迁移至分层架构)
This commit is contained in:
176
backend/internal/config/config_test.go
Normal file
176
backend/internal/config/config_test.go
Normal file
@@ -0,0 +1,176 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
func TestDefaultConfig(t *testing.T) {
|
||||
cfg := DefaultConfig()
|
||||
require.NotNil(t, cfg)
|
||||
|
||||
assert.Equal(t, 9826, cfg.Server.Port)
|
||||
assert.Equal(t, 30*time.Second, cfg.Server.ReadTimeout)
|
||||
assert.Equal(t, 30*time.Second, cfg.Server.WriteTimeout)
|
||||
|
||||
assert.Equal(t, 10, cfg.Database.MaxIdleConns)
|
||||
assert.Equal(t, 100, cfg.Database.MaxOpenConns)
|
||||
assert.Equal(t, 1*time.Hour, cfg.Database.ConnMaxLifetime)
|
||||
|
||||
assert.Equal(t, "info", cfg.Log.Level)
|
||||
assert.Equal(t, 100, cfg.Log.MaxSize)
|
||||
assert.Equal(t, 10, cfg.Log.MaxBackups)
|
||||
assert.Equal(t, 30, cfg.Log.MaxAge)
|
||||
assert.Equal(t, true, cfg.Log.Compress)
|
||||
}
|
||||
|
||||
func TestConfig_Validate(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
modify func(*Config)
|
||||
wantErr bool
|
||||
errMsg string
|
||||
}{
|
||||
{
|
||||
name: "默认配置有效",
|
||||
modify: func(c *Config) {},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "端口号为0无效",
|
||||
modify: func(c *Config) { c.Server.Port = 0 },
|
||||
wantErr: true,
|
||||
errMsg: "无效的端口号",
|
||||
},
|
||||
{
|
||||
name: "端口号超出范围无效",
|
||||
modify: func(c *Config) { c.Server.Port = 70000 },
|
||||
wantErr: true,
|
||||
errMsg: "无效的端口号",
|
||||
},
|
||||
{
|
||||
name: "端口号为1有效",
|
||||
modify: func(c *Config) { c.Server.Port = 1 },
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "端口号为65535有效",
|
||||
modify: func(c *Config) { c.Server.Port = 65535 },
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "无效日志级别",
|
||||
modify: func(c *Config) { c.Log.Level = "invalid" },
|
||||
wantErr: true,
|
||||
errMsg: "无效的日志级别",
|
||||
},
|
||||
{
|
||||
name: "debug级别有效",
|
||||
modify: func(c *Config) { c.Log.Level = "debug" },
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "warn级别有效",
|
||||
modify: func(c *Config) { c.Log.Level = "warn" },
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "error级别有效",
|
||||
modify: func(c *Config) { c.Log.Level = "error" },
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "数据库路径为空无效",
|
||||
modify: func(c *Config) { c.Database.Path = "" },
|
||||
wantErr: true,
|
||||
errMsg: "数据库路径不能为空",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
cfg := DefaultConfig()
|
||||
tt.modify(cfg)
|
||||
err := cfg.Validate()
|
||||
if tt.wantErr {
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), tt.errMsg)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetConfigDir(t *testing.T) {
|
||||
dir, err := GetConfigDir()
|
||||
require.NoError(t, err)
|
||||
assert.NotEmpty(t, dir)
|
||||
assert.Contains(t, dir, ".nex")
|
||||
}
|
||||
|
||||
func TestGetDBPath(t *testing.T) {
|
||||
path, err := GetDBPath()
|
||||
require.NoError(t, err)
|
||||
assert.NotEmpty(t, path)
|
||||
assert.Contains(t, path, "config.db")
|
||||
}
|
||||
|
||||
func TestGetConfigPath(t *testing.T) {
|
||||
path, err := GetConfigPath()
|
||||
require.NoError(t, err)
|
||||
assert.NotEmpty(t, path)
|
||||
assert.Contains(t, path, "config.yaml")
|
||||
}
|
||||
|
||||
func TestSaveAndLoadConfig(t *testing.T) {
|
||||
// 使用临时目录覆盖配置路径
|
||||
dir := t.TempDir()
|
||||
|
||||
cfg := &Config{
|
||||
Server: ServerConfig{
|
||||
Port: 9999,
|
||||
ReadTimeout: 10 * time.Second,
|
||||
WriteTimeout: 20 * time.Second,
|
||||
},
|
||||
Database: DatabaseConfig{
|
||||
Path: filepath.Join(dir, "test.db"),
|
||||
MaxIdleConns: 5,
|
||||
MaxOpenConns: 50,
|
||||
ConnMaxLifetime: 30 * time.Minute,
|
||||
},
|
||||
Log: LogConfig{
|
||||
Level: "debug",
|
||||
Path: filepath.Join(dir, "log"),
|
||||
MaxSize: 50,
|
||||
MaxBackups: 5,
|
||||
MaxAge: 7,
|
||||
Compress: false,
|
||||
},
|
||||
}
|
||||
|
||||
// 保存配置
|
||||
configPath := filepath.Join(dir, "config.yaml")
|
||||
data, err := yaml.Marshal(cfg)
|
||||
require.NoError(t, err)
|
||||
err = os.WriteFile(configPath, data, 0644)
|
||||
require.NoError(t, err)
|
||||
|
||||
// 加载配置
|
||||
data, err = os.ReadFile(configPath)
|
||||
require.NoError(t, err)
|
||||
loaded := &Config{}
|
||||
err = yaml.Unmarshal(data, loaded)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, cfg.Server.Port, loaded.Server.Port)
|
||||
assert.Equal(t, cfg.Log.Level, loaded.Log.Level)
|
||||
assert.Equal(t, cfg.Database.MaxIdleConns, loaded.Database.MaxIdleConns)
|
||||
assert.Equal(t, cfg.Log.Compress, loaded.Log.Compress)
|
||||
}
|
||||
Reference in New Issue
Block a user