From e17d2d897475bf617376266f8989e6ec5555668a Mon Sep 17 00:00:00 2001 From: Gonzalo Rodriguez Date: Tue, 20 Mar 2018 19:06:54 -0300 Subject: [PATCH 1/3] Acceptance test throttling with a dynamic limit --- spec/acceptance/throttling_spec.rb | 35 +++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/spec/acceptance/throttling_spec.rb b/spec/acceptance/throttling_spec.rb index 2ad4605..e7b2361 100644 --- a/spec/acceptance/throttling_spec.rb +++ b/spec/acceptance/throttling_spec.rb @@ -2,9 +2,11 @@ require_relative "../spec_helper" require "timecop" describe "#throttle" do - it "allows one request per minute by IP" do + before do Rack::Attack.cache.store = ActiveSupport::Cache::MemoryStore.new + end + it "allows one request per minute by IP" do Rack::Attack.throttle("by ip", limit: 1, period: 60) do |request| request.ip end @@ -29,4 +31,35 @@ describe "#throttle" do assert_equal 200, last_response.status end end + + it "supports limit to be dynamic" do + # Could be used to have different rate limits for authorized + # vs general requests + limit_proc = lambda do |request| + if request.get_header("X-APIKey") == "private-secret" + 2 + else + 1 + end + end + + Rack::Attack.throttle("by ip", limit: limit_proc, period: 60) do |request| + request.ip + end + + get "/", {}, "REMOTE_ADDR" => "1.2.3.4" + assert_equal 200, last_response.status + + get "/", {}, "REMOTE_ADDR" => "1.2.3.4" + assert_equal 429, last_response.status + + get "/", {}, "REMOTE_ADDR" => "5.6.7.8", "X-APIKey" => "private-secret" + assert_equal 200, last_response.status + + get "/", {}, "REMOTE_ADDR" => "5.6.7.8", "X-APIKey" => "private-secret" + assert_equal 200, last_response.status + + get "/", {}, "REMOTE_ADDR" => "5.6.7.8", "X-APIKey" => "private-secret" + assert_equal 429, last_response.status + end end From 08b2cc4d950cceb80d6fbbf886ac33fd2e9737cf Mon Sep 17 00:00:00 2001 From: Gonzalo Rodriguez Date: Wed, 21 Mar 2018 17:10:27 -0300 Subject: [PATCH 2/3] Acceptance test throttling with a dynamic period --- spec/acceptance/throttling_spec.rb | 50 ++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/spec/acceptance/throttling_spec.rb b/spec/acceptance/throttling_spec.rb index e7b2361..233016c 100644 --- a/spec/acceptance/throttling_spec.rb +++ b/spec/acceptance/throttling_spec.rb @@ -62,4 +62,54 @@ describe "#throttle" do get "/", {}, "REMOTE_ADDR" => "5.6.7.8", "X-APIKey" => "private-secret" assert_equal 429, last_response.status end + + it "supports period to be dynamic" do + # Could be used to have different rate limits for authorized + # vs general requests + period_proc = lambda do |request| + if request.get_header("X-APIKey") == "private-secret" + 10 + else + 30 + end + end + + Rack::Attack.throttle("by ip", limit: 1, period: period_proc) do |request| + request.ip + end + + # Using Time#at to align to start/end of periods exactly + # to achieve consistenty in different test runs + + Timecop.travel(Time.at(0)) do + get "/", {}, "REMOTE_ADDR" => "1.2.3.4" + assert_equal 200, last_response.status + + get "/", {}, "REMOTE_ADDR" => "1.2.3.4" + assert_equal 429, last_response.status + end + + Timecop.travel(Time.at(10)) do + get "/", {}, "REMOTE_ADDR" => "1.2.3.4" + assert_equal 429, last_response.status + end + + Timecop.travel(Time.at(30)) do + get "/", {}, "REMOTE_ADDR" => "1.2.3.4" + assert_equal 200, last_response.status + end + + Timecop.travel(Time.at(0)) do + get "/", {}, "REMOTE_ADDR" => "5.6.7.8", "X-APIKey" => "private-secret" + assert_equal 200, last_response.status + + get "/", {}, "REMOTE_ADDR" => "5.6.7.8", "X-APIKey" => "private-secret" + assert_equal 429, last_response.status + end + + Timecop.travel(Time.at(10)) do + get "/", {}, "REMOTE_ADDR" => "5.6.7.8", "X-APIKey" => "private-secret" + assert_equal 200, last_response.status + end + end end From 0ff1b5be83189f5af5f526cbfb37f2c8ef3c7302 Mon Sep 17 00:00:00 2001 From: Gonzalo Rodriguez Date: Wed, 21 Mar 2018 17:29:44 -0300 Subject: [PATCH 3/3] Make throttling_spec work when running it with rails 4.2 --- spec/acceptance/throttling_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/acceptance/throttling_spec.rb b/spec/acceptance/throttling_spec.rb index 233016c..396589a 100644 --- a/spec/acceptance/throttling_spec.rb +++ b/spec/acceptance/throttling_spec.rb @@ -36,7 +36,7 @@ describe "#throttle" do # Could be used to have different rate limits for authorized # vs general requests limit_proc = lambda do |request| - if request.get_header("X-APIKey") == "private-secret" + if request.env["X-APIKey"] == "private-secret" 2 else 1 @@ -67,7 +67,7 @@ describe "#throttle" do # Could be used to have different rate limits for authorized # vs general requests period_proc = lambda do |request| - if request.get_header("X-APIKey") == "private-secret" + if request.env["X-APIKey"] == "private-secret" 10 else 30