Some checks failed
CI/CD Pipeline / Test (push) Failing after 22m19s
CI/CD Pipeline / Security Scan (push) Failing after 5m57s
CI/CD Pipeline / Build (amd64, darwin) (push) Has been skipped
CI/CD Pipeline / Build (amd64, linux) (push) Has been skipped
CI/CD Pipeline / Build (amd64, windows) (push) Has been skipped
CI/CD Pipeline / Build (arm64, darwin) (push) Has been skipped
CI/CD Pipeline / Build (arm64, linux) (push) Has been skipped
CI/CD Pipeline / Build Docker Image (push) Has been skipped
CI/CD Pipeline / Create Release (push) Has been skipped
450 lines
12 KiB
Go
450 lines
12 KiB
Go
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")
|
|
})
|
|
})
|
|
} |