If the user makes a request while rate limited, penalize them 1 second for that request, up to a maximum of 30 seconds. This means that if a user doesn't stop making requests after being rate limited, then they will stay rate limited forever until they stop. This is to temp ban bots, especially spam bots, that flood requests while ignoring HTTP errors or rate limits. (Note that this is on a per-endpoint basis. Being rate limited on one endpoint won't penalize you for making calls to other endpoints.)
73 lines
2.7 KiB
Ruby
73 lines
2.7 KiB
Ruby
require 'test_helper'
|
|
|
|
class RateLimitTest < ActiveSupport::TestCase
|
|
context "RateLimit: " do
|
|
context "#limit! method" do
|
|
should "create a new rate limit object if none exists, or update it if it already exists" do
|
|
assert_difference("RateLimit.count", 1) do
|
|
RateLimiter.new("write", ["users/1"]).limited?
|
|
end
|
|
|
|
assert_difference("RateLimit.count", 0) do
|
|
RateLimiter.new("write", ["users/1"]).limited?
|
|
end
|
|
|
|
assert_difference("RateLimit.count", 1) do
|
|
RateLimiter.new("write", ["users/1", "ip/1.2.3.4"]).limited?
|
|
end
|
|
|
|
assert_difference("RateLimit.count", 0) do
|
|
RateLimiter.new("write", ["users/1", "ip/1.2.3.4"]).limited?
|
|
end
|
|
end
|
|
|
|
should "include the cost of the first action when initializing the limit" do
|
|
limiter = RateLimiter.new("write", ["users/1"], burst: 10, cost: 1)
|
|
assert_equal(9, limiter.rate_limits.first.points)
|
|
end
|
|
|
|
should "be limited and penalize the caller 1 second if the point count is negative" do
|
|
freeze_time
|
|
create(:rate_limit, action: "write", key: "users/1", points: -1)
|
|
limiter = RateLimiter.new("write", ["users/1"], cost: 1)
|
|
|
|
assert_equal(true, limiter.limited?)
|
|
assert_equal(-2, limiter.rate_limits.first.points)
|
|
end
|
|
|
|
should "not be limited if the point count was positive before the action" do
|
|
freeze_time
|
|
create(:rate_limit, action: "write", key: "users/1", points: 0.01)
|
|
limiter = RateLimiter.new("write", ["users/1"], cost: 1)
|
|
|
|
assert_equal(false, limiter.limited?)
|
|
assert_equal(-0.99, limiter.rate_limits.first.points)
|
|
end
|
|
|
|
should "refill the points at the correct rate" do
|
|
freeze_time
|
|
create(:rate_limit, action: "write", key: "users/1", points: -2)
|
|
|
|
limiter = RateLimiter.new("write", ["users/1"], cost: 1, rate: 1, burst: 10)
|
|
assert_equal(true, limiter.limited?)
|
|
assert_equal(-3, limiter.rate_limits.first.points)
|
|
|
|
travel 1.second
|
|
limiter = RateLimiter.new("write", ["users/1"], cost: 1, rate: 1, burst: 10)
|
|
assert_equal(true, limiter.limited?)
|
|
assert_equal(-3, limiter.rate_limits.first.points)
|
|
|
|
travel 5.second
|
|
limiter = RateLimiter.new("write", ["users/1"], cost: 1, rate: 1, burst: 10)
|
|
assert_equal(false, limiter.limited?)
|
|
assert_equal(1, limiter.rate_limits.first.points)
|
|
|
|
travel 60.second
|
|
limiter = RateLimiter.new("write", ["users/1"], cost: 1, rate: 1, burst: 10)
|
|
assert_equal(false, limiter.limited?)
|
|
assert_equal(9, limiter.rate_limits.first.points)
|
|
end
|
|
end
|
|
end
|
|
end
|