package unit import ( "fmt" "io/ioutil" "os" "path/filepath" "testing" "time" "github.com/smartystreets/goconvey/convey" "github.com/subconverter-go/internal/logging" ) // TestLoggerCreation 测试日志记录器的创建 func TestLoggerCreation(t *testing.T) { convey.Convey("日志记录器创建测试", t, func() { convey.Convey("创建默认日志记录器", func() { logger, err := logging.NewDefaultLogger() convey.So(err, convey.ShouldBeNil) convey.So(logger, convey.ShouldNotBeNil) config := logger.GetConfig() convey.So(config, convey.ShouldNotBeNil) convey.So(config.Level, convey.ShouldEqual, "info") convey.So(config.Format, convey.ShouldEqual, "text") convey.So(config.Output, convey.ShouldEqual, "stdout") }) convey.Convey("创建自定义配置日志记录器", func() { config := &logging.LoggingConfig{ Level: "debug", Format: "json", Output: "stdout", ReportCaller: true, EnableColor: false, } logger, err := logging.NewLogger(config) convey.So(err, convey.ShouldBeNil) convey.So(logger, convey.ShouldNotBeNil) actualConfig := logger.GetConfig() convey.So(actualConfig.Level, convey.ShouldEqual, "debug") convey.So(actualConfig.Format, convey.ShouldEqual, "json") convey.So(actualConfig.ReportCaller, convey.ShouldBeTrue) }) convey.Convey("创建空配置日志记录器", func() { logger, err := logging.NewLogger(nil) convey.So(err, convey.ShouldBeNil) convey.So(logger, convey.ShouldNotBeNil) config := logger.GetConfig() convey.So(config, convey.ShouldNotBeNil) convey.So(config.Level, convey.ShouldEqual, "info") // 默认值 }) }) } // TestLoggerConfiguration 测试日志配置功能 func TestLoggerConfiguration(t *testing.T) { convey.Convey("日志配置测试", t, func() { convey.Convey("无效配置处理", func() { config := &logging.LoggingConfig{ Level: "invalid_level", } logger, err := logging.NewLogger(config) convey.So(err, convey.ShouldNotBeNil) convey.So(logger, convey.ShouldBeNil) convey.So(err.Error(), convey.ShouldContain, "invalid log level") }) convey.Convey("动态更新配置", func() { logger, err := logging.NewDefaultLogger() convey.So(err, convey.ShouldBeNil) newConfig := &logging.LoggingConfig{ Level: "debug", Format: "json", Output: "stdout", EnableColor: false, } err = logger.UpdateConfig(newConfig) convey.So(err, convey.ShouldBeNil) updatedConfig := logger.GetConfig() convey.So(updatedConfig.Level, convey.ShouldEqual, "debug") convey.So(updatedConfig.Format, convey.ShouldEqual, "json") }) }) } // TestLoggerOutput 测试日志输出功能 func TestLoggerOutput(t *testing.T) { convey.Convey("日志输出测试", t, func() { convey.Convey("标准输出测试", func() { // 重定向标准输出以捕获日志 oldStdout := os.Stdout r, w, _ := os.Pipe() os.Stdout = w logger, err := logging.NewDefaultLogger() convey.So(err, convey.ShouldBeNil) logger.Info("Test message") // 恢复标准输出 w.Close() os.Stdout = oldStdout // 读取捕获的输出 output, _ := ioutil.ReadAll(r) convey.So(len(output) > 0, convey.ShouldBeTrue) convey.So(string(output), convey.ShouldContain, "Test message") }) convey.Convey("文件输出测试", func() { tempDir := t.TempDir() logFile := filepath.Join(tempDir, "test.log") config := &logging.LoggingConfig{ Level: "info", Format: "text", Output: "file", FilePath: logFile, } logger, err := logging.NewLogger(config) convey.So(err, convey.ShouldBeNil) logger.Info("File test message") // 等待日志写入 time.Sleep(10 * time.Millisecond) // 读取日志文件 content, err := ioutil.ReadFile(logFile) convey.So(err, convey.ShouldBeNil) convey.So(string(content), convey.ShouldContain, "File test message") // 清理 logger.Close() }) }) } // TestLoggerLevels 测试不同日志级别 func TestLoggerLevels(t *testing.T) { convey.Convey("日志级别测试", t, func() { convey.Convey("Debug级别日志", func() { config := &logging.LoggingConfig{ Level: "debug", Format: "text", Output: "stdout", } logger, err := logging.NewLogger(config) convey.So(err, convey.ShouldBeNil) // 重定向输出 oldStdout := os.Stdout r, w, _ := os.Pipe() os.Stdout = w logger.Debug("Debug message") logger.Info("Info message") w.Close() os.Stdout = oldStdout output, _ := ioutil.ReadAll(r) outputStr := string(output) convey.So(outputStr, convey.ShouldContain, "Debug message") convey.So(outputStr, convey.ShouldContain, "Info message") }) convey.Convey("Info级别日志", func() { config := &logging.LoggingConfig{ Level: "info", Format: "text", Output: "stdout", } logger, err := logging.NewLogger(config) convey.So(err, convey.ShouldBeNil) // 重定向输出 oldStdout := os.Stdout r, w, _ := os.Pipe() os.Stdout = w logger.Debug("Debug message") // 不应该输出 logger.Info("Info message") // 应该输出 w.Close() os.Stdout = oldStdout output, _ := ioutil.ReadAll(r) outputStr := string(output) convey.So(outputStr, convey.ShouldNotContain, "Debug message") convey.So(outputStr, convey.ShouldContain, "Info message") }) }) } // TestLoggerFormats 测试不同日志格式 func TestLoggerFormats(t *testing.T) { convey.Convey("日志格式测试", t, func() { convey.Convey("Text格式", func() { config := &logging.LoggingConfig{ Level: "info", Format: "text", Output: "stdout", } logger, err := logging.NewLogger(config) convey.So(err, convey.ShouldBeNil) // 重定向输出 oldStdout := os.Stdout r, w, _ := os.Pipe() os.Stdout = w logger.Info("Text format test") w.Close() os.Stdout = oldStdout output, _ := ioutil.ReadAll(r) outputStr := string(output) convey.So(outputStr, convey.ShouldContain, "Text format test") convey.So(outputStr, convey.ShouldContain, "level=info") // text格式特征 }) convey.Convey("JSON格式", func() { config := &logging.LoggingConfig{ Level: "info", Format: "json", Output: "stdout", } logger, err := logging.NewLogger(config) convey.So(err, convey.ShouldBeNil) // 重定向输出 oldStdout := os.Stdout r, w, _ := os.Pipe() os.Stdout = w logger.Info("JSON format test") w.Close() os.Stdout = oldStdout output, _ := ioutil.ReadAll(r) outputStr := string(output) convey.So(outputStr, convey.ShouldContain, "JSON format test") convey.So(outputStr, convey.ShouldContain, `"level":"info"`) // JSON格式特征 }) }) } // TestLoggerWithFields 测试带字段的日志记录 func TestLoggerWithFields(t *testing.T) { convey.Convey("带字段日志测试", t, func() { logger, err := logging.NewDefaultLogger() convey.So(err, convey.ShouldBeNil) // 重定向输出 oldStdout := os.Stdout r, w, _ := os.Pipe() os.Stdout = w fields := map[string]interface{}{ "user_id": "123", "request_id": "abc-def", "operation": "test", } logger.WithFields(fields).Info("Message with fields") w.Close() os.Stdout = oldStdout output, _ := ioutil.ReadAll(r) outputStr := string(output) convey.So(outputStr, convey.ShouldContain, "Message with fields") convey.So(outputStr, convey.ShouldContain, "user_id=123") convey.So(outputStr, convey.ShouldContain, "request_id=abc-def") convey.So(outputStr, convey.ShouldContain, "operation=test") }) } // TestLoggerLogEntry 测试使用LogEntry记录日志 func TestLoggerLogEntry(t *testing.T) { convey.Convey("LogEntry日志测试", t, func() { logger, err := logging.NewDefaultLogger() convey.So(err, convey.ShouldBeNil) // 重定向输出 oldStdout := os.Stdout r, w, _ := os.Pipe() os.Stdout = w entry := logging.NewLogEntryWithLocation(logging.INFO, "Test with LogEntry"). WithField("test_field", "test_value"). WithError(fmt.Errorf("test error")). WithRequest("GET", "/test", 200). WithDuration(100 * time.Millisecond) err = logger.Log(entry) convey.So(err, convey.ShouldBeNil) w.Close() os.Stdout = oldStdout output, _ := ioutil.ReadAll(r) outputStr := string(output) convey.So(outputStr, convey.ShouldContain, "Test with LogEntry") convey.So(outputStr, convey.ShouldContain, "test_field=test_value") convey.So(outputStr, convey.ShouldContain, "test error") convey.So(outputStr, convey.ShouldContain, "method=GET") convey.So(outputStr, convey.ShouldContain, "path=/test") convey.So(outputStr, convey.ShouldContain, "status_code=200") convey.So(outputStr, convey.ShouldContain, "duration_ms=100") }) } // TestLoggerSpecialMethods 测试特殊日志方法 func TestLoggerSpecialMethods(t *testing.T) { convey.Convey("特殊日志方法测试", t, func() { logger, err := logging.NewDefaultLogger() convey.So(err, convey.ShouldBeNil) // 重定向输出 oldStdout := os.Stdout r, w, _ := os.Pipe() os.Stdout = w // 测试操作日志 endOp := logger.LogOperation("test_operation", map[string]interface{}{"param": "value"}) time.Sleep(10 * time.Millisecond) // 模拟操作耗时 endOp() // 测试HTTP请求日志 logger.LogHTTPRequest("GET", "/api/test", 200, 50*time.Millisecond, map[string]interface{}{"user_id": "123"}) // 测试转换日志 logger.LogConversion("clash", "https://example.com", 10, 100*time.Millisecond, true) // 测试代理验证日志 logger.LogProxyValidation("test-proxy", "ss", true, 50, nil) w.Close() os.Stdout = oldStdout output, _ := ioutil.ReadAll(r) outputStr := string(output) convey.So(outputStr, convey.ShouldContain, "Operation started") convey.So(outputStr, convey.ShouldContain, "Operation completed") convey.So(outputStr, convey.ShouldContain, "test_operation") convey.So(outputStr, convey.ShouldContain, "GET /api/test - 200") convey.So(outputStr, convey.ShouldContain, "Conversion") convey.So(outputStr, convey.ShouldContain, "Proxy validation") }) } // TestGlobalLogger 测试全局日志记录器 func TestGlobalLogger(t *testing.T) { convey.Convey("全局日志记录器测试", t, func() { convey.Convey("获取默认日志记录器", func() { logger := logging.GetDefaultLogger() convey.So(logger, convey.ShouldNotBeNil) // 重定向输出 oldStdout := os.Stdout r, w, _ := os.Pipe() os.Stdout = w logging.Info("Global logger test") w.Close() os.Stdout = oldStdout output, _ := ioutil.ReadAll(r) convey.So(len(output) > 0, convey.ShouldBeTrue) }) convey.Convey("设置自定义全局日志记录器", func() { customLogger, err := logging.NewDefaultLogger() convey.So(err, convey.ShouldBeNil) logging.SetDefaultLogger(customLogger) // 验证设置成功 currentLogger := logging.GetDefaultLogger() convey.So(currentLogger, convey.ShouldEqual, customLogger) }) }) } // TestLoggerUtilities 测试日志工具函数 func TestLoggerUtilities(t *testing.T) { convey.Convey("日志工具函数测试", t, func() { convey.Convey("获取调用者信息", func() { file, line, funcName := logging.GetCallerInfo() convey.So(file, convey.ShouldNotBeEmpty) convey.So(line > 0, convey.ShouldBeTrue) convey.So(funcName, convey.ShouldNotBeEmpty) }) }) } // TestLoggerErrorHandling 测试错误处理 func TestLoggerErrorHandling(t *testing.T) { convey.Convey("日志错误处理测试", t, func() { convey.Convey("记录错误日志", func() { logger, err := logging.NewDefaultLogger() convey.So(err, convey.ShouldBeNil) // 重定向输出 oldStdout := os.Stdout r, w, _ := os.Pipe() os.Stdout = w testErr := fmt.Errorf("test error occurred") logger.WithError(testErr).Error("Error message") w.Close() os.Stdout = oldStdout output, _ := ioutil.ReadAll(r) outputStr := string(output) convey.So(outputStr, convey.ShouldContain, "Error message") convey.So(outputStr, convey.ShouldContain, "test error occurred") }) convey.Convey("无效LogEntry处理", func() { logger, err := logging.NewDefaultLogger() convey.So(err, convey.ShouldBeNil) err = logger.Log(nil) convey.So(err, convey.ShouldNotBeNil) convey.So(err.Error(), convey.ShouldContain, "cannot be nil") }) }) }