There are several steps depending on how much involved the tests are, what parts are tested and, of course, how long it takes to run the tests.
For unit testing we use rspec puppet, and we can check that our manifests and modules compile and contain the expected values. It can be used to test that specific types, classes or definitions are in the compiled catalog and that the parameters math the expectations.
Later on we can do some integration testing starting a new VM with Vagrant and checking that there are no errors in the provisioning, as well as checking that some conditions are met.
For rspec-puppet, PuppetLabs has created a project called puppetlabs_spec_helper that let’s us avoid writing a bunch of boilerplate. A missing point though is that it only allows to use modules for testing from git. If you’re already using librarian-puppet (and you should!) you can easily use the same Puppetfile for deploying modules and to test them. Doing otherwise sounds like a bit of useless testing, you could end with different versions in different development machines, CI server, puppet master,… So just add a call to librarian puppet in your rakefile to populate the rspec-puppet fixtures before running the specs.
Unfortunately rspec-puppet doesn’t work with Puppet 3.0.x and at least Puppet 3.1.0-rc1 is required. It was a bit of a setback when we moved to Puppet 3 and started using hiera, which is proving to be very useful to have simpler manifests and external data injected for our Maestro installations with Puppet from scratch.
You can also use the same Puppetfile to start Vagrant boxes with the exact same version of the modules. We are using Cucumber and Aruba to execute vagrant, provision the VM with puppet and check several things, like open ports, services up,… but that’s a different story 🙂
Example
In this puppet-for-java-devs project you will find the bits that showcase all these tools integrated. It includes definition of a 3-tier system with Puppet definitions for a postgresql database, tomcat nodes with a war installed and apache nodes fronting them.
Install all required gems
bundle install
Install all Puppet modules with Puppet Librarian
librarian-puppet install
Run the specs with puppet-rspec
bundle exec rake
Start all the vms with Vagrant
vagrant up
Rakefile
require 'bundler' Bundler.require(:rake) require 'rake/clean' require 'puppetlabs_spec_helper/rake_tasks' CLEAN.include('modules', 'spec/fixtures/', 'doc') CLOBBER.include('.tmp', '.librarian') task :librarian_spec_prep do sh "librarian-puppet install" end task :spec_prep => :librarian_spec_prep task :default => [:spec]
Puppetfile for librarian-puppet
forge 'http://forge.puppetlabs.com' mod 'puppetlabs/java', '0.1.6' mod 'puppetlabs/apache', '0.4.0' mod 'inkling/postgresql', '0.2.0' mod 'puppetlabs/firewall', '0.0.4' mod 'tomcat', :git => 'https://github.com/carlossg/puppet-tomcat.git', :ref => 'centos' mod 'maestrodev/maven', '1.x' mod 'stahnma/epel', '0.0.2' mod 'maestrodev/avahi', '1.x' mod 'other', :path => 'mymodules/other'
tomcat_spec.rb with rspec-puppet
require 'spec_helper' describe 'tomcat1.acme.com' do let(:facts) { {:osfamily => 'RedHat', :operatingsystem => 'CentOS', :operatingsystemrelease => 6.3} } it { should contain_class('java').with_distribution /openjdk/ } it "configure webapp" do should contain_maven('/srv/tomcat/appfuse/webapps/ROOT.war') should contain_maven('/srv/tomcat/appfuse/webapps/ROOT/WEB-INF/lib/postgresql-9.1-901.jdbc4.jar') end end
Vagrantfile
Vagrant::Config.run do |config| config.vm.box = "CentOS-6.3-x86_64-minimal" config.vm.box_url = "https://dl.dropbox.com/u/7225008/Vagrant/CentOS-6.3-x86_64-minimal.box" config.vm.customize ["modifyvm", :id, "--rtcuseutc", "on"] # use UTC clock https://github.com/mitchellh/vagrant/issues/912 # db server config.vm.define :db do |config| config.vm.host_name = "db.acme.local" config.vm.customize ["modifyvm", :id, "--name", "db"] # name for VirtualBox GUI config.vm.forward_port 5432, 5432 config.vm.network :hostonly, "192.168.33.10" config.vm.provision :puppet do |puppet| puppet.module_path = "modules" puppet.manifest_file = "site.pp" end end # tomcat server config.vm.define :tomcat1 do |config| config.vm.host_name = "tomcat1.acme.local" config.vm.customize ["modifyvm", :id, "--name", "tomcat1"] # name for VirtualBox GUI config.vm.forward_port 8080, 8081 config.vm.network :hostonly, "192.168.33.11" config.vm.provision :puppet do |puppet| puppet.module_path = "modules" puppet.manifest_file = "site.pp" end end # web server config.vm.define :www do |config| config.vm.host_name = "www.acme.local" config.vm.customize ["modifyvm", :id, "--name", "www"] # name for VirtualBox GUI config.vm.forward_port 80, 8080 config.vm.network :hostonly, "192.168.33.12" config.vm.provision :puppet do |puppet| puppet.module_path = "modules" puppet.manifest_file = "site.pp" end end end