Infrastruktur – News

Puppet Test Driven Development: Part I – Create a simple class

12 März 2015

Now that all the setup work is done (see Puppet Test Driven Development: Part 0 – Setup your environment), you can start writing some code. You are going to develop this module in a behavior/test driven manner, meaning you will write tests to describe how the module should behave before writing the actual code.

We will create an openldap::client class that, when declared, will install the OpenLDAP clients tools, including the ldapsearch command, so that we can connect to an LDAP server.

Write your first acceptance test

Getting started

Now for the first tests, we will create a test to validate the openldap::client class' behavior in spec/acceptance/openldap__client_spec.rb. By convention, you should use a double underscore to replace the double colon in the class name.

The first thing to do in any test file is require our spec_helper_acceptance.rb file.

The first acceptance test: testing that the Puppet catalog converges at first run

Line 6 – 8

Store the Puppet manifest to run with apply_manifest() in the pp variable.

Line 10

Run the manifest and catch any failure.

Line 11

Run the manifest a second time and catch any change. Your manifest should converge at first run.

If you run your tests right now, you should see a nasty block of errors because the openldap::client class doesn’t actually exist yet. Let’s test with the centos7 nodeset:

Line 1

The command to launch includes the nodeset to use in the environment variable BEAKER_set and specify the acceptance test to run.

Line 3 – 4

The label of the describe blocks in the acceptance test (line 3 and 4 of spec/acceptance/openldap__client_spec.rb)

Line 5

Scp Puppet manifests to the virtual machine

Line 6

Result of the test (failure)

Line 13 – 22

Detail of the failure

Line 24

Acceptance test run timer summary

Line 25

Acceptance test result summary

Line 27 – 29

Failure summary   It basically says that the Puppet catalog does not even compile because it can’t find the openldap::client class. So let’s write a unit test that verifies that, at least, the catalog compiles.

Write your first unit test

 

Getting started

We’ll now write a unit test for our openldap::client class that validates that the Puppet catalog compiles. Unit tests for classes lives in spec/classes, so let’s create the directory first.

Then, we’ll create a unit test file for the class openldap::client in spec/classes/openldap__client_spec.rb.

The first thing to do in any test file is to require our spec_helper.rb file.

The first unit test : testing that the catalog compiles

As first test, you should always be sure that your catalog compiles.

Line 4

Test that verifies that the catalog actually compiles.

If you run your test right now, you should also see a big block of errors because the class does not exist yet.

Line 1

The command to run to launch unit tests. It tells bundler to exec the rake task spec (defined in puppetlabs_spec_helper) with the environment variable SPEC_OPTS set to -d which sets the output format to documentation for a cleaner output.

Line 3

The label of the describe block (line 3 of spec/classes/openldap__client_spec.rb)

Line 4

Result of the unit test

Line 6 – 11

Details of the failures

Line 13

Unit test timer summary

Line 14

Unit test summary

Line 16 – 18

Failures summary

Write the class

 

Getting started

Now that everything is set up, let’s write the actual Puppet code! First, create the directory where our manifests will live.

Next, create our openldap::client class

If you save and run the unit tests again now, you’ll see that now that the class exists, our unit test passes.

and our acceptance test also passes.

but it doesn’t yet do what we want… Let’s add the acceptance test that describe what we really want, i.e. be able to connect to an ldap server.

The next check: testing that we can actually connect to an ldap server

You’ll test that you can really connect to a public ldap test server with ldapsearch. First, you need to create a method that will launch the ldapsearch command. Put it in your spec_helper_acceptance.rb so that you can use it in all your acceptance test files

Line 1

Function declaration

Line 2

Use the shell beaker DSL function to actually launch command

Now you can use it in your acceptance test:

Line 15 – 19

Declare a new test that actually runs the ldapsearch command. If you save and run beaker you’ll have an error because it doesn’t find the ldapsearch command:

The ldapsearch command is available in the openldap-client package on RedHat, so let’s be sure that a package resource with named openldap-clients exists in the catalog.

If you save and run the unit tests, you should have an error because you don’t actually have a file resource named openldap-clients in your catalog

So, let’s fix this adding the installation of ldap client tools in openldap::client class:

And launch the unit tests again:

Then, the acceptance tests:

Now we have the behavior we wanted. We can connect to an ldap server. At least on Centos/RedHat7… But what happens if you run the tests on Debian 7? Let’s see…

It fails because the package openldap-clients does not exist on Debian and thus, the ldapsearch command is not installed.

On Debian, the ldapsearch command lives in the ldap-utils package and not in openldap-clients.

We have to be sure that, on Debian family OS, Puppet installs the ldap-utils package and not the openldap-clients package. For that, we can test the content of the catalog with a unit tests.

rspec-puppet sends the :facts hash to the Puppet compiler to populate the facts or top scope variables you use in your manifests.

We have to add some logic in our unit test because our catalog will be different.

You can either populate the :facts hash yourself:

Or, probably better, let rspec-puppet-facts (https://github.com/mcanevet/rspec-puppet-facts) populate the :facts hash for you and avoid duplicate code:

Line 4

Loop over every supported operating system declared in your metadata.json.

Add the rspec-puppet-facts gem to your Gemfile:

And update your gemset:

Load rspec-puppet-facts in your spec/spec_helper.rb

Then, run the unit tests again

Now we can fix the openldap::client class:

And run the tests again

It works!

Let’s try the acceptance test with the Debian7 nodeset to test the actual behavior:

It works too!

Now that you know how to develop a simple Puppet class in a behavior/test driver manner, we will see in Part 2 how to code a more complex class.

 

Hinterlassen Sie einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

2 commentaires

  1. Martin sagt:

    Hi Mickaël,

    Great work on taking the time to write this down and explaining in great detail how to start with Puppet TDD.

    I’m looking forward to Part 2. Also wondering how one would include hiera databindings lookup in this example.

    e.g.
    class openldap::client($package_name) { }

    How do you test this in your suite?