Files
pig-farm-controller/internal/logs/logs_test.go
huang cf011f18f2 1. 重写logs
2. logs增加单测
3. task更换新的log实例
4. 配置文件增加日志相关配置
2025-09-11 20:37:29 +08:00

129 lines
4.1 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 logs_test
import (
"bytes"
"context"
"errors"
"strings"
"testing"
"time"
"git.huangwc.com/pig/pig-farm-controller/internal/config"
"git.huangwc.com/pig/pig-farm-controller/internal/logs"
"github.com/stretchr/testify/assert"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
// captureOutput 是一个辅助函数,用于捕获 logger 的输出到内存缓冲区
func captureOutput(cfg config.LogConfig) (*logs.Logger, *bytes.Buffer) {
var buf bytes.Buffer
// 使用一个简单的 Console Encoder 进行测试,方便断言字符串
encoderConfig := zap.NewDevelopmentEncoderConfig()
encoderConfig.EncodeTime = nil // 忽略时间,避免测试结果不一致
encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
encoderConfig.EncodeCaller = nil // 忽略调用者信息
encoder := zapcore.NewConsoleEncoder(encoderConfig)
writer := zapcore.AddSync(&buf)
level := zap.NewAtomicLevel()
_ = level.UnmarshalText([]byte(cfg.Level))
core := zapcore.NewCore(encoder, writer, level)
// 在测试中我们直接操作 zap Logger而不是通过封装的 NewLogger以注入内存 writer
zapLogger := zap.New(core)
logger := &logs.Logger{SugaredLogger: zapLogger.Sugar()}
return logger, &buf
}
func TestNewLogger(t *testing.T) {
t.Run("Constructor does not panic", func(t *testing.T) {
// 测试 Console 格式
cfgConsole := config.LogConfig{Level: "info", Format: "console"}
assert.NotPanics(t, func() { logs.NewLogger(cfgConsole) })
// 测试 JSON 格式
cfgJSON := config.LogConfig{Level: "info", Format: "json"}
assert.NotPanics(t, func() { logs.NewLogger(cfgJSON) })
// 测试文件日志启用
// 不实际写入文件,只确保构造函数能正常运行
cfgFile := config.LogConfig{
Level: "info",
EnableFile: true,
FilePath: "test.log",
}
assert.NotPanics(t, func() { logs.NewLogger(cfgFile) })
})
}
func TestLogger_Write_ForGin(t *testing.T) {
logger, buf := captureOutput(config.LogConfig{Level: "info"})
ginLog := "[GIN-debug] Listening and serving HTTP on :8080\n"
_, err := logger.Write([]byte(ginLog))
assert.NoError(t, err)
output := buf.String()
// logger.Write 会将 gin 的日志转为 info 级别
assert.Contains(t, output, "INFO")
assert.Contains(t, output, strings.TrimSpace(ginLog))
}
func TestGormLogger(t *testing.T) {
logger, buf := captureOutput(config.LogConfig{Level: "debug"}) // 设置为 debug 以捕获所有级别
gormLogger := logs.NewGormLogger(logger)
// 模拟 GORM 的 Trace 调用参数
ctx := context.Background()
sql := "SELECT * FROM users WHERE id = 1"
rows := int64(1)
fc := func() (string, int64) {
return sql, rows
}
t.Run("Slow Query", func(t *testing.T) {
buf.Reset()
// 模拟一个耗时超过 200ms 的查询
begin := time.Now().Add(-300 * time.Millisecond)
gormLogger.Trace(ctx, begin, fc, nil)
output := buf.String()
assert.Contains(t, output, "WARN", "应包含 WARN 级别")
assert.Contains(t, output, "[GORM] slow query", "应包含慢查询信息")
// 修复:不再检查严格的 JSON 格式,只检查关键内容
assert.Contains(t, output, "SELECT * FROM users WHERE id = 1", "应包含 SQL 语句")
})
t.Run("Error Query", func(t *testing.T) {
buf.Reset()
queryError := errors.New("syntax error")
gormLogger.Trace(ctx, time.Now(), fc, queryError)
output := buf.String()
assert.Contains(t, output, "ERROR")
assert.Contains(t, output, "[GORM] error: syntax error")
})
t.Run("Record Not Found Error is Skipped", func(t *testing.T) {
buf.Reset()
queryError := errors.New("record not found") // 模拟 GORM 的 RecordNotFound 错误
gormLogger.Trace(ctx, time.Now(), fc, queryError)
// 在修复 logs.go 中的 bug 后,这里应该为空
assert.Empty(t, buf.String(), "开启 SkipErrRecordNotFound 后record not found 错误不应产生任何日志")
})
t.Run("Normal Query", func(t *testing.T) {
buf.Reset()
// 模拟一个快速查询
gormLogger.Trace(ctx, time.Now(), fc, nil)
output := buf.String()
assert.Contains(t, output, "DEBUG") // 正常查询是 Debug 级别
assert.Contains(t, output, "[GORM] trace")
})
}