From 3f590e4774772999d66170b6c0991ef070b8893f Mon Sep 17 00:00:00 2001 From: Gonzalo Rodriguez Date: Fri, 22 Jun 2018 14:51:38 -0300 Subject: [PATCH 1/8] Acceptance tests already cover integration with RedisCacheStore and MemCacheStore --- spec/integration/rack_attack_cache_spec.rb | 5 ----- 1 file changed, 5 deletions(-) diff --git a/spec/integration/rack_attack_cache_spec.rb b/spec/integration/rack_attack_cache_spec.rb index 98f5568..6f7b55c 100644 --- a/spec/integration/rack_attack_cache_spec.rb +++ b/spec/integration/rack_attack_cache_spec.rb @@ -16,23 +16,18 @@ describe Rack::Attack::Cache do end require 'active_support/cache/dalli_store' - require 'active_support/cache/mem_cache_store' require 'active_support/cache/redis_store' - require 'active_support/cache/redis_cache_store' if ActiveSupport.version.to_s.to_f >= 5.2 require 'connection_pool' cache_stores = [ ActiveSupport::Cache::MemoryStore.new, ActiveSupport::Cache::DalliStore.new("127.0.0.1"), ActiveSupport::Cache::RedisStore.new("127.0.0.1"), - ActiveSupport::Cache::MemCacheStore.new("127.0.0.1"), Dalli::Client.new, ConnectionPool.new { Dalli::Client.new }, Redis::Store.new ] - cache_stores << ActiveSupport::Cache::RedisCacheStore.new if defined?(ActiveSupport::Cache::RedisCacheStore) - cache_stores.each do |store| store = Rack::Attack::StoreProxy.build(store) From 92f3b7fbd0221031da42f93accb6b45e63d9a337 Mon Sep 17 00:00:00 2001 From: Gonzalo Rodriguez Date: Fri, 22 Jun 2018 10:52:23 -0300 Subject: [PATCH 2/8] Acceptance test ActiveSupport::Cache::RedisStore (redis-activesupport) as cache store backend --- .../stores/active_support_redis_store_spec.rb | 39 +++++++++++++++++++ spec/integration/rack_attack_cache_spec.rb | 2 - 2 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 spec/acceptance/stores/active_support_redis_store_spec.rb diff --git a/spec/acceptance/stores/active_support_redis_store_spec.rb b/spec/acceptance/stores/active_support_redis_store_spec.rb new file mode 100644 index 0000000..0b446e4 --- /dev/null +++ b/spec/acceptance/stores/active_support_redis_store_spec.rb @@ -0,0 +1,39 @@ +require_relative "../../spec_helper" +require_relative "../../support/cache_store_helper" + +require "redis-activesupport" +require "timecop" + +describe "ActiveSupport::Cache::RedisStore as a cache backend" do + before do + Rack::Attack.cache.store = ActiveSupport::Cache::RedisStore.new + end + + after do + Rack::Attack.cache.store.flushdb + end + + it_works_for_cache_backed_features + + it "doesn't leak keys" do + Rack::Attack.throttle("by ip", limit: 1, period: 1) do |request| + request.ip + end + + key = nil + + # Freeze time during these statement to be sure that the key used by rack attack is the same + # we pre-calculate in local variable `key` + Timecop.freeze do + key = "rack::attack:#{Time.now.to_i}:by ip:1.2.3.4" + + get "/", {}, "REMOTE_ADDR" => "1.2.3.4" + end + + assert Rack::Attack.cache.store.read(key) + + sleep 2.1 + + assert_nil Rack::Attack.cache.store.read(key) + end +end diff --git a/spec/integration/rack_attack_cache_spec.rb b/spec/integration/rack_attack_cache_spec.rb index 6f7b55c..9a13720 100644 --- a/spec/integration/rack_attack_cache_spec.rb +++ b/spec/integration/rack_attack_cache_spec.rb @@ -16,13 +16,11 @@ describe Rack::Attack::Cache do end require 'active_support/cache/dalli_store' - require 'active_support/cache/redis_store' require 'connection_pool' cache_stores = [ ActiveSupport::Cache::MemoryStore.new, ActiveSupport::Cache::DalliStore.new("127.0.0.1"), - ActiveSupport::Cache::RedisStore.new("127.0.0.1"), Dalli::Client.new, ConnectionPool.new { Dalli::Client.new }, Redis::Store.new From 93b1bf4c861c2df5dfd06c5b0349c1f5c70f2cc9 Mon Sep 17 00:00:00 2001 From: Gonzalo Rodriguez Date: Fri, 22 Jun 2018 11:59:55 -0300 Subject: [PATCH 3/8] Acceptance test Redis::Store (redis-store) as cache store backend --- spec/acceptance/stores/redis_store_spec.rb | 39 ++++++++++++++++++++++ spec/integration/rack_attack_cache_spec.rb | 3 +- 2 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 spec/acceptance/stores/redis_store_spec.rb diff --git a/spec/acceptance/stores/redis_store_spec.rb b/spec/acceptance/stores/redis_store_spec.rb new file mode 100644 index 0000000..17e5a0a --- /dev/null +++ b/spec/acceptance/stores/redis_store_spec.rb @@ -0,0 +1,39 @@ +require_relative "../../spec_helper" +require_relative "../../support/cache_store_helper" + +require "redis-store" +require "timecop" + +describe "ActiveSupport::Cache::RedisStore as a cache backend" do + before do + Rack::Attack.cache.store = ::Redis::Store.new + end + + after do + Rack::Attack.cache.store.flushdb + end + + it_works_for_cache_backed_features + + it "doesn't leak keys" do + Rack::Attack.throttle("by ip", limit: 1, period: 1) do |request| + request.ip + end + + key = nil + + # Freeze time during these statement to be sure that the key used by rack attack is the same + # we pre-calculate in local variable `key` + Timecop.freeze do + key = "rack::attack:#{Time.now.to_i}:by ip:1.2.3.4" + + get "/", {}, "REMOTE_ADDR" => "1.2.3.4" + end + + assert Rack::Attack.cache.store.read(key) + + sleep 2.1 + + assert_nil Rack::Attack.cache.store.read(key) + end +end diff --git a/spec/integration/rack_attack_cache_spec.rb b/spec/integration/rack_attack_cache_spec.rb index 9a13720..4e76552 100644 --- a/spec/integration/rack_attack_cache_spec.rb +++ b/spec/integration/rack_attack_cache_spec.rb @@ -22,8 +22,7 @@ describe Rack::Attack::Cache do ActiveSupport::Cache::MemoryStore.new, ActiveSupport::Cache::DalliStore.new("127.0.0.1"), Dalli::Client.new, - ConnectionPool.new { Dalli::Client.new }, - Redis::Store.new + ConnectionPool.new { Dalli::Client.new } ] cache_stores.each do |store| From bca253c674a59f0edea5c027faf78c05cc044c61 Mon Sep 17 00:00:00 2001 From: Gonzalo Rodriguez Date: Fri, 22 Jun 2018 12:06:46 -0300 Subject: [PATCH 4/8] Acceptance test ActiveSupport::Cache::DalliStore (via dalli) as cache store backend --- .../stores/active_support_dalli_store_spec.rb | 39 +++++++++++++++++++ spec/integration/rack_attack_cache_spec.rb | 2 - 2 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 spec/acceptance/stores/active_support_dalli_store_spec.rb diff --git a/spec/acceptance/stores/active_support_dalli_store_spec.rb b/spec/acceptance/stores/active_support_dalli_store_spec.rb new file mode 100644 index 0000000..b3be95f --- /dev/null +++ b/spec/acceptance/stores/active_support_dalli_store_spec.rb @@ -0,0 +1,39 @@ +require_relative "../../spec_helper" +require_relative "../../support/cache_store_helper" + +require "active_support/cache/dalli_store" +require "timecop" + +describe "ActiveSupport::Cache::DalliStore as a cache backend" do + before do + Rack::Attack.cache.store = ActiveSupport::Cache::DalliStore.new + end + + after do + Rack::Attack.cache.store.clear + end + + it_works_for_cache_backed_features + + it "doesn't leak keys" do + Rack::Attack.throttle("by ip", limit: 1, period: 1) do |request| + request.ip + end + + key = nil + + # Freeze time during these statement to be sure that the key used by rack attack is the same + # we pre-calculate in local variable `key` + Timecop.freeze do + key = "rack::attack:#{Time.now.to_i}:by ip:1.2.3.4" + + get "/", {}, "REMOTE_ADDR" => "1.2.3.4" + end + + assert Rack::Attack.cache.store.fetch(key) + + sleep 2.1 + + assert_nil Rack::Attack.cache.store.fetch(key) + end +end diff --git a/spec/integration/rack_attack_cache_spec.rb b/spec/integration/rack_attack_cache_spec.rb index 4e76552..a349dbf 100644 --- a/spec/integration/rack_attack_cache_spec.rb +++ b/spec/integration/rack_attack_cache_spec.rb @@ -15,12 +15,10 @@ describe Rack::Attack::Cache do sleep(@expires_in * 1.1) # Add 10% to reduce errors end - require 'active_support/cache/dalli_store' require 'connection_pool' cache_stores = [ ActiveSupport::Cache::MemoryStore.new, - ActiveSupport::Cache::DalliStore.new("127.0.0.1"), Dalli::Client.new, ConnectionPool.new { Dalli::Client.new } ] From 831e4e9e977670b6f9978831dda5fe74bb3ea83b Mon Sep 17 00:00:00 2001 From: Gonzalo Rodriguez Date: Fri, 22 Jun 2018 12:14:56 -0300 Subject: [PATCH 5/8] Acceptance test Dalli::Client (via dalli) as cache store backend --- spec/acceptance/stores/dalli_client_spec.rb | 39 +++++++++++++++++++++ spec/integration/rack_attack_cache_spec.rb | 1 - 2 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 spec/acceptance/stores/dalli_client_spec.rb diff --git a/spec/acceptance/stores/dalli_client_spec.rb b/spec/acceptance/stores/dalli_client_spec.rb new file mode 100644 index 0000000..e01ab3f --- /dev/null +++ b/spec/acceptance/stores/dalli_client_spec.rb @@ -0,0 +1,39 @@ +require_relative "../../spec_helper" +require_relative "../../support/cache_store_helper" + +require "dalli" +require "timecop" + +describe "Dalli::Client as a cache backend" do + before do + Rack::Attack.cache.store = Dalli::Client.new + end + + after do + Rack::Attack.cache.store.flush_all + end + + it_works_for_cache_backed_features + + it "doesn't leak keys" do + Rack::Attack.throttle("by ip", limit: 1, period: 1) do |request| + request.ip + end + + key = nil + + # Freeze time during these statement to be sure that the key used by rack attack is the same + # we pre-calculate in local variable `key` + Timecop.freeze do + key = "rack::attack:#{Time.now.to_i}:by ip:1.2.3.4" + + get "/", {}, "REMOTE_ADDR" => "1.2.3.4" + end + + assert Rack::Attack.cache.store.fetch(key) + + sleep 2.1 + + assert_nil Rack::Attack.cache.store.fetch(key) + end +end diff --git a/spec/integration/rack_attack_cache_spec.rb b/spec/integration/rack_attack_cache_spec.rb index a349dbf..cbea458 100644 --- a/spec/integration/rack_attack_cache_spec.rb +++ b/spec/integration/rack_attack_cache_spec.rb @@ -19,7 +19,6 @@ describe Rack::Attack::Cache do cache_stores = [ ActiveSupport::Cache::MemoryStore.new, - Dalli::Client.new, ConnectionPool.new { Dalli::Client.new } ] From 1f05ff30d57ba200973713ef503524adf06acc0a Mon Sep 17 00:00:00 2001 From: Gonzalo Rodriguez Date: Fri, 22 Jun 2018 12:22:55 -0300 Subject: [PATCH 6/8] Fix namespace of test file names --- ...che_store_spec.rb => active_support_mem_cache_store_spec.rb} | 2 +- ..._spec.rb => active_support_redis_cache_store_pooled_spec.rb} | 2 +- ...e_store_spec.rb => active_support_redis_cache_store_spec.rb} | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename spec/acceptance/stores/{mem_cache_store_spec.rb => active_support_mem_cache_store_spec.rb} (92%) rename spec/acceptance/stores/{redis_cache_store_pooled_spec.rb => active_support_redis_cache_store_pooled_spec.rb} (92%) rename spec/acceptance/stores/{redis_cache_store_spec.rb => active_support_redis_cache_store_spec.rb} (92%) diff --git a/spec/acceptance/stores/mem_cache_store_spec.rb b/spec/acceptance/stores/active_support_mem_cache_store_spec.rb similarity index 92% rename from spec/acceptance/stores/mem_cache_store_spec.rb rename to spec/acceptance/stores/active_support_mem_cache_store_spec.rb index 6c593f1..1a4e7f7 100644 --- a/spec/acceptance/stores/mem_cache_store_spec.rb +++ b/spec/acceptance/stores/active_support_mem_cache_store_spec.rb @@ -3,7 +3,7 @@ require_relative "../../support/cache_store_helper" require "timecop" -describe "MemCacheStore as a cache backend" do +describe "ActiveSupport::Cache::MemCacheStore as a cache backend" do before do Rack::Attack.cache.store = ActiveSupport::Cache::MemCacheStore.new end diff --git a/spec/acceptance/stores/redis_cache_store_pooled_spec.rb b/spec/acceptance/stores/active_support_redis_cache_store_pooled_spec.rb similarity index 92% rename from spec/acceptance/stores/redis_cache_store_pooled_spec.rb rename to spec/acceptance/stores/active_support_redis_cache_store_pooled_spec.rb index cd54b30..8c006bb 100644 --- a/spec/acceptance/stores/redis_cache_store_pooled_spec.rb +++ b/spec/acceptance/stores/active_support_redis_cache_store_pooled_spec.rb @@ -4,7 +4,7 @@ require_relative "../../support/cache_store_helper" require "timecop" if ActiveSupport.version >= Gem::Version.new("5.2.0") - describe "RedisCacheStore (pooled) as a cache backend" do + describe "ActiveSupport::Cache::RedisCacheStore (pooled) as a cache backend" do before do Rack::Attack.cache.store = ActiveSupport::Cache::RedisCacheStore.new(pool_size: 2) end diff --git a/spec/acceptance/stores/redis_cache_store_spec.rb b/spec/acceptance/stores/active_support_redis_cache_store_spec.rb similarity index 92% rename from spec/acceptance/stores/redis_cache_store_spec.rb rename to spec/acceptance/stores/active_support_redis_cache_store_spec.rb index b819749..495a6a2 100644 --- a/spec/acceptance/stores/redis_cache_store_spec.rb +++ b/spec/acceptance/stores/active_support_redis_cache_store_spec.rb @@ -4,7 +4,7 @@ require_relative "../../support/cache_store_helper" require "timecop" if ActiveSupport.version >= Gem::Version.new("5.2.0") - describe "RedisCacheStore as a cache backend" do + describe "ActiveSupport::Cache::RedisCacheStore as a cache backend" do before do Rack::Attack.cache.store = ActiveSupport::Cache::RedisCacheStore.new end From bcc1f5857e1d57acea6a9cfce35ae44b50bcec6f Mon Sep 17 00:00:00 2001 From: Gonzalo Rodriguez Date: Fri, 22 Jun 2018 14:11:34 -0300 Subject: [PATCH 7/8] Acceptance test ActiveSupport::Cache::MemoryStore (via activesupport) as cache store backend --- .../active_support_memory_store_spec.rb | 38 +++++ spec/integration/rack_attack_cache_spec.rb | 137 +++++++++--------- 2 files changed, 103 insertions(+), 72 deletions(-) create mode 100644 spec/acceptance/stores/active_support_memory_store_spec.rb diff --git a/spec/acceptance/stores/active_support_memory_store_spec.rb b/spec/acceptance/stores/active_support_memory_store_spec.rb new file mode 100644 index 0000000..94de429 --- /dev/null +++ b/spec/acceptance/stores/active_support_memory_store_spec.rb @@ -0,0 +1,38 @@ +require_relative "../../spec_helper" +require_relative "../../support/cache_store_helper" + +require "timecop" + +describe "ActiveSupport::Cache::MemoryStore as a cache backend" do + before do + Rack::Attack.cache.store = ActiveSupport::Cache::MemoryStore.new + end + + after do + Rack::Attack.cache.store.clear + end + + it_works_for_cache_backed_features + + it "doesn't leak keys" do + Rack::Attack.throttle("by ip", limit: 1, period: 1) do |request| + request.ip + end + + key = nil + + # Freeze time during these statement to be sure that the key used by rack attack is the same + # we pre-calculate in local variable `key` + Timecop.freeze do + key = "rack::attack:#{Time.now.to_i}:by ip:1.2.3.4" + + get "/", {}, "REMOTE_ADDR" => "1.2.3.4" + end + + assert Rack::Attack.cache.store.fetch(key) + + sleep 2.1 + + assert_nil Rack::Attack.cache.store.fetch(key) + end +end diff --git a/spec/integration/rack_attack_cache_spec.rb b/spec/integration/rack_attack_cache_spec.rb index cbea458..25148d8 100644 --- a/spec/integration/rack_attack_cache_spec.rb +++ b/spec/integration/rack_attack_cache_spec.rb @@ -17,96 +17,89 @@ describe Rack::Attack::Cache do require 'connection_pool' - cache_stores = [ - ActiveSupport::Cache::MemoryStore.new, - ConnectionPool.new { Dalli::Client.new } - ] + store = Rack::Attack::StoreProxy.build(ConnectionPool.new { Dalli::Client.new }) - cache_stores.each do |store| - store = Rack::Attack::StoreProxy.build(store) + describe "with #{store.class}" do + before do + @cache = Rack::Attack::Cache.new + @key = "rack::attack:cache-test-key" + @expires_in = 1 + @cache.store = store + delete(@key) + end - describe "with #{store.class}" do - before do - @cache = Rack::Attack::Cache.new - @key = "rack::attack:cache-test-key" - @expires_in = 1 - @cache.store = store - delete(@key) + after { delete(@key) } + + describe "do_count once" do + it "should be 1" do + @cache.send(:do_count, @key, @expires_in).must_equal 1 end + end - after { delete(@key) } - - describe "do_count once" do - it "should be 1" do - @cache.send(:do_count, @key, @expires_in).must_equal 1 - end + describe "do_count twice" do + it "must be 2" do + @cache.send(:do_count, @key, @expires_in) + @cache.send(:do_count, @key, @expires_in).must_equal 2 end + end - describe "do_count twice" do - it "must be 2" do - @cache.send(:do_count, @key, @expires_in) - @cache.send(:do_count, @key, @expires_in).must_equal 2 - end + describe "do_count after expires_in" do + it "must be 1" do + @cache.send(:do_count, @key, @expires_in) + sleep_until_expired + @cache.send(:do_count, @key, @expires_in).must_equal 1 end + end - describe "do_count after expires_in" do - it "must be 1" do - @cache.send(:do_count, @key, @expires_in) - sleep_until_expired - @cache.send(:do_count, @key, @expires_in).must_equal 1 - end + describe "write" do + it "should write a value to the store with prefix" do + @cache.write("cache-test-key", "foobar", 1) + store.read(@key).must_equal "foobar" end + end - describe "write" do - it "should write a value to the store with prefix" do - @cache.write("cache-test-key", "foobar", 1) - store.read(@key).must_equal "foobar" - end + describe "write after expiry" do + it "must not have a value" do + @cache.write("cache-test-key", "foobar", @expires_in) + sleep_until_expired + store.read(@key).must_be :nil? end + end - describe "write after expiry" do - it "must not have a value" do - @cache.write("cache-test-key", "foobar", @expires_in) - sleep_until_expired - store.read(@key).must_be :nil? - end + describe "read" do + it "must read the value with a prefix" do + store.write(@key, "foobar", :expires_in => @expires_in) + @cache.read("cache-test-key").must_equal "foobar" end + end - describe "read" do - it "must read the value with a prefix" do - store.write(@key, "foobar", :expires_in => @expires_in) - @cache.read("cache-test-key").must_equal "foobar" - end + describe "delete" do + it "must delete the value" do + store.write(@key, "foobar", :expires_in => @expires_in) + @cache.read('cache-test-key').must_equal "foobar" + store.delete(@key) + assert_nil @cache.read('cache-test-key') end + end - describe "delete" do - it "must delete the value" do - store.write(@key, "foobar", :expires_in => @expires_in) - @cache.read('cache-test-key').must_equal "foobar" - store.delete(@key) - assert_nil @cache.read('cache-test-key') - end + describe "cache#delete" do + it "must delete the value" do + @cache.write("cache-test-key", "foobar", 1) + store.read(@key).must_equal "foobar" + @cache.delete('cache-test-key') + store.read(@key).must_be :nil? end + end - describe "cache#delete" do - it "must delete the value" do - @cache.write("cache-test-key", "foobar", 1) - store.read(@key).must_equal "foobar" - @cache.delete('cache-test-key') - store.read(@key).must_be :nil? - end - end - - describe "reset_count" do - it "must delete the value" do - period = 1.minute - unprefixed_key = 'cache-test-key' - @cache.count(unprefixed_key, period) - period_key, _ = @cache.send(:key_and_expiry, 'cache-test-key', period) - store.read(period_key).to_i.must_equal 1 - @cache.reset_count(unprefixed_key, period) - assert_nil store.read(period_key) - end + describe "reset_count" do + it "must delete the value" do + period = 1.minute + unprefixed_key = 'cache-test-key' + @cache.count(unprefixed_key, period) + period_key, _ = @cache.send(:key_and_expiry, 'cache-test-key', period) + store.read(period_key).to_i.must_equal 1 + @cache.reset_count(unprefixed_key, period) + assert_nil store.read(period_key) end end end From 9cc49b4760ae1aeb3cff4b1502412fec6d24a051 Mon Sep 17 00:00:00 2001 From: Gonzalo Rodriguez Date: Fri, 22 Jun 2018 14:41:48 -0300 Subject: [PATCH 8/8] Acceptance test ConnectionPool with Dalli::Client (via connection_pool and dalli) as cache store backend --- .../connection_pool_dalli_client_spec.rb | 40 +++++++ spec/integration/rack_attack_cache_spec.rb | 106 ------------------ 2 files changed, 40 insertions(+), 106 deletions(-) create mode 100644 spec/acceptance/stores/connection_pool_dalli_client_spec.rb delete mode 100644 spec/integration/rack_attack_cache_spec.rb diff --git a/spec/acceptance/stores/connection_pool_dalli_client_spec.rb b/spec/acceptance/stores/connection_pool_dalli_client_spec.rb new file mode 100644 index 0000000..a852d03 --- /dev/null +++ b/spec/acceptance/stores/connection_pool_dalli_client_spec.rb @@ -0,0 +1,40 @@ +require_relative "../../spec_helper" +require_relative "../../support/cache_store_helper" + +require "connection_pool" +require "dalli" +require "timecop" + +describe "ConnectionPool with Dalli::Client as a cache backend" do + before do + Rack::Attack.cache.store = ConnectionPool.new { Dalli::Client.new } + end + + after do + Rack::Attack.cache.store.with { |client| client.flush_all } + end + + it_works_for_cache_backed_features + + it "doesn't leak keys" do + Rack::Attack.throttle("by ip", limit: 1, period: 1) do |request| + request.ip + end + + key = nil + + # Freeze time during these statement to be sure that the key used by rack attack is the same + # we pre-calculate in local variable `key` + Timecop.freeze do + key = "rack::attack:#{Time.now.to_i}:by ip:1.2.3.4" + + get "/", {}, "REMOTE_ADDR" => "1.2.3.4" + end + + assert(Rack::Attack.cache.store.with { |client| client.fetch(key) }) + + sleep 2.1 + + assert_nil(Rack::Attack.cache.store.with { |client| client.fetch(key) }) + end +end diff --git a/spec/integration/rack_attack_cache_spec.rb b/spec/integration/rack_attack_cache_spec.rb deleted file mode 100644 index 25148d8..0000000 --- a/spec/integration/rack_attack_cache_spec.rb +++ /dev/null @@ -1,106 +0,0 @@ -require_relative '../spec_helper' - -describe Rack::Attack::Cache do - # A convenience method for deleting a key from cache. - # Slightly different than @cache.delete, which adds a prefix. - def delete(key) - if @cache.store.respond_to?(:delete) - @cache.store.delete(key) - else - @cache.store.del(key) - end - end - - def sleep_until_expired - sleep(@expires_in * 1.1) # Add 10% to reduce errors - end - - require 'connection_pool' - - store = Rack::Attack::StoreProxy.build(ConnectionPool.new { Dalli::Client.new }) - - describe "with #{store.class}" do - before do - @cache = Rack::Attack::Cache.new - @key = "rack::attack:cache-test-key" - @expires_in = 1 - @cache.store = store - delete(@key) - end - - after { delete(@key) } - - describe "do_count once" do - it "should be 1" do - @cache.send(:do_count, @key, @expires_in).must_equal 1 - end - end - - describe "do_count twice" do - it "must be 2" do - @cache.send(:do_count, @key, @expires_in) - @cache.send(:do_count, @key, @expires_in).must_equal 2 - end - end - - describe "do_count after expires_in" do - it "must be 1" do - @cache.send(:do_count, @key, @expires_in) - sleep_until_expired - @cache.send(:do_count, @key, @expires_in).must_equal 1 - end - end - - describe "write" do - it "should write a value to the store with prefix" do - @cache.write("cache-test-key", "foobar", 1) - store.read(@key).must_equal "foobar" - end - end - - describe "write after expiry" do - it "must not have a value" do - @cache.write("cache-test-key", "foobar", @expires_in) - sleep_until_expired - store.read(@key).must_be :nil? - end - end - - describe "read" do - it "must read the value with a prefix" do - store.write(@key, "foobar", :expires_in => @expires_in) - @cache.read("cache-test-key").must_equal "foobar" - end - end - - describe "delete" do - it "must delete the value" do - store.write(@key, "foobar", :expires_in => @expires_in) - @cache.read('cache-test-key').must_equal "foobar" - store.delete(@key) - assert_nil @cache.read('cache-test-key') - end - end - - describe "cache#delete" do - it "must delete the value" do - @cache.write("cache-test-key", "foobar", 1) - store.read(@key).must_equal "foobar" - @cache.delete('cache-test-key') - store.read(@key).must_be :nil? - end - end - - describe "reset_count" do - it "must delete the value" do - period = 1.minute - unprefixed_key = 'cache-test-key' - @cache.count(unprefixed_key, period) - period_key, _ = @cache.send(:key_and_expiry, 'cache-test-key', period) - store.read(period_key).to_i.must_equal 1 - @cache.reset_count(unprefixed_key, period) - assert_nil store.read(period_key) - end - end - end -end