This document discusses testing driven development of Puppet modules. It covers using puppet-lint to check style, puppet-syntax to validate code, and rspec-puppet to test catalogs and verify relationships. Packer is used to build consistent virtual machine images, Vagrant manages virtual environments for testing, and Beaker runs acceptance tests across multiple platforms. The goal is to create a virtuous cycle of testing, validation, and development feedback to continuously improve module quality.
10. Development
puppet-lint
Manifest lint check:
$ puppet lint manifests/**/*
WARNING: top-scope variable being used without an explicit namespace on line 4
WARNING: class inheriting from params class on line 26
WARNING: class not documented on line 1
WARNING: line has more than 80 characters on line 52
10 / 45
11. Development
puppet-lint
Manifest lint cleanup:
$ puppet-lint -f demo.pp
FIXED: string containing only a variable on line 1
FIXED: variable not enclosed in {} on line 5
FIXED: indentation of => is not properly aligned on line 2
FIXED: indentation of => is not properly aligned on line 3
FIXED: indentation of => is not properly aligned on line 5
WARNING: ensure found on line but it's not the first attribute on line 4
11 / 45
13. Development
puppet-lint
puppet-syntax
Manifest validation:
$ puppet parser validate manifests/bad.pp
Error: Could not parse for environment production: Syntax error at 'demo';
expected '}' at /Users/nan/src/puppet-demo/manifests/bad.pp:4
13 / 45
18. Development
puppet-lint
puppet-syntax
rspec-puppet
Supply system facts and class parameters:
let(:facts) {{ :osfamily => 'redhat' }}
let(:params) {{
:keys_enable => true,
:keys_file => '/etc/ntp/ntp.keys',
:keys_trusted => ['1', '2', '3'],
:keys_controlkey => '2',
:keys_requestkey => '3',
}}
18 / 45
19. Development
puppet-lint
puppet-syntax
rspec-puppet
require 'spec_helper'
describe 'ntp' do
Dir.glob('tests/*.pp').each do |file|
let(:facts) {{ :osfamily => 'redhat' }}
context file do
let(:pre_condition) { File.read(file) }
it{ should compile }
end
end
end
19 / 45
20. Development
puppet-lint
puppet-syntax
rspec-puppet
Puppet Class:
describe 'ntp' do
let(:facts) {{ :osfamily => 'RedHat' }}
let(:params) {{
:iburst_enable => true,
}}
it do
should contain_file('/etc/ntp.conf').with({
'content' => /iburstn/,
})
end
end
20 / 45
21. Development
puppet-lint
puppet-syntax
rspec-puppet
Define Type
describe 'mysql::db', :type => :define do
let(:facts) {{ :osfamily => 'RedHat' }}
let(:title) { 'test_db' }
let(:params) {
{ 'user' => 'testuser',
'password' => 'testpass',
}
}
...
end
21 / 45
41. Testing
Packer
Vagrant
Beaker
it 'should run successfully' do
pp = "class { 'ntp': }"
# Apply twice to ensure no errors the second time.
apply_manifest(pp, :catch_failures => true) do |r|
expect(r.stderr).not_to match(/error/i)
end
apply_manifest(pp, :catch_failures => true) do |r|
expect(r.stderr).not_to eq(/error/i)
expect(r.exit_code).to be_zero
end
end
41 / 45
42. Testing
Packer
Vagrant
Beaker
it 'starts the service' do
pp = <<-EOS
class { 'ntp':
service_enable => true,
service_ensure => running,
service_manage => true,
service_name => '#{servicename}'
}
EOS
apply_manifest(pp, :catch_failures => true)
end
describe service(servicename) do
it { should be_running }
it { should be_enabled }
end
42 / 45
43. Testing
Packer
Vagrant
Beaker
Summary
Packer: VM build
Vagrant: VM clone and testing
Beaker: Automated testing
43 / 45