Hiera fixtures for puppet-rspec tests.
Add this line to your application's Gemfile:
gem 'hiera-puppet-helper'
And then execute:
$ bundle
Or install it yourself as:
$ gem install hiera-puppet-helper
- If you plan to use multiple hiera_config contexts or assign different values to the hiera_data variable, then you must put the tests in different files.
- Use hiera-puppet-helper < 2.0.0 for puppet versions < 3.0.0
Note: you can find a working example inside the example/ directory of this gem.
The following assumes that you are already be familiar with rspec-puppet.
To use this gem add the following include to spec/spec_helper.rb:
require 'hiera-puppet-helper'
For the purpose of demonstrating a Hiera fixture, lets assume there is the following contrived example of a Puppet class:
modules/example/manifests/init.pp
class example {
notify { 'foo': message => hiera('foo_message') }
}
In your specs for this class you can define a Hiera fixture by setting 'hiera_data' to a hash that contains the data that you want the Puppet 'hiera' function to return:
spec/classes/example_spec.rb
describe "example" do
let(:hiera_data) { { :foo_message => "bar" } }
it { should contain_notify("foo").with_message("bar") }
end
It is possible to load the hiera fixtures with any Hiera backend, just define a method 'hiera_config' that returns the desired Hiera configuration. For a list of possible configuration options, see https://github.com/puppetlabs/hiera#configuration.
The following example spec loads the Hiera fixture data from Yaml files:
spec/classes/example_spec.rb
describe "example" do
let(:hiera_config) do
{ :backends => ['yaml'],
:hierarchy => [
'%{fqdn}/%{calling_module}',
'%{calling_module}'],
:yaml => {
:datadir => File.expand_path(File.join(__FILE__, '..', '..', 'hieradata')) }}
end
it { should contain_notify("foo").with_message("bar") }
end
Be aware that setting 'hiera_config' takes precedence before setting 'hiera_data', meaning with the above Hiera configuration, the value of 'hiera_data' will be ignored. The next example will demonstrate how to address that.
If you want a combination of fixture data from Yaml files and fixture data from 'hiera_data', you can use the Hiera 'rspec' backend, which is also provided by this gem. The 'rspec' backend uses its configuration hash as data store to look up data. The following example combine both the 'rspec' backend, and the 'yaml' backend, with the effect that the data is first looked up in the 'hiera_data' fixture defined by the spec and then in Yaml files as well:
spec/classes/example_spec.rb
describe "example" do
let(:hiera_config) do
{ :backends => ['rspec', 'yaml'],
:hierarchy => [
'%{fqdn}/%{calling_module}',
'%{calling_module}'],
:yaml => {
:datadir => File.expand_path(File.join(__FILE__, '..', '..', 'hieradata')) },
:rspec => respond_to?(:hiera_data) ? hiera_data : {} }
end
it { should contain_notify("foo").with_message("bar") }
end
To avoid having to copy-paste the Hiera configuration into each and every spec, you can use a shared context. The following is a full-featured example that demonstrates the use of a shared context.
spec/spec_helper.rb
require 'hiera-puppet-helper'
fixture_path = File.expand_path(File.join(__FILE__, '..', 'fixtures'))
shared_context "hieradata" do
let(:hiera_config) do
{ :backends => ['rspec', 'yaml'],
:hierarchy => [
'%{fqdn}/%{calling_module}',
'%{calling_module}'],
:yaml => {
:datadir => File.join(fixture_path, 'hieradata') },
:rspec => respond_to?(:hiera_data) ? hiera_data : {} }
end
end
spec/classes/example_spec.rb
describe "example" do
include_context "hieradata"
it { should contain_notify("foo").with_message("bar") }
end
Right now, the Gem would not support multiple let(:hiera_data)
for one class normally:
describe "in-line hiera_data test" do
let(:hiera_data) { { :bar_message => "a" } }
it { should contain_notify("bar").with_message("a") }
end
describe "in-line hiera_data test in one file" do
let(:hiera_data) { { :bar_message => "b" } }
it { should contain_notify("bar").with_message("b") }
end
However, you can fix this by adding let(:facts) {{ :cache_bust => Time.now }}
which will invalidate the cache for each test, meaning that the hiera data will work:
describe "example::bar" do
let(:facts) {{ :cache_bust => Time.now }}
describe "first in-line hiera_data test with a" do
let(:hiera_data) { { :bar_message => "a" } }
it { should contain_notify("bar").with_message("a") }
end
describe "second in-line hiera_data test with b" do
let(:hiera_data) { { :bar_message => "b" } }
it { should contain_notify("bar").with_message("b") }
end
end