mirror of
https://github.com/samsonjs/rack-attack.git
synced 2026-04-27 15:07:41 +00:00
Allow to reset state between tests
This commit is contained in:
parent
64f879395d
commit
9923012fe8
4 changed files with 51 additions and 0 deletions
|
|
@ -14,6 +14,7 @@ module Rack
|
||||||
class Error < StandardError; end
|
class Error < StandardError; end
|
||||||
class MisconfiguredStoreError < Error; end
|
class MisconfiguredStoreError < Error; end
|
||||||
class MissingStoreError < Error; end
|
class MissingStoreError < Error; end
|
||||||
|
class IncompatibleStoreError < Error; end
|
||||||
|
|
||||||
autoload :Check, 'rack/attack/check'
|
autoload :Check, 'rack/attack/check'
|
||||||
autoload :Throttle, 'rack/attack/throttle'
|
autoload :Throttle, 'rack/attack/throttle'
|
||||||
|
|
@ -53,6 +54,10 @@ module Rack
|
||||||
@configuration.clear_configuration
|
@configuration.clear_configuration
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def reset!
|
||||||
|
cache.reset!
|
||||||
|
end
|
||||||
|
|
||||||
extend Forwardable
|
extend Forwardable
|
||||||
def_delegators(
|
def_delegators(
|
||||||
:@configuration,
|
:@configuration,
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,17 @@ module Rack
|
||||||
store.delete("#{prefix}:#{unprefixed_key}")
|
store.delete("#{prefix}:#{unprefixed_key}")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def reset!
|
||||||
|
if store.respond_to?(:delete_matched)
|
||||||
|
store.delete_matched("#{prefix}*")
|
||||||
|
else
|
||||||
|
raise(
|
||||||
|
Rack::Attack::IncompatibleStoreError,
|
||||||
|
"Configured store #{store.class.name} doesn't respond to #delete_matched method"
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def key_and_expiry(unprefixed_key, period)
|
def key_and_expiry(unprefixed_key, period)
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,19 @@ module Rack
|
||||||
rescuing { del(key) }
|
rescuing { del(key) }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def delete_matched(matcher, _options = nil)
|
||||||
|
cursor = "0"
|
||||||
|
|
||||||
|
rescuing do
|
||||||
|
# Fetch keys in batches using SCAN to avoid blocking the Redis server.
|
||||||
|
loop do
|
||||||
|
cursor, keys = scan(cursor, match: matcher, count: 1000)
|
||||||
|
del(*keys) unless keys.empty?
|
||||||
|
break if cursor == "0"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def rescuing
|
def rescuing
|
||||||
|
|
|
||||||
|
|
@ -99,4 +99,26 @@ describe 'Rack::Attack' do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe 'reset!' do
|
||||||
|
it 'raises an error when is not supported by cache store' do
|
||||||
|
Rack::Attack.cache.store = Class.new
|
||||||
|
assert_raises(Rack::Attack::IncompatibleStoreError) do
|
||||||
|
Rack::Attack.reset!
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if defined?(Redis)
|
||||||
|
it 'should delete rack attack keys' do
|
||||||
|
redis = Redis.new
|
||||||
|
redis.set('key', 'value')
|
||||||
|
redis.set("#{Rack::Attack.cache.prefix}::key", 'value')
|
||||||
|
Rack::Attack.cache.store = redis
|
||||||
|
Rack::Attack.reset!
|
||||||
|
|
||||||
|
_(redis.get('key')).must_equal 'value'
|
||||||
|
_(redis.get("#{Rack::Attack.cache.prefix}::key")).must_be_nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue