59
Puppet RSpec Why You Should, Too

Puppet Loves RSpec, Why You Should, Too

Embed Size (px)

DESCRIPTION

"Puppet Loves RSpec, Why You Should, Too" by Dennis Rowe at Puppet Camp Austin 2013.

Citation preview

Page 1: Puppet Loves RSpec, Why You Should, Too

Puppet ❤ RSpecWhy You Should, Too

Page 2: Puppet Loves RSpec, Why You Should, Too

Dennis RoweSenior DevOps Engineer

Cirrus Logic (cirrus.com)

shr3kst3r on Twitter, Github, and Freenode

Page 3: Puppet Loves RSpec, Why You Should, Too

• Setup of Puppet RSpec

• Quick RSpec primer

• Review some RSpec code

• Opinions on testing

Page 4: Puppet Loves RSpec, Why You Should, Too

Testing is like free kittens

Page 5: Puppet Loves RSpec, Why You Should, Too
Page 6: Puppet Loves RSpec, Why You Should, Too

Not Testing?

Page 7: Puppet Loves RSpec, Why You Should, Too
Page 8: Puppet Loves RSpec, Why You Should, Too

So, RSpechttps://github.com/rodjek/rspec-puppet

http://rspec-puppet.com/tutorial/https://github.com/puppetlabs/puppetlabs_spec_helper

Page 9: Puppet Loves RSpec, Why You Should, Too

First, Install RVM

• RVM = Ruby Version Manager

• https://rvm.io/

• Allows us to manage ruby versions and gemsets

• Specify ruby version in repo/.rvmrc

• source ~/.rvm/scripts/rvm

Page 10: Puppet Loves RSpec, Why You Should, Too

% curl -L https://get.rvm.io | bash -s stable --rails --autolibs=enabled

% rvm use ruby-1.9.3@puppet-camp-austin --install --create 

% ruby -v

ruby 1.9.3p392 [x86_64-darwin12.2.1]

Page 11: Puppet Loves RSpec, Why You Should, Too

• http://rubygems.org

• Specifies exactly what gems are used

• `bundle install` installs the gems in our gemset

Gemfile Time

Page 12: Puppet Loves RSpec, Why You Should, Too

Example Gemfile

source :rubygems

gem "puppet", "~> 3.1.1"

gem "puppetlabs_spec_helper", "~> 0.4.1"

Page 13: Puppet Loves RSpec, Why You Should, Too

Gemfile.lock

GEM remote: http://rubygems.org/ specs: diff-lcs (1.2.4) facter (1.7.0) hiera (1.2.1) json_pure json_pure (1.7.7) puppet (3.1.1) facter (~> 1.6)

Page 14: Puppet Loves RSpec, Why You Should, Too

RSpec Prep

• mkdir -p spec/classes/puppet-camp-austin/

• Add Rakefilerequire 'rubygems'

require 'puppetlabs_spec_helper/rake_tasks'

• Add spec/spec_helper.rbrequire 'rubygems'

require 'puppetlabs_spec_helper/module_spec_helper'

Page 15: Puppet Loves RSpec, Why You Should, Too

Setup .fixtures.yml

% cat .fixtures.yml

fixtures:

symlinks:

puppet-camp-austin: "#{source_dir}"

Page 16: Puppet Loves RSpec, Why You Should, Too

Quick Overview of RSpec Constructs

Page 17: Puppet Loves RSpec, Why You Should, Too

describe

• Expresses the concept of the block

• They can be nested

• The first level describe should be a class, define, function, or host

Page 18: Puppet Loves RSpec, Why You Should, Too

Example describedescribe “myfunction” do

describe “it should do this” do

...

end

describe “it should also do this”

...

end

end

Page 19: Puppet Loves RSpec, Why You Should, Too

lets

let(:title) { ‘namevar’ }

let(:params) {{‘var1’ => ‘foo’, ...}}

let(:node) { ‘ahost.example.com’ }

let(:facts) {{:osfamily => 'Debian', ...}}

Page 20: Puppet Loves RSpec, Why You Should, Too

Matchers

• include_class

• contain_{package, service, user, etc}

Page 21: Puppet Loves RSpec, Why You Should, Too

should or should_not

it { should include_class(‘foobarz’) }

it { should_not include_class(‘foobarz’)}

it { should contain_package(‘fooz’) }

it { should contain_user(‘barz’) }

Page 22: Puppet Loves RSpec, Why You Should, Too

Now moving on

Page 23: Puppet Loves RSpec, Why You Should, Too

So, let us add an example class

Page 24: Puppet Loves RSpec, Why You Should, Too

% cat manifests/example1.pp

class puppet-camp-austin::example1 {

}

Page 25: Puppet Loves RSpec, Why You Should, Too

cat spec/classes/puppet-camp-austin/example1_spec.rb

require 'spec_helper'

describe 'puppet-camp-austin::example1' do

it 'should include git' do

should contain_package('git')

end

end

Page 26: Puppet Loves RSpec, Why You Should, Too

Let us run RSpec% rake spec

F

Failures:

1) puppet-camp-austin::example1 should include git

Failure/Error: should contain_package('git')

expected that the catalogue would contain Package[git]

# ./spec/classes/puppet-camp-austin/example1_spec.rb:5:in `block (2 levels) in <top (required)>'

Page 27: Puppet Loves RSpec, Why You Should, Too

Oh no! We Failed!

Page 28: Puppet Loves RSpec, Why You Should, Too

% cat manifests/example1.pp

class puppet-camp-austin::example1 {

package { 'git':

ensure => installed

}

}

Page 29: Puppet Loves RSpec, Why You Should, Too

% rake spec

.

Finished in 0.11266 seconds

1 example, 0 failures

Page 30: Puppet Loves RSpec, Why You Should, Too

Now we are cooking with peanut oil!

Page 31: Puppet Loves RSpec, Why You Should, Too

Happy Happy Happy

Page 32: Puppet Loves RSpec, Why You Should, Too

Deep Thoughts

Page 33: Puppet Loves RSpec, Why You Should, Too

“It is what you don’t expect that most

needs looking for.”-- Neal Stephenson, Anathem

Page 34: Puppet Loves RSpec, Why You Should, Too

What should we test?

• Non-obvious things

• Complex things

• Bugs

Page 35: Puppet Loves RSpec, Why You Should, Too

Time for something not obvious

Page 36: Puppet Loves RSpec, Why You Should, Too

Let us say we decided we wanted to let a puppet

forge module install git for us. Oh look, there is

a module called puppetlabs/git!

Page 37: Puppet Loves RSpec, Why You Should, Too

Let us add the module to .fixtures.yml

% cat .fixtures.yml

fixtures:

repositories:

git: git://github.com/puppetlabs/puppetlabs-git.git

symlinks:

puppet-camp-austin: "#{source_dir}"

Page 38: Puppet Loves RSpec, Why You Should, Too

Add the git class

% cat manifests/example2.pp

class puppet-camp-austin::example2 {

include 'git'}

Page 39: Puppet Loves RSpec, Why You Should, Too

Add a test% cat spec/classes/puppet-camp-austin/example2_spec.rb

require 'spec_helper'

describe 'puppet-camp-austin::example2' do

it 'should include git' do

should contain_package('git')

end

end

Page 40: Puppet Loves RSpec, Why You Should, Too

Run the Tests (I am sure they will pass)

% rake spec

.F

Failures:

1) puppet-camp-austin::example2 should include git

Failure/Error: should contain_package('git')

expected that the catalogue would contain Package[git]

# ./spec/classes/puppet-camp-austin/example2_spec.rb:5:in `block (2 levels) in <top (required)>'

Page 41: Puppet Loves RSpec, Why You Should, Too

What?

The git module doesn’t install git? Is this crazy??!

Page 42: Puppet Loves RSpec, Why You Should, Too

OK, let us go look

class git {

  package { 'git-core':    ensure => installed,

  }}

Page 43: Puppet Loves RSpec, Why You Should, Too

Should you be testing 3rd party modules

this way?Probably not.

It depends.

Page 44: Puppet Loves RSpec, Why You Should, Too

Has it burned you in the past?It did me :(

Page 45: Puppet Loves RSpec, Why You Should, Too

Let us try this again

Page 46: Puppet Loves RSpec, Why You Should, Too

We write a testdescribe 'puppet-camp-austin::example3' do describe 'operating system is Debian' do let(:facts) { {:operatingsystem => 'Debian'} }

it 'should include git' do should contain_package('git') end end

describe 'operating system is MINIX' do let(:facts) { {:operatingsystem => 'MINIX'} }

it 'should notify a warning' do should contain_notify('git cannot be install for this package') end endend

Page 47: Puppet Loves RSpec, Why You Should, Too

Maybe we go to lunch, forget about our test, come back, write some code...

Page 48: Puppet Loves RSpec, Why You Should, Too

This is the code we write

class puppet-camp-austin::example3 {

Package { ensure => "installed" }

case $operatingsystem {

'RedHat', 'CentOS': { package {'git': } }

/^(Debian|Ubuntu)$/:{ package {'git': } }

default: { package {'git-core': } }

}

}

Page 49: Puppet Loves RSpec, Why You Should, Too

Test it!

rspec ./spec/classes/puppet-camp-austin/example3_spec.rb:15 # puppet-camp-austin::example3 operating system is MINIX should notify a warning

Page 50: Puppet Loves RSpec, Why You Should, Too

D’oh!

Page 51: Puppet Loves RSpec, Why You Should, Too

Let us add that notify

class puppet-camp-austin::example3 {

Package { ensure => "installed" }

case $operatingsystem {

'RedHat', 'CentOS': { package {'git': } }

/^(Debian|Ubuntu)$/:{ package {'git': } }

default: { notify {'git cannot be install for this package': } }

}

}

Page 52: Puppet Loves RSpec, Why You Should, Too

It works!

% rake spec

..

Finished in 0.13768 seconds2 examples, 0 failures

Page 53: Puppet Loves RSpec, Why You Should, Too

In Retrospect

Page 54: Puppet Loves RSpec, Why You Should, Too

Puppet + RSpec Rocks

Page 55: Puppet Loves RSpec, Why You Should, Too

Why are you not doing it!!?

Page 56: Puppet Loves RSpec, Why You Should, Too

You should test interesting things

Page 57: Puppet Loves RSpec, Why You Should, Too

Don’t be scared to break it!

Page 58: Puppet Loves RSpec, Why You Should, Too

My contrived examples are at https://

github.com/shr3kst3r/puppet-camp-austin

Page 59: Puppet Loves RSpec, Why You Should, Too

Questions and maybe some answers?