first commit
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

This commit is contained in:
Rogee
2025-09-28 10:05:07 +08:00
commit 7fcabe0225
481 changed files with 125127 additions and 0 deletions

450
tests/unit/test_logger.go Normal file
View File

@@ -0,0 +1,450 @@
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")
})
})
}