Reputation: 407
So I'm trying to write a unit test (via ChefSpec) for one of my Chef recipes but I am getting some odd behaviour.
My recipe in question is including the rvm::system_install recipe and apparently this is causing issues with ChefSpec:
Failures:
1) theoracle::prereqs installs libyaml libyaml-devel sqlite-devel
Failure/Error: let(:chef_run) { ChefSpec::Runner.new.converge('theoracle::prereqs')}
NoMethodError:
undefined method `each' for nil:NilClass
# /Users/jdoe/workspace/cookbooks/rvm/libraries/chef_rvm_recipe_helpers.rb:44:in `install_pkg_prereqs'
# /Users/jdoe/workspace/cookbooks/rvm/recipes/system_install.rb:29:in `from_file'
# ./recipes/prereqs.rb:22:in `from_file'
# ./spec/unit/recipes/prereqs_spec.rb:6:in `block (2 levels) in <top (required)>'
# ./spec/unit/recipes/prereqs_spec.rb:15:in `block (2 levels) in <top (required)>'
The offending code segment:
/Users/jdoe/workspace/cookbooks/rvm/libraries/chef_rvm_recipe_helpers.rb:
41: def install_pkg_prereqs(install_now = node.recipe?("rvm::gem_package"))
42: return if mac_with_no_homebrew
43:
44>> node[:rvm][:install_pkgs].each do |pkg|
45: p = package pkg do
This is how my test looks like:
require 'spec_helper'
describe 'theoracle::prereqs' do
let(:chef_run) { ChefSpec::Runner.new.converge('theoracle::prereqs')}
it 'installs libyaml libyaml-devel sqlite-devel' do
%W( libyaml libyaml-devel sqlite-devel ).each do |pkg|
expect(chef_run).to_install_package(pkg)
end
end
end
This is the theoracle::prereqs
recipe (part of it):
%W( libyaml libyaml-devel sqlite-devel ).each do |pkg|
package pkg do
action :install
end
end
include_recipe 'rvm::system_install'
Upvotes: 1
Views: 434
Reputation: 26997
Here is what is happening:
node[:rvm][:install_pkgs]
is returning nil
. Thus you are calling nil.each
and getting the exception. Unfortunately there are a number of possibilities of why that attribute could be nil
.
In your theoracle
cookbook, have you added a dependency on the rvm
cookbook in your metadata.rb
?
depends 'rvm'
Without this line, Chef will not load the RVM cookbook (and thus not load its attributes), causing the install_pkgs
attribute to be nil
.
If you look at the code for determining the value of that attribute in the chef-rvm
cookbook, you can see that node[:rvm][:install_pkgs]
is only set under the following conditions:
case platform
when "redhat","centos","fedora","scientific","amazon"
node.set['rvm']['install_pkgs'] = %w{sed grep tar gzip bzip2 bash curl git}
default['rvm']['user_home_root'] = '/home'
when "debian","ubuntu","suse"
node.set['rvm']['install_pkgs'] = %w{sed grep tar gzip bzip2 bash curl git-core}
default['rvm']['user_home_root'] = '/home'
when "gentoo"
node.set['rvm']['install_pkgs'] = %w{git}
default['rvm']['user_home_root'] = '/home'
when "mac_os_x", "mac_os_x_server"
node.set['rvm']['install_pkgs'] = %w{git}
default['rvm']['user_home_root'] = '/Users'
end
In the case of ChefSpec, all Ohai data (which is what sets the platform
key), is mocked to allow control over this behavior. Most likely, ChefSpec is reporting its platform as chefspec
, and since that case
statement has no default block, the attribute is nil
.
To fix this issue, tell ChefSpec to behave like a particular OS:
ChefSpec::Runner.new(platform: 'ubuntu', version: '12.04')
Or manually set the attribute in your test:
let(:chef_run) do
ChefSpec::Runner.new do |node|
node.set['rvm']['install_pkgs'] = %w(whatever)
end.converge(described_recipe)
end
Upvotes: 1