Testing all platforms you support
A few days ago, I blogged about using CSH.each_hardware
to ensure you have
code coverage for the various hardware platforms you support. I use the same
methodology for testing all the OS/version combinations we support. In the CSH
(ChefSpecHelper) gem the following code resides:
module CSH
PLATFORMS = {
supported: [
%w[centos 5.8],
%w[centos 6.3],
%w[centos 6.4],
%w[centos 6.5]
],
unsupported: [
%w[ubuntu 12.04]
]
}
def self.each_platform(*kinds, &block)
array = []
kinds = [:supported] if kinds.empty?
kinds.each do |k|
fail "Unknown kind #{k.inspect}" unless PLATFORMS.include?(k)
array.concat PLATFORMS[k]
end
array.map do |platform, version|
yield platform, version
end
end
end
Say you have a dummy::grub recipe that is platform specific:
package 'grubby' do
package_name 'mkinitrd' if node['platform_version'].to_i < 6
end
The corresponding spec test would look like:
describe 'dummy::grub' do
CSH.each_platform do |platform, version|
context "on #{platform}-#{version}" do
let :runner do
ChefSpec::Runner.new(platform: platform, version: version).converge(described_recipe)
end
it 'converges' do
expect(runner).to install_package('grubby')
if version.to_i < 6
expect(runner).to install_package('grubby').with(package_name: 'mkinitrd')
end
end
end
end
end
The great thing about controlling this centrally is that you don’t have to modify spec tests across your complete cookbook set. In the next weeks when we power off the remaining CentOS-6.3 machines, I’ll just remove the entry and we’ll stop executing those tests.
You can combine this methodology with CSH.each_hardware
and ensure that
all supported nodes are covered.
describe 'raid::utils' do
CSH.each_platform do |platform, version|
CSH.each_hardware do |machine, json|
context "#{platform}-#{version} on #{machine}" do
let :runner do
ChefSpec::Runner.new(platform: platform, version: version) do |node|
node.automatic.merge! json['automatic']
end.converge(described_recipe)
end
it 'converges' do
if machine =~ /^PowerEdge/ && version.to_i == 5
expect(runner).to install_package('raidcfg')
else
expect(runner).not_to install_package('raidcfg')
end
if machine =~ /^PowerEdge/ && version.to_i == 6
expect(runner).to install_package('MegaCli')
expect(runner).to install_package('MegaLogR')
else
expect(runner).not_to install_package('MegaCli')
expect(runner).not_to install_package('MegaLogR')
end
if machine =~ /^ProLiant/
expect(runner).to install_package('hpacucli')
else
expect(runner).not_to install_package('hpacucli')
end
end
end
end
end
end
Sure you could collapse these tests down into just the bare minimum needed to have coverage. But why? Since chefspec is so fast, you might as well take a more black box approach to these tests. In the future there may be more or different permutations to test. It is better to have the scaffolding in place instead of having to retrofit it later.