package config import ( "os" "path/filepath" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/zap" "go.uber.org/zap/zaptest" ) func TestNewConfigWatcher(t *testing.T) { logger := zaptest.NewLogger(t) config := &Config{LogLevel: "INFO"} reloader := NewConfigReloader(config, logger) watcher, err := NewConfigWatcher(reloader, logger) require.NoError(t, err) assert.NotNil(t, watcher) defer watcher.Stop() } func TestConfigWatcher_Watch(t *testing.T) { logger := zaptest.NewLogger(t) config := &Config{LogLevel: "INFO"} reloader := NewConfigReloader(config, logger) watcher, err := NewConfigWatcher(reloader, logger) require.NoError(t, err) defer watcher.Stop() // Créer un fichier temporaire tmpDir := t.TempDir() tmpFile := filepath.Join(tmpDir, ".env.test") err = os.WriteFile(tmpFile, []byte("LOG_LEVEL=DEBUG\n"), 0644) require.NoError(t, err) err = watcher.Watch([]string{tmpFile}) require.NoError(t, err) // Vérifier que le fichier est surveillé watchedFiles := watcher.GetWatchedFiles() assert.Contains(t, watchedFiles, tmpFile) } func TestConfigWatcher_Stop(t *testing.T) { logger := zaptest.NewLogger(t) config := &Config{LogLevel: "INFO"} reloader := NewConfigReloader(config, logger) watcher, err := NewConfigWatcher(reloader, logger) require.NoError(t, err) err = watcher.Stop() assert.NoError(t, err) } func TestConfigWatcher_GetWatchedFiles(t *testing.T) { logger := zaptest.NewLogger(t) config := &Config{LogLevel: "INFO"} reloader := NewConfigReloader(config, logger) watcher, err := NewConfigWatcher(reloader, logger) require.NoError(t, err) defer watcher.Stop() // Aucun fichier surveillé initialement files := watcher.GetWatchedFiles() assert.Empty(t, files) // Ajouter un fichier tmpDir := t.TempDir() tmpFile := filepath.Join(tmpDir, ".env.test") err = os.WriteFile(tmpFile, []byte("LOG_LEVEL=DEBUG\n"), 0644) require.NoError(t, err) err = watcher.Watch([]string{tmpFile}) require.NoError(t, err) files = watcher.GetWatchedFiles() assert.Contains(t, files, tmpFile) } func TestConfigWatcher_MultipleFiles(t *testing.T) { logger := zaptest.NewLogger(t) config := &Config{LogLevel: "INFO"} reloader := NewConfigReloader(config, logger) watcher, err := NewConfigWatcher(reloader, logger) require.NoError(t, err) defer watcher.Stop() tmpDir := t.TempDir() file1 := filepath.Join(tmpDir, ".env") file2 := filepath.Join(tmpDir, ".env.production") err = os.WriteFile(file1, []byte("LOG_LEVEL=DEBUG\n"), 0644) require.NoError(t, err) err = os.WriteFile(file2, []byte("LOG_LEVEL=ERROR\n"), 0644) require.NoError(t, err) err = watcher.Watch([]string{file1, file2}) require.NoError(t, err) watchedFiles := watcher.GetWatchedFiles() assert.Contains(t, watchedFiles, file1) assert.Contains(t, watchedFiles, file2) } func TestConfigWatcher_InvalidFile(t *testing.T) { logger := zaptest.NewLogger(t) config := &Config{LogLevel: "INFO"} reloader := NewConfigReloader(config, logger) watcher, err := NewConfigWatcher(reloader, logger) require.NoError(t, err) defer watcher.Stop() // Essayer de surveiller un fichier inexistant // Ne devrait pas planter, juste logger un avertissement err = watcher.Watch([]string{"/nonexistent/file.env"}) // Le watch peut échouer mais ne doit pas planter if err != nil { t.Logf("Expected error for nonexistent file: %v", err) } } func TestConfigWatcher_FileChangeDetection(t *testing.T) { if testing.Short() { t.Skip("Skipping test that requires file watching in short mode") } logger := zaptest.NewLogger(t) config := &Config{LogLevel: "INFO"} reloader := NewConfigReloader(config, logger) watcher, err := NewConfigWatcher(reloader, logger) require.NoError(t, err) defer watcher.Stop() // Créer un fichier temporaire tmpDir := t.TempDir() tmpFile := filepath.Join(tmpDir, ".env.test") err = os.WriteFile(tmpFile, []byte("LOG_LEVEL=DEBUG\n"), 0644) require.NoError(t, err) err = watcher.Watch([]string{tmpFile}) require.NoError(t, err) // Attendre que le watcher soit prêt time.Sleep(100 * time.Millisecond) // Modifier le fichier err = os.WriteFile(tmpFile, []byte("LOG_LEVEL=ERROR\n"), 0644) require.NoError(t, err) // Attendre le debounce + reload (500ms debounce + marge) time.Sleep(700 * time.Millisecond) // Le reload devrait avoir été déclenché // Note: Le reload peut ne pas avoir modifié config.LogLevel si le fichier .env // n'est pas chargé par LoadEnvFiles, mais on vérifie au moins que le watcher // a détecté le changement watchedFiles := watcher.GetWatchedFiles() assert.Contains(t, watchedFiles, tmpFile) } func TestNewConfigWatcher_Error(t *testing.T) { // Test avec un logger invalide ne devrait pas causer d'erreur // mais si fsnotify.NewWatcher() échoue, on devrait avoir une erreur // Dans la pratique, cette fonction ne devrait pas échouer sur la plupart des systèmes logger := zap.NewNop() config := &Config{LogLevel: "INFO"} reloader := NewConfigReloader(config, logger) watcher, err := NewConfigWatcher(reloader, logger) // Sur la plupart des systèmes, cela ne devrait pas échouer if err != nil { t.Logf("NewConfigWatcher failed (may be expected on some systems): %v", err) } else { require.NotNil(t, watcher) watcher.Stop() } } func TestConfigWatcher_StopMultipleTimes(t *testing.T) { logger := zaptest.NewLogger(t) config := &Config{LogLevel: "INFO"} reloader := NewConfigReloader(config, logger) watcher, err := NewConfigWatcher(reloader, logger) require.NoError(t, err) // Arrêter plusieurs fois ne devrait pas planter err = watcher.Stop() assert.NoError(t, err) // Essayer d'arrêter à nouveau err = watcher.Stop() // Peut retourner une erreur mais ne doit pas planter if err != nil { t.Logf("Second Stop() returned error (may be expected): %v", err) } } func TestConfigWatcher_EmptyFileList(t *testing.T) { logger := zaptest.NewLogger(t) config := &Config{LogLevel: "INFO"} reloader := NewConfigReloader(config, logger) watcher, err := NewConfigWatcher(reloader, logger) require.NoError(t, err) defer watcher.Stop() // Surveiller une liste vide err = watcher.Watch([]string{}) assert.NoError(t, err) files := watcher.GetWatchedFiles() assert.Empty(t, files) } func TestConfigWatcher_RelativePath(t *testing.T) { logger := zaptest.NewLogger(t) config := &Config{LogLevel: "INFO"} reloader := NewConfigReloader(config, logger) watcher, err := NewConfigWatcher(reloader, logger) require.NoError(t, err) defer watcher.Stop() tmpDir := t.TempDir() // Créer le fichier absFile := filepath.Join(tmpDir, ".env.test") err = os.WriteFile(absFile, []byte("LOG_LEVEL=DEBUG\n"), 0644) require.NoError(t, err) // Changer vers le répertoire temporaire oldDir, err := os.Getwd() require.NoError(t, err) defer os.Chdir(oldDir) err = os.Chdir(tmpDir) require.NoError(t, err) // Essayer de surveiller avec un chemin relatif err = watcher.Watch([]string{".env.test"}) require.NoError(t, err) // Vérifier que le chemin absolu est surveillé watchedFiles := watcher.GetWatchedFiles() assert.NotEmpty(t, watchedFiles) // Le chemin absolu devrait être dans la liste found := false for _, file := range watchedFiles { if filepath.Base(file) == ".env.test" { found = true break } } assert.True(t, found, "Relative path should be converted to absolute path") }