Skip to content

jveski/puppet-spec

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

puppet-spec

Build Status

Test Puppet code with Puppet code.

Why not rspec-puppet?

Puppet-spec is intended to provide a low barrier to entry for those new to testing, and is idiomatic for anyone familiar with the Puppet DSL. Rspec-puppet, while more powerful, is far more complex and requires past exposure to Ruby and rspec. Don't think of puppet-spec as an attempt to undermine the wide adoption of rspec-puppet in the community, but rather the fulfilment of an unmet, yet significant need.

Getting Started

Installation

Puppet Module

You can install the Puppet spec module by cloning this repository into your modulepath, or by running puppet module install jordan/spec. The puppet spec command will be available once the module has been installed.

Rubygem

If your Puppet module has a Gemfile, you can add the gem puppet-spec as a dependency and include the bundled rake task to simplify the process of invoking your test suite. Just add require puppet-spec/tasks to your Rakefile, and run rake puppetspec to invoke the test suite.

Requirements

Puppet spec is tested on all permutations of the below versions.

Puppet:

  • 4.2.1
  • 4.2.0
  • 4.1.0
  • 4.0.0

Ruby:

  • 2.2.0
  • 2.1.0
  • 2.0.0
  • 1.9.3

A simple test case

file { '/tmp/test':
  ensure  => present,
  content => 'The file content',
}

assertion { 'that the file has the correct contents':
  subject     => File['/tmp/test'],
  attribute   => 'content',
  expectation => 'The file content',
}

assertion { 'that the file is present':
  subject     => File['/tmp/test'],
  attribute   => 'ensure',
  expectation => 'present',
}

The Assertion Resource Type

Title

The assertion's title should reflect what it is attempting to prove. This value will not used during evaluation, and serves only to provide insight to the user in the event that the assertion fails.

Subject

A resource reference to the resource under test, i.e. File['/etc/puppetlabs/puppet/puppet.conf'].

Attribute

If the attribute parameter is not provided, the assertion will prove only the presence of the subject resource in the catalog. Otherwise, attribute can be used to select which attribute of the subject resource the assertion will set an expectation on.

Expectation

Expectation should be set to the expected value of the subject's attribute as determined by the subject and attribute params. It's required if attribute is provided.

Ensure

Defaults to 'present', and accepts values 'present' and 'absent'. If the ensure attribute is set to absent, the assertion will validate that the subject is absent from the catalog. Expectation and attribute cannot be set in conjunction with ensure => 'absent'.

Puppet spec test cases are just manifests that contain assertion resource declarations. A typical test case is essentially an example (smoke test) with assertions. The assertions prove that the referenced resources have been included in the catalog and have the expected attributes. Test cases tend to look something like the below.

include apache

assertion { 'that the apache::ssl class is in the catalog':
  subject => Class['apache::ssl'],
}

assertion { 'that the apache package version is correct':
  subject     => Package['apache::package'],
  attribute   => 'ensure',
  expectation => '1.2.3',
}
...

Any spec manifests stored in the module-under-test's spec directory with a *_spec.pp suffix will be evaluated when puppet spec is executed. Failed assertions are printed to the console rspec style.

Stubbing

In order to effectively unit test a class, we may need to stub certain dependencies and/or potential side affects. Puppet spec provides three functions that can be used to stub at the Puppet compiler's top scope. Naturally, test cases are parsed top down, so the stub functions must be called before any affected resources are evaluated.

For examples, check out the acceptance test suite.

stub_facts({})

Stub_facts takes a hash of fact/value pairs, and... stubs them. Technically it just defines top scope variables, but stub_top_scope_variables() doesn't quite roll off the tongue.

stub_class('')

Stub_class stubs a given class. The stubbed class will accept values for any param. Classes can be namespaced as expected with the scope indicator.

stub_type('')

Stub_type stubs a defined type. Any parameters will be accepted and can be asserted upon. Like the stub_class function, the type name can be namespaced as you would expect.

Fixtures

Asserting on attributes with a long value can cause test suites to become unmanageably large, so Puppet spec provides a fixture function which reads from a given file underneath spec/fixtures.

Example

assertion { 'that the file has the correct very long contents':
  subject     => File['/tmp/largefile'],
  attribute   => 'content',
  expectation => fixture('file_contents'), #This would load the file `<module>/spec/fixtures/file_contents`
}

Negative Assertions

Considering that Puppet modules often make use of logical expressions to exclude resources from the catalog, Puppet spec's assertion resource type has an ensure attribute, which when given the value absent, sets an expectation on the absence of a resource from the catalog.

assertion { 'that the undesired file is not in the catalog':
  ensure  => absent,
  subject => File['/tmp/should/not/be/around'],
}

Want to pitch in?

I wrote this tool because I felt that the community could use an approachable testing mechanism in Puppet's native tongue. If you feel the same, feel free to take on an open GH issue, or find a bug.