github.com/gofiber/fiber/v2@v2.47.0/middleware/limiter/limiter_test.go (about) 1 package limiter 2 3 import ( 4 "io" 5 "net/http/httptest" 6 "sync" 7 "testing" 8 "time" 9 10 "github.com/gofiber/fiber/v2" 11 "github.com/gofiber/fiber/v2/internal/storage/memory" 12 "github.com/gofiber/fiber/v2/utils" 13 14 "github.com/valyala/fasthttp" 15 ) 16 17 // go test -run Test_Limiter_Concurrency_Store -race -v 18 func Test_Limiter_Concurrency_Store(t *testing.T) { 19 t.Parallel() 20 // Test concurrency using a custom store 21 22 app := fiber.New() 23 24 app.Use(New(Config{ 25 Max: 50, 26 Expiration: 2 * time.Second, 27 Storage: memory.New(), 28 })) 29 30 app.Get("/", func(c *fiber.Ctx) error { 31 return c.SendString("Hello tester!") 32 }) 33 34 var wg sync.WaitGroup 35 singleRequest := func(wg *sync.WaitGroup) { 36 defer wg.Done() 37 resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil)) 38 utils.AssertEqual(t, nil, err) 39 utils.AssertEqual(t, fiber.StatusOK, resp.StatusCode) 40 41 body, err := io.ReadAll(resp.Body) 42 utils.AssertEqual(t, nil, err) 43 utils.AssertEqual(t, "Hello tester!", string(body)) 44 } 45 46 for i := 0; i <= 49; i++ { 47 wg.Add(1) 48 go singleRequest(&wg) 49 } 50 51 wg.Wait() 52 53 resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil)) 54 utils.AssertEqual(t, nil, err) 55 utils.AssertEqual(t, 429, resp.StatusCode) 56 57 time.Sleep(3 * time.Second) 58 59 resp, err = app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil)) 60 utils.AssertEqual(t, nil, err) 61 utils.AssertEqual(t, 200, resp.StatusCode) 62 } 63 64 // go test -run Test_Limiter_Concurrency -race -v 65 func Test_Limiter_Concurrency(t *testing.T) { 66 t.Parallel() 67 // Test concurrency using a default store 68 69 app := fiber.New() 70 71 app.Use(New(Config{ 72 Max: 50, 73 Expiration: 2 * time.Second, 74 })) 75 76 app.Get("/", func(c *fiber.Ctx) error { 77 return c.SendString("Hello tester!") 78 }) 79 80 var wg sync.WaitGroup 81 singleRequest := func(wg *sync.WaitGroup) { 82 defer wg.Done() 83 resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil)) 84 utils.AssertEqual(t, nil, err) 85 utils.AssertEqual(t, fiber.StatusOK, resp.StatusCode) 86 87 body, err := io.ReadAll(resp.Body) 88 utils.AssertEqual(t, nil, err) 89 utils.AssertEqual(t, "Hello tester!", string(body)) 90 } 91 92 for i := 0; i <= 49; i++ { 93 wg.Add(1) 94 go singleRequest(&wg) 95 } 96 97 wg.Wait() 98 99 resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil)) 100 utils.AssertEqual(t, nil, err) 101 utils.AssertEqual(t, 429, resp.StatusCode) 102 103 time.Sleep(3 * time.Second) 104 105 resp, err = app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil)) 106 utils.AssertEqual(t, nil, err) 107 utils.AssertEqual(t, 200, resp.StatusCode) 108 } 109 110 // go test -run Test_Limiter_Fixed_Window_No_Skip_Choices -v 111 func Test_Limiter_Fixed_Window_No_Skip_Choices(t *testing.T) { 112 t.Parallel() 113 app := fiber.New() 114 115 app.Use(New(Config{ 116 Max: 2, 117 Expiration: 2 * time.Second, 118 SkipFailedRequests: false, 119 SkipSuccessfulRequests: false, 120 LimiterMiddleware: FixedWindow{}, 121 })) 122 123 app.Get("/:status", func(c *fiber.Ctx) error { 124 if c.Params("status") == "fail" { //nolint:goconst // False positive 125 return c.SendStatus(400) 126 } 127 return c.SendStatus(200) 128 }) 129 130 resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/fail", nil)) 131 utils.AssertEqual(t, nil, err) 132 utils.AssertEqual(t, 400, resp.StatusCode) 133 134 resp, err = app.Test(httptest.NewRequest(fiber.MethodGet, "/success", nil)) 135 utils.AssertEqual(t, nil, err) 136 utils.AssertEqual(t, 200, resp.StatusCode) 137 138 resp, err = app.Test(httptest.NewRequest(fiber.MethodGet, "/success", nil)) 139 utils.AssertEqual(t, nil, err) 140 utils.AssertEqual(t, 429, resp.StatusCode) 141 142 time.Sleep(3 * time.Second) 143 144 resp, err = app.Test(httptest.NewRequest(fiber.MethodGet, "/success", nil)) 145 utils.AssertEqual(t, nil, err) 146 utils.AssertEqual(t, 200, resp.StatusCode) 147 } 148 149 // go test -run Test_Limiter_Fixed_Window_Custom_Storage_No_Skip_Choices -v 150 func Test_Limiter_Fixed_Window_Custom_Storage_No_Skip_Choices(t *testing.T) { 151 t.Parallel() 152 app := fiber.New() 153 154 app.Use(New(Config{ 155 Max: 2, 156 Expiration: 2 * time.Second, 157 SkipFailedRequests: false, 158 SkipSuccessfulRequests: false, 159 Storage: memory.New(), 160 LimiterMiddleware: FixedWindow{}, 161 })) 162 163 app.Get("/:status", func(c *fiber.Ctx) error { 164 if c.Params("status") == "fail" { 165 return c.SendStatus(400) 166 } 167 return c.SendStatus(200) 168 }) 169 170 resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/fail", nil)) 171 utils.AssertEqual(t, nil, err) 172 utils.AssertEqual(t, 400, resp.StatusCode) 173 174 resp, err = app.Test(httptest.NewRequest(fiber.MethodGet, "/success", nil)) 175 utils.AssertEqual(t, nil, err) 176 utils.AssertEqual(t, 200, resp.StatusCode) 177 178 resp, err = app.Test(httptest.NewRequest(fiber.MethodGet, "/success", nil)) 179 utils.AssertEqual(t, nil, err) 180 utils.AssertEqual(t, 429, resp.StatusCode) 181 182 time.Sleep(3 * time.Second) 183 184 resp, err = app.Test(httptest.NewRequest(fiber.MethodGet, "/success", nil)) 185 utils.AssertEqual(t, nil, err) 186 utils.AssertEqual(t, 200, resp.StatusCode) 187 } 188 189 // go test -run Test_Limiter_Sliding_Window_No_Skip_Choices -v 190 func Test_Limiter_Sliding_Window_No_Skip_Choices(t *testing.T) { 191 t.Parallel() 192 app := fiber.New() 193 194 app.Use(New(Config{ 195 Max: 2, 196 Expiration: 2 * time.Second, 197 SkipFailedRequests: false, 198 SkipSuccessfulRequests: false, 199 LimiterMiddleware: SlidingWindow{}, 200 })) 201 202 app.Get("/:status", func(c *fiber.Ctx) error { 203 if c.Params("status") == "fail" { 204 return c.SendStatus(400) 205 } 206 return c.SendStatus(200) 207 }) 208 209 resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/fail", nil)) 210 utils.AssertEqual(t, nil, err) 211 utils.AssertEqual(t, 400, resp.StatusCode) 212 213 resp, err = app.Test(httptest.NewRequest(fiber.MethodGet, "/success", nil)) 214 utils.AssertEqual(t, nil, err) 215 utils.AssertEqual(t, 200, resp.StatusCode) 216 217 resp, err = app.Test(httptest.NewRequest(fiber.MethodGet, "/success", nil)) 218 utils.AssertEqual(t, nil, err) 219 utils.AssertEqual(t, 429, resp.StatusCode) 220 221 time.Sleep(4 * time.Second) 222 223 resp, err = app.Test(httptest.NewRequest(fiber.MethodGet, "/success", nil)) 224 utils.AssertEqual(t, nil, err) 225 utils.AssertEqual(t, 200, resp.StatusCode) 226 } 227 228 // go test -run Test_Limiter_Sliding_Window_Custom_Storage_No_Skip_Choices -v 229 func Test_Limiter_Sliding_Window_Custom_Storage_No_Skip_Choices(t *testing.T) { 230 t.Parallel() 231 app := fiber.New() 232 233 app.Use(New(Config{ 234 Max: 2, 235 Expiration: 2 * time.Second, 236 SkipFailedRequests: false, 237 SkipSuccessfulRequests: false, 238 Storage: memory.New(), 239 LimiterMiddleware: SlidingWindow{}, 240 })) 241 242 app.Get("/:status", func(c *fiber.Ctx) error { 243 if c.Params("status") == "fail" { 244 return c.SendStatus(400) 245 } 246 return c.SendStatus(200) 247 }) 248 249 resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/fail", nil)) 250 utils.AssertEqual(t, nil, err) 251 utils.AssertEqual(t, 400, resp.StatusCode) 252 253 resp, err = app.Test(httptest.NewRequest(fiber.MethodGet, "/success", nil)) 254 utils.AssertEqual(t, nil, err) 255 utils.AssertEqual(t, 200, resp.StatusCode) 256 257 resp, err = app.Test(httptest.NewRequest(fiber.MethodGet, "/success", nil)) 258 utils.AssertEqual(t, nil, err) 259 utils.AssertEqual(t, 429, resp.StatusCode) 260 261 time.Sleep(4 * time.Second) 262 263 resp, err = app.Test(httptest.NewRequest(fiber.MethodGet, "/success", nil)) 264 utils.AssertEqual(t, nil, err) 265 utils.AssertEqual(t, 200, resp.StatusCode) 266 } 267 268 // go test -run Test_Limiter_Fixed_Window_Skip_Failed_Requests -v 269 func Test_Limiter_Fixed_Window_Skip_Failed_Requests(t *testing.T) { 270 t.Parallel() 271 app := fiber.New() 272 273 app.Use(New(Config{ 274 Max: 1, 275 Expiration: 2 * time.Second, 276 SkipFailedRequests: true, 277 LimiterMiddleware: FixedWindow{}, 278 })) 279 280 app.Get("/:status", func(c *fiber.Ctx) error { 281 if c.Params("status") == "fail" { 282 return c.SendStatus(400) 283 } 284 return c.SendStatus(200) 285 }) 286 287 resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/fail", nil)) 288 utils.AssertEqual(t, nil, err) 289 utils.AssertEqual(t, 400, resp.StatusCode) 290 291 resp, err = app.Test(httptest.NewRequest(fiber.MethodGet, "/success", nil)) 292 utils.AssertEqual(t, nil, err) 293 utils.AssertEqual(t, 200, resp.StatusCode) 294 295 resp, err = app.Test(httptest.NewRequest(fiber.MethodGet, "/success", nil)) 296 utils.AssertEqual(t, nil, err) 297 utils.AssertEqual(t, 429, resp.StatusCode) 298 299 time.Sleep(3 * time.Second) 300 301 resp, err = app.Test(httptest.NewRequest(fiber.MethodGet, "/success", nil)) 302 utils.AssertEqual(t, nil, err) 303 utils.AssertEqual(t, 200, resp.StatusCode) 304 } 305 306 // go test -run Test_Limiter_Fixed_Window_Custom_Storage_Skip_Failed_Requests -v 307 func Test_Limiter_Fixed_Window_Custom_Storage_Skip_Failed_Requests(t *testing.T) { 308 t.Parallel() 309 app := fiber.New() 310 311 app.Use(New(Config{ 312 Max: 1, 313 Expiration: 2 * time.Second, 314 Storage: memory.New(), 315 SkipFailedRequests: true, 316 LimiterMiddleware: FixedWindow{}, 317 })) 318 319 app.Get("/:status", func(c *fiber.Ctx) error { 320 if c.Params("status") == "fail" { 321 return c.SendStatus(400) 322 } 323 return c.SendStatus(200) 324 }) 325 326 resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/fail", nil)) 327 utils.AssertEqual(t, nil, err) 328 utils.AssertEqual(t, 400, resp.StatusCode) 329 330 resp, err = app.Test(httptest.NewRequest(fiber.MethodGet, "/success", nil)) 331 utils.AssertEqual(t, nil, err) 332 utils.AssertEqual(t, 200, resp.StatusCode) 333 334 resp, err = app.Test(httptest.NewRequest(fiber.MethodGet, "/success", nil)) 335 utils.AssertEqual(t, nil, err) 336 utils.AssertEqual(t, 429, resp.StatusCode) 337 338 time.Sleep(3 * time.Second) 339 340 resp, err = app.Test(httptest.NewRequest(fiber.MethodGet, "/success", nil)) 341 utils.AssertEqual(t, nil, err) 342 utils.AssertEqual(t, 200, resp.StatusCode) 343 } 344 345 // go test -run Test_Limiter_Sliding_Window_Skip_Failed_Requests -v 346 func Test_Limiter_Sliding_Window_Skip_Failed_Requests(t *testing.T) { 347 t.Parallel() 348 app := fiber.New() 349 350 app.Use(New(Config{ 351 Max: 1, 352 Expiration: 2 * time.Second, 353 SkipFailedRequests: true, 354 LimiterMiddleware: SlidingWindow{}, 355 })) 356 357 app.Get("/:status", func(c *fiber.Ctx) error { 358 if c.Params("status") == "fail" { 359 return c.SendStatus(400) 360 } 361 return c.SendStatus(200) 362 }) 363 364 resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/fail", nil)) 365 utils.AssertEqual(t, nil, err) 366 utils.AssertEqual(t, 400, resp.StatusCode) 367 368 resp, err = app.Test(httptest.NewRequest(fiber.MethodGet, "/success", nil)) 369 utils.AssertEqual(t, nil, err) 370 utils.AssertEqual(t, 200, resp.StatusCode) 371 372 resp, err = app.Test(httptest.NewRequest(fiber.MethodGet, "/success", nil)) 373 utils.AssertEqual(t, nil, err) 374 utils.AssertEqual(t, 429, resp.StatusCode) 375 376 time.Sleep(4 * time.Second) 377 378 resp, err = app.Test(httptest.NewRequest(fiber.MethodGet, "/success", nil)) 379 utils.AssertEqual(t, nil, err) 380 utils.AssertEqual(t, 200, resp.StatusCode) 381 } 382 383 // go test -run Test_Limiter_Sliding_Window_Custom_Storage_Skip_Failed_Requests -v 384 func Test_Limiter_Sliding_Window_Custom_Storage_Skip_Failed_Requests(t *testing.T) { 385 t.Parallel() 386 app := fiber.New() 387 388 app.Use(New(Config{ 389 Max: 1, 390 Expiration: 2 * time.Second, 391 Storage: memory.New(), 392 SkipFailedRequests: true, 393 LimiterMiddleware: SlidingWindow{}, 394 })) 395 396 app.Get("/:status", func(c *fiber.Ctx) error { 397 if c.Params("status") == "fail" { 398 return c.SendStatus(400) 399 } 400 return c.SendStatus(200) 401 }) 402 403 resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/fail", nil)) 404 utils.AssertEqual(t, nil, err) 405 utils.AssertEqual(t, 400, resp.StatusCode) 406 407 resp, err = app.Test(httptest.NewRequest(fiber.MethodGet, "/success", nil)) 408 utils.AssertEqual(t, nil, err) 409 utils.AssertEqual(t, 200, resp.StatusCode) 410 411 resp, err = app.Test(httptest.NewRequest(fiber.MethodGet, "/success", nil)) 412 utils.AssertEqual(t, nil, err) 413 utils.AssertEqual(t, 429, resp.StatusCode) 414 415 time.Sleep(4 * time.Second) 416 417 resp, err = app.Test(httptest.NewRequest(fiber.MethodGet, "/success", nil)) 418 utils.AssertEqual(t, nil, err) 419 utils.AssertEqual(t, 200, resp.StatusCode) 420 } 421 422 // go test -run Test_Limiter_Fixed_Window_Skip_Successful_Requests -v 423 func Test_Limiter_Fixed_Window_Skip_Successful_Requests(t *testing.T) { 424 t.Parallel() 425 // Test concurrency using a default store 426 427 app := fiber.New() 428 429 app.Use(New(Config{ 430 Max: 1, 431 Expiration: 2 * time.Second, 432 SkipSuccessfulRequests: true, 433 LimiterMiddleware: FixedWindow{}, 434 })) 435 436 app.Get("/:status", func(c *fiber.Ctx) error { 437 if c.Params("status") == "fail" { 438 return c.SendStatus(400) 439 } 440 return c.SendStatus(200) 441 }) 442 443 resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/success", nil)) 444 utils.AssertEqual(t, nil, err) 445 utils.AssertEqual(t, 200, resp.StatusCode) 446 447 resp, err = app.Test(httptest.NewRequest(fiber.MethodGet, "/fail", nil)) 448 utils.AssertEqual(t, nil, err) 449 utils.AssertEqual(t, 400, resp.StatusCode) 450 451 resp, err = app.Test(httptest.NewRequest(fiber.MethodGet, "/fail", nil)) 452 utils.AssertEqual(t, nil, err) 453 utils.AssertEqual(t, 429, resp.StatusCode) 454 455 time.Sleep(3 * time.Second) 456 457 resp, err = app.Test(httptest.NewRequest(fiber.MethodGet, "/fail", nil)) 458 utils.AssertEqual(t, nil, err) 459 utils.AssertEqual(t, 400, resp.StatusCode) 460 } 461 462 // go test -run Test_Limiter_Fixed_Window_Custom_Storage_Skip_Successful_Requests -v 463 func Test_Limiter_Fixed_Window_Custom_Storage_Skip_Successful_Requests(t *testing.T) { 464 t.Parallel() 465 // Test concurrency using a default store 466 467 app := fiber.New() 468 469 app.Use(New(Config{ 470 Max: 1, 471 Expiration: 2 * time.Second, 472 Storage: memory.New(), 473 SkipSuccessfulRequests: true, 474 LimiterMiddleware: FixedWindow{}, 475 })) 476 477 app.Get("/:status", func(c *fiber.Ctx) error { 478 if c.Params("status") == "fail" { 479 return c.SendStatus(400) 480 } 481 return c.SendStatus(200) 482 }) 483 484 resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/success", nil)) 485 utils.AssertEqual(t, nil, err) 486 utils.AssertEqual(t, 200, resp.StatusCode) 487 488 resp, err = app.Test(httptest.NewRequest(fiber.MethodGet, "/fail", nil)) 489 utils.AssertEqual(t, nil, err) 490 utils.AssertEqual(t, 400, resp.StatusCode) 491 492 resp, err = app.Test(httptest.NewRequest(fiber.MethodGet, "/fail", nil)) 493 utils.AssertEqual(t, nil, err) 494 utils.AssertEqual(t, 429, resp.StatusCode) 495 496 time.Sleep(3 * time.Second) 497 498 resp, err = app.Test(httptest.NewRequest(fiber.MethodGet, "/fail", nil)) 499 utils.AssertEqual(t, nil, err) 500 utils.AssertEqual(t, 400, resp.StatusCode) 501 } 502 503 // go test -run Test_Limiter_Sliding_Window_Skip_Successful_Requests -v 504 func Test_Limiter_Sliding_Window_Skip_Successful_Requests(t *testing.T) { 505 t.Parallel() 506 // Test concurrency using a default store 507 508 app := fiber.New() 509 510 app.Use(New(Config{ 511 Max: 1, 512 Expiration: 2 * time.Second, 513 SkipSuccessfulRequests: true, 514 LimiterMiddleware: SlidingWindow{}, 515 })) 516 517 app.Get("/:status", func(c *fiber.Ctx) error { 518 if c.Params("status") == "fail" { 519 return c.SendStatus(400) 520 } 521 return c.SendStatus(200) 522 }) 523 524 resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/success", nil)) 525 utils.AssertEqual(t, nil, err) 526 utils.AssertEqual(t, 200, resp.StatusCode) 527 528 resp, err = app.Test(httptest.NewRequest(fiber.MethodGet, "/fail", nil)) 529 utils.AssertEqual(t, nil, err) 530 utils.AssertEqual(t, 400, resp.StatusCode) 531 532 resp, err = app.Test(httptest.NewRequest(fiber.MethodGet, "/fail", nil)) 533 utils.AssertEqual(t, nil, err) 534 utils.AssertEqual(t, 429, resp.StatusCode) 535 536 time.Sleep(4 * time.Second) 537 538 resp, err = app.Test(httptest.NewRequest(fiber.MethodGet, "/fail", nil)) 539 utils.AssertEqual(t, nil, err) 540 utils.AssertEqual(t, 400, resp.StatusCode) 541 } 542 543 // go test -run Test_Limiter_Sliding_Window_Custom_Storage_Skip_Successful_Requests -v 544 func Test_Limiter_Sliding_Window_Custom_Storage_Skip_Successful_Requests(t *testing.T) { 545 t.Parallel() 546 // Test concurrency using a default store 547 548 app := fiber.New() 549 550 app.Use(New(Config{ 551 Max: 1, 552 Expiration: 2 * time.Second, 553 Storage: memory.New(), 554 SkipSuccessfulRequests: true, 555 LimiterMiddleware: SlidingWindow{}, 556 })) 557 558 app.Get("/:status", func(c *fiber.Ctx) error { 559 if c.Params("status") == "fail" { 560 return c.SendStatus(400) 561 } 562 return c.SendStatus(200) 563 }) 564 565 resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/success", nil)) 566 utils.AssertEqual(t, nil, err) 567 utils.AssertEqual(t, 200, resp.StatusCode) 568 569 resp, err = app.Test(httptest.NewRequest(fiber.MethodGet, "/fail", nil)) 570 utils.AssertEqual(t, nil, err) 571 utils.AssertEqual(t, 400, resp.StatusCode) 572 573 resp, err = app.Test(httptest.NewRequest(fiber.MethodGet, "/fail", nil)) 574 utils.AssertEqual(t, nil, err) 575 utils.AssertEqual(t, 429, resp.StatusCode) 576 577 time.Sleep(4 * time.Second) 578 579 resp, err = app.Test(httptest.NewRequest(fiber.MethodGet, "/fail", nil)) 580 utils.AssertEqual(t, nil, err) 581 utils.AssertEqual(t, 400, resp.StatusCode) 582 } 583 584 // go test -v -run=^$ -bench=Benchmark_Limiter_Custom_Store -benchmem -count=4 585 func Benchmark_Limiter_Custom_Store(b *testing.B) { 586 app := fiber.New() 587 588 app.Use(New(Config{ 589 Max: 100, 590 Expiration: 60 * time.Second, 591 Storage: memory.New(), 592 })) 593 594 app.Get("/", func(c *fiber.Ctx) error { 595 return c.SendString("Hello, World!") 596 }) 597 598 h := app.Handler() 599 600 fctx := &fasthttp.RequestCtx{} 601 fctx.Request.Header.SetMethod(fiber.MethodGet) 602 fctx.Request.SetRequestURI("/") 603 604 b.ResetTimer() 605 606 for n := 0; n < b.N; n++ { 607 h(fctx) 608 } 609 } 610 611 // go test -run Test_Limiter_Next 612 func Test_Limiter_Next(t *testing.T) { 613 t.Parallel() 614 app := fiber.New() 615 app.Use(New(Config{ 616 Next: func(_ *fiber.Ctx) bool { 617 return true 618 }, 619 })) 620 621 resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil)) 622 utils.AssertEqual(t, nil, err) 623 utils.AssertEqual(t, fiber.StatusNotFound, resp.StatusCode) 624 } 625 626 func Test_Limiter_Headers(t *testing.T) { 627 t.Parallel() 628 app := fiber.New() 629 630 app.Use(New(Config{ 631 Max: 50, 632 Expiration: 2 * time.Second, 633 })) 634 635 app.Get("/", func(c *fiber.Ctx) error { 636 return c.SendString("Hello tester!") 637 }) 638 639 fctx := &fasthttp.RequestCtx{} 640 fctx.Request.Header.SetMethod(fiber.MethodGet) 641 fctx.Request.SetRequestURI("/") 642 643 app.Handler()(fctx) 644 645 utils.AssertEqual(t, "50", string(fctx.Response.Header.Peek("X-RateLimit-Limit"))) 646 if v := string(fctx.Response.Header.Peek("X-RateLimit-Remaining")); v == "" { 647 t.Errorf("The X-RateLimit-Remaining header is not set correctly - value is an empty string.") 648 } 649 if v := string(fctx.Response.Header.Peek("X-RateLimit-Reset")); !(v == "1" || v == "2") { 650 t.Errorf("The X-RateLimit-Reset header is not set correctly - value is out of bounds.") 651 } 652 } 653 654 // go test -v -run=^$ -bench=Benchmark_Limiter -benchmem -count=4 655 func Benchmark_Limiter(b *testing.B) { 656 app := fiber.New() 657 658 app.Use(New(Config{ 659 Max: 100, 660 Expiration: 60 * time.Second, 661 })) 662 663 app.Get("/", func(c *fiber.Ctx) error { 664 return c.SendString("Hello, World!") 665 }) 666 667 h := app.Handler() 668 669 fctx := &fasthttp.RequestCtx{} 670 fctx.Request.Header.SetMethod(fiber.MethodGet) 671 fctx.Request.SetRequestURI("/") 672 673 b.ResetTimer() 674 675 for n := 0; n < b.N; n++ { 676 h(fctx) 677 } 678 } 679 680 // go test -run Test_Sliding_Window -race -v 681 func Test_Sliding_Window(t *testing.T) { 682 t.Parallel() 683 app := fiber.New() 684 app.Use(New(Config{ 685 Max: 10, 686 Expiration: 2 * time.Second, 687 Storage: memory.New(), 688 LimiterMiddleware: SlidingWindow{}, 689 })) 690 691 app.Get("/", func(c *fiber.Ctx) error { 692 return c.SendString("Hello tester!") 693 }) 694 695 singleRequest := func(shouldFail bool) { 696 resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil)) 697 if shouldFail { 698 utils.AssertEqual(t, nil, err) 699 utils.AssertEqual(t, 429, resp.StatusCode) 700 } else { 701 utils.AssertEqual(t, nil, err) 702 utils.AssertEqual(t, fiber.StatusOK, resp.StatusCode) 703 } 704 } 705 706 for i := 0; i < 5; i++ { 707 singleRequest(false) 708 } 709 710 time.Sleep(2 * time.Second) 711 712 for i := 0; i < 5; i++ { 713 singleRequest(false) 714 } 715 716 time.Sleep(3 * time.Second) 717 718 for i := 0; i < 5; i++ { 719 singleRequest(false) 720 } 721 722 time.Sleep(4 * time.Second) 723 724 for i := 0; i < 9; i++ { 725 singleRequest(false) 726 } 727 }