I'm getting started writing tests for my Chef cookbooks. I'm using ChefSpec to unit test my cookbooks. I need to install a Chef Server on one of my hosts and I would like to write a test for that. So far I have:
A ChefSpec test file in spec/default_spec.rb
:
require 'chefspec'
require 'chefspec/berkshelf'
describe 'my_chef_server::default' do
let(:chef_run) { ChefSpec::Runner.new.converge(described_recipe) }
it 'includes the chef-server recipe' do
expect(chef_run).to include_recipe('chef-server')
end
end
A metadata.rb
file which declares that the chef-server
cookbook is a dependency.
depends 'chef-server'
A recipes/default.rb
which includes the chef-server
recipe:
include_recipe 'chef-server'
When I run my tests (using rspec
) I get an error:
================================================================================
Recipe Compile Error in /var/folders/5g/dq2jk1sn30dgf7p4qhbvcjq80000gn/T/d20140429-77773-nxjusi/cookbooks/my_chef_server/recipes/default.rb
================================================================================
RuntimeError
------------
Could not locate chef-server package matching version 'latest' for node.
Cookbook Trace:
---------------
/var/folders/5g/dq2jk1sn30dgf7p4qhbvcjq80000gn/T/d20140429-77773-nxjusi/cookbooks/chef-server/recipes/default.rb:31:in `from_file'
/var/folders/5g/dq2jk1sn30dgf7p4qhbvcjq80000gn/T/d20140429-77773-nxjusi/cookbooks/my_chef_server/recipes/default.rb:11:in `from_file'
Relevant File Content:
----------------------
/var/folders/5g/dq2jk1sn30dgf7p4qhbvcjq80000gn/T/d20140429-77773-nxjusi/cookbooks/chef-server/recipes/default.rb:
24: node['chef-server']['nightlies']
25: )
26: unless omnibus_package
27: err_msg = 'Could not locate chef-server'
28: err_msg << ' pre-release' if node['chef-server']['prereleases']
29: err_msg << ' nightly' if node['chef-server']['nightlies']
30: err_msg << " package matching version '#{node['chef-server']['version']}' for node."
31>> fail err_msg
32: end
33: else
34: omnibus_package = node['chef-server']['package_file']
35: end
36:
37: package_name = ::File.basename(omnibus_package)
38: package_local_path = "#{Chef::Config[:file_cache_path]}/#{package_name}"
39:
40: # Ensure :file_cache_path exists
F.
Failures:
1) my_chef_server::default includes the chef-server recipe
Failure/Error: let(:chef_run) { ChefSpec::Runner.new.converge(described_recipe) }
RuntimeError:
Could not locate chef-server package matching version 'latest' for node.
# /var/folders/5g/dq2jk1sn30dgf7p4qhbvcjq80000gn/T/d20140429-77773-nxjusi/cookbooks/chef-server/recipes/default.rb:31:in `from_file'
# /var/folders/5g/dq2jk1sn30dgf7p4qhbvcjq80000gn/T/d20140429-77773-nxjusi/cookbooks/my_chef_server/recipes/default.rb:11:in `from_file'
# ./spec/default_spec.rb:6:in `block (2 levels) in <top (required)>'
# ./spec/default_spec.rb:9:in `block (2 levels) in <top (required)>'
Finished in 0.28717 seconds
2 examples, 1 failure
Failed examples:
rspec ./spec/default_spec.rb:8 # my_chef_server::default includes the chef-server recipe
As far as I can tell, ChefSpec is correctly loading and executing my cookbook and running the dependent chef-server
cookbook. However, the error shows that the chef-server
cookbook is not able to install the latest chef-server package.
How should I write or mock my test so that I can correctly test that Chef Server is installed successfully?
So this is largely due to a new instance of a class named
OmnitruckClient
being created in the chef-server default recipe. The OmnitruckClient is basically an HTTP call to the Omnitruck endpoint which is meant to return a URL where the chef-server recipe will then download the package from.There's a couple of ways handling the testing of this behavior that I can think of.
Since the native ChefSpec virtual 'platform' is named
chefsepc
, the Omnitruck service will never respond with a correct URL link, so one method would be to supply a platform and version to the Spec test, which may have other values later on.You can supply these selections in either the general configuration for RSpec, or per-test case (or even each converge).
I find it simplest to set these in the spec_helper.rb file. See here for more on the configuration options.
Another mode may be to try mocking/stubbing out the OmnitruckClient class (or the Net::HTTP.get method it uses), but it seemed like this might be a little more confusing, and I couldn't actually get that to work yet.