package logging import ( "os" "path/filepath" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/zap" ) func TestNewLoggerWithRotation_Production(t *testing.T) { tmpDir := t.TempDir() logFile := filepath.Join(tmpDir, "test.log") logger, err := NewLoggerWithRotation("production", logFile, "INFO") require.NoError(t, err) require.NotNil(t, logger) // Écrire quelques logs for i := 0; i < 100; i++ { logger.Info("test log", zap.Int("iteration", i)) } // Vérifier que le fichier de log existe _, err = os.Stat(logFile) assert.NoError(t, err, "Log file should exist") // Sync pour s'assurer que tout est écrit _ = logger.Sync() // Vérifier que le fichier n'est pas vide fileInfo, err := os.Stat(logFile) require.NoError(t, err) assert.Greater(t, fileInfo.Size(), int64(0), "Log file should not be empty") } func TestNewLoggerWithRotation_Development(t *testing.T) { tmpDir := t.TempDir() logFile := filepath.Join(tmpDir, "test-dev.log") logger, err := NewLoggerWithRotation("development", logFile, "DEBUG") require.NoError(t, err) require.NotNil(t, logger) // Écrire quelques logs logger.Debug("debug message", zap.String("key", "value")) logger.Info("info message", zap.Int("count", 42)) logger.Warn("warn message", zap.Bool("flag", true)) logger.Error("error message", zap.String("error", "test error")) // Sync pour s'assurer que tout est écrit _ = logger.Sync() // Vérifier que le fichier existe _, err = os.Stat(logFile) assert.NoError(t, err, "Log file should exist") } func TestNewLoggerWithRotation_ManyLogs(t *testing.T) { tmpDir := t.TempDir() logFile := filepath.Join(tmpDir, "test-many.log") logger, err := NewLoggerWithRotation("production", logFile, "INFO") require.NoError(t, err) require.NotNil(t, logger) // Écrire beaucoup de logs pour tester la rotation // Note: On ne peut pas facilement déclencher la rotation dans un test // car elle nécessite 100MB de logs, mais on peut vérifier que ça fonctionne for i := 0; i < 10000; i++ { logger.Info("test log", zap.Int("iteration", i)) } // Sync pour s'assurer que tout est écrit _ = logger.Sync() // Vérifier que le fichier existe _, err = os.Stat(logFile) assert.NoError(t, err, "Log file should exist") // Vérifier que le fichier contient des données fileInfo, err := os.Stat(logFile) require.NoError(t, err) assert.Greater(t, fileInfo.Size(), int64(0), "Log file should contain logs") } func TestNewLoggerWithRotation_AllLogLevels(t *testing.T) { tmpDir := t.TempDir() logFile := filepath.Join(tmpDir, "test-levels.log") logger, err := NewLoggerWithRotation("production", logFile, "DEBUG") require.NoError(t, err) require.NotNil(t, logger) // Tester tous les niveaux de log logger.Debug("debug message") logger.Info("info message") logger.Warn("warn message") logger.Error("error message") // Sync pour s'assurer que tout est écrit _ = logger.Sync() // Vérifier que le fichier existe _, err = os.Stat(logFile) assert.NoError(t, err, "Log file should exist") } func TestNewLoggerWithRotation_WithFields(t *testing.T) { tmpDir := t.TempDir() logFile := filepath.Join(tmpDir, "test-fields.log") logger, err := NewLoggerWithRotation("production", logFile, "INFO") require.NoError(t, err) require.NotNil(t, logger) // Créer un logger avec des champs contextuels contextLogger := logger.With( zap.String("request_id", "req-123"), zap.String("user_id", "user-456"), ) // Écrire des logs avec le logger contextuel contextLogger.Info("request processed", zap.String("action", "login")) contextLogger.Error("request failed", zap.String("action", "update")) // Sync pour s'assurer que tout est écrit _ = logger.Sync() // Vérifier que le fichier existe _, err = os.Stat(logFile) assert.NoError(t, err, "Log file should exist") } func TestNewLoggerWithRotation_NoDataLoss(t *testing.T) { tmpDir := t.TempDir() logFile := filepath.Join(tmpDir, "test-noloss.log") logger, err := NewLoggerWithRotation("production", logFile, "INFO") require.NoError(t, err) require.NotNil(t, logger) // Écrire des logs avec différents patterns messages := []string{ "First message", "Second message", "Third message", "Fourth message", "Fifth message", } for _, msg := range messages { logger.Info(msg, zap.String("timestamp", time.Now().Format(time.RFC3339))) } // Sync pour s'assurer que tout est écrit err = logger.Sync() require.NoError(t, err, "Sync should not fail") // Vérifier que le fichier existe et contient des données fileInfo, err := os.Stat(logFile) require.NoError(t, err) assert.Greater(t, fileInfo.Size(), int64(0), "Log file should contain all messages") } func TestNewLoggerWithRotation_ConcurrentWrites(t *testing.T) { tmpDir := t.TempDir() logFile := filepath.Join(tmpDir, "test-concurrent.log") logger, err := NewLoggerWithRotation("production", logFile, "INFO") require.NoError(t, err) require.NotNil(t, logger) // Écrire des logs de manière concurrente done := make(chan bool, 10) for i := 0; i < 10; i++ { go func(id int) { for j := 0; j < 100; j++ { logger.Info("concurrent log", zap.Int("goroutine", id), zap.Int("iteration", j)) } done <- true }(i) } // Attendre que toutes les goroutines terminent for i := 0; i < 10; i++ { <-done } // Sync pour s'assurer que tout est écrit _ = logger.Sync() // Vérifier que le fichier existe _, err = os.Stat(logFile) assert.NoError(t, err, "Log file should exist") // Vérifier que le fichier contient des données fileInfo, err := os.Stat(logFile) require.NoError(t, err) assert.Greater(t, fileInfo.Size(), int64(0), "Log file should contain logs from all goroutines") }