Tuesday, May 20, 2014

Puppet rspec testing with automatic hiera lookups (implicit hiera lookup like puppet 3.x)

This article is an add-on to my other article regarding puppet & rspec.
This article only covers automatic hiera lookups used during rspec puppet runs.
Many thanks to Jan (janwaech<at>gmail<dot>com) who spend the time digging into rspec-puppet code finding this nice solution.



Basic Setup:


Gemfile


# Install via
# bundle install --path vendor/gems
#
source "https://rubygems.org"

gem "mocha", :require => false
gem 'puppet',       '>= 3.1.1'
gem 'puppet-lint'
gem 'facter',       '>= 1.6.10'
gem 'rspec-puppet', :git => "https://github.com/rodjek/rspec-puppet.git"
gem 'rake',         '>= 0.9.2'
gem 'puppetlabs_spec_helper', '0.3.0'
gem 'test-unit'

Rakefile


require 'rake'
require 'rake/tasklib'
require 'rspec/core/rake_task'
require 'rubygems'
require 'puppetlabs_spec_helper/rake_tasks'

require 'hiera'
require 'puppet-lint'

desc "Run the tests"
RSpec::Core::RakeTask.new(:test) do |t|
  t.rspec_opts = ['--color', '-f d']
  t.pattern = 'spec/*/*_spec.rb'
end

desc 'Run puppet-lint on the one manifests'
task :onelint do
  PuppetLint.configuration.with_filename = true

  linter = PuppetLint.new
  matched_files = FileList['spec/fixtures/modules/one/manifests/**/*.pp']

  matched_files.to_a.each do |puppet_file|
    linter.file = puppet_file
    linter.run
  end

  fail if linter.errors? || (
    linter.warnings? && PuppetLint.configuration.fail_on_warnings
    )
end

task :default => [:spec_prep, :test, :onelint, :spec_clean]
 

spec/spec_helper.rb


require 'test/unit'
require 'mocha/setup'
require 'puppetlabs_spec_helper/module_spec_helper'

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

# include common helpers
support_path = File.expand_path(File.join(File.dirname(__FILE__), '..',
                                          'spec/support/*.rb'))
Dir[support_path].each {|f| require f}

RSpec.configure do |c|
  c.config = '/doesnotexist'
  c.manifest_dir = File.join(fixture_path, 'manifests')

  c.hiera_config = File.join(fixture_path, 'hiera/hiera.yaml')
  c.mock_with :mocha
end


Hiera configuration


spec/fixtures/hiera/hiera.yaml


---
:backends:
  - yaml
:hierarchy:

  - %{::osfamily}
  - test

:yaml:
    :datadir: 'spec/fixtures/hiera' 

spec/fixtures/hiera/test.yaml

--- 
myvariable: 'myvalue'

 spec/fixtures/hiera/Debian.yaml

--- 
myvariable: 'myDebian'

spec/fixtures/hiera/RedHat.yaml

---
myvariable: 'myRedHat'

Hiera integration


spec/classes/test_spec.rb


require 'spec_helper'

# test our main class (init.pp)
describe 'stdmodule', :type => :class  do     # <- set the class name
 

    context 'on Debian system' do
        let (:facts) {{ :osfamily => 'Debian' }}
        it { should contain_class('stdmodule') }                        # <- check for classes included
        it { should contain_class('stdmodule').with_myparam('myDebian') }    # <- check for classes with parameters

    end
    context 'on RedHat system' do
        let (:facts) {{ :osfamily => 'RedHat' }}
        it { should contain_class('stdmodule') }                        # <- check for classes included
        it { should contain_class('stdmodule').with_myparam('myRedHat') }    # <- check for classes with parameters

    end
    context 'on Debian system' do
        let (:facts) {{ :osfamily => 'FooBar' }}
        it { should contain_class('stdmodule') }                        # <- check for classes included
        it { should contain_class('stdmodule').with_myparam('myvalue') }    # <- check for classes with parameters

    end
end