package middleware import ( "encoding/json" "net/http" "net/http/httptest" "testing" "veza-backend-api/internal/errors" "veza-backend-api/internal/metrics" "github.com/gin-gonic/gin" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/zap" ) func TestErrorHandler_RecordsMetrics(t *testing.T) { gin.SetMode(gin.TestMode) logger := zap.NewNop() errorMetrics := metrics.NewErrorMetrics() router := gin.New() router.Use(ErrorHandler(logger, errorMetrics, true)) router.GET("/test", func(c *gin.Context) { c.Error(errors.NewNotFoundError("User")) }) w := httptest.NewRecorder() req := httptest.NewRequest("GET", "/test", nil) router.ServeHTTP(w, req) assert.Equal(t, http.StatusNotFound, w.Code) // Vérifier que les métriques ont été enregistrées stats := errorMetrics.GetStats() assert.Equal(t, int64(1), stats["total_errors"]) errorsByCode := stats["errors_by_code"].(map[errors.ErrorCode]int64) assert.Equal(t, int64(1), errorsByCode[errors.ErrCodeNotFound]) errorsByHTTPStatus := stats["errors_by_http_status"].(map[int]int64) assert.Equal(t, int64(1), errorsByHTTPStatus[404]) } func TestErrorHandler_RecordsMetricsForValidationError(t *testing.T) { gin.SetMode(gin.TestMode) logger := zap.NewNop() errorMetrics := metrics.NewErrorMetrics() router := gin.New() router.Use(ErrorHandler(logger, errorMetrics, true)) router.GET("/test", func(c *gin.Context) { c.Error(errors.NewValidationError("Invalid input")) }) w := httptest.NewRecorder() req := httptest.NewRequest("GET", "/test", nil) router.ServeHTTP(w, req) assert.Equal(t, http.StatusBadRequest, w.Code) stats := errorMetrics.GetStats() assert.Equal(t, int64(1), stats["total_errors"]) errorsByHTTPStatus := stats["errors_by_http_status"].(map[int]int64) assert.Equal(t, int64(1), errorsByHTTPStatus[400]) } func TestErrorHandler_RecordsMetricsForInternalError(t *testing.T) { gin.SetMode(gin.TestMode) logger := zap.NewNop() errorMetrics := metrics.NewErrorMetrics() router := gin.New() router.Use(ErrorHandler(logger, errorMetrics, true)) router.GET("/test", func(c *gin.Context) { c.Error(errors.New(errors.ErrCodeInternal, "Something went wrong")) }) w := httptest.NewRecorder() req := httptest.NewRequest("GET", "/test", nil) router.ServeHTTP(w, req) assert.Equal(t, http.StatusInternalServerError, w.Code) stats := errorMetrics.GetStats() assert.Equal(t, int64(1), stats["total_errors"]) errorsByCode := stats["errors_by_code"].(map[errors.ErrorCode]int64) assert.Equal(t, int64(1), errorsByCode[errors.ErrCodeInternal]) errorsByHTTPStatus := stats["errors_by_http_status"].(map[int]int64) assert.Equal(t, int64(1), errorsByHTTPStatus[500]) } func TestErrorHandler_RecordsMultipleErrors(t *testing.T) { gin.SetMode(gin.TestMode) logger := zap.NewNop() errorMetrics := metrics.NewErrorMetrics() router := gin.New() router.Use(ErrorHandler(logger, errorMetrics, true)) router.GET("/notfound", func(c *gin.Context) { c.Error(errors.NewNotFoundError("Resource")) }) router.GET("/validation", func(c *gin.Context) { c.Error(errors.NewValidationError("Invalid")) }) router.GET("/internal", func(c *gin.Context) { c.Error(errors.New(errors.ErrCodeInternal, "Error")) }) // Simuler plusieurs erreurs httptest.NewRecorder() req1 := httptest.NewRequest("GET", "/notfound", nil) w1 := httptest.NewRecorder() router.ServeHTTP(w1, req1) req2 := httptest.NewRequest("GET", "/validation", nil) w2 := httptest.NewRecorder() router.ServeHTTP(w2, req2) req3 := httptest.NewRequest("GET", "/internal", nil) w3 := httptest.NewRecorder() router.ServeHTTP(w3, req3) stats := errorMetrics.GetStats() assert.Equal(t, int64(3), stats["total_errors"]) errorsByHTTPStatus := stats["errors_by_http_status"].(map[int]int64) assert.Equal(t, int64(1), errorsByHTTPStatus[404]) assert.Equal(t, int64(1), errorsByHTTPStatus[400]) assert.Equal(t, int64(1), errorsByHTTPStatus[500]) } func TestErrorHandler_WorksWithoutMetrics(t *testing.T) { gin.SetMode(gin.TestMode) logger := zap.NewNop() router := gin.New() // Passer nil pour les métriques - ne doit pas planter router.Use(ErrorHandler(logger, nil, true)) router.GET("/test", func(c *gin.Context) { c.Error(errors.NewNotFoundError("User")) }) w := httptest.NewRecorder() req := httptest.NewRequest("GET", "/test", nil) router.ServeHTTP(w, req) assert.Equal(t, http.StatusNotFound, w.Code) var response map[string]interface{} err := json.Unmarshal(w.Body.Bytes(), &response) require.NoError(t, err) errorObj := response["error"].(map[string]interface{}) assert.Equal(t, float64(errors.ErrCodeNotFound), errorObj["code"]) }