From 651256a0c2ff3da11466b75ecdca5877754840ae Mon Sep 17 00:00:00 2001 From: kingecg Date: Thu, 5 Jun 2025 20:43:16 +0800 Subject: [PATCH] add config Path: .git/config [core] repositoryformatversion = 0 filemode = true bare = false --- config/.gitkeep | 0 config/config.go | 91 +++++++++++++++++++++ config/config_test.go | 104 ++++++++++++++++++++++++ design/todo/00000_config_design_impl.md | 20 +++++ go.mod | 8 ++ go.sum | 11 +++ 6 files changed, 234 insertions(+) create mode 100644 config/.gitkeep create mode 100644 config/config.go create mode 100644 config/config_test.go create mode 100644 design/todo/00000_config_design_impl.md create mode 100644 go.sum diff --git a/config/.gitkeep b/config/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/config/config.go b/config/config.go new file mode 100644 index 0000000..027abc7 --- /dev/null +++ b/config/config.go @@ -0,0 +1,91 @@ +package config + +import ( + "fmt" + "io/ioutil" + "os" + "path/filepath" + "sync" + + "encoding/json" + + "gopkg.in/yaml.v2" +) + +// Config 系统配置结构体 +type Config struct { + Server ServerConfig `yaml:"server" json:"server"` + Storage StorageConfig `yaml:"storage" json:"storage"` +} + +// ServerConfig 服务器配置 +type ServerConfig struct { + Host string `yaml:"host" json:"host"` + Port int `yaml:"port" json:"port"` +} + +// StorageConfig 存储配置 +type StorageConfig struct { + Engine string `yaml:"engine" json:"engine"` + DataPath string `yaml:"dataPath" json:"dataPath"` +} + +var ( + configInstance *Config + once sync.Once +) + +// NewDefaultConfig 创建默认配置 +func NewDefaultConfig() *Config { + return &Config{ + Server: ServerConfig{ + Host: "0.0.0.0", + Port: 27017, + }, + Storage: StorageConfig{ + Engine: "memory", + DataPath: "/var/lib/goaidb", + }, + } +} + +// ParseConfig 解析配置文件 +// 支持JSON和YAML格式 +// 返回解析后的配置对象和错误信息 +func ParseConfig(filePath string) (*Config, error) { + // 检查文件是否存在 + if _, err := os.Stat(filePath); os.IsNotExist(err) { + return nil, fmt.Errorf("配置文件不存在: %s", filePath) + } + + // 读取文件内容 + data, err := ioutil.ReadFile(filePath) + if err != nil { + return nil, fmt.Errorf("读取配置文件失败: %v", err) + } + + // 根据文件扩展名选择解析方式 + var cfg Config + switch filepath.Ext(filePath) { + case ".json": + if err := json.Unmarshal(data, &cfg); err != nil { + return nil, fmt.Errorf("JSON解析失败: %v", err) + } + case ".yaml", ".yml": + if err := yaml.Unmarshal(data, &cfg); err != nil { + return nil, fmt.Errorf("YAML解析失败: %v", err) + } + default: + return nil, fmt.Errorf("不支持的配置文件格式") + } + + return &cfg, nil +} + +// GetConfig 获取全局配置实例 +func GetConfig() *Config { + once.Do(func() { + configInstance = NewDefaultConfig() + }) + return configInstance +} diff --git a/config/config_test.go b/config/config_test.go new file mode 100644 index 0000000..b04731e --- /dev/null +++ b/config/config_test.go @@ -0,0 +1,104 @@ +package config + +import ( + "os" + "path/filepath" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestParseConfig_JSON(t *testing.T) { + // 创建临时JSON配置文件 + tmpFile, err := os.CreateTemp("", "*.json") + assert.NoError(t, err) + defer os.Remove(tmpFile.Name()) + + // 写入测试配置内容 + testConfig := `{ + "server": { + "host": "127.0.0.1", + "port": 8080 + }, + "storage": { + "engine": "rocksdb", + "dataPath": "/test/data" + } + }` + + _, err = tmpFile.WriteString(testConfig) + assert.NoError(t, err) + tmpFile.Close() + + // 测试解析功能 + cfg, err := ParseConfig(tmpFile.Name()) + assert.NoError(t, err) + assert.NotNil(t, cfg) + assert.Equal(t, "127.0.0.1", cfg.Server.Host) + assert.Equal(t, 8080, cfg.Server.Port) + assert.Equal(t, "rocksdb", cfg.Storage.Engine) + assert.Equal(t, "/test/data", cfg.Storage.DataPath) +} + +func TestParseConfig_YAML(t *testing.T) { + // 创建临时YAML配置文件 + tmpFile, err := os.CreateTemp("", "*.yaml") + assert.NoError(t, err) + defer os.Remove(tmpFile.Name()) + + // 写入测试配置内容 + testConfig := `server: + host: 127.0.0.1 + port: 8080 +storage: + engine: rocksdb + dataPath: /test/data` + + _, err = tmpFile.WriteString(testConfig) + assert.NoError(t, err) + tmpFile.Close() + + // 测试解析功能 + cfg, err := ParseConfig(tmpFile.Name()) + assert.NoError(t, err) + assert.NotNil(t, cfg) + assert.Equal(t, "127.0.0.1", cfg.Server.Host) + assert.Equal(t, 8080, cfg.Server.Port) + assert.Equal(t, "rocksdb", cfg.Storage.Engine) + assert.Equal(t, "/test/data", cfg.Storage.DataPath) +} + +func TestParseConfig_Default(t *testing.T) { + // 测试默认配置 + cfg := GetConfig() + assert.NotNil(t, cfg) + assert.Equal(t, "0.0.0.0", cfg.Server.Host) + assert.Equal(t, 27017, cfg.Server.Port) + assert.Equal(t, "memory", cfg.Storage.Engine) + assert.Equal(t, "/var/lib/goaidb", cfg.Storage.DataPath) +} + +func TestParseConfig_InvalidFormat(t *testing.T) { + // 创建临时无效格式配置文件 + tmpFile, err := os.CreateTemp("", "*.txt") + assert.NoError(t, err) + defer os.Remove(tmpFile.Name()) + + // 写入任意内容 + _, err = tmpFile.WriteString("invalid config content") + assert.NoError(t, err) + tmpFile.Close() + + // 测试不支持的格式 + _, err = ParseConfig(tmpFile.Name()) + assert.Error(t, err) + assert.Contains(t, err.Error(), "不支持的配置文件格式") +} + +func TestParseConfig_FileNotFound(t *testing.T) { + // 测试不存在的文件 + notExistFile := filepath.Join("not", "exist", "config.json") + _, err := ParseConfig(notExistFile) + assert.Error(t, err) + assert.Contains(t, err.Error(), "配置文件不存在") +} diff --git a/design/todo/00000_config_design_impl.md b/design/todo/00000_config_design_impl.md new file mode 100644 index 0000000..7b164dc --- /dev/null +++ b/design/todo/00000_config_design_impl.md @@ -0,0 +1,20 @@ +# 00000: 配置设计实现 + +## 目标 + +- 设计配置文件结构,并实现配置文件解析功能。 +- 配置文件需要支持json和yaml格式 +- 实现完整的单元测试覆盖 + +## 子任务分解 +- [x] 设计配置文件结构 +- [x] 实现配置文件解析功能 +- [x] 设计默认配置数据 +- [x] 实现全局方法获取指定配置项的值 +- [x] 实现JSON格式解析测试 +- [x] 实现YAML格式解析测试 +- [x] 实现默认配置测试 +- [x] 实现错误处理测试 + +## 完成状态 +✅ 已完成 \ No newline at end of file diff --git a/go.mod b/go.mod index 544ec75..37ad9ec 100644 --- a/go.mod +++ b/go.mod @@ -5,3 +5,11 @@ go 1.23 // 可选:如果使用MongoDB官方驱动进行测试 // replace github.com/mongodb/mongo-go-driver => github.com/mongodb/mongo-go-driver/v2 v2.0.0 // require github.com/mongodb/mongo-go-driver/v2 v2.0.0 + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/stretchr/testify v1.10.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..e8d4fcb --- /dev/null +++ b/go.sum @@ -0,0 +1,11 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=