package middleware import ( "net/http" "net/http/httptest" "testing" "github.com/gin-gonic/gin" ) func newTestEngine(mw gin.HandlerFunc) *gin.Engine { gin.SetMode(gin.TestMode) engine := gin.New() engine.GET("/x", mw, func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{"ok": true}) }) return engine } func TestRateLimiter_AllowsWithinLimit(t *testing.T) { engine := newTestEngine(RateLimiter(3, 1)) for i := 0; i < 3; i++ { req := httptest.NewRequest(http.MethodGet, "/x", nil) req.RemoteAddr = "1.2.3.4:1111" w := httptest.NewRecorder() engine.ServeHTTP(w, req) if w.Code != http.StatusOK { t.Fatalf("request %d: expected 200, got %d", i+1, w.Code) } } } func TestRateLimiter_BlocksOverLimit(t *testing.T) { engine := newTestEngine(RateLimiter(2, 0)) // بدون شارژ دوباره، فقط ۲ تا مجازه for i := 0; i < 2; i++ { req := httptest.NewRequest(http.MethodGet, "/x", nil) req.RemoteAddr = "5.6.7.8:2222" w := httptest.NewRecorder() engine.ServeHTTP(w, req) if w.Code != http.StatusOK { t.Fatalf("request %d: expected 200, got %d", i+1, w.Code) } } req := httptest.NewRequest(http.MethodGet, "/x", nil) req.RemoteAddr = "5.6.7.8:2222" w := httptest.NewRecorder() engine.ServeHTTP(w, req) if w.Code != http.StatusTooManyRequests { t.Fatalf("expected 429 on 3rd request, got %d", w.Code) } } func TestRateLimiter_SeparateBucketsPerIP(t *testing.T) { engine := newTestEngine(RateLimiter(1, 0)) req1 := httptest.NewRequest(http.MethodGet, "/x", nil) req1.RemoteAddr = "9.9.9.9:1" w1 := httptest.NewRecorder() engine.ServeHTTP(w1, req1) if w1.Code != http.StatusOK { t.Fatalf("expected 200 for first IP, got %d", w1.Code) } req2 := httptest.NewRequest(http.MethodGet, "/x", nil) req2.RemoteAddr = "8.8.8.8:1" w2 := httptest.NewRecorder() engine.ServeHTTP(w2, req2) if w2.Code != http.StatusOK { t.Fatalf("expected 200 for a different IP (separate bucket), got %d", w2.Code) } }