package metrics import ( "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "veza-backend-api/internal/errors" ) func TestNewAggregatedMetrics(t *testing.T) { agg := NewAggregatedMetrics() require.NotNil(t, agg) assert.NotNil(t, agg.windows) assert.NotNil(t, agg.windowSizes) assert.Equal(t, 3, len(agg.windowSizes)) // 1m, 5m, 1h } func TestAggregatedMetrics_AddError(t *testing.T) { agg := NewAggregatedMetrics() // Ajouter une erreur agg.AddError("1m", errors.ErrCodeValidation, 400) agg.AddError("5m", errors.ErrCodeValidation, 400) agg.AddError("1h", errors.ErrCodeValidation, 400) // Vérifier que les fenêtres ont été créées windows1m := agg.GetAggregated("1m") assert.Greater(t, len(windows1m), 0) windows5m := agg.GetAggregated("5m") assert.Greater(t, len(windows5m), 0) windows1h := agg.GetAggregated("1h") assert.Greater(t, len(windows1h), 0) // Vérifier que l'erreur a été comptabilisée assert.Equal(t, int64(1), windows1m[len(windows1m)-1].Errors) assert.Equal(t, int64(1), windows5m[len(windows5m)-1].Errors) assert.Equal(t, int64(1), windows1h[len(windows1h)-1].Errors) } func TestAggregatedMetrics_AddMultipleErrors(t *testing.T) { agg := NewAggregatedMetrics() // Ajouter plusieurs erreurs dans la même fenêtre for i := 0; i < 5; i++ { agg.AddError("1m", errors.ErrCodeInternal, 500) } windows := agg.GetAggregated("1m") require.Greater(t, len(windows), 0) // Vérifier que toutes les erreurs sont dans la dernière fenêtre lastWindow := windows[len(windows)-1] assert.Equal(t, int64(5), lastWindow.Errors) assert.Equal(t, int64(5), lastWindow.ErrorsByCode[errors.ErrCodeInternal]) assert.Equal(t, int64(5), lastWindow.ErrorsByHTTPStatus[500]) } func TestAggregatedMetrics_AddRequest(t *testing.T) { agg := NewAggregatedMetrics() // Ajouter des requêtes agg.AddRequest("1m") agg.AddRequest("1m") agg.AddRequest("5m") windows1m := agg.GetAggregated("1m") require.Greater(t, len(windows1m), 0) assert.Equal(t, int64(2), windows1m[len(windows1m)-1].Requests) windows5m := agg.GetAggregated("5m") require.Greater(t, len(windows5m), 0) assert.Equal(t, int64(1), windows5m[len(windows5m)-1].Requests) } func TestAggregatedMetrics_GetAggregated(t *testing.T) { agg := NewAggregatedMetrics() // Ajouter des erreurs pour différentes fenêtres agg.AddError("1m", errors.ErrCodeValidation, 400) agg.AddError("5m", errors.ErrCodeNotFound, 404) windows1m := agg.GetAggregated("1m") require.Greater(t, len(windows1m), 0) // Vérifier la structure de la fenêtre window := windows1m[len(windows1m)-1] assert.NotZero(t, window.Start) assert.NotZero(t, window.End) assert.Greater(t, window.End.Unix(), window.Start.Unix()) } func TestAggregatedMetrics_GetAllAggregated(t *testing.T) { agg := NewAggregatedMetrics() // Ajouter des métriques pour toutes les fenêtres agg.AddError("1m", errors.ErrCodeValidation, 400) agg.AddError("5m", errors.ErrCodeNotFound, 404) agg.AddError("1h", errors.ErrCodeInternal, 500) allWindows := agg.GetAllAggregated() assert.Contains(t, allWindows, "1m") assert.Contains(t, allWindows, "5m") assert.Contains(t, allWindows, "1h") assert.Greater(t, len(allWindows["1m"]), 0) assert.Greater(t, len(allWindows["5m"]), 0) assert.Greater(t, len(allWindows["1h"]), 0) } func TestAggregatedMetrics_SlidingWindow(t *testing.T) { agg := NewAggregatedMetrics() // Simuler plusieurs fenêtres en ajoutant des erreurs avec des délais now := time.Now() // Ajouter une erreur maintenant agg.AddError("1m", errors.ErrCodeValidation, 400) // Attendre un peu (pas besoin d'attendre 1 minute, on teste juste la logique) windows1 := agg.GetAggregated("1m") assert.Equal(t, 1, len(windows1)) // Ajouter une autre erreur - devrait être dans la même fenêtre si on est dans la même minute agg.AddError("1m", errors.ErrCodeValidation, 400) windows2 := agg.GetAggregated("1m") // Soit la même fenêtre (si même minute), soit une nouvelle assert.GreaterOrEqual(t, len(windows2), 1) // Le total devrait être au moins 2 erreurs totalErrors := int64(0) for _, w := range windows2 { totalErrors += w.Errors } assert.GreaterOrEqual(t, totalErrors, int64(2)) // S'assurer que le temps n'est pas dans le futur for _, w := range windows2 { assert.LessOrEqual(t, w.Start.Unix(), now.Unix()+60) // Max 1 minute dans le futur assert.LessOrEqual(t, w.End.Unix(), now.Unix()+120) // Max 2 minutes dans le futur } } func TestAggregatedMetrics_InvalidWindowType(t *testing.T) { agg := NewAggregatedMetrics() // Ajouter une erreur avec un type de fenêtre invalide agg.AddError("invalid", errors.ErrCodeValidation, 400) // Ne devrait pas créer de fenêtre windows := agg.GetAggregated("invalid") assert.Equal(t, 0, len(windows)) } func TestAggregatedMetrics_ErrorsByCode(t *testing.T) { agg := NewAggregatedMetrics() // Ajouter différentes erreurs avec différents codes agg.AddError("1m", errors.ErrCodeValidation, 400) agg.AddError("1m", errors.ErrCodeNotFound, 404) agg.AddError("1m", errors.ErrCodeValidation, 400) windows := agg.GetAggregated("1m") require.Greater(t, len(windows), 0) lastWindow := windows[len(windows)-1] // Vérifier que les erreurs sont comptabilisées par code assert.Equal(t, int64(2), lastWindow.ErrorsByCode[errors.ErrCodeValidation]) assert.Equal(t, int64(1), lastWindow.ErrorsByCode[errors.ErrCodeNotFound]) } func TestAggregatedMetrics_ErrorsByHTTPStatus(t *testing.T) { agg := NewAggregatedMetrics() // Ajouter différentes erreurs avec différents status HTTP agg.AddError("1m", errors.ErrCodeValidation, 400) agg.AddError("1m", errors.ErrCodeNotFound, 404) agg.AddError("1m", errors.ErrCodeInternal, 500) agg.AddError("1m", errors.ErrCodeValidation, 400) windows := agg.GetAggregated("1m") require.Greater(t, len(windows), 0) lastWindow := windows[len(windows)-1] // Vérifier que les erreurs sont comptabilisées par status HTTP assert.Equal(t, int64(2), lastWindow.ErrorsByHTTPStatus[400]) assert.Equal(t, int64(1), lastWindow.ErrorsByHTTPStatus[404]) assert.Equal(t, int64(1), lastWindow.ErrorsByHTTPStatus[500]) } func TestErrorMetrics_IntegrationWithAggregation(t *testing.T) { errorMetrics := NewErrorMetrics() require.NotNil(t, errorMetrics.aggregated) // Enregistrer des erreurs errorMetrics.RecordError(errors.ErrCodeValidation, 400) errorMetrics.RecordError(errors.ErrCodeNotFound, 404) // Vérifier que l'agrégation a été mise à jour windows1m := errorMetrics.GetAggregatedMetrics().GetAggregated("1m") require.Greater(t, len(windows1m), 0) lastWindow := windows1m[len(windows1m)-1] assert.GreaterOrEqual(t, lastWindow.Errors, int64(2)) }