veza/veza-backend-api/internal/middleware/recovery_test.go
2025-12-16 11:23:49 -05:00

173 lines
4.4 KiB
Go

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")
}