| |
| |
| package middleware |
|
|
| import ( |
| "errors" |
| "net/http" |
| "net/http/httptest" |
| "testing" |
|
|
| "github.com/gin-gonic/gin" |
| "github.com/sirupsen/logrus" |
| "github.com/stretchr/testify/assert" |
| ) |
|
|
| func setupTestRouter() *gin.Engine { |
| gin.SetMode(gin.TestMode) |
| return gin.New() |
| } |
|
|
| func TestRequestIDMiddleware(t *testing.T) { |
| router := setupTestRouter() |
| router.Use(RequestID()) |
| router.GET("/test", func(c *gin.Context) { |
| id := c.GetString("request_id") |
| c.JSON(200, gin.H{"request_id": id}) |
| }) |
|
|
| t.Run("generates request ID when not provided", func(t *testing.T) { |
| w := httptest.NewRecorder() |
| req, _ := http.NewRequest("GET", "/test", http.NoBody) |
| router.ServeHTTP(w, req) |
|
|
| assert.Equal(t, 200, w.Code) |
| |
| assert.Contains(t, w.Body.String(), "request_id") |
| |
| assert.NotEmpty(t, w.Header().Get("X-Request-ID")) |
| }) |
|
|
| t.Run("uses existing request ID from header", func(t *testing.T) { |
| w := httptest.NewRecorder() |
| req, _ := http.NewRequest("GET", "/test", http.NoBody) |
| req.Header.Set("X-Request-ID", "test-request-id-123") |
| router.ServeHTTP(w, req) |
|
|
| assert.Equal(t, 200, w.Code) |
| assert.Contains(t, w.Body.String(), "test-request-id-123") |
| assert.Equal(t, "test-request-id-123", w.Header().Get("X-Request-ID")) |
| }) |
| } |
|
|
| func TestErrorHandler(t *testing.T) { |
| router := setupTestRouter() |
| router.Use(RequestID()) |
| router.Use(ErrorHandler(logrus.New())) |
|
|
| router.GET("/error", func(c *gin.Context) { |
| c.Error(errors.New("test error")) |
| c.Abort() |
| }) |
|
|
| router.GET("/success", func(c *gin.Context) { |
| c.JSON(200, gin.H{"status": "ok"}) |
| }) |
|
|
| t.Run("handles errors gracefully", func(t *testing.T) { |
| w := httptest.NewRecorder() |
| req, _ := http.NewRequest("GET", "/error", http.NoBody) |
| router.ServeHTTP(w, req) |
|
|
| assert.Equal(t, 500, w.Code) |
| assert.Contains(t, w.Body.String(), "An unexpected error occurred") |
| }) |
|
|
| t.Run("passes through successful requests", func(t *testing.T) { |
| w := httptest.NewRecorder() |
| req, _ := http.NewRequest("GET", "/success", http.NoBody) |
| router.ServeHTTP(w, req) |
|
|
| assert.Equal(t, 200, w.Code) |
| assert.Contains(t, w.Body.String(), "ok") |
| }) |
| } |
|
|
| func TestRecoveryMiddleware(t *testing.T) { |
| router := setupTestRouter() |
| router.Use(RecoveryMiddleware(nil)) |
| router.Use(RequestID()) |
| router.Use(ErrorHandler(logrus.New())) |
|
|
| router.GET("/panic", func(c *gin.Context) { |
| panic("test panic") |
| }) |
|
|
| router.GET("/normal", func(c *gin.Context) { |
| c.JSON(200, gin.H{"status": "ok"}) |
| }) |
|
|
| t.Run("recovers from panic", func(t *testing.T) { |
| w := httptest.NewRecorder() |
| req, _ := http.NewRequest("GET", "/panic", http.NoBody) |
| router.ServeHTTP(w, req) |
|
|
| assert.Equal(t, 500, w.Code) |
| assert.Contains(t, w.Body.String(), "An internal server error occurred") |
| }) |
|
|
| t.Run("normal requests work after panic recovery", func(t *testing.T) { |
| w := httptest.NewRecorder() |
| req, _ := http.NewRequest("GET", "/normal", http.NoBody) |
| router.ServeHTTP(w, req) |
|
|
| assert.Equal(t, 200, w.Code) |
| assert.Contains(t, w.Body.String(), "ok") |
| }) |
| } |
|
|
| func TestSafeHandler(t *testing.T) { |
| router := setupTestRouter() |
| router.Use(RequestID()) |
| router.Use(ErrorHandler(logrus.New())) |
|
|
| router.GET("/safe-panic", SafeHandler(func(c *gin.Context) { |
| panic("safe handler panic") |
| })) |
|
|
| t.Run("safe handler recovers from panic", func(t *testing.T) { |
| w := httptest.NewRecorder() |
| req, _ := http.NewRequest("GET", "/safe-panic", http.NoBody) |
| router.ServeHTTP(w, req) |
|
|
| assert.Equal(t, 500, w.Code) |
| assert.Contains(t, w.Body.String(), "An internal server error occurred") |
| }) |
| } |
|
|