rspec-puppet

repository·master·Indexed 18 days ago

https://github.com/rodjek/rspec-puppet

A testing framework for Puppet manifests and modules using RSpec. It enables developers to verify Puppet code by compiling catalogues and inspecting resources, facts, and parameters. The framework includes matchers for verifying resource existence, parameters, resource counts, and relationships, as well as support for testing custom types and type aliases.

Tokens
25.8K
Snippets
105
Records
128
Agent score
60%

What's inside rspec-puppet

  1. Understand the purpose of rspec-puppet tests

    master

    rspec-puppet is not designed to test the result of a manifest on a live system. Instead, it tests the behavior of Puppet when it compiles your manifests into a catalogue of Puppet resources.

    Key testing principles:

    • Test the Catalogue: Verify that the expected resources (files, packages, services, etc.) are present in the compiled catalogue.
    • Test the First Level: When testing a high-level class (e.g., a webserver role), only test for the existence of the resources or types it directly includes (e.g., apache::vhost). Do not test the internal resources of those sub-components; that is the responsibility of the tests for those specific components.
  2. Test recursive resource dependencies

    master

    Starting from version 2.3.0, rspec-puppet supports recursive dependency checking for relationship matchers like before, require, subscribe, and notify. This means if you have a dependency chain File[a] -> File[b] -> File[c], you can match the relationship between the first and last element directly.

    Example: contain_file('a').that_comes_before('File[c]') will now correctly match the chain.

  3. Organize Puppet module tests using naming conventions

    master

    To ensure tests are automatically placed in the correct groups and have access to custom matchers, follow this directory structure:

    module/
      ├── manifests/
      ├── lib/
      └── spec/
           ├── spec_helper.rb
           ├── classes/
           │     └── <class_name>_spec.rb
           ├── defines/
           │     └── <define_name>_spec.rb
           ├── applications/
           │     └── <application_name>_spec.rb
           ├── functions/
           │     └── <function_name>_spec.rb
           ├── types/
           │     └── <type_name>_spec.rb
           ├── type_aliases/
           │     └── <type_alias_name>_spec.rb
           └── hosts/
                 └── <host_name>_spec.rb
    module/
      ├── manifests/
      ├── lib/
      └── spec/
           ├── spec_helper.rb
           ├── classes/
           │     └── <class_name>_spec.rb
           ├── defines/
           │     └── <define_name>_spec.rb
           ├── applications/
           │     └── <application_name>_spec.rb
           ├── functions/
           │     └── <function_name>_spec.rb
           ├── types/
           │     └── <type_name>_spec.rb
           ├── type_aliases/
           │     └── <type_alias_name>_spec.rb
           └── hosts/
                 └── <host_name>_spec.rb
  4. How to test Puppet Applications

    master

    Testing Puppet Applications (available in Puppet >= 4.3.0) requires a specific test structure because applications act like defined types and require a title.

    Key requirements for the test setup:

    1. Node Definition: You must define a node variable so it can be referenced in the nodes parameter.
    2. Title: You must define a title for the application instance.
    3. Node References: The nodes parameter requires node reference mappings to resource mappings. You must use the ref method to create these references; passing a standard string will not work.
    4. Single-Node Constraint: Cross-node support is currently unavailable. Ensure your tests are modeled to be single-node to avoid errors.
    describe '<application name>' do
      let(:node) { '<host name>' }
      let(:title) { '<application instance title>' }
      let(:params) do
        {
          'nodes' => {
            ref('Node', node) => ref('<capitalised application name>', title),
          }
          # any additional app parameters
        }
      end
    
      # tests go here
    end
  5. Access the parser scope for complex function testing

    master

    Some complex functions require access to the current parser's scope (e.g., for stubbing lookupvar). You can access scope directly in your tests.

    Note: This approach does not work when testing manifests that use custom functions. For custom functions, you must define a replacement function directly using Puppet::Parser::Functions.newfunction within a before(:each) block.

    # Stubbing scope
    
    before(:each) { scope.expects(:lookupvar).with('some_variable').returns('some_value') }
    
    # Replacing a custom function
    
    before(:each) do
        Puppet::Parser::Functions.newfunction(:custom_function, :type => :rvalue) { |args| 
            raise ArgumentError, 'expected foobar' unless args[0] == 'foobar'
            'expected value'
        }
    end
  6. Group elements using the Data API

    master

    You can group elements using the data-match-height="group-name" attribute (or the data-mh shorthand). All elements sharing the same group name will be set to the same height, regardless of their position in the DOM.

    Note: When using the Data API, byRow is automatically enabled.

    <div data-mh="my-group">My text</div>
    <div data-mh="my-group">Some other text</div>
    <div data-mh="my-other-group">Even more text</div>
    <div data-mh="my-other-group">The last bit of text</div>
  7. Test Puppet hosts with rspec-puppet

    master

    To test a specific host (node), create a spec file located under spec/hosts/. The test runner will look for a node definition in your site.pp matching the host name, compile the catalogue for that host, and execute the tests against the resulting catalogue.

    Ensure you require spec_helper at the top of your spec file.

    require 'spec_helper'
    
    describe '<host name>' do
      # your tests go here
    end
  8. Organize tests for Puppet Types

    master

    Tests for Puppet types must be placed in the spec/types directory. The filename should follow the pattern <type_name>_spec.rb. For example, a type named sudoers_entry should have its tests located at spec/types/sudoers_entry_spec.rb.

    require 'spec_helper'
    
    describe '<type name>' do
      # tests go here
    end