Files
go-simple-graphql/logging/logger_test.go
T
2025-05-23 12:59:04 +01:00

400 lines
10 KiB
Go

package libpack_logger
import (
"bytes"
"fmt"
"testing"
"time"
"github.com/goccy/go-json"
"github.com/goccy/go-reflect"
)
func (suite *LoggerTestSuite) Test_LogMessageString() {
msg := &LogMessage{
Message: "test message",
}
assert.Equal("test message", msg.String())
}
func callLoggerMethod(logger *Logger, methodName string, message *LogMessage) {
// Get the method by name using reflection
method := reflect.ValueOf(logger).MethodByName(methodName)
if method.IsValid() {
// Call the method with the message as an argument
method.Call([]reflect.Value{reflect.ValueOf(message)})
} else {
fmt.Printf("Method %s does not exist on Logger\n", methodName)
}
}
func (suite *LoggerTestSuite) Test_LogsLevelsPrint() {
output := &bytes.Buffer{}
logger := New().SetOutput(output)
tests := []struct {
pairs map[string]any
name string
method string
message string
loggerMinLevel int
messageLogLevel int
wantOutput bool
}{
{
name: "Log: Debug, Level: Debug - no pairs",
method: "Debug",
loggerMinLevel: LEVEL_DEBUG,
messageLogLevel: LEVEL_DEBUG,
message: "debug message",
wantOutput: true,
},
{
name: "Log: Info, Level: Info - one pair",
method: "Info",
loggerMinLevel: LEVEL_INFO,
messageLogLevel: LEVEL_INFO,
message: "info message",
pairs: map[string]any{
"key": "value",
},
wantOutput: true,
},
{
name: "Log: Info, Level: Warn - with pairs",
method: "Info",
loggerMinLevel: LEVEL_WARN,
messageLogLevel: LEVEL_INFO,
message: "warn message",
pairs: map[string]any{
"key1": "value1",
"key2": "value2",
},
wantOutput: false,
},
{
name: "Log: Warn, Level: Info - with 500 pairs",
method: "Warn",
loggerMinLevel: LEVEL_INFO,
messageLogLevel: LEVEL_WARN,
message: "warn message with 500 pairs",
pairs: func() map[string]any {
pairs := make(map[string]any)
for i := 0; i < 500; i++ {
pairs[fmt.Sprintf("key%d", i)] = fmt.Sprintf("value%d", i)
}
return pairs
}(),
wantOutput: true,
},
}
for _, tt := range tests {
suite.T().Run(tt.name, func(t *testing.T) {
msg := &LogMessage{
Message: tt.message,
Pairs: tt.pairs,
}
output.Reset()
// Set logger's minimum log level
logger.SetMinLogLevel(tt.loggerMinLevel)
fmt.Println("Logger min log level:", LevelNames[logger.minLogLevel])
// Call the logging method
callLoggerMethod(logger, tt.method, msg)
logOutput := output.String()
fmt.Println("Output:", logOutput)
if tt.wantOutput {
var loggedMessage map[string]any
err := json.Unmarshal([]byte(logOutput), &loggedMessage)
if err != nil {
t.Fatalf("Error unmarshalling log message: %v\nLog output: %s", err, logOutput)
}
if !containsLogMessage(logOutput, tt.message) {
t.Errorf("Expected log message %q, but got %q", tt.message, logOutput)
}
assert.Equal(LevelNames[tt.messageLogLevel], loggedMessage["level"])
if tt.pairs != nil {
for k, v := range tt.pairs {
assert.Equal(v, loggedMessage[k])
}
}
} else {
assert.Equal("", logOutput)
}
})
}
}
func containsLogMessage(logOutput, expectedMessage string) bool {
return bytes.Contains([]byte(logOutput), []byte(expectedMessage))
}
func (suite *LoggerTestSuite) Test_SetFormat() {
logger := New().SetFormat(time.RFC3339Nano)
assert.Equal(time.RFC3339Nano, logger.format)
}
func (suite *LoggerTestSuite) Test_SetMinLogLevel() {
logger := New().SetMinLogLevel(LEVEL_DEBUG)
assert.Equal(LEVEL_DEBUG, logger.minLogLevel)
}
func (suite *LoggerTestSuite) Test_ShouldLog() {
logger := New().SetMinLogLevel(LEVEL_WARN)
assert.True(logger.shouldLog(LEVEL_WARN))
assert.True(logger.shouldLog(LEVEL_ERROR))
assert.False(logger.shouldLog(LEVEL_INFO))
assert.False(logger.shouldLog(LEVEL_DEBUG))
}
func (suite *LoggerTestSuite) Test_GetLogLevel() {
tests := []struct {
name string
level string
expected int
}{
{"debug level", "debug", LEVEL_DEBUG},
{"info level", "info", LEVEL_INFO},
{"warn level", "warn", LEVEL_WARN},
{"error level", "error", LEVEL_ERROR},
{"fatal level", "fatal", LEVEL_FATAL},
{"uppercase debug", "DEBUG", LEVEL_DEBUG},
{"mixed case warn", "WaRn", LEVEL_WARN},
{"unknown level", "unknown", defaultMinLevel},
{"empty string", "", defaultMinLevel},
}
for _, tt := range tests {
suite.T().Run(tt.name, func(t *testing.T) {
result := GetLogLevel(tt.level)
assert.Equal(tt.expected, result)
})
}
}
func (suite *LoggerTestSuite) Test_Warning() {
output := &bytes.Buffer{}
logger := New().SetOutput(output).SetMinLogLevel(LEVEL_WARN)
msg := &LogMessage{
Message: "warning message",
Pairs: map[string]any{"key": "value"},
}
logger.Warning(msg)
logOutput := output.String()
fmt.Printf("DEBUG: logOutput = %q\n", logOutput)
fmt.Printf("DEBUG: logOutput length = %d\n", len(logOutput))
assert.NotEmpty(logOutput)
var loggedMessage map[string]any
err := json.Unmarshal([]byte(logOutput), &loggedMessage)
fmt.Printf("DEBUG: unmarshal error = %v\n", err)
fmt.Printf("DEBUG: loggedMessage = %+v\n", loggedMessage)
assert.NoError(err)
assert.Equal("warn", loggedMessage["level"])
assert.Equal("warning message", loggedMessage["message"])
}
func (suite *LoggerTestSuite) Test_Error() {
output := &bytes.Buffer{}
logger := New().SetOutput(output).SetMinLogLevel(LEVEL_ERROR)
msg := &LogMessage{
Message: "error message",
Pairs: map[string]any{"error": "test error"},
}
logger.Error(msg)
logOutput := output.String()
assert.NotEmpty(logOutput)
var loggedMessage map[string]any
err := json.Unmarshal([]byte(logOutput), &loggedMessage)
assert.NoError(err)
assert.Equal("error", loggedMessage["level"])
assert.Equal("error message", loggedMessage["message"])
assert.Equal("test error", loggedMessage["error"])
}
func (suite *LoggerTestSuite) Test_Fatal() {
output := &bytes.Buffer{}
logger := New().SetOutput(output).SetMinLogLevel(LEVEL_FATAL)
msg := &LogMessage{
Message: "fatal message",
Pairs: map[string]any{"fatal": "test fatal"},
}
logger.Fatal(msg)
logOutput := output.String()
assert.NotEmpty(logOutput)
var loggedMessage map[string]any
err := json.Unmarshal([]byte(logOutput), &loggedMessage)
assert.NoError(err)
assert.Equal("fatal", loggedMessage["level"])
assert.Equal("fatal message", loggedMessage["message"])
assert.Equal("test fatal", loggedMessage["fatal"])
}
func (suite *LoggerTestSuite) Test_SetFieldName() {
// Save original field names
originalFieldNames := make(map[string]string)
for k, v := range fieldNames {
originalFieldNames[k] = v
}
// Restore original field names after test
defer func() {
for k, v := range originalFieldNames {
fieldNames[k] = v
}
}()
logger := New()
// Test setting custom field names
logger.SetFieldName("timestamp", "time")
logger.SetFieldName("level", "severity")
logger.SetFieldName("message", "msg")
output := &bytes.Buffer{}
logger.SetOutput(output)
msg := &LogMessage{
Message: "test message",
}
logger.Info(msg)
logOutput := output.String()
assert.NotEmpty(logOutput)
var loggedMessage map[string]any
err := json.Unmarshal([]byte(logOutput), &loggedMessage)
assert.NoError(err)
// Check that custom field names are used
assert.Contains(loggedMessage, "time")
assert.Contains(loggedMessage, "severity")
assert.Contains(loggedMessage, "msg")
assert.Equal("info", loggedMessage["severity"])
assert.Equal("test message", loggedMessage["msg"])
}
func (suite *LoggerTestSuite) Test_SetShowCaller() {
output := &bytes.Buffer{}
logger := New().SetOutput(output).SetShowCaller(true)
msg := &LogMessage{
Message: "test message with caller",
}
logger.Info(msg)
logOutput := output.String()
assert.NotEmpty(logOutput)
var loggedMessage map[string]any
err := json.Unmarshal([]byte(logOutput), &loggedMessage)
assert.NoError(err)
// Check that caller information is included
assert.Contains(loggedMessage, "caller")
caller, ok := loggedMessage["caller"].(string)
assert.True(ok)
assert.Contains(caller, "logger_test.go:")
}
func (suite *LoggerTestSuite) Test_GetCaller() {
// Test getCaller function indirectly through SetShowCaller
output := &bytes.Buffer{}
logger := New().SetOutput(output).SetShowCaller(true).SetMinLogLevel(LEVEL_DEBUG)
msg := &LogMessage{
Message: "caller test",
}
logger.Debug(msg)
logOutput := output.String()
assert.NotEmpty(logOutput)
var loggedMessage map[string]any
err := json.Unmarshal([]byte(logOutput), &loggedMessage)
assert.NoError(err)
caller, exists := loggedMessage["caller"]
assert.True(exists)
assert.NotEmpty(caller)
// Caller should be in format "file:line"
callerStr, ok := caller.(string)
assert.True(ok)
assert.Contains(callerStr, ":")
}
func (suite *LoggerTestSuite) Test_LogWithNilPairs() {
output := &bytes.Buffer{}
logger := New().SetOutput(output)
msg := &LogMessage{
Message: "message with nil pairs",
Pairs: nil,
}
logger.Info(msg)
logOutput := output.String()
assert.NotEmpty(logOutput)
var loggedMessage map[string]any
err := json.Unmarshal([]byte(logOutput), &loggedMessage)
assert.NoError(err)
assert.Equal("info", loggedMessage["level"])
assert.Equal("message with nil pairs", loggedMessage["message"])
}
func (suite *LoggerTestSuite) Test_LogLevelFiltering() {
output := &bytes.Buffer{}
logger := New().SetOutput(output).SetMinLogLevel(LEVEL_WARN)
// These should not produce output (below minimum level)
logger.Debug(&LogMessage{Message: "debug message"})
logger.Info(&LogMessage{Message: "info message"})
debugInfoOutput := output.String()
assert.Empty(debugInfoOutput)
// These should produce output (at or above minimum level)
logger.Warn(&LogMessage{Message: "warn message"})
warnOutput := output.String()
assert.NotEmpty(warnOutput)
assert.Contains(warnOutput, "warn message")
output.Reset()
logger.Error(&LogMessage{Message: "error message"})
errorOutput := output.String()
assert.NotEmpty(errorOutput)
assert.Contains(errorOutput, "error message")
output.Reset()
logger.Fatal(&LogMessage{Message: "fatal message"})
fatalOutput := output.String()
assert.NotEmpty(fatalOutput)
assert.Contains(fatalOutput, "fatal message")
}