package middleware import ( "net/http" "net/http/httptest" "testing" "github.com/gin-gonic/gin" ) func init() { gin.SetMode(gin.TestMode) } func TestRequestID_SetsHeader(t *testing.T) { r := gin.New() r.Use(RequestID) r.GET("/", func(c *gin.Context) { c.Status(http.StatusOK) }) req := httptest.NewRequest(http.MethodGet, "/", nil) rr := httptest.NewRecorder() r.ServeHTTP(rr, req) reqID := rr.Header().Get("X-Request-ID") if reqID == "" { t.Fatal("expected X-Request-ID header to be set, but it was empty") } // 8 random bytes = 16 hex characters if len(reqID) != 16 { t.Errorf("expected X-Request-ID length 16, got %d (%q)", len(reqID), reqID) } } func TestRequestID_UniquePerRequest(t *testing.T) { r := gin.New() r.Use(RequestID) r.GET("/", func(c *gin.Context) { c.Status(http.StatusOK) }) req1 := httptest.NewRequest(http.MethodGet, "/", nil) rr1 := httptest.NewRecorder() r.ServeHTTP(rr1, req1) req2 := httptest.NewRequest(http.MethodGet, "/", nil) rr2 := httptest.NewRecorder() r.ServeHTTP(rr2, req2) id1 := rr1.Header().Get("X-Request-ID") id2 := rr2.Header().Get("X-Request-ID") if id1 == id2 { t.Errorf("expected unique request IDs, but both were %q", id1) } } func TestLogging_DoesNotPanic(t *testing.T) { r := gin.New() r.Use(Logging) r.GET("/test-path", func(c *gin.Context) { c.Status(http.StatusOK) }) req := httptest.NewRequest(http.MethodGet, "/test-path", nil) rr := httptest.NewRecorder() // Should not panic r.ServeHTTP(rr, req) if rr.Code != http.StatusOK { t.Errorf("expected status 200, got %d", rr.Code) } } func TestLogging_RecordsStatus(t *testing.T) { r := gin.New() r.Use(Logging) r.GET("/missing", func(c *gin.Context) { c.Status(http.StatusNotFound) }) req := httptest.NewRequest(http.MethodGet, "/missing", nil) rr := httptest.NewRecorder() r.ServeHTTP(rr, req) if rr.Code != http.StatusNotFound { t.Errorf("expected status 404, got %d", rr.Code) } } func TestRecovery_CatchesPanics(t *testing.T) { r := gin.New() r.Use(Recovery) r.GET("/", func(c *gin.Context) { panic("something went wrong") }) req := httptest.NewRequest(http.MethodGet, "/", nil) rr := httptest.NewRecorder() // Should not propagate the panic r.ServeHTTP(rr, req) if rr.Code != http.StatusInternalServerError { t.Errorf("expected status 500, got %d", rr.Code) } } func TestRecovery_PassesThroughNormally(t *testing.T) { r := gin.New() r.Use(Recovery) r.GET("/", func(c *gin.Context) { c.String(http.StatusOK, "ok") }) req := httptest.NewRequest(http.MethodGet, "/", nil) rr := httptest.NewRecorder() r.ServeHTTP(rr, req) if rr.Code != http.StatusOK { t.Errorf("expected status 200, got %d", rr.Code) } if rr.Body.String() != "ok" { t.Errorf("expected body %q, got %q", "ok", rr.Body.String()) } }