Module: ChefSpec::Cacher

Defined in:
lib/chefspec/cacher.rb

Overview

The cacher module allows for ultra-fast tests by caching the results of a CCR in memory across an example group. In testing, this can reduce the total testing time by a factor of 10x. This strategy is not the default behavior, because it has implications surrounding stubbing and is not threadsafe!

The credit for this approach and code belongs to Juri TimoŇ°in (DracoAter). Please see his original blog post below for an in-depth explanation of how and why this approach is faster.

Examples:

Using the Cacher module

First, require the Cacher module in your +spec_helper.rb+:

  RSpec.configure do |config|
    config.extend(ChefSpec::Cacher)
  end

Next, change your +let+ blocks to +cached+ blocks:

  let(:chef_run) { ... } #=> cached(:chef_run) { ... }

Finally, celebrate!

See Also:

Constant Summary collapse

FINALIZER =
lambda { |id| @@cache.delete(id) }
@@cache =
{}

Instance Method Summary collapse

Instance Method Details

#cached(name, &block) ⇒ Object


36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/chefspec/cacher.rb', line 36

def cached(name, &block)
  location = ancestors.first.[:location]
  unless ancestors.first.[:description].nil? || location.nil?
    location += ancestors.first.[:description]
  end
  location ||= ancestors.first.[:parent_example_group][:location]

  define_method(name) do
    key = [location, name.to_s].join('.')
    unless @@cache.has_key?(Thread.current.object_id)
      ObjectSpace.define_finalizer(Thread.current, FINALIZER)
    end
    @@cache[Thread.current.object_id] ||= {}
    @@cache[Thread.current.object_id][key] ||= instance_eval(&block)
  end
end

#cached!(name, &block) ⇒ Object


53
54
55
56
57
# File 'lib/chefspec/cacher.rb', line 53

def cached!(name, &block)
  cached(name, &block)

  before { send(name) }
end