rack-attack 5.3.1 → 5.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/rack/attack.rb +22 -22
- data/lib/rack/attack/check.rb +6 -8
- data/lib/rack/attack/store_proxy/redis_cache_store_proxy.rb +2 -2
- data/lib/rack/attack/throttle.rb +10 -10
- data/lib/rack/attack/track.rb +3 -3
- data/lib/rack/attack/version.rb +1 -1
- data/spec/acceptance/stores/active_support_dalli_store_spec.rb +41 -0
- data/spec/acceptance/stores/active_support_mem_cache_store_spec.rb +40 -0
- data/spec/acceptance/stores/{mem_cache_store_spec.rb → active_support_memory_store_spec.rb} +5 -5
- data/spec/acceptance/stores/{redis_cache_store_pooled_spec.rb → active_support_redis_cache_store_pooled_spec.rb} +4 -4
- data/spec/acceptance/stores/{redis_cache_store_spec.rb → active_support_redis_cache_store_spec.rb} +4 -4
- data/spec/acceptance/stores/active_support_redis_store_spec.rb +40 -0
- data/spec/acceptance/stores/connection_pool_dalli_client_spec.rb +42 -0
- data/spec/acceptance/stores/dalli_client_spec.rb +41 -0
- data/spec/acceptance/stores/redis_store_spec.rb +40 -0
- data/spec/integration/offline_spec.rb +21 -19
- data/spec/rack_attack_track_spec.rb +4 -4
- data/spec/spec_helper.rb +15 -8
- metadata +65 -150
- data/spec/integration/rack_attack_cache_spec.rb +0 -124
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 30b1caccf538327c289b6e4962e2deadc4d7c5fc8509eb1adbf4383c950bd4ad
|
4
|
+
data.tar.gz: 4b8af97dca4e04414712cce9ba21cc7940f46e2072d3cc9e288b5bf54d066bba
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f439d0196c505e73f10671f30d1b9cf919fb1b185468f38915817782cfecdc59d6405bd4d1a895e956de2f788c33524f232bd5c4eadee36dffe1883b0954efdb
|
7
|
+
data.tar.gz: a736973564ec15f143fbb6b5067441eea50cbc33385a557b1d6d13180b5237982cc676de6ee97989e06fa97185666811945b85d6a8263c19c0a16446407afa22
|
data/lib/rack/attack.rb
CHANGED
@@ -81,40 +81,40 @@ class Rack::Attack
|
|
81
81
|
blocklists
|
82
82
|
end
|
83
83
|
|
84
|
-
def safelisted?(
|
85
|
-
ip_safelists.any? { |safelist| safelist.
|
86
|
-
safelists.any? { |_name, safelist| safelist.
|
84
|
+
def safelisted?(request)
|
85
|
+
ip_safelists.any? { |safelist| safelist.matched_by?(request) } ||
|
86
|
+
safelists.any? { |_name, safelist| safelist.matched_by?(request) }
|
87
87
|
end
|
88
88
|
|
89
|
-
def whitelisted?(
|
89
|
+
def whitelisted?(request)
|
90
90
|
warn "[DEPRECATION] 'Rack::Attack.whitelisted?' is deprecated. Please use 'safelisted?' instead."
|
91
|
-
safelisted?(
|
91
|
+
safelisted?(request)
|
92
92
|
end
|
93
93
|
|
94
|
-
def blocklisted?(
|
95
|
-
ip_blocklists.any? { |blocklist| blocklist.
|
96
|
-
blocklists.any? { |_name, blocklist| blocklist.
|
94
|
+
def blocklisted?(request)
|
95
|
+
ip_blocklists.any? { |blocklist| blocklist.matched_by?(request) } ||
|
96
|
+
blocklists.any? { |_name, blocklist| blocklist.matched_by?(request) }
|
97
97
|
end
|
98
98
|
|
99
|
-
def blacklisted?(
|
99
|
+
def blacklisted?(request)
|
100
100
|
warn "[DEPRECATION] 'Rack::Attack.blacklisted?' is deprecated. Please use 'blocklisted?' instead."
|
101
|
-
blocklisted?(
|
101
|
+
blocklisted?(request)
|
102
102
|
end
|
103
103
|
|
104
|
-
def throttled?(
|
104
|
+
def throttled?(request)
|
105
105
|
throttles.any? do |_name, throttle|
|
106
|
-
throttle
|
106
|
+
throttle.matched_by?(request)
|
107
107
|
end
|
108
108
|
end
|
109
109
|
|
110
|
-
def tracked?(
|
111
|
-
tracks.each_value do |
|
112
|
-
|
110
|
+
def tracked?(request)
|
111
|
+
tracks.each_value do |track|
|
112
|
+
track.matched_by?(request)
|
113
113
|
end
|
114
114
|
end
|
115
115
|
|
116
|
-
def instrument(
|
117
|
-
notifier.instrument('rack.attack',
|
116
|
+
def instrument(request)
|
117
|
+
notifier.instrument('rack.attack', request) if notifier
|
118
118
|
end
|
119
119
|
|
120
120
|
def cache
|
@@ -167,16 +167,16 @@ class Rack::Attack
|
|
167
167
|
|
168
168
|
def call(env)
|
169
169
|
env['PATH_INFO'] = PathNormalizer.normalize_path(env['PATH_INFO'])
|
170
|
-
|
170
|
+
request = Rack::Attack::Request.new(env)
|
171
171
|
|
172
|
-
if safelisted?(
|
172
|
+
if safelisted?(request)
|
173
173
|
@app.call(env)
|
174
|
-
elsif blocklisted?(
|
174
|
+
elsif blocklisted?(request)
|
175
175
|
self.class.blocklisted_response.call(env)
|
176
|
-
elsif throttled?(
|
176
|
+
elsif throttled?(request)
|
177
177
|
self.class.throttled_response.call(env)
|
178
178
|
else
|
179
|
-
tracked?(
|
179
|
+
tracked?(request)
|
180
180
|
@app.call(env)
|
181
181
|
end
|
182
182
|
end
|
data/lib/rack/attack/check.rb
CHANGED
@@ -7,17 +7,15 @@ module Rack
|
|
7
7
|
@type = options.fetch(:type, nil)
|
8
8
|
end
|
9
9
|
|
10
|
-
def
|
11
|
-
block
|
10
|
+
def matched_by?(request)
|
11
|
+
block.call(request).tap do |match|
|
12
12
|
if match
|
13
|
-
|
14
|
-
|
15
|
-
Rack::Attack.instrument(
|
13
|
+
request.env["rack.attack.matched"] = name
|
14
|
+
request.env["rack.attack.match_type"] = type
|
15
|
+
Rack::Attack.instrument(request)
|
16
16
|
end
|
17
|
-
|
17
|
+
end
|
18
18
|
end
|
19
|
-
|
20
|
-
alias_method :match?, :[]
|
21
19
|
end
|
22
20
|
end
|
23
21
|
end
|
@@ -5,7 +5,7 @@ module Rack
|
|
5
5
|
module StoreProxy
|
6
6
|
class RedisCacheStoreProxy < SimpleDelegator
|
7
7
|
def self.handle?(store)
|
8
|
-
defined?(::ActiveSupport::Cache::RedisCacheStore) && store.is_a?(::ActiveSupport::Cache::RedisCacheStore)
|
8
|
+
defined?(::Redis) && defined?(::ActiveSupport::Cache::RedisCacheStore) && store.is_a?(::ActiveSupport::Cache::RedisCacheStore)
|
9
9
|
end
|
10
10
|
|
11
11
|
def increment(name, amount = 1, options = {})
|
@@ -16,7 +16,7 @@ module Rack
|
|
16
16
|
if options[:expires_in] && !read(name)
|
17
17
|
write(name, amount, options)
|
18
18
|
|
19
|
-
|
19
|
+
amount
|
20
20
|
else
|
21
21
|
super
|
22
22
|
end
|
data/lib/rack/attack/throttle.rb
CHANGED
@@ -18,12 +18,12 @@ module Rack
|
|
18
18
|
Rack::Attack.cache
|
19
19
|
end
|
20
20
|
|
21
|
-
def
|
22
|
-
discriminator = block
|
21
|
+
def matched_by?(request)
|
22
|
+
discriminator = block.call(request)
|
23
23
|
return false unless discriminator
|
24
24
|
|
25
|
-
current_period = period.respond_to?(:call) ? period.call(
|
26
|
-
current_limit = limit.respond_to?(:call) ? limit.call(
|
25
|
+
current_period = period.respond_to?(:call) ? period.call(request) : period
|
26
|
+
current_limit = limit.respond_to?(:call) ? limit.call(request) : limit
|
27
27
|
key = "#{name}:#{discriminator}"
|
28
28
|
count = cache.count(key, current_period)
|
29
29
|
|
@@ -32,15 +32,15 @@ module Rack
|
|
32
32
|
:period => current_period,
|
33
33
|
:limit => current_limit
|
34
34
|
}
|
35
|
-
(
|
35
|
+
(request.env['rack.attack.throttle_data'] ||= {})[name] = data
|
36
36
|
|
37
37
|
(count > current_limit).tap do |throttled|
|
38
38
|
if throttled
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
Rack::Attack.instrument(
|
39
|
+
request.env['rack.attack.matched'] = name
|
40
|
+
request.env['rack.attack.match_discriminator'] = discriminator
|
41
|
+
request.env['rack.attack.match_type'] = type
|
42
|
+
request.env['rack.attack.match_data'] = data
|
43
|
+
Rack::Attack.instrument(request)
|
44
44
|
end
|
45
45
|
end
|
46
46
|
end
|
data/lib/rack/attack/track.rb
CHANGED
@@ -1,8 +1,6 @@
|
|
1
1
|
module Rack
|
2
2
|
class Attack
|
3
3
|
class Track
|
4
|
-
extend Forwardable
|
5
|
-
|
6
4
|
attr_reader :filter
|
7
5
|
|
8
6
|
def initialize(name, options = {}, block)
|
@@ -15,7 +13,9 @@ module Rack
|
|
15
13
|
end
|
16
14
|
end
|
17
15
|
|
18
|
-
|
16
|
+
def matched_by?(request)
|
17
|
+
filter.matched_by?(request)
|
18
|
+
end
|
19
19
|
end
|
20
20
|
end
|
21
21
|
end
|
data/lib/rack/attack/version.rb
CHANGED
@@ -0,0 +1,41 @@
|
|
1
|
+
require_relative "../../spec_helper"
|
2
|
+
|
3
|
+
if defined?(::Dalli)
|
4
|
+
require_relative "../../support/cache_store_helper"
|
5
|
+
require "active_support/cache/dalli_store"
|
6
|
+
require "timecop"
|
7
|
+
|
8
|
+
describe "ActiveSupport::Cache::DalliStore as a cache backend" do
|
9
|
+
before do
|
10
|
+
Rack::Attack.cache.store = ActiveSupport::Cache::DalliStore.new
|
11
|
+
end
|
12
|
+
|
13
|
+
after do
|
14
|
+
Rack::Attack.cache.store.clear
|
15
|
+
end
|
16
|
+
|
17
|
+
it_works_for_cache_backed_features
|
18
|
+
|
19
|
+
it "doesn't leak keys" do
|
20
|
+
Rack::Attack.throttle("by ip", limit: 1, period: 1) do |request|
|
21
|
+
request.ip
|
22
|
+
end
|
23
|
+
|
24
|
+
key = nil
|
25
|
+
|
26
|
+
# Freeze time during these statement to be sure that the key used by rack attack is the same
|
27
|
+
# we pre-calculate in local variable `key`
|
28
|
+
Timecop.freeze do
|
29
|
+
key = "rack::attack:#{Time.now.to_i}:by ip:1.2.3.4"
|
30
|
+
|
31
|
+
get "/", {}, "REMOTE_ADDR" => "1.2.3.4"
|
32
|
+
end
|
33
|
+
|
34
|
+
assert Rack::Attack.cache.store.fetch(key)
|
35
|
+
|
36
|
+
sleep 2.1
|
37
|
+
|
38
|
+
assert_nil Rack::Attack.cache.store.fetch(key)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require_relative "../../spec_helper"
|
2
|
+
|
3
|
+
if defined?(::Dalli)
|
4
|
+
require_relative "../../support/cache_store_helper"
|
5
|
+
require "timecop"
|
6
|
+
|
7
|
+
describe "ActiveSupport::Cache::MemCacheStore as a cache backend" do
|
8
|
+
before do
|
9
|
+
Rack::Attack.cache.store = ActiveSupport::Cache::MemCacheStore.new
|
10
|
+
end
|
11
|
+
|
12
|
+
after do
|
13
|
+
Rack::Attack.cache.store.flush_all
|
14
|
+
end
|
15
|
+
|
16
|
+
it_works_for_cache_backed_features
|
17
|
+
|
18
|
+
it "doesn't leak keys" do
|
19
|
+
Rack::Attack.throttle("by ip", limit: 1, period: 1) do |request|
|
20
|
+
request.ip
|
21
|
+
end
|
22
|
+
|
23
|
+
key = nil
|
24
|
+
|
25
|
+
# Freeze time during these statement to be sure that the key used by rack attack is the same
|
26
|
+
# we pre-calculate in local variable `key`
|
27
|
+
Timecop.freeze do
|
28
|
+
key = "rack::attack:#{Time.now.to_i}:by ip:1.2.3.4"
|
29
|
+
|
30
|
+
get "/", {}, "REMOTE_ADDR" => "1.2.3.4"
|
31
|
+
end
|
32
|
+
|
33
|
+
assert Rack::Attack.cache.store.get(key)
|
34
|
+
|
35
|
+
sleep 2.1
|
36
|
+
|
37
|
+
assert_nil Rack::Attack.cache.store.get(key)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -3,13 +3,13 @@ require_relative "../../support/cache_store_helper"
|
|
3
3
|
|
4
4
|
require "timecop"
|
5
5
|
|
6
|
-
describe "
|
6
|
+
describe "ActiveSupport::Cache::MemoryStore as a cache backend" do
|
7
7
|
before do
|
8
|
-
Rack::Attack.cache.store = ActiveSupport::Cache::
|
8
|
+
Rack::Attack.cache.store = ActiveSupport::Cache::MemoryStore.new
|
9
9
|
end
|
10
10
|
|
11
11
|
after do
|
12
|
-
Rack::Attack.cache.store.
|
12
|
+
Rack::Attack.cache.store.clear
|
13
13
|
end
|
14
14
|
|
15
15
|
it_works_for_cache_backed_features
|
@@ -29,10 +29,10 @@ describe "MemCacheStore as a cache backend" do
|
|
29
29
|
get "/", {}, "REMOTE_ADDR" => "1.2.3.4"
|
30
30
|
end
|
31
31
|
|
32
|
-
assert Rack::Attack.cache.store.
|
32
|
+
assert Rack::Attack.cache.store.fetch(key)
|
33
33
|
|
34
34
|
sleep 2.1
|
35
35
|
|
36
|
-
assert_nil Rack::Attack.cache.store.
|
36
|
+
assert_nil Rack::Attack.cache.store.fetch(key)
|
37
37
|
end
|
38
38
|
end
|
@@ -1,10 +1,10 @@
|
|
1
1
|
require_relative "../../spec_helper"
|
2
|
-
require_relative "../../support/cache_store_helper"
|
3
2
|
|
4
|
-
|
3
|
+
if defined?(::ConnectionPool) && defined?(::Redis) && defined?(::ActiveSupport::Cache::RedisCacheStore)
|
4
|
+
require_relative "../../support/cache_store_helper"
|
5
|
+
require "timecop"
|
5
6
|
|
6
|
-
|
7
|
-
describe "RedisCacheStore (pooled) as a cache backend" do
|
7
|
+
describe "ActiveSupport::Cache::RedisCacheStore (pooled) as a cache backend" do
|
8
8
|
before do
|
9
9
|
Rack::Attack.cache.store = ActiveSupport::Cache::RedisCacheStore.new(pool_size: 2)
|
10
10
|
end
|
data/spec/acceptance/stores/{redis_cache_store_spec.rb → active_support_redis_cache_store_spec.rb}
RENAMED
@@ -1,10 +1,10 @@
|
|
1
1
|
require_relative "../../spec_helper"
|
2
|
-
require_relative "../../support/cache_store_helper"
|
3
2
|
|
4
|
-
|
3
|
+
if defined?(::Redis) && defined?(::ActiveSupport::Cache::RedisCacheStore)
|
4
|
+
require_relative "../../support/cache_store_helper"
|
5
|
+
require "timecop"
|
5
6
|
|
6
|
-
|
7
|
-
describe "RedisCacheStore as a cache backend" do
|
7
|
+
describe "ActiveSupport::Cache::RedisCacheStore as a cache backend" do
|
8
8
|
before do
|
9
9
|
Rack::Attack.cache.store = ActiveSupport::Cache::RedisCacheStore.new
|
10
10
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require_relative "../../spec_helper"
|
2
|
+
|
3
|
+
if defined?(::ActiveSupport::Cache::RedisStore)
|
4
|
+
require_relative "../../support/cache_store_helper"
|
5
|
+
require "timecop"
|
6
|
+
|
7
|
+
describe "ActiveSupport::Cache::RedisStore as a cache backend" do
|
8
|
+
before do
|
9
|
+
Rack::Attack.cache.store = ActiveSupport::Cache::RedisStore.new
|
10
|
+
end
|
11
|
+
|
12
|
+
after do
|
13
|
+
Rack::Attack.cache.store.flushdb
|
14
|
+
end
|
15
|
+
|
16
|
+
it_works_for_cache_backed_features
|
17
|
+
|
18
|
+
it "doesn't leak keys" do
|
19
|
+
Rack::Attack.throttle("by ip", limit: 1, period: 1) do |request|
|
20
|
+
request.ip
|
21
|
+
end
|
22
|
+
|
23
|
+
key = nil
|
24
|
+
|
25
|
+
# Freeze time during these statement to be sure that the key used by rack attack is the same
|
26
|
+
# we pre-calculate in local variable `key`
|
27
|
+
Timecop.freeze do
|
28
|
+
key = "rack::attack:#{Time.now.to_i}:by ip:1.2.3.4"
|
29
|
+
|
30
|
+
get "/", {}, "REMOTE_ADDR" => "1.2.3.4"
|
31
|
+
end
|
32
|
+
|
33
|
+
assert Rack::Attack.cache.store.read(key)
|
34
|
+
|
35
|
+
sleep 2.1
|
36
|
+
|
37
|
+
assert_nil Rack::Attack.cache.store.read(key)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require_relative "../../spec_helper"
|
2
|
+
|
3
|
+
if defined?(::Dalli) && defined?(::ConnectionPool)
|
4
|
+
require_relative "../../support/cache_store_helper"
|
5
|
+
require "connection_pool"
|
6
|
+
require "dalli"
|
7
|
+
require "timecop"
|
8
|
+
|
9
|
+
describe "ConnectionPool with Dalli::Client as a cache backend" do
|
10
|
+
before do
|
11
|
+
Rack::Attack.cache.store = ConnectionPool.new { Dalli::Client.new }
|
12
|
+
end
|
13
|
+
|
14
|
+
after do
|
15
|
+
Rack::Attack.cache.store.with { |client| client.flush_all }
|
16
|
+
end
|
17
|
+
|
18
|
+
it_works_for_cache_backed_features
|
19
|
+
|
20
|
+
it "doesn't leak keys" do
|
21
|
+
Rack::Attack.throttle("by ip", limit: 1, period: 1) do |request|
|
22
|
+
request.ip
|
23
|
+
end
|
24
|
+
|
25
|
+
key = nil
|
26
|
+
|
27
|
+
# Freeze time during these statement to be sure that the key used by rack attack is the same
|
28
|
+
# we pre-calculate in local variable `key`
|
29
|
+
Timecop.freeze do
|
30
|
+
key = "rack::attack:#{Time.now.to_i}:by ip:1.2.3.4"
|
31
|
+
|
32
|
+
get "/", {}, "REMOTE_ADDR" => "1.2.3.4"
|
33
|
+
end
|
34
|
+
|
35
|
+
assert(Rack::Attack.cache.store.with { |client| client.fetch(key) })
|
36
|
+
|
37
|
+
sleep 2.1
|
38
|
+
|
39
|
+
assert_nil(Rack::Attack.cache.store.with { |client| client.fetch(key) })
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require_relative "../../spec_helper"
|
2
|
+
|
3
|
+
if defined?(::Dalli)
|
4
|
+
require_relative "../../support/cache_store_helper"
|
5
|
+
require "dalli"
|
6
|
+
require "timecop"
|
7
|
+
|
8
|
+
describe "Dalli::Client as a cache backend" do
|
9
|
+
before do
|
10
|
+
Rack::Attack.cache.store = Dalli::Client.new
|
11
|
+
end
|
12
|
+
|
13
|
+
after do
|
14
|
+
Rack::Attack.cache.store.flush_all
|
15
|
+
end
|
16
|
+
|
17
|
+
it_works_for_cache_backed_features
|
18
|
+
|
19
|
+
it "doesn't leak keys" do
|
20
|
+
Rack::Attack.throttle("by ip", limit: 1, period: 1) do |request|
|
21
|
+
request.ip
|
22
|
+
end
|
23
|
+
|
24
|
+
key = nil
|
25
|
+
|
26
|
+
# Freeze time during these statement to be sure that the key used by rack attack is the same
|
27
|
+
# we pre-calculate in local variable `key`
|
28
|
+
Timecop.freeze do
|
29
|
+
key = "rack::attack:#{Time.now.to_i}:by ip:1.2.3.4"
|
30
|
+
|
31
|
+
get "/", {}, "REMOTE_ADDR" => "1.2.3.4"
|
32
|
+
end
|
33
|
+
|
34
|
+
assert Rack::Attack.cache.store.fetch(key)
|
35
|
+
|
36
|
+
sleep 2.1
|
37
|
+
|
38
|
+
assert_nil Rack::Attack.cache.store.fetch(key)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require_relative "../../spec_helper"
|
2
|
+
require_relative "../../support/cache_store_helper"
|
3
|
+
|
4
|
+
if defined?(::Redis::Store)
|
5
|
+
require "timecop"
|
6
|
+
|
7
|
+
describe "ActiveSupport::Cache::RedisStore as a cache backend" do
|
8
|
+
before do
|
9
|
+
Rack::Attack.cache.store = ::Redis::Store.new
|
10
|
+
end
|
11
|
+
|
12
|
+
after do
|
13
|
+
Rack::Attack.cache.store.flushdb
|
14
|
+
end
|
15
|
+
|
16
|
+
it_works_for_cache_backed_features
|
17
|
+
|
18
|
+
it "doesn't leak keys" do
|
19
|
+
Rack::Attack.throttle("by ip", limit: 1, period: 1) do |request|
|
20
|
+
request.ip
|
21
|
+
end
|
22
|
+
|
23
|
+
key = nil
|
24
|
+
|
25
|
+
# Freeze time during these statement to be sure that the key used by rack attack is the same
|
26
|
+
# we pre-calculate in local variable `key`
|
27
|
+
Timecop.freeze do
|
28
|
+
key = "rack::attack:#{Time.now.to_i}:by ip:1.2.3.4"
|
29
|
+
|
30
|
+
get "/", {}, "REMOTE_ADDR" => "1.2.3.4"
|
31
|
+
end
|
32
|
+
|
33
|
+
assert Rack::Attack.cache.store.read(key)
|
34
|
+
|
35
|
+
sleep 2.1
|
36
|
+
|
37
|
+
assert_nil Rack::Attack.cache.store.read(key)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -1,6 +1,4 @@
|
|
1
1
|
require 'active_support/cache'
|
2
|
-
require 'redis-activesupport'
|
3
|
-
require 'dalli'
|
4
2
|
require_relative '../spec_helper'
|
5
3
|
|
6
4
|
OfflineExamples = Minitest::SharedExamples.new do
|
@@ -17,27 +15,31 @@ OfflineExamples = Minitest::SharedExamples.new do
|
|
17
15
|
end
|
18
16
|
end
|
19
17
|
|
20
|
-
|
21
|
-
|
18
|
+
if defined?(::ActiveSupport::Cache::RedisStore)
|
19
|
+
describe 'when Redis is offline' do
|
20
|
+
include OfflineExamples
|
22
21
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
22
|
+
before do
|
23
|
+
@cache = Rack::Attack::Cache.new
|
24
|
+
# Use presumably unused port for Redis client
|
25
|
+
@cache.store = ActiveSupport::Cache::RedisStore.new(:host => '127.0.0.1', :port => 3333)
|
26
|
+
end
|
27
|
+
end
|
28
28
|
end
|
29
29
|
|
30
|
-
|
31
|
-
|
30
|
+
if defined?(::Dalli)
|
31
|
+
describe 'when Memcached is offline' do
|
32
|
+
include OfflineExamples
|
32
33
|
|
33
|
-
|
34
|
-
|
34
|
+
before do
|
35
|
+
Dalli.logger.level = Logger::FATAL
|
35
36
|
|
36
|
-
|
37
|
-
|
38
|
-
|
37
|
+
@cache = Rack::Attack::Cache.new
|
38
|
+
@cache.store = Dalli::Client.new('127.0.0.1:22122')
|
39
|
+
end
|
39
40
|
|
40
|
-
|
41
|
-
|
42
|
-
|
41
|
+
after do
|
42
|
+
Dalli.logger.level = Logger::INFO
|
43
|
+
end
|
44
|
+
end
|
43
45
|
end
|
@@ -47,15 +47,15 @@ describe 'Rack::Attack.track' do
|
|
47
47
|
|
48
48
|
describe "without limit and period options" do
|
49
49
|
it "should assign the track filter to a Check instance" do
|
50
|
-
|
51
|
-
|
50
|
+
track = Rack::Attack.track("homepage") { |req| req.path == "/" }
|
51
|
+
track.filter.class.must_equal Rack::Attack::Check
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
55
55
|
describe "with limit and period options" do
|
56
56
|
it "should assign the track filter to a Throttle instance" do
|
57
|
-
|
58
|
-
|
57
|
+
track = Rack::Attack.track("homepage", :limit => 10, :period => 10) { |req| req.path == "/" }
|
58
|
+
track.filter.class.must_equal Rack::Attack::Throttle
|
59
59
|
end
|
60
60
|
end
|
61
61
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -9,16 +9,23 @@ require 'action_dispatch'
|
|
9
9
|
|
10
10
|
require "rack/attack"
|
11
11
|
|
12
|
-
begin
|
13
|
-
require 'pry'
|
14
|
-
rescue LoadError
|
15
|
-
# nothing to do here
|
16
|
-
end
|
17
|
-
|
18
12
|
if RUBY_ENGINE == "ruby"
|
19
13
|
require "byebug"
|
20
14
|
end
|
21
15
|
|
16
|
+
def safe_require(name)
|
17
|
+
begin
|
18
|
+
require name
|
19
|
+
rescue LoadError
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
safe_require "connection_pool"
|
24
|
+
safe_require "dalli"
|
25
|
+
safe_require "redis"
|
26
|
+
safe_require "redis-activesupport"
|
27
|
+
safe_require "redis-store"
|
28
|
+
|
22
29
|
class MiniTest::Spec
|
23
30
|
include Rack::Test::Methods
|
24
31
|
|
@@ -36,14 +43,14 @@ class MiniTest::Spec
|
|
36
43
|
end
|
37
44
|
|
38
45
|
def app
|
39
|
-
Rack::Builder.new
|
46
|
+
Rack::Builder.new do
|
40
47
|
# Use Rack::Lint to test that rack-attack is complying with the rack spec
|
41
48
|
use Rack::Lint
|
42
49
|
use Rack::Attack
|
43
50
|
use Rack::Lint
|
44
51
|
|
45
52
|
run lambda { |_env| [200, {}, ['Hello World']] }
|
46
|
-
|
53
|
+
end.to_app
|
47
54
|
end
|
48
55
|
|
49
56
|
def self.it_allows_ok_requests
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rack-attack
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.3.
|
4
|
+
version: 5.3.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aaron Suggs
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-06-
|
11
|
+
date: 2018-06-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|
@@ -24,244 +24,146 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: actionpack
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - ">="
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: 3.0.0
|
34
|
-
type: :development
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - ">="
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: 3.0.0
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: activesupport
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - ">="
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: 3.0.0
|
48
|
-
type: :development
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - ">="
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: 3.0.0
|
55
27
|
- !ruby/object:Gem::Dependency
|
56
28
|
name: appraisal
|
57
29
|
requirement: !ruby/object:Gem::Requirement
|
58
30
|
requirements:
|
59
|
-
- - "
|
31
|
+
- - "~>"
|
60
32
|
- !ruby/object:Gem::Version
|
61
|
-
version: '
|
33
|
+
version: '2.2'
|
62
34
|
type: :development
|
63
35
|
prerelease: false
|
64
36
|
version_requirements: !ruby/object:Gem::Requirement
|
65
37
|
requirements:
|
66
|
-
- - "
|
38
|
+
- - "~>"
|
67
39
|
- !ruby/object:Gem::Version
|
68
|
-
version: '
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
|
-
name: connection_pool
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
72
|
-
requirements:
|
73
|
-
- - ">="
|
74
|
-
- !ruby/object:Gem::Version
|
75
|
-
version: '0'
|
76
|
-
type: :development
|
77
|
-
prerelease: false
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
79
|
-
requirements:
|
80
|
-
- - ">="
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
version: '0'
|
83
|
-
- !ruby/object:Gem::Dependency
|
84
|
-
name: dalli
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
86
|
-
requirements:
|
87
|
-
- - ">="
|
88
|
-
- !ruby/object:Gem::Version
|
89
|
-
version: '0'
|
90
|
-
type: :development
|
91
|
-
prerelease: false
|
92
|
-
version_requirements: !ruby/object:Gem::Requirement
|
93
|
-
requirements:
|
94
|
-
- - ">="
|
95
|
-
- !ruby/object:Gem::Version
|
96
|
-
version: '0'
|
97
|
-
- !ruby/object:Gem::Dependency
|
98
|
-
name: guard-minitest
|
99
|
-
requirement: !ruby/object:Gem::Requirement
|
100
|
-
requirements:
|
101
|
-
- - ">="
|
102
|
-
- !ruby/object:Gem::Version
|
103
|
-
version: '0'
|
104
|
-
type: :development
|
105
|
-
prerelease: false
|
106
|
-
version_requirements: !ruby/object:Gem::Requirement
|
107
|
-
requirements:
|
108
|
-
- - ">="
|
109
|
-
- !ruby/object:Gem::Version
|
110
|
-
version: '0'
|
111
|
-
- !ruby/object:Gem::Dependency
|
112
|
-
name: memcache-client
|
113
|
-
requirement: !ruby/object:Gem::Requirement
|
114
|
-
requirements:
|
115
|
-
- - ">="
|
116
|
-
- !ruby/object:Gem::Version
|
117
|
-
version: '0'
|
118
|
-
type: :development
|
119
|
-
prerelease: false
|
120
|
-
version_requirements: !ruby/object:Gem::Requirement
|
121
|
-
requirements:
|
122
|
-
- - ">="
|
123
|
-
- !ruby/object:Gem::Version
|
124
|
-
version: '0'
|
40
|
+
version: '2.2'
|
125
41
|
- !ruby/object:Gem::Dependency
|
126
42
|
name: minitest
|
127
43
|
requirement: !ruby/object:Gem::Requirement
|
128
44
|
requirements:
|
129
|
-
- - "
|
45
|
+
- - "~>"
|
130
46
|
- !ruby/object:Gem::Version
|
131
|
-
version: '
|
47
|
+
version: '5.11'
|
132
48
|
type: :development
|
133
49
|
prerelease: false
|
134
50
|
version_requirements: !ruby/object:Gem::Requirement
|
135
51
|
requirements:
|
136
|
-
- - "
|
52
|
+
- - "~>"
|
137
53
|
- !ruby/object:Gem::Version
|
138
|
-
version: '
|
54
|
+
version: '5.11'
|
139
55
|
- !ruby/object:Gem::Dependency
|
140
56
|
name: minitest-stub-const
|
141
57
|
requirement: !ruby/object:Gem::Requirement
|
142
58
|
requirements:
|
143
|
-
- - "
|
144
|
-
- !ruby/object:Gem::Version
|
145
|
-
version: '0'
|
146
|
-
type: :development
|
147
|
-
prerelease: false
|
148
|
-
version_requirements: !ruby/object:Gem::Requirement
|
149
|
-
requirements:
|
150
|
-
- - ">="
|
151
|
-
- !ruby/object:Gem::Version
|
152
|
-
version: '0'
|
153
|
-
- !ruby/object:Gem::Dependency
|
154
|
-
name: pry
|
155
|
-
requirement: !ruby/object:Gem::Requirement
|
156
|
-
requirements:
|
157
|
-
- - ">="
|
59
|
+
- - "~>"
|
158
60
|
- !ruby/object:Gem::Version
|
159
|
-
version: '0'
|
61
|
+
version: '0.6'
|
160
62
|
type: :development
|
161
63
|
prerelease: false
|
162
64
|
version_requirements: !ruby/object:Gem::Requirement
|
163
65
|
requirements:
|
164
|
-
- - "
|
66
|
+
- - "~>"
|
165
67
|
- !ruby/object:Gem::Version
|
166
|
-
version: '0'
|
68
|
+
version: '0.6'
|
167
69
|
- !ruby/object:Gem::Dependency
|
168
70
|
name: rack-test
|
169
71
|
requirement: !ruby/object:Gem::Requirement
|
170
72
|
requirements:
|
171
|
-
- - "
|
73
|
+
- - "~>"
|
172
74
|
- !ruby/object:Gem::Version
|
173
|
-
version: '0'
|
75
|
+
version: '1.0'
|
174
76
|
type: :development
|
175
77
|
prerelease: false
|
176
78
|
version_requirements: !ruby/object:Gem::Requirement
|
177
79
|
requirements:
|
178
|
-
- - "
|
80
|
+
- - "~>"
|
179
81
|
- !ruby/object:Gem::Version
|
180
|
-
version: '0'
|
82
|
+
version: '1.0'
|
181
83
|
- !ruby/object:Gem::Dependency
|
182
84
|
name: rake
|
183
85
|
requirement: !ruby/object:Gem::Requirement
|
184
86
|
requirements:
|
185
|
-
- - "
|
87
|
+
- - "~>"
|
186
88
|
- !ruby/object:Gem::Version
|
187
|
-
version: '
|
89
|
+
version: '12.3'
|
188
90
|
type: :development
|
189
91
|
prerelease: false
|
190
92
|
version_requirements: !ruby/object:Gem::Requirement
|
191
93
|
requirements:
|
192
|
-
- - "
|
94
|
+
- - "~>"
|
193
95
|
- !ruby/object:Gem::Version
|
194
|
-
version: '
|
96
|
+
version: '12.3'
|
195
97
|
- !ruby/object:Gem::Dependency
|
196
|
-
name:
|
98
|
+
name: rubocop
|
197
99
|
requirement: !ruby/object:Gem::Requirement
|
198
100
|
requirements:
|
199
|
-
- -
|
101
|
+
- - '='
|
200
102
|
- !ruby/object:Gem::Version
|
201
|
-
version:
|
103
|
+
version: 0.57.2
|
202
104
|
type: :development
|
203
105
|
prerelease: false
|
204
106
|
version_requirements: !ruby/object:Gem::Requirement
|
205
107
|
requirements:
|
206
|
-
- -
|
108
|
+
- - '='
|
207
109
|
- !ruby/object:Gem::Version
|
208
|
-
version:
|
110
|
+
version: 0.57.2
|
209
111
|
- !ruby/object:Gem::Dependency
|
210
|
-
name:
|
112
|
+
name: timecop
|
211
113
|
requirement: !ruby/object:Gem::Requirement
|
212
114
|
requirements:
|
213
|
-
- -
|
115
|
+
- - "~>"
|
214
116
|
- !ruby/object:Gem::Version
|
215
|
-
version: 0.
|
117
|
+
version: 0.9.1
|
216
118
|
type: :development
|
217
119
|
prerelease: false
|
218
120
|
version_requirements: !ruby/object:Gem::Requirement
|
219
121
|
requirements:
|
220
|
-
- -
|
122
|
+
- - "~>"
|
221
123
|
- !ruby/object:Gem::Version
|
222
|
-
version: 0.
|
124
|
+
version: 0.9.1
|
223
125
|
- !ruby/object:Gem::Dependency
|
224
|
-
name:
|
126
|
+
name: byebug
|
225
127
|
requirement: !ruby/object:Gem::Requirement
|
226
128
|
requirements:
|
227
|
-
- - "
|
129
|
+
- - "~>"
|
228
130
|
- !ruby/object:Gem::Version
|
229
|
-
version: '0'
|
131
|
+
version: '10.0'
|
230
132
|
type: :development
|
231
133
|
prerelease: false
|
232
134
|
version_requirements: !ruby/object:Gem::Requirement
|
233
135
|
requirements:
|
234
|
-
- - "
|
136
|
+
- - "~>"
|
235
137
|
- !ruby/object:Gem::Version
|
236
|
-
version: '0'
|
138
|
+
version: '10.0'
|
237
139
|
- !ruby/object:Gem::Dependency
|
238
|
-
name:
|
140
|
+
name: actionpack
|
239
141
|
requirement: !ruby/object:Gem::Requirement
|
240
142
|
requirements:
|
241
143
|
- - ">="
|
242
144
|
- !ruby/object:Gem::Version
|
243
|
-
version:
|
145
|
+
version: 3.0.0
|
244
146
|
type: :development
|
245
147
|
prerelease: false
|
246
148
|
version_requirements: !ruby/object:Gem::Requirement
|
247
149
|
requirements:
|
248
150
|
- - ">="
|
249
151
|
- !ruby/object:Gem::Version
|
250
|
-
version:
|
152
|
+
version: 3.0.0
|
251
153
|
- !ruby/object:Gem::Dependency
|
252
|
-
name:
|
154
|
+
name: activesupport
|
253
155
|
requirement: !ruby/object:Gem::Requirement
|
254
156
|
requirements:
|
255
157
|
- - ">="
|
256
158
|
- !ruby/object:Gem::Version
|
257
|
-
version:
|
159
|
+
version: 3.0.0
|
258
160
|
type: :development
|
259
161
|
prerelease: false
|
260
162
|
version_requirements: !ruby/object:Gem::Requirement
|
261
163
|
requirements:
|
262
164
|
- - ">="
|
263
165
|
- !ruby/object:Gem::Version
|
264
|
-
version:
|
166
|
+
version: 3.0.0
|
265
167
|
description: A rack middleware for throttling and blocking abusive requests
|
266
168
|
email: aaron@ktheory.com
|
267
169
|
executables: []
|
@@ -302,16 +204,21 @@ files:
|
|
302
204
|
- spec/acceptance/safelisting_ip_spec.rb
|
303
205
|
- spec/acceptance/safelisting_spec.rb
|
304
206
|
- spec/acceptance/safelisting_subnet_spec.rb
|
305
|
-
- spec/acceptance/stores/
|
306
|
-
- spec/acceptance/stores/
|
307
|
-
- spec/acceptance/stores/
|
207
|
+
- spec/acceptance/stores/active_support_dalli_store_spec.rb
|
208
|
+
- spec/acceptance/stores/active_support_mem_cache_store_spec.rb
|
209
|
+
- spec/acceptance/stores/active_support_memory_store_spec.rb
|
210
|
+
- spec/acceptance/stores/active_support_redis_cache_store_pooled_spec.rb
|
211
|
+
- spec/acceptance/stores/active_support_redis_cache_store_spec.rb
|
212
|
+
- spec/acceptance/stores/active_support_redis_store_spec.rb
|
213
|
+
- spec/acceptance/stores/connection_pool_dalli_client_spec.rb
|
214
|
+
- spec/acceptance/stores/dalli_client_spec.rb
|
215
|
+
- spec/acceptance/stores/redis_store_spec.rb
|
308
216
|
- spec/acceptance/throttling_spec.rb
|
309
217
|
- spec/acceptance/track_spec.rb
|
310
218
|
- spec/acceptance/track_throttle_spec.rb
|
311
219
|
- spec/allow2ban_spec.rb
|
312
220
|
- spec/fail2ban_spec.rb
|
313
221
|
- spec/integration/offline_spec.rb
|
314
|
-
- spec/integration/rack_attack_cache_spec.rb
|
315
222
|
- spec/rack_attack_dalli_proxy_spec.rb
|
316
223
|
- spec/rack_attack_path_normalizer_spec.rb
|
317
224
|
- spec/rack_attack_request_spec.rb
|
@@ -323,7 +230,10 @@ files:
|
|
323
230
|
homepage: https://github.com/kickstarter/rack-attack
|
324
231
|
licenses:
|
325
232
|
- MIT
|
326
|
-
metadata:
|
233
|
+
metadata:
|
234
|
+
bug_tracker_uri: https://github.com/kickstarter/rack-attack/issues
|
235
|
+
changelog_uri: https://github.com/kickstarter/rack-attack/blob/master/CHANGELOG.md
|
236
|
+
source_code_uri: https://github.com/kickstarter/rack-attack
|
327
237
|
post_install_message:
|
328
238
|
rdoc_options:
|
329
239
|
- "--charset=UTF-8"
|
@@ -347,7 +257,6 @@ specification_version: 4
|
|
347
257
|
summary: Block & throttle abusive requests
|
348
258
|
test_files:
|
349
259
|
- spec/integration/offline_spec.rb
|
350
|
-
- spec/integration/rack_attack_cache_spec.rb
|
351
260
|
- spec/rack_attack_path_normalizer_spec.rb
|
352
261
|
- spec/acceptance/safelisting_subnet_spec.rb
|
353
262
|
- spec/acceptance/track_throttle_spec.rb
|
@@ -366,9 +275,15 @@ test_files:
|
|
366
275
|
- spec/acceptance/safelisting_spec.rb
|
367
276
|
- spec/acceptance/cache_store_config_for_throttle_spec.rb
|
368
277
|
- spec/acceptance/fail2ban_spec.rb
|
369
|
-
- spec/acceptance/stores/
|
370
|
-
- spec/acceptance/stores/
|
371
|
-
- spec/acceptance/stores/
|
278
|
+
- spec/acceptance/stores/active_support_redis_cache_store_spec.rb
|
279
|
+
- spec/acceptance/stores/active_support_memory_store_spec.rb
|
280
|
+
- spec/acceptance/stores/active_support_redis_store_spec.rb
|
281
|
+
- spec/acceptance/stores/active_support_mem_cache_store_spec.rb
|
282
|
+
- spec/acceptance/stores/active_support_redis_cache_store_pooled_spec.rb
|
283
|
+
- spec/acceptance/stores/connection_pool_dalli_client_spec.rb
|
284
|
+
- spec/acceptance/stores/active_support_dalli_store_spec.rb
|
285
|
+
- spec/acceptance/stores/redis_store_spec.rb
|
286
|
+
- spec/acceptance/stores/dalli_client_spec.rb
|
372
287
|
- spec/acceptance/customizing_blocked_response_spec.rb
|
373
288
|
- spec/spec_helper.rb
|
374
289
|
- spec/allow2ban_spec.rb
|
@@ -1,124 +0,0 @@
|
|
1
|
-
require_relative '../spec_helper'
|
2
|
-
|
3
|
-
describe Rack::Attack::Cache do
|
4
|
-
# A convenience method for deleting a key from cache.
|
5
|
-
# Slightly different than @cache.delete, which adds a prefix.
|
6
|
-
def delete(key)
|
7
|
-
if @cache.store.respond_to?(:delete)
|
8
|
-
@cache.store.delete(key)
|
9
|
-
else
|
10
|
-
@cache.store.del(key)
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
def sleep_until_expired
|
15
|
-
sleep(@expires_in * 1.1) # Add 10% to reduce errors
|
16
|
-
end
|
17
|
-
|
18
|
-
require 'active_support/cache/dalli_store'
|
19
|
-
require 'active_support/cache/mem_cache_store'
|
20
|
-
require 'active_support/cache/redis_store'
|
21
|
-
require 'active_support/cache/redis_cache_store' if ActiveSupport.version.to_s.to_f >= 5.2
|
22
|
-
require 'connection_pool'
|
23
|
-
|
24
|
-
cache_stores = [
|
25
|
-
ActiveSupport::Cache::MemoryStore.new,
|
26
|
-
ActiveSupport::Cache::DalliStore.new("127.0.0.1"),
|
27
|
-
ActiveSupport::Cache::RedisStore.new("127.0.0.1"),
|
28
|
-
ActiveSupport::Cache::MemCacheStore.new("127.0.0.1"),
|
29
|
-
Dalli::Client.new,
|
30
|
-
ConnectionPool.new { Dalli::Client.new },
|
31
|
-
Redis::Store.new
|
32
|
-
]
|
33
|
-
|
34
|
-
cache_stores << ActiveSupport::Cache::RedisCacheStore.new if defined?(ActiveSupport::Cache::RedisCacheStore)
|
35
|
-
|
36
|
-
cache_stores.each do |store|
|
37
|
-
store = Rack::Attack::StoreProxy.build(store)
|
38
|
-
|
39
|
-
describe "with #{store.class}" do
|
40
|
-
before {
|
41
|
-
@cache = Rack::Attack::Cache.new
|
42
|
-
@key = "rack::attack:cache-test-key"
|
43
|
-
@expires_in = 1
|
44
|
-
@cache.store = store
|
45
|
-
delete(@key)
|
46
|
-
}
|
47
|
-
|
48
|
-
after { delete(@key) }
|
49
|
-
|
50
|
-
describe "do_count once" do
|
51
|
-
it "should be 1" do
|
52
|
-
@cache.send(:do_count, @key, @expires_in).must_equal 1
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
describe "do_count twice" do
|
57
|
-
it "must be 2" do
|
58
|
-
@cache.send(:do_count, @key, @expires_in)
|
59
|
-
@cache.send(:do_count, @key, @expires_in).must_equal 2
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
describe "do_count after expires_in" do
|
64
|
-
it "must be 1" do
|
65
|
-
@cache.send(:do_count, @key, @expires_in)
|
66
|
-
sleep_until_expired
|
67
|
-
@cache.send(:do_count, @key, @expires_in).must_equal 1
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
describe "write" do
|
72
|
-
it "should write a value to the store with prefix" do
|
73
|
-
@cache.write("cache-test-key", "foobar", 1)
|
74
|
-
store.read(@key).must_equal "foobar"
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
describe "write after expiry" do
|
79
|
-
it "must not have a value" do
|
80
|
-
@cache.write("cache-test-key", "foobar", @expires_in)
|
81
|
-
sleep_until_expired
|
82
|
-
store.read(@key).must_be :nil?
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
describe "read" do
|
87
|
-
it "must read the value with a prefix" do
|
88
|
-
store.write(@key, "foobar", :expires_in => @expires_in)
|
89
|
-
@cache.read("cache-test-key").must_equal "foobar"
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
describe "delete" do
|
94
|
-
it "must delete the value" do
|
95
|
-
store.write(@key, "foobar", :expires_in => @expires_in)
|
96
|
-
@cache.read('cache-test-key').must_equal "foobar"
|
97
|
-
store.delete(@key)
|
98
|
-
assert_nil @cache.read('cache-test-key')
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
describe "cache#delete" do
|
103
|
-
it "must delete the value" do
|
104
|
-
@cache.write("cache-test-key", "foobar", 1)
|
105
|
-
store.read(@key).must_equal "foobar"
|
106
|
-
@cache.delete('cache-test-key')
|
107
|
-
store.read(@key).must_be :nil?
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
describe "reset_count" do
|
112
|
-
it "must delete the value" do
|
113
|
-
period = 1.minute
|
114
|
-
unprefixed_key = 'cache-test-key'
|
115
|
-
@cache.count(unprefixed_key, period)
|
116
|
-
period_key, _ = @cache.send(:key_and_expiry, 'cache-test-key', period)
|
117
|
-
store.read(period_key).to_i.must_equal 1
|
118
|
-
@cache.reset_count(unprefixed_key, period)
|
119
|
-
assert_nil store.read(period_key)
|
120
|
-
end
|
121
|
-
end
|
122
|
-
end
|
123
|
-
end
|
124
|
-
end
|