Files
junhong_cmp_fiber/pkg/logger/logger_test.go
2025-11-11 15:53:01 +08:00

519 lines
12 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package logger
import (
"os"
"path/filepath"
"testing"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
// TestInitLoggers 测试日志初始化T026
func TestInitLoggers(t *testing.T) {
// 创建临时目录用于日志文件
tempDir := t.TempDir()
tests := []struct {
name string
level string
development bool
appLogConfig LogRotationConfig
accessLogConfig LogRotationConfig
wantErr bool
validateFunc func(t *testing.T)
}{
{
name: "production mode with info level",
level: "info",
development: false,
appLogConfig: LogRotationConfig{
Filename: filepath.Join(tempDir, "app-prod.log"),
MaxSize: 10,
MaxBackups: 3,
MaxAge: 7,
Compress: true,
},
accessLogConfig: LogRotationConfig{
Filename: filepath.Join(tempDir, "access-prod.log"),
MaxSize: 10,
MaxBackups: 3,
MaxAge: 7,
Compress: true,
},
wantErr: false,
validateFunc: func(t *testing.T) {
if appLogger == nil {
t.Error("appLogger should not be nil")
}
if accessLogger == nil {
t.Error("accessLogger should not be nil")
}
// 写入一条日志以触发文件创建
GetAppLogger().Info("test log creation")
Sync()
// 验证日志文件创建
if _, err := os.Stat(filepath.Join(tempDir, "app-prod.log")); os.IsNotExist(err) {
t.Error("app log file should be created after writing")
}
},
},
{
name: "development mode with debug level",
level: "debug",
development: true,
appLogConfig: LogRotationConfig{
Filename: filepath.Join(tempDir, "app-dev.log"),
MaxSize: 5,
MaxBackups: 2,
MaxAge: 3,
Compress: false,
},
accessLogConfig: LogRotationConfig{
Filename: filepath.Join(tempDir, "access-dev.log"),
MaxSize: 5,
MaxBackups: 2,
MaxAge: 3,
Compress: false,
},
wantErr: false,
validateFunc: func(t *testing.T) {
if appLogger == nil {
t.Error("appLogger should not be nil in dev mode")
}
if accessLogger == nil {
t.Error("accessLogger should not be nil in dev mode")
}
},
},
{
name: "warn level logging",
level: "warn",
development: false,
appLogConfig: LogRotationConfig{
Filename: filepath.Join(tempDir, "app-warn.log"),
MaxSize: 10,
MaxBackups: 3,
MaxAge: 7,
Compress: true,
},
accessLogConfig: LogRotationConfig{
Filename: filepath.Join(tempDir, "access-warn.log"),
MaxSize: 10,
MaxBackups: 3,
MaxAge: 7,
Compress: true,
},
wantErr: false,
validateFunc: func(t *testing.T) {
if appLogger == nil {
t.Error("appLogger should not be nil")
}
},
},
{
name: "error level logging",
level: "error",
development: false,
appLogConfig: LogRotationConfig{
Filename: filepath.Join(tempDir, "app-error.log"),
MaxSize: 10,
MaxBackups: 3,
MaxAge: 7,
Compress: true,
},
accessLogConfig: LogRotationConfig{
Filename: filepath.Join(tempDir, "access-error.log"),
MaxSize: 10,
MaxBackups: 3,
MaxAge: 7,
Compress: true,
},
wantErr: false,
validateFunc: func(t *testing.T) {
if appLogger == nil {
t.Error("appLogger should not be nil")
}
},
},
{
name: "invalid level defaults to info",
level: "invalid",
development: false,
appLogConfig: LogRotationConfig{
Filename: filepath.Join(tempDir, "app-invalid.log"),
MaxSize: 10,
MaxBackups: 3,
MaxAge: 7,
Compress: true,
},
accessLogConfig: LogRotationConfig{
Filename: filepath.Join(tempDir, "access-invalid.log"),
MaxSize: 10,
MaxBackups: 3,
MaxAge: 7,
Compress: true,
},
wantErr: false,
validateFunc: func(t *testing.T) {
if appLogger == nil {
t.Error("appLogger should not be nil even with invalid level")
}
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := InitLoggers(tt.level, tt.development, tt.appLogConfig, tt.accessLogConfig)
if (err != nil) != tt.wantErr {
t.Errorf("InitLoggers() error = %v, wantErr %v", err, tt.wantErr)
return
}
if tt.validateFunc != nil {
tt.validateFunc(t)
}
})
}
}
// TestGetAppLogger 测试获取应用日志记录器T026
func TestGetAppLogger(t *testing.T) {
// 创建临时目录
tempDir := t.TempDir()
tests := []struct {
name string
setupFunc func()
wantNil bool
}{
{
name: "after initialization",
setupFunc: func() {
InitLoggers("info", false,
LogRotationConfig{
Filename: filepath.Join(tempDir, "app-get.log"),
MaxSize: 10,
MaxBackups: 3,
MaxAge: 7,
Compress: true,
},
LogRotationConfig{
Filename: filepath.Join(tempDir, "access-get.log"),
MaxSize: 10,
MaxBackups: 3,
MaxAge: 7,
Compress: true,
},
)
},
wantNil: false,
},
{
name: "before initialization returns nop logger",
setupFunc: func() {
// 重置全局变量
appLogger = nil
},
wantNil: false, // GetAppLogger 应该返回 nop logger不是 nil
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.setupFunc()
logger := GetAppLogger()
if logger == nil {
t.Error("GetAppLogger() should never return nil, should return nop logger instead")
}
})
}
}
// TestGetAccessLogger 测试获取访问日志记录器T028
func TestGetAccessLogger(t *testing.T) {
// 创建临时目录
tempDir := t.TempDir()
tests := []struct {
name string
setupFunc func()
wantNil bool
}{
{
name: "after initialization",
setupFunc: func() {
InitLoggers("info", false,
LogRotationConfig{
Filename: filepath.Join(tempDir, "app-access.log"),
MaxSize: 10,
MaxBackups: 3,
MaxAge: 7,
Compress: true,
},
LogRotationConfig{
Filename: filepath.Join(tempDir, "access-access.log"),
MaxSize: 10,
MaxBackups: 3,
MaxAge: 7,
Compress: true,
},
)
},
wantNil: false,
},
{
name: "before initialization returns nop logger",
setupFunc: func() {
// 重置全局变量
accessLogger = nil
},
wantNil: false, // GetAccessLogger 应该返回 nop logger不是 nil
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.setupFunc()
logger := GetAccessLogger()
if logger == nil {
t.Error("GetAccessLogger() should never return nil, should return nop logger instead")
}
})
}
}
// TestSync 测试日志缓冲区刷新T028
func TestSync(t *testing.T) {
// 创建临时目录
tempDir := t.TempDir()
tests := []struct {
name string
setupFunc func()
wantErr bool
}{
{
name: "sync after initialization",
setupFunc: func() {
InitLoggers("info", false,
LogRotationConfig{
Filename: filepath.Join(tempDir, "app-sync.log"),
MaxSize: 10,
MaxBackups: 3,
MaxAge: 7,
Compress: true,
},
LogRotationConfig{
Filename: filepath.Join(tempDir, "access-sync.log"),
MaxSize: 10,
MaxBackups: 3,
MaxAge: 7,
Compress: true,
},
)
},
wantErr: false,
},
{
name: "sync before initialization",
setupFunc: func() {
appLogger = nil
accessLogger = nil
},
wantErr: false, // 应该优雅地处理 nil 情况
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.setupFunc()
err := Sync()
if (err != nil) != tt.wantErr {
t.Errorf("Sync() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}
// TestParseLevel 测试日志级别解析T026
func TestParseLevel(t *testing.T) {
tests := []struct {
name string
level string
want zapcore.Level
}{
{
name: "debug level",
level: "debug",
want: zapcore.DebugLevel,
},
{
name: "info level",
level: "info",
want: zapcore.InfoLevel,
},
{
name: "warn level",
level: "warn",
want: zapcore.WarnLevel,
},
{
name: "error level",
level: "error",
want: zapcore.ErrorLevel,
},
{
name: "invalid level defaults to info",
level: "invalid",
want: zapcore.InfoLevel,
},
{
name: "empty level defaults to info",
level: "",
want: zapcore.InfoLevel,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := parseLevel(tt.level)
if got != tt.want {
t.Errorf("parseLevel() = %v, want %v", got, tt.want)
}
})
}
}
// TestDualLoggerSystem 测试双日志系统T028
func TestDualLoggerSystem(t *testing.T) {
// 创建临时目录
tempDir := t.TempDir()
appLogFile := filepath.Join(tempDir, "app-dual.log")
accessLogFile := filepath.Join(tempDir, "access-dual.log")
// 初始化双日志系统
err := InitLoggers("info", false,
LogRotationConfig{
Filename: appLogFile,
MaxSize: 10,
MaxBackups: 3,
MaxAge: 7,
Compress: false, // 不压缩以便检查内容
},
LogRotationConfig{
Filename: accessLogFile,
MaxSize: 10,
MaxBackups: 3,
MaxAge: 7,
Compress: false,
},
)
if err != nil {
t.Fatalf("InitLoggers failed: %v", err)
}
// 写入应用日志
appLog := GetAppLogger()
appLog.Info("test app log message",
zap.String("module", "test"),
zap.Int("code", 200),
)
// 写入访问日志
accessLog := GetAccessLogger()
accessLog.Info("test access log message",
zap.String("method", "GET"),
zap.String("path", "/api/test"),
zap.Int("status", 200),
zap.Duration("latency", 100),
)
// 刷新缓冲区
if err := Sync(); err != nil {
t.Fatalf("Sync failed: %v", err)
}
// 验证应用日志文件存在并有内容
appLogContent, err := os.ReadFile(appLogFile)
if err != nil {
t.Fatalf("Failed to read app log file: %v", err)
}
if len(appLogContent) == 0 {
t.Error("App log file should not be empty")
}
// 验证访问日志文件存在并有内容
accessLogContent, err := os.ReadFile(accessLogFile)
if err != nil {
t.Fatalf("Failed to read access log file: %v", err)
}
if len(accessLogContent) == 0 {
t.Error("Access log file should not be empty")
}
// 验证两个日志文件是独立的
if string(appLogContent) == string(accessLogContent) {
t.Error("App log and access log should have different content")
}
}
// TestLoggerReinitialization 测试日志重新初始化T026
func TestLoggerReinitialization(t *testing.T) {
// 创建临时目录
tempDir := t.TempDir()
// 第一次初始化
err := InitLoggers("info", false,
LogRotationConfig{
Filename: filepath.Join(tempDir, "app-reinit1.log"),
MaxSize: 10,
MaxBackups: 3,
MaxAge: 7,
Compress: true,
},
LogRotationConfig{
Filename: filepath.Join(tempDir, "access-reinit1.log"),
MaxSize: 10,
MaxBackups: 3,
MaxAge: 7,
Compress: true,
},
)
if err != nil {
t.Fatalf("First InitLoggers failed: %v", err)
}
firstAppLogger := GetAppLogger()
// 第二次初始化(重新初始化)
err = InitLoggers("debug", true,
LogRotationConfig{
Filename: filepath.Join(tempDir, "app-reinit2.log"),
MaxSize: 5,
MaxBackups: 2,
MaxAge: 3,
Compress: false,
},
LogRotationConfig{
Filename: filepath.Join(tempDir, "access-reinit2.log"),
MaxSize: 5,
MaxBackups: 2,
MaxAge: 3,
Compress: false,
},
)
if err != nil {
t.Fatalf("Second InitLoggers failed: %v", err)
}
secondAppLogger := GetAppLogger()
// 验证重新初始化后日志记录器已更新
if firstAppLogger == secondAppLogger {
t.Error("Logger should be replaced after reinitialization")
}
}