blob: 84193fdae928e012367aae1d1abe985f0b4299bb [file] [log] [blame]
package logger
import (
"bytes"
"encoding/json"
"path/filepath"
"strings"
"testing"
"github.com/korap/korap-mcp/config"
"github.com/rs/zerolog"
"github.com/stretchr/testify/assert"
)
func TestSetupLogger(t *testing.T) {
t.Run("should setup logger with default configuration", func(t *testing.T) {
cfg := &config.LoggingConfig{
Level: "info",
Format: "json",
}
logger, err := SetupLogger(cfg)
assert.NoError(t, err)
assert.NotNil(t, logger)
})
t.Run("should setup logger with text format", func(t *testing.T) {
cfg := &config.LoggingConfig{
Level: "debug",
Format: "text",
}
logger, err := SetupLogger(cfg)
assert.NoError(t, err)
assert.NotNil(t, logger)
})
t.Run("should setup logger with file output", func(t *testing.T) {
// Create temporary file
tmpDir := t.TempDir()
logFile := filepath.Join(tmpDir, "test.log")
cfg := &config.LoggingConfig{
Level: "warn",
Format: "json",
File: logFile,
}
logger, err := SetupLogger(cfg)
assert.NoError(t, err)
assert.NotNil(t, logger)
// Test logging to file
logger.Info().Msg("test message")
// Verify file was created
assert.FileExists(t, logFile)
})
t.Run("should return error for invalid log level", func(t *testing.T) {
cfg := &config.LoggingConfig{
Level: "invalid",
Format: "json",
}
_, err := SetupLogger(cfg)
assert.Error(t, err)
assert.Contains(t, strings.ToLower(err.Error()), "unknown level")
})
t.Run("should return error for invalid file path", func(t *testing.T) {
cfg := &config.LoggingConfig{
Level: "info",
Format: "json",
File: "/invalid/path/test.log",
}
_, err := SetupLogger(cfg)
assert.Error(t, err)
})
}
func TestGetLogger(t *testing.T) {
t.Run("should return configured logger", func(t *testing.T) {
cfg := &config.LoggingConfig{
Level: "debug",
Format: "json",
}
logger := GetLogger(cfg)
assert.NotNil(t, logger)
})
t.Run("should return fallback logger on configuration error", func(t *testing.T) {
cfg := &config.LoggingConfig{
Level: "invalid",
Format: "json",
}
logger := GetLogger(cfg)
assert.NotNil(t, logger)
})
}
func TestLoggerOutput(t *testing.T) {
t.Run("should produce structured JSON output", func(t *testing.T) {
var buf bytes.Buffer
// Create a logger that writes to our buffer
logger := zerolog.New(&buf).With().Timestamp().Logger()
// Log a message
logger.Info().Str("test", "value").Msg("test message")
// Parse the JSON output
var logEntry map[string]any
err := json.Unmarshal(buf.Bytes(), &logEntry)
assert.NoError(t, err)
// Verify log structure
assert.Equal(t, "info", logEntry["level"])
assert.Equal(t, "test message", logEntry["message"])
assert.Equal(t, "value", logEntry["test"])
assert.Contains(t, logEntry, "time")
})
t.Run("should respect log levels", func(t *testing.T) {
var buf bytes.Buffer
// Set global level to warn
zerolog.SetGlobalLevel(zerolog.WarnLevel)
logger := zerolog.New(&buf).With().Timestamp().Logger()
// Try to log at different levels
logger.Debug().Msg("debug message")
logger.Info().Msg("info message")
logger.Warn().Msg("warn message")
// Only warn message should be present
output := buf.String()
assert.NotContains(t, output, "debug message")
assert.NotContains(t, output, "info message")
assert.Contains(t, output, "warn message")
// Reset global level
zerolog.SetGlobalLevel(zerolog.InfoLevel)
})
}
func TestLoggerIntegration(t *testing.T) {
t.Run("should work with all supported log levels", func(t *testing.T) {
levels := []string{"trace", "debug", "info", "warn", "error", "fatal", "panic"}
for _, level := range levels {
cfg := &config.LoggingConfig{
Level: level,
Format: "json",
}
logger, err := SetupLogger(cfg)
if level == "panic" {
// panic level might not be supported in all contexts
continue
}
assert.NoError(t, err, "Failed to setup logger with level: %s", level)
assert.NotNil(t, logger, "Logger should not be nil for level: %s", level)
}
})
t.Run("should work with different output formats", func(t *testing.T) {
formats := []string{"json", "text"}
for _, format := range formats {
cfg := &config.LoggingConfig{
Level: "info",
Format: format,
}
logger, err := SetupLogger(cfg)
assert.NoError(t, err, "Failed to setup logger with format: %s", format)
assert.NotNil(t, logger, "Logger should not be nil for format: %s", format)
}
})
}
func TestLoggerErrorHandling(t *testing.T) {
t.Run("should handle errors gracefully in GetLogger", func(t *testing.T) {
// Test with various invalid configurations
invalidConfigs := []*config.LoggingConfig{
{Level: "invalid-level", Format: "json"},
{Level: "info", Format: "json", File: "/dev/null/invalid"},
}
for _, cfg := range invalidConfigs {
logger := GetLogger(cfg)
// Should not panic and should return a valid logger
assert.NotNil(t, logger)
// Should be able to log
logger.Info().Msg("test message")
}
})
}