Test Driven Development with Puppet
Upcoming SlideShare
Loading in...5
×
 

Test Driven Development with Puppet

on

  • 953 views

Presented at Puppet Camp London 2014 "Test Driven Development with Puppet" by Gareth Rushgrove, Government Digital Service

Presented at Puppet Camp London 2014 "Test Driven Development with Puppet" by Gareth Rushgrove, Government Digital Service

Statistics

Views

Total Views
953
Views on SlideShare
911
Embed Views
42

Actions

Likes
7
Downloads
30
Comments
0

2 Embeds 42

http://puppetlabs.com 26
https://puppetlabs.com 16

Accessibility

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

Test Driven Development with Puppet Test Driven Development with Puppet Presentation Transcript

  • Test Driven Development! for Puppet! Puppet needs software development Gareth Rushgrove
  • Who (Who is this person?)
  • @garethr
  • UK Government Digital Service
  • The problem (This isn’t a rant, but…)
  • Who here is a software developer? Gareth Rushgrove
  • If you’re writing Puppet code you’re a software developer Gareth Rushgrove
  • As a software developer it’s your job to learn software engineering practices Gareth Rushgrove
  • What is Test Driven Development (And why should you care)
  • A common practice in software engineering Gareth Rushgrove
  • Not just testing Gareth Rushgrove
  • Encourages simple designs and inspires confidence Gareth Rushgrove
  • First write an (initially failing) automated test case Gareth Rushgrove
  • Then produce the minimum amount of code to pass that test Gareth Rushgrove
  • And finally refactor the new code to acceptable standards Gareth Rushgrove
  • Test Driven Design Gareth Rushgrove
  • Gareth Rushgrove
  • Unit testing with RSpec and Guard (Not puppet specific)
  • A unit is the smallest testable part of an application Gareth Rushgrove
  • Testing puppet requires a little Ruby knowledge so we’ll use Ruby examples Gareth Rushgrove
  • class Person def say(word) end end Gareth Rushgrove
  • First lets write a test. For this we use the RSpec testing framework Gareth Rushgrove
  • require 'person' ! describe Person, "#say" do it "should say something" do ! end end Gareth Rushgrove
  • require 'person' ! describe Person, "#say" do it "should say something" do bob = Person.new bob.say("hello").should eq("hello everyone") end end Gareth Rushgrove
  • Now lets run our test. It should fail Gareth Rushgrove
  • rspec Gareth Rushgrove
  • Failures: 1) Person#say should say something Failure/Error: bob.say("hello").should eq("hello everyone") expected: "hello everyone" got: nil Finished in 0.00171 seconds 1 example, 1 failure Gareth Rushgrove
  • Now lets write the implementation Gareth Rushgrove
  • class Person def say(word) word + " everyone" end end Gareth Rushgrove
  • And run our test again Gareth Rushgrove
  • Person#say should say something ! Finished in 0.00199 seconds 1 example, 0 failures Gareth Rushgrove
  • Why not have tests automatically run whenever you change the code? Gareth Rushgrove
  • That’s what Guard does Gareth Rushgrove
  • guard :rspec, cmd: 'bundle exec rspec' do watch(%r{^spec/.+_spec.rb$}) watch(%r{^lib/.+.rb$}) { 'spec' } end Gareth Rushgrove
  • guard Gareth Rushgrove
  • Lets see a quick demo Gareth Rushgrove
  • Why test puppet code at all (Testing declarative languages)
  • Modules increasingly contain logic Gareth Rushgrove
  • Modules increasingly take arguments Gareth Rushgrove
  • Modules increasingly have interfaces with other modules Gareth Rushgrove
  • Modules increasingly used in many operating system and version combinations Gareth Rushgrove
  • Modules increasingly used in many Ruby and Puppet version combinations Gareth Rushgrove
  • Unit testing puppet with rspec-puppet (Finally some puppet code)
  • Unit testing for Puppet
  • A very simple puppet class Gareth Rushgrove
  • class sample { } Gareth Rushgrove
  • First write the test Gareth Rushgrove
  • require 'spec_helper' ! describe "sample" do it { should create_file('/tmp/sample')} end Gareth Rushgrove
  • Then run the test Gareth Rushgrove
  • sample should contain File[/tmp/sample] (FAILED - 1) ! Finished in 0.4584 seconds 1 example, 1 failure Gareth Rushgrove
  • And then write the (puppet) code to make the test pass Gareth Rushgrove
  • class sample { file { "/tmp/sample": ensure => present, } } Gareth Rushgrove
  • sample should contain File[/tmp/sample] ! Finished in 0.3881 seconds 1 example, 0 failures Gareth Rushgrove
  • Lets run the tests automatically whenever you change anything Gareth Rushgrove
  • guard :rspec, cmd: 'bundle exec rspec' do watch(%r{^spec/.+_spec.rb$}) watch(%r{^manifests/.+.pp$}) { 'spec' } end Gareth Rushgrove
  • Lets see a quick demo of that too Gareth Rushgrove
  • You can also test hosts, defines, facts, functions, hieradata Gareth Rushgrove
  • Syntax checking, linting, oh my (Creating a build process)
  • puppet-lint Gareth Rushgrove
  • Puppet! style guide
  • Available! as a gem
  • puppet-lint --with-filename /etc/puppet/modules foo/manifests/bar.pp: trailing whitespace found on line 1 apache/manifests/server.pp: variable not enclosed in {} on line 56 Gareth Rushgrove
  • puppet-syntax Gareth Rushgrove
  • Validate Puppet and ERB syntax
  • require 'puppet-syntax/tasks/puppet-syntax' Gareth Rushgrove
  • rake syntax ---> syntax:manifests ---> syntax:templates ---> syntax:hiera:yaml Gareth Rushgrove
  • What is Rake and why do we use it (Still no puppet)
  • Rake is a Ruby! build tool Gareth Rushgrove
  • It’s like Make but in Ruby Gareth Rushgrove
  • It’s very easy to distribute Rake tasks as Ruby gems Gareth Rushgrove
  • rake Gareth Rushgrove
  • rake <command> Gareth Rushgrove
  • rake -T Gareth Rushgrove
  • Lets make a command to run lint, syntax and spec Gareth Rushgrove
  • task :test => [ :syntax, :lint, :spec, ] Gareth Rushgrove
  • rake test Gareth Rushgrove
  • Acceptance testing with beaker (Living on the edge)
  • Acceptance test against real systems Gareth Rushgrove
  • Test what actually happens, not what is meant to happen Gareth Rushgrove
  • Build by Gareth Rushgrove
  • Very new Gareth Rushgrove
  • Test against different operating systems Gareth Rushgrove
  • HOSTS: ubuntu-server-12042-x64: roles: - master platform: ubuntu-server-12.04-amd64 box: ubuntu-server-12042-x64-vbox4210-nocm box_url: http://puppet-vagrant-boxes.puppetlabs.com/u hypervisor: vagrant ! CONFIG: log_level: verbose type: foss Gareth Rushgrove
  • HOSTS: centos-64-x64: roles: - master platform: el-6-x86_64 box : centos-64-x64-vbox4210-nocm box_url : http://puppet-vagrant-boxes.puppetlabs.com/ hypervisor : vagrant ! CONFIG: log_level: verbose type: foss Gareth Rushgrove
  • Supports multiple hypervisors Gareth Rushgrove
  • Vagrant hypervisor
  • VSphere hypervisor
  • Helpers to install puppet and modules Gareth Rushgrove
  • install_puppet Gareth Rushgrove
  • puppet('module', 'install', 'puppetlabs-stdlib') Gareth Rushgrove
  • Test that Puppet runs without errors Gareth Rushgrove
  • context 'default parameters' do it 'should work with no errors' do pp = “class { 'sample': }” ! expect(apply_manifest(pp).exit_code).to_not eq(1) end end Gareth Rushgrove
  • Test runs are idempotent Gareth Rushgrove
  • context 'default parameters' do it 'should work with no errors' do pp = “class { 'sample': }” ! expect(apply_manifest(pp).exit_code).to_not eq(1) expect(apply_manifest(pp).exit_code).to eq(0) end end Gareth Rushgrove
  • Test that the module installs packages, run services, etc. Gareth Rushgrove
  • Gareth Rushgrove
  • describe package('nginx') do it { should be_installed } end ! describe service('nginx') do it { should be_enabled } it { should be_running } end ! describe port(80) do it { should be_listening} end Gareth Rushgrove
  • Other useful tools (and what we’re still missing)
  • Fixtures, matchers
  • Gareth Rushgrove
  • Nice continuous integration
  • Test pull request branches too
  • --- language: ruby bundler_args: --without development before_install: rm Gemfile.lock || true rvm: - 1.8.7 - 1.9.3 - 2.0.0 script: bundle exec rake test env: - PUPPET_VERSION="~> 2.7.0" - PUPPET_VERSION="~> 3.1.0" - PUPPET_VERSION="~> 3.2.0" - PUPPET_VERSION="~> 3.3.0" - PUPPET_VERSION="~> 3.4.0" Gareth Rushgrove
  • Official! ruby support
  • matrix: exclude: - rvm: 2.0.0 env: PUPPET_VERSION="~> 2.7.0" - rvm: 2.0.0 env: PUPPET_VERSION="~> 3.1.0" - rvm: 1.9.3 env: PUPPET_VERSION="~> 2.7.0" Gareth Rushgrove
  • Experimental code coverage support in rspec-puppet master Gareth Rushgrove
  • at_exit { RSpec::Puppet::Coverage.report! } Gareth Rushgrove
  • Total resources: 24 Touched resources: 8 Resource coverage: 33.33% ! Untouched resources: Class[Nginx] File[preferences.d] Anchor[apt::update] Class[Apt::Params] File[sources.list] Exec[Required packages: 'debian-keyring debian-arch Anchor[apt::source::nginx] Class[Apt::Update] File[configure-apt-proxy] Apt::Key[Add key: 7BD9BF62 from Apt::Source nginx] Anchor[apt::key/Add key: 7BD9BF62 from Apt::Source Anchor[apt::key 7BD9BF62 present] File[nginx.list]Gareth Rushgrove
  • A puppet module skeleton with everything working out of the box Gareth Rushgrove
  • puppet module skeleton
  • puppet module generate sample Gareth Rushgrove
  • A pretty complete example (The Docker module)
  • Gareth Rushgrove
  • Gareth Rushgrove Featured on the Forge
  • Gareth Rushgrove 50 pull request and counting
  • Gareth Rushgrove Contributing guidelines
  • Gareth Rushgrove
  • Gareth Rushgrove Currently has 121 tests
  • 6 classes, 2 defines, 413 lines of puppet code, 387 lines of test code Gareth Rushgrove
  • Take away (If all you remember is…)
  • Infrastructure as code Gareth Rushgrove
  • The first test is the hardest Gareth Rushgrove
  • Politely demand tests for contributions Gareth Rushgrove
  • Test the interface not the implementation Gareth Rushgrove
  • Questions? (And thanks for listening)