package unit import ( "os" "path/filepath" "testing" "time" "github.com/smartystreets/goconvey/convey" "github.com/subconverter-go/internal/config" ) // TestConfigManagerCreation 测试配置管理器创建 func TestConfigManagerCreation(t *testing.T) { convey.Convey("配置管理器创建测试", t, func() { convey.Convey("创建默认配置管理器", func() { manager, err := config.NewConfigManager("") convey.So(err, convey.ShouldBeNil) convey.So(manager, convey.ShouldNotBeNil) // 验证默认配置 cfg := manager.GetConfig() convey.So(cfg, convey.ShouldNotBeNil) convey.So(cfg.Server.Host, convey.ShouldEqual, "0.0.0.0") convey.So(cfg.Server.Port, convey.ShouldEqual, 25500) convey.So(cfg.Logging.Level, convey.ShouldEqual, "info") convey.So(cfg.Conversion.DefaultTarget, convey.ShouldEqual, "clash") // 清理 manager.Close() }) convey.Convey("创建带配置文件的配置管理器", func() { // 创建临时配置文件 tempDir := t.TempDir() configFile := filepath.Join(tempDir, "test.yaml") configContent := ` server: host: "127.0.0.1" port: 8080 logging: level: "debug" format: "json" security: access_tokens: ["test-token"] ` err := os.WriteFile(configFile, []byte(configContent), 0644) convey.So(err, convey.ShouldBeNil) // 创建配置管理器 manager, err := config.NewConfigManager(configFile) convey.So(err, convey.ShouldBeNil) convey.So(manager, convey.ShouldNotBeNil) // 验证配置 cfg := manager.GetConfig() convey.So(cfg.Server.Host, convey.ShouldEqual, "127.0.0.1") convey.So(cfg.Server.Port, convey.ShouldEqual, 8080) convey.So(cfg.Logging.Level, convey.ShouldEqual, "debug") convey.So(len(cfg.Security.AccessTokens), convey.ShouldEqual, 1) convey.So(cfg.Security.AccessTokens[0], convey.ShouldEqual, "test-token") // 清理 manager.Close() }) }) } // TestConfigManagerDefaults 测试默认配置 func TestConfigManagerDefaults(t *testing.T) { convey.Convey("默认配置测试", t, func() { manager, err := config.NewConfigManager("") convey.So(err, convey.ShouldBeNil) defer manager.Close() cfg := manager.GetConfig() convey.Convey("服务器默认配置", func() { convey.So(cfg.Server.Host, convey.ShouldEqual, "0.0.0.0") convey.So(cfg.Server.Port, convey.ShouldEqual, 25500) convey.So(cfg.Server.ReadTimeout, convey.ShouldEqual, 30) convey.So(cfg.Server.WriteTimeout, convey.ShouldEqual, 30) convey.So(cfg.Server.MaxRequestSize, convey.ShouldEqual, 10*1024*1024) }) convey.Convey("日志默认配置", func() { convey.So(cfg.Logging.Level, convey.ShouldEqual, "info") convey.So(cfg.Logging.Format, convey.ShouldEqual, "json") convey.So(cfg.Logging.Output, convey.ShouldEqual, "stdout") }) convey.Convey("安全默认配置", func() { convey.So(len(cfg.Security.AccessTokens), convey.ShouldEqual, 0) convey.So(len(cfg.Security.CorsOrigins), convey.ShouldEqual, 1) convey.So(cfg.Security.CorsOrigins[0], convey.ShouldEqual, "*") convey.So(cfg.Security.RateLimit, convey.ShouldEqual, 0) convey.So(cfg.Security.Timeout, convey.ShouldEqual, 60) }) convey.Convey("转换默认配置", func() { convey.So(cfg.Conversion.DefaultTarget, convey.ShouldEqual, "clash") convey.So(cfg.Conversion.DefaultEmoji, convey.ShouldBeFalse) convey.So(cfg.Conversion.DefaultUDP, convey.ShouldBeFalse) convey.So(cfg.Conversion.MaxNodes, convey.ShouldEqual, 0) convey.So(cfg.Conversion.CacheTimeout, convey.ShouldEqual, 60) }) }) } // TestConfigManagerEnvironmentVariables 测试环境变量配置 func TestConfigManagerEnvironmentVariables(t *testing.T) { convey.Convey("环境变量配置测试", t, func() { // 设置环境变量 os.Setenv("SUBCONVERTER_HOST", "192.168.1.100") os.Setenv("SUBCONVERTER_PORT", "9000") os.Setenv("SUBCONVERTER_LOG_LEVEL", "debug") os.Setenv("SUBCONVERTER_ACCESS_TOKENS", "test-token") defer func() { os.Unsetenv("SUBCONVERTER_HOST") os.Unsetenv("SUBCONVERTER_PORT") os.Unsetenv("SUBCONVERTER_LOG_LEVEL") os.Unsetenv("SUBCONVERTER_ACCESS_TOKENS") }() manager, err := config.NewConfigManager("") convey.So(err, convey.ShouldBeNil) defer manager.Close() cfg := manager.GetConfig() convey.So(cfg.Server.Host, convey.ShouldEqual, "192.168.1.100") convey.So(cfg.Server.Port, convey.ShouldEqual, 9000) convey.So(cfg.Logging.Level, convey.ShouldEqual, "debug") convey.So(len(cfg.Security.AccessTokens), convey.ShouldEqual, 1) convey.So(cfg.Security.AccessTokens[0], convey.ShouldEqual, "test-token") }) } // TestConfigManagerUpdateConfig 测试配置更新 func TestConfigManagerUpdateConfig(t *testing.T) { convey.Convey("配置更新测试", t, func() { manager, err := config.NewConfigManager("") convey.So(err, convey.ShouldBeNil) defer manager.Close() convey.Convey("更新配置", func() { newConfig := manager.GetConfig().Clone() newConfig.Server.Host = "127.0.0.1" newConfig.Server.Port = 8080 newConfig.Logging.Level = "debug" err := manager.UpdateConfig(newConfig) convey.So(err, convey.ShouldBeNil) // 验证配置已更新 updatedConfig := manager.GetConfig() convey.So(updatedConfig.Server.Host, convey.ShouldEqual, "127.0.0.1") convey.So(updatedConfig.Server.Port, convey.ShouldEqual, 8080) convey.So(updatedConfig.Logging.Level, convey.ShouldEqual, "debug") }) convey.Convey("无效配置处理", func() { invalidConfig := manager.GetConfig().Clone() invalidConfig.Server.Port = -1 // 无效端口 err := manager.UpdateConfig(invalidConfig) convey.So(err, convey.ShouldNotBeNil) convey.So(err.Error(), convey.ShouldContain, "invalid port") }) }) } // TestConfigManagerPartialAccess 测试配置部分访问 func TestConfigManagerPartialAccess(t *testing.T) { convey.Convey("配置部分访问测试", t, func() { manager, err := config.NewConfigManager("") convey.So(err, convey.ShouldBeNil) defer manager.Close() convey.Convey("获取服务器配置", func() { serverConfig := manager.GetServerConfig() convey.So(serverConfig, convey.ShouldNotBeNil) convey.So(serverConfig.Host, convey.ShouldEqual, "0.0.0.0") convey.So(serverConfig.Port, convey.ShouldEqual, 25500) // 修改返回的配置不应该影响原始配置 serverConfig.Host = "modified" originalConfig := manager.GetConfig() convey.So(originalConfig.Server.Host, convey.ShouldEqual, "0.0.0.0") }) convey.Convey("获取日志配置", func() { loggingConfig := manager.GetLoggingConfig() convey.So(loggingConfig, convey.ShouldNotBeNil) convey.So(loggingConfig.Level, convey.ShouldEqual, "info") convey.So(loggingConfig.Format, convey.ShouldEqual, "json") }) convey.Convey("获取安全配置", func() { securityConfig := manager.GetSecurityConfig() convey.So(securityConfig, convey.ShouldNotBeNil) convey.So(len(securityConfig.AccessTokens), convey.ShouldEqual, 0) convey.So(securityConfig.RateLimit, convey.ShouldEqual, 0) }) convey.Convey("获取转换配置", func() { conversionConfig := manager.GetConversionConfig() convey.So(conversionConfig, convey.ShouldNotBeNil) convey.So(conversionConfig.DefaultTarget, convey.ShouldEqual, "clash") convey.So(conversionConfig.DefaultEmoji, convey.ShouldBeFalse) }) }) } // TestConfigManagerSaveConfig 测试配置保存 func TestConfigManagerSaveConfig(t *testing.T) { convey.Convey("配置保存测试", t, func() { tempDir := t.TempDir() configFile := filepath.Join(tempDir, "test.yaml") // 创建配置管理器 manager, err := config.NewConfigManager(configFile) convey.So(err, convey.ShouldBeNil) defer manager.Close() convey.Convey("保存配置到文件", func() { // 修改配置 newConfig := manager.GetConfig().Clone() newConfig.Server.Host = "127.0.0.1" newConfig.Server.Port = 9090 newConfig.Logging.Level = "debug" err := manager.UpdateConfig(newConfig) convey.So(err, convey.ShouldBeNil) // 检查文件是否存在 _, err = os.Stat(configFile) convey.So(err, convey.ShouldBeNil) // 从文件重新加载配置验证 newManager, err := config.NewConfigManager(configFile) convey.So(err, convey.ShouldBeNil) defer newManager.Close() loadedConfig := newManager.GetConfig() convey.So(loadedConfig.Server.Host, convey.ShouldEqual, "127.0.0.1") convey.So(loadedConfig.Server.Port, convey.ShouldEqual, 9090) convey.So(loadedConfig.Logging.Level, convey.ShouldEqual, "debug") }) }) } // TestConfigManagerBasicAccess 测试基本配置访问 func TestConfigManagerBasicAccess(t *testing.T) { convey.Convey("基本配置访问测试", t, func() { manager, err := config.NewConfigManager("") convey.So(err, convey.ShouldBeNil) defer manager.Close() convey.Convey("GetString方法", func() { host := manager.GetString("server.host") convey.So(host, convey.ShouldEqual, "0.0.0.0") level := manager.GetString("logging.level") convey.So(level, convey.ShouldEqual, "info") }) convey.Convey("GetInt方法", func() { port := manager.GetInt("server.port") convey.So(port, convey.ShouldEqual, 25500) timeout := manager.GetInt("conversion.timeout_seconds") convey.So(timeout, convey.ShouldEqual, 30) }) convey.Convey("GetBool方法", func() { cors := manager.GetBool("server.enable_cors") convey.So(cors, convey.ShouldBeTrue) auth := manager.GetBool("security.enable_auth") convey.So(auth, convey.ShouldBeFalse) }) convey.Convey("GetStringSlice方法", func() { formats := manager.GetStringSlice("conversion.supported_formats") convey.So(formats, convey.ShouldNotBeNil) convey.So(len(formats) > 0, convey.ShouldBeTrue) convey.So(formats, convey.ShouldContain, "clash") }) convey.Convey("IsSet方法", func() { convey.So(manager.IsSet("server.host"), convey.ShouldBeTrue) convey.So(manager.IsSet("nonexistent.key"), convey.ShouldBeFalse) }) convey.Convey("Set方法", func() { manager.Set("test.key", "test_value") value := manager.GetString("test.key") convey.So(value, convey.ShouldEqual, "test_value") }) }) } // TestConfigManagerWatchConfig 测试配置监听 func TestConfigManagerWatchConfig(t *testing.T) { convey.Convey("配置监听测试", t, func() { tempDir := t.TempDir() configFile := filepath.Join(tempDir, "test.yaml") // 创建初始配置文件 configContent := ` server: host: "0.0.0.0" port: 25500 logging: level: "info" ` err := os.WriteFile(configFile, []byte(configContent), 0644) convey.So(err, convey.ShouldBeNil) // 创建配置管理器 manager, err := config.NewConfigManager(configFile) convey.So(err, convey.ShouldBeNil) defer manager.Close() configChanged := make(chan bool, 1) // 开始监听配置变化 manager.WatchConfig(func(cfg *config.Configuration) { configChanged <- true }) convey.Convey("监听配置文件变化", func() { // 修改配置文件 newConfigContent := ` server: host: "127.0.0.1" port: 8080 logging: level: "debug" ` err := os.WriteFile(configFile, []byte(newConfigContent), 0644) convey.So(err, convey.ShouldBeNil) // 等待配置变化事件 select { case changed := <-configChanged: convey.So(changed, convey.ShouldBeTrue) // 验证配置已更新 updatedConfig := manager.GetConfig() convey.So(updatedConfig.Server.Host, convey.ShouldEqual, "127.0.0.1") convey.So(updatedConfig.Server.Port, convey.ShouldEqual, 8080) convey.So(updatedConfig.Logging.Level, convey.ShouldEqual, "debug") case <-time.After(2 * time.Second): convey.So(false, convey.ShouldBeTrue) // 超时失败 } }) }) }