How to use rspec-puppet for testing multiple modules

If you have been following the rspec-puppet tutorial, it is likely that you setup your module testing using rspec-puppet-init. While this works for single modules, you will require a different setup when testing multiple modules in a larger project.

In case you haven’t been using rvm and bundler, you should. rvm manages multiple versions of ruby and this will go a long way for your project when you would like to test compatibility. bundler is a dependency management software that makes environment consistent between development, testing and production. These will take more pain out of your setup. We will be using them in this demo. So go ahead and get your download started.

We will name our project rspec-puppet-demo. We will create subdirectories and our target structure should look like the following:

$ tree rspec-puppet-demo
rspec-puppet-demo/
├── Gemfile
├── Rakefile
├── manifests
│   └── site.pp
├── modules
│   ├── foo
│   │   ├── manifests
│   │   │   └── init.pp
│   │   └── spec
│   │       └── classes
│   │            └── foo_spec.rb
│   └── bar
|       ├── manifests
|       |   └── init.pp
|       └── spec
│           └── classes
│                └── bar_spec.rb
└── spec
    ├── fixtures
    │   ├── manifests
    │   │   └── site.pp
    │   └── modules
    │       ├── foo
    │       |   └── manifests -> ../../../../modules/foo/manifests
    │       └── bar
    │           └── manifests -> ../../../../modules/bar/manifests
    └── spec_helper.rb

Notice that modules foo and bar contain their own spec directory. For brevity, only the classes directory is shown here. Complex modules will require more tests, thus may need defines, hosts, and functions.

Now, we would like to be able to run all module tests from project root, so we create the fixtures directory in rspec-puppet-demo/spec. There are two important things to note from rspec-puppet docs, first, Puppet expects to be able to read a site.pp file when running tests and that Puppet’s manifest autoloader requires fixtures directory point to the module contents.

For the first to be true, we create an empty site.pp file.

$ mkdir -p spec/fixtures/manifests
$ touch spec/fixtures/manifests/site.pp

Next we create our symlinks. We start with the module foo. The same commands will work on our module bar.

$ mkdir -p spec/fixtures/modules/foo
$ cd spec/fixtures/modules/foo
$ ln -s ../../../../modules/foo/manifests

If you have a complex module you may need to create more symlinks. Typically, the following folders can be present under your modules directory: files, lib, modules and templates.

At this point, we need to configure our spec_helper.rb file to locate our fixtures directory. Our file will look like:

require 'rspec-puppet'

fixture_path = File.expand_path(File.join(__FILE__, '..', 'fixtures'))

RSpec.configure do |c|
  c.module_path = File.join(fixture_path, 'modules')
  c.manifest_dir = File.join(fixture_path, 'manifests')
end

Next, we configure our Rakefile. Our objective is to be able to run our spec tests via rake, and we tell rake where our tests are located. Looking back at our directory structure, our tests are located at modules/*/spec/*/*_spec.rb. Our Rakefile would look like the following:

require 'rake'
require 'rspec/core/rake_task'

RSpec::Core::RakeTask.new(:spec) do |t|
  t.pattern = 'modules/*/spec/*/*_spec.rb'
end

task :default => :spec

Finally, we configure bundler and write our Gemfile. The packages we need to run our tests will be specified here. It should look like:

source 'https://rubygems.org'

gem 'puppet',       :require => false
gem 'rake',         :require => false
gem 'rspec-puppet', :require => false

Now, all there is to do is to run bundle install which will download dependencies for us. And we are able to run tests with bundle exec rake.