Some checks failed
Build RPM Package / Build RPM Packages (CentOS 7, Rocky 8/9/10) (push) Has been cancelled
- Correction race condition dans tlsparse avec mutex par ConnectionFlow - Fix fuite mémoire buffer HelloBuffer - Ajout rotation de fichiers logs (100MB, 3 backups) - Implémentation queue asynchrone avec reconnexion exponentielle (socket UNIX) - Validation BPF (caractères, longueur, parenthèses) - Augmentation snapLen pcap de 1600 à 65535 bytes - Permissions fichiers sécurisées (0600) - Ajout 46 tests unitaires (capture, output, logging) - Passage go test -race sans erreur Tests: go test -race ./... ✓ Build: go build ./... ✓ Lint: go vet ./... ✓ Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
239 lines
6.3 KiB
Go
239 lines
6.3 KiB
Go
package logging
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"log"
|
|
"strings"
|
|
"testing"
|
|
|
|
"ja4sentinel/api"
|
|
)
|
|
|
|
func TestIsLogLevelEnabled(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
loggerLevel string
|
|
messageLevel string
|
|
want bool
|
|
}{
|
|
{name: "debug logger accepts debug", loggerLevel: "debug", messageLevel: "debug", want: true},
|
|
{name: "debug logger accepts info", loggerLevel: "debug", messageLevel: "info", want: true},
|
|
{name: "info logger rejects debug", loggerLevel: "info", messageLevel: "debug", want: false},
|
|
{name: "info logger accepts info", loggerLevel: "info", messageLevel: "info", want: true},
|
|
{name: "warn logger rejects info", loggerLevel: "warn", messageLevel: "info", want: false},
|
|
{name: "warn logger accepts error", loggerLevel: "warn", messageLevel: "error", want: true},
|
|
{name: "error logger accepts only error", loggerLevel: "error", messageLevel: "error", want: true},
|
|
{name: "error logger rejects warn", loggerLevel: "error", messageLevel: "warn", want: false},
|
|
{name: "invalid level rejects all", loggerLevel: "invalid", messageLevel: "info", want: false},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
logger := NewServiceLogger(tt.loggerLevel)
|
|
if got := logger.isLogLevelEnabled(tt.messageLevel); got != tt.want {
|
|
t.Fatalf("isLogLevelEnabled(%q) = %v, want %v", tt.messageLevel, got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDebug_NotEmittedWhenLoggerLevelInfo(t *testing.T) {
|
|
logger := NewServiceLogger("info")
|
|
var buf bytes.Buffer
|
|
logger.out = log.New(&buf, "", 0)
|
|
|
|
logger.Debug("service", "debug message", map[string]string{"k": "v"})
|
|
|
|
if buf.Len() != 0 {
|
|
t.Fatalf("expected no output for debug at info level, got: %s", buf.String())
|
|
}
|
|
}
|
|
|
|
func TestLog_UppercaseDebug_NotEmittedWhenLoggerLevelInfo(t *testing.T) {
|
|
logger := NewServiceLogger("info")
|
|
var buf bytes.Buffer
|
|
logger.out = log.New(&buf, "", 0)
|
|
|
|
logger.Log("service", "DEBUG", "debug message", nil)
|
|
|
|
if strings.TrimSpace(buf.String()) != "" {
|
|
t.Fatalf("expected no output for uppercase DEBUG at info level, got: %s", buf.String())
|
|
}
|
|
}
|
|
|
|
func TestInfo_EmitedWhenLoggerLevelInfo(t *testing.T) {
|
|
logger := NewServiceLogger("info")
|
|
var buf bytes.Buffer
|
|
logger.out = log.New(&buf, "", 0)
|
|
|
|
logger.Info("service", "info message", map[string]string{"key": "value"})
|
|
|
|
if buf.Len() == 0 {
|
|
t.Fatal("expected output for info at info level")
|
|
}
|
|
|
|
// Verify JSON format
|
|
var got map[string]interface{}
|
|
if err := json.Unmarshal(buf.Bytes(), &got); err != nil {
|
|
t.Fatalf("output is not valid JSON: %v", err)
|
|
}
|
|
|
|
if got["level"] != "INFO" {
|
|
t.Errorf("level = %v, want INFO", got["level"])
|
|
}
|
|
if got["component"] != "service" {
|
|
t.Errorf("component = %v, want service", got["component"])
|
|
}
|
|
if got["message"] != "info message" {
|
|
t.Errorf("message = %v, want info message", got["message"])
|
|
}
|
|
if got["key"] != "value" {
|
|
t.Errorf("key = %v, want value", got["key"])
|
|
}
|
|
}
|
|
|
|
func TestWarn_EmitedWhenLoggerLevelWarn(t *testing.T) {
|
|
logger := NewServiceLogger("warn")
|
|
var buf bytes.Buffer
|
|
logger.out = log.New(&buf, "", 0)
|
|
|
|
logger.Warn("service", "warn message", nil)
|
|
|
|
if buf.Len() == 0 {
|
|
t.Fatal("expected output for warn at warn level")
|
|
}
|
|
}
|
|
|
|
func TestError_AlwaysEmitted(t *testing.T) {
|
|
levels := []string{"debug", "info", "warn", "error"}
|
|
for _, level := range levels {
|
|
t.Run(level, func(t *testing.T) {
|
|
logger := NewServiceLogger(level)
|
|
var buf bytes.Buffer
|
|
logger.out = log.New(&buf, "", 0)
|
|
|
|
logger.Error("service", "error message", map[string]string{"error": "test"})
|
|
|
|
if buf.Len() == 0 {
|
|
t.Fatalf("expected output for error at %s level", level)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestLog_EmptyDetails(t *testing.T) {
|
|
logger := NewServiceLogger("debug")
|
|
var buf bytes.Buffer
|
|
logger.out = log.New(&buf, "", 0)
|
|
|
|
logger.Info("service", "test message", nil)
|
|
|
|
if buf.Len() == 0 {
|
|
t.Fatal("expected output")
|
|
}
|
|
|
|
var got map[string]interface{}
|
|
if err := json.Unmarshal(buf.Bytes(), &got); err != nil {
|
|
t.Fatalf("output is not valid JSON: %v", err)
|
|
}
|
|
|
|
// Details should not be present when nil/empty
|
|
if _, ok := got["details"]; ok {
|
|
t.Error("details should not be present when nil")
|
|
}
|
|
}
|
|
|
|
func TestLog_WithDetails(t *testing.T) {
|
|
logger := NewServiceLogger("debug")
|
|
var buf bytes.Buffer
|
|
logger.out = log.New(&buf, "", 0)
|
|
|
|
details := map[string]string{
|
|
"error": "test error",
|
|
"trace_id": "abc123",
|
|
}
|
|
logger.Info("service", "test message", details)
|
|
|
|
var got map[string]interface{}
|
|
if err := json.Unmarshal(buf.Bytes(), &got); err != nil {
|
|
t.Fatalf("output is not valid JSON: %v", err)
|
|
}
|
|
|
|
if got["error"] != "test error" {
|
|
t.Errorf("error = %v, want test error", got["error"])
|
|
}
|
|
if got["trace_id"] != "abc123" {
|
|
t.Errorf("trace_id = %v, want abc123", got["trace_id"])
|
|
}
|
|
}
|
|
|
|
func TestLog_TimestampPresent(t *testing.T) {
|
|
logger := NewServiceLogger("debug")
|
|
var buf bytes.Buffer
|
|
logger.out = log.New(&buf, "", 0)
|
|
|
|
logger.Info("service", "test", nil)
|
|
|
|
var got map[string]interface{}
|
|
if err := json.Unmarshal(buf.Bytes(), &got); err != nil {
|
|
t.Fatalf("output is not valid JSON: %v", err)
|
|
}
|
|
|
|
if _, ok := got["timestamp"]; !ok {
|
|
t.Error("timestamp should be present")
|
|
}
|
|
}
|
|
|
|
func TestLoggerFactory(t *testing.T) {
|
|
factory := &LoggerFactory{}
|
|
|
|
// Test NewLogger with different levels
|
|
levels := []string{"debug", "info", "warn", "error"}
|
|
for _, level := range levels {
|
|
t.Run(level, func(t *testing.T) {
|
|
logger := factory.NewLogger(level)
|
|
if logger == nil {
|
|
t.Fatalf("NewLogger(%q) returned nil", level)
|
|
}
|
|
})
|
|
}
|
|
|
|
// Test NewDefaultLogger
|
|
logger := factory.NewDefaultLogger()
|
|
if logger == nil {
|
|
t.Fatal("NewDefaultLogger() returned nil")
|
|
}
|
|
}
|
|
|
|
func TestServiceLogger_ImplementsApiLogger(t *testing.T) {
|
|
logger := NewServiceLogger("debug")
|
|
|
|
// Verify it implements the interface
|
|
var _ api.Logger = logger
|
|
}
|
|
|
|
func TestServiceLogger_ConcurrentLogging(t *testing.T) {
|
|
logger := NewServiceLogger("debug")
|
|
var buf bytes.Buffer
|
|
logger.out = log.New(&buf, "", 0)
|
|
|
|
done := make(chan bool)
|
|
for i := 0; i < 10; i++ {
|
|
go func(id int) {
|
|
logger.Info("service", "concurrent message", map[string]string{"id": string(rune(id))})
|
|
done <- true
|
|
}(i)
|
|
}
|
|
|
|
for i := 0; i < 10; i++ {
|
|
<-done
|
|
}
|
|
|
|
// Should have 10 lines
|
|
lines := strings.Split(strings.TrimSpace(buf.String()), "\n")
|
|
if len(lines) != 10 {
|
|
t.Errorf("expected 10 lines, got %d", len(lines))
|
|
}
|
|
}
|