afdnyw
Last Updated: February 25, 2016
·
4.312K
· mlafeldt
2190d7a468f51fa3be5eabfc9397a28b

Testing code inside ruby_block with ChefSpec

I've recently written a wrapper cookbook that installs Ruby using rbenv and ruby_build.

The cookbook's default recipe looks like this:

include_recipe 'ruby_build'
include_recipe 'rbenv::system'

# Fix PATH so that rbenv will be available immediately.
ruby_block "Add rbenv to PATH" do
  block do
    rbenv_root = node['rbenv']['root_path']
    ENV['PATH'] = "#{rbenv_root}/shims:#{rbenv_root}/bin:#{ENV['PATH']}"
  end
end

Writing ChefSpec examples for this turned out to be tricky, since the code inside the ruby_block is only evaluated during convergence and not at compile time. I could have written a simple RSpec matcher to check that the resource ruby_block[Add rbenv to PATH] is executed at all, but I wanted to verify the actual code as well (ChefSpec 0.9.0 doesn't support ruby_block by default).

As luck would have it, this tip by Andrew Crump helped me to come up with the following spec:

describe 'The recipe ruby::default' do
  let (:chef_run) do
    chef_run = ChefSpec::ChefRunner.new
    chef_run.node.automatic_attrs['platform'] = 'ubuntu'
    chef_run.converge 'ruby::default'
    chef_run
  end

  # ...

  it 'should add rbenv to PATH' do
    # run actual ruby_block resource to check PATH
    chef_run.resources.find { |r| r.name == 'Add rbenv to PATH' }.old_run_action(:create)
    rbenv_root = chef_run.node['rbenv']['root_path']
    ENV['PATH'].should include "#{rbenv_root}/shims"
    ENV['PATH'].should include "#{rbenv_root}/bin"
  end
end

As you can see, the only way to test code inside ruby_block is to actually converge the resource. I know that this is not always an option, but here it is.

4 Responses
Add your response

15575
D3b2094f1b3386e660bb737e797f5dcc

Hi @mlafeldt, thanks for sharing! Great tip!

FYI ChefSpec 3.4.0+ now seems to require this slight change:

chef_run.find_resources(:ruby_block).find { |r| r.name == 'Add rbenv to PATH' }.old_run_action(:create)
over 1 year ago ·
15579
2190d7a468f51fa3be5eabfc9397a28b

@steve-jansen Good to know. Thank you!

over 1 year ago ·
15687
Accaf690f3d97aab6e6e02adac8150be

Looks like the newest hotness would be:
ruby chef_run.ruby_block('Add rbenv to PATH').old_run_action(:create)

over 1 year ago ·
23657
B15a85b154553eac6dcdbcd9c522f44b

Thanks for initiating this conversation.

When working with ruby_blocks or really any ruby I try to extract that ruby into a method and then test that method. Here's an example that I created after someone pointed to your great solution.

https://github.com/burtlo/cookbook-testing-ruby_block/commit/942a6dfb5e89f3e5dfccb746fe6e82c89a0abbc6

over 1 year ago ·