package middleware import ( "encoding/json" "net/http" "net/http/httptest" "testing" "veza-backend-api/internal/errors" "github.com/gin-gonic/gin" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/zap" ) func TestRecovery(t *testing.T) { gin.SetMode(gin.TestMode) logger := zap.NewNop() router := gin.New() router.Use(Recovery(logger, true)) router.GET("/test", func(c *gin.Context) { panic("test panic") }) w := httptest.NewRecorder() req := httptest.NewRequest("GET", "/test", nil) router.ServeHTTP(w, req) assert.Equal(t, http.StatusInternalServerError, 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.ErrCodeInternal), errorObj["code"]) assert.Equal(t, "Internal server error", errorObj["message"]) } func TestRecovery_WithRequestID(t *testing.T) { gin.SetMode(gin.TestMode) logger := zap.NewNop() router := gin.New() router.Use(RequestID()) router.Use(Recovery(logger, true)) router.GET("/test", func(c *gin.Context) { panic("panic with request ID") }) w := httptest.NewRecorder() req := httptest.NewRequest("GET", "/test", nil) router.ServeHTTP(w, req) assert.Equal(t, http.StatusInternalServerError, w.Code) assert.NotEmpty(t, w.Header().Get("X-Request-ID")) } func TestRecovery_WithUserID(t *testing.T) { gin.SetMode(gin.TestMode) logger := zap.NewNop() router := gin.New() router.Use(RequestID()) router.Use(Recovery(logger, true)) router.GET("/test", func(c *gin.Context) { c.Set("user_id", int64(42)) panic("panic with user ID") }) w := httptest.NewRecorder() req := httptest.NewRequest("GET", "/test", nil) router.ServeHTTP(w, req) assert.Equal(t, http.StatusInternalServerError, w.Code) } func TestRecovery_DifferentPanicTypes(t *testing.T) { gin.SetMode(gin.TestMode) logger := zap.NewNop() tests := []struct { name string panic interface{} }{ {"string panic", "string error"}, {"error panic", assert.AnError}, {"int panic", 42}, {"nil panic", nil}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { router := gin.New() router.Use(Recovery(logger, true)) router.GET("/test", func(c *gin.Context) { panic(tt.panic) }) w := httptest.NewRecorder() req := httptest.NewRequest("GET", "/test", nil) router.ServeHTTP(w, req) assert.Equal(t, http.StatusInternalServerError, 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.ErrCodeInternal), errorObj["code"]) }) } } func TestRecovery_NoPanic(t *testing.T) { gin.SetMode(gin.TestMode) logger := zap.NewNop() router := gin.New() router.Use(Recovery(logger, true)) router.GET("/test", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{"success": true}) }) w := httptest.NewRecorder() req := httptest.NewRequest("GET", "/test", nil) router.ServeHTTP(w, req) assert.Equal(t, http.StatusOK, w.Code) assert.Contains(t, w.Body.String(), "success") } func TestRecovery_StackTrace(t *testing.T) { gin.SetMode(gin.TestMode) // Créer un logger qui capture les logs var loggedFields []zap.Field captureLogger := zap.NewNop() // Note: En production, on utiliserait un logger qui capture vraiment // Pour ce test, on vérifie juste que le code ne panique pas router := gin.New() router.Use(RequestID()) router.Use(Recovery(captureLogger, true)) router.GET("/test", func(c *gin.Context) { panic("test for stack trace") }) w := httptest.NewRecorder() req := httptest.NewRequest("GET", "/test", nil) router.ServeHTTP(w, req) assert.Equal(t, http.StatusInternalServerError, w.Code) // Vérifier que le logger a été appelé (pas de panic dans le logger) _ = loggedFields // Utilisé pour éviter l'avertissement } func TestRecovery_AbortsRequest(t *testing.T) { gin.SetMode(gin.TestMode) logger := zap.NewNop() router := gin.New() router.Use(Recovery(logger, true)) router.GET("/test", func(c *gin.Context) { panic("test abort") // code unreachable removed }) w := httptest.NewRecorder() req := httptest.NewRequest("GET", "/test", nil) router.ServeHTTP(w, req) assert.Equal(t, http.StatusInternalServerError, w.Code) assert.NotContains(t, w.Body.String(), "should") }