More hardware-specific testing
Most of chefspec examples test whether recipes create various resources. While useful, don’t overlook that attribute files can also contain logic. This code is just as worthy of unit tests as recipes.
Say you have a recipe that configures the machine’s serial console. Using
Chef::Util::FileEdit
it manipulates /etc/inittab
. Based on the hardware, it
could be ttyS0
or ttyS1
. And since VMs don’t have serial consoles, you don’t
want to run agetty
.
So you’ve split the logic up between attributes and the recipe. Given the following attributes file:
require 'chef/sugar'
default['console'].tap do |console|
console['port'] = 'S1'
console['baud'] = '115200'
console['term'] = 'ansi'
unless node.deep_fetch('virtualization', 'role').nil?
# VMs don't have serial consoles
console['port'] = nil
end
case node.deep_fetch('dmi', 'system', 'product_name')
when 'PowerEdge M610', 'PowerEdge M710HD', 'PowerEdge M620'
console['port'] = 'S0'
end
end
There are five different paths through this code. The net result is three
different values for node['console']['port']
: S0
, S1
, and nil
.
describe 'console::default' do
CSH.each_hardware do |desc, ohai|
context "on #{desc}" do
let :runner do
ChefSpec::Runner.new do |node|
node.automatic.merge! ohai['automatic']
end.converge(described_recipe)
end
it 'converges' do
case desc
when /_Guest$/
expect(runner.node['console']['port']).to be_nil
when /^PowerEdge_(M610|M710HD|M620)$/
expect(runner.node['console']['port']).to eq('S0')
else
expect(runner.node['console']['port']).to eq('S1')
end
expect(runner.node['console']['baud']).to eq('115200')
expect(runner.node['console']['term']).to eq('ansi')
end
end
end
end
Now that the attributes have been verified, you can write spec tests for the recipe code.