1

I've written a cron job to update some cached values in the background (rather than doing it while a user waits). I have a scenario that runs that cron job and then reads the cache to see if the values are set correctly.

The problem is that Rails.cache.read("key") is returning "Cache read: key\n" not the value, and if I debug and inspect Rails.cache I get a ActiveSupport::Cache::BlackHoleStore returned - not a good sign.

This makes sense of course because the following is included in my cucumber.env:

config.action_controller.perform_caching             = false
require File.join(RAILS_ROOT, 'lib', 'black_hole_store.rb')
config.cache_store = :black_hole_store

What I want is to override this at runtime - we have about a thousand scenarios and this is the only one that needs the cache active. I tried the following from the debugger prompt without any luck:

(rdb:1) ActionController::Base.perform_caching = true
true
(rdb:1) ActionController::Base.perform_caching
true
(rdb:1) Rails.cache
#<ActiveSupport::Cache::BlackHoleStore:0x101b6dc60 @logger_off=false>
(rdb:1) ActionController::Base.cache_store = :memory_store
:memory_store
(rdb:1) Rails.cache
#<ActiveSupport::Cache::BlackHoleStore:0x101b6dc60 @logger_off=false>

Anyone know how to do this?

Jack Chu
  • 6,791
  • 4
  • 38
  • 44
jim
  • 1,025
  • 12
  • 17

3 Answers3

2

Try this...tag your scenarios with @enable_caching and add these hooks to your support/env.rb file:

Before '@enable_caching' do
  ActionController::Base.perform_caching = true
end

After '@enable_caching' do
  ActionController::Base.perform_caching = false
end
Andrew
  • 227,796
  • 193
  • 515
  • 708
2

Ok, so I eventually got to the bottom of this.

The short answer is Rails.cache is an alias for RAILS_CACHE, and while there's no Rails.cache= method you can assign to RAILS_CACHE, e.g.:

ActionController::Base.perform_caching = true
ActionController::Base.cache_store = :memory_store
RAILS_CACHE = ActionController::Base.cache_store

You could probably also do RAILS_CACHE = ActiveSupport::Cache.lookup_store(:memory_cache) but that seems a bit dirtier to me.

The longer answer is to use a step to wrap a table of other steps with code that enables and then disables the cache, to ensure you don't break other tests by leaving caching enabled - this kind of mistake is nasty to track down.

This would look something like:

When /^I do the following steps with caching enabled:$/ do |table|
  old_perform_caching = ActionController::Base.perform_caching
  old_action_controller_cache = ActionController::Base.cache_store
  old_rails_cache = RAILS_CACHE

  ActionController::Base.perform_caching = true
  ActionController::Base.cache_store = :memory_store
  RAILS_CACHE = ActionController::Base.cache_store

  steps table.raw.flatten.join("\n")

  ActionController::Base.perform_caching = old_perform_caching
  ActionController::Base.cache_store = old_action_controller_cache
  RAILS_CACHE = old_rails_cache
end

And using it would look something like:

 When I do the following steps with caching enabled:            
 | When I run "rake cron:nightly"             |
 | Then the cache for "x" should return "6"   |
 |  And the cache for "y" should return "13"  |
 |  And the cache for "z" should return "800" |

The steps in the table have obviously been implemented elsewhere.

jim
  • 1,025
  • 12
  • 17
  • 1
    An alternative would be to tag the scenario(s) you want to run with the cache with @cache. You could then implement the logic to enable the cache before the scenarios and disable it afterwards in you env.rb file in a before block and an after block. – AlistairH May 05 '11 at 10:03
0

This seems kind of related to my question/anser here. The issue is that you can't change cache_store after Rails is initialized. There's a cache initializer that gets run during Rails initialization. As far as I'm aware, you can't change it after it's initialized. Perhaps you can mock the cache read/write?

Community
  • 1
  • 1
Jack Chu
  • 6,791
  • 4
  • 38
  • 44