Testing Chef roles and environments

Dan Stark picture Dan Stark · Apr 23, 2015 · Viewed 7.1k times · Source

I'm new to Chef and have been using Test Kitchen to test the validity of my cookbooks, which works great. Now I'm trying to ensure that environment-specific attributes are correct on production nodes prior to running Chef initially. These would be defined in a role.

For example, I may have recipes that converge using a Vagrant box with dev settings, which validates the cookbook. I want to be able to test that a production node's role. I think I want these tests as the source of truth describing my environment. Looking at Test Kitchen's documentation, this seems beyond its scope.

Is my assumption correct? Is there a better approach to test a cookbook before the first time Chef is run on a production node to ensure it has the correct settings?

Answer

Mark O'Connor picture Mark O'Connor · Apr 25, 2015

I pleasantly discovered that chef_zero uses the "test/integration" directory as it's chef repository.

Just create your roles under

  • test/integration/roles

Example

Standard Chef cookbook layout.

├── attributes
│   └── default.rb
├── Berksfile
├── Berksfile.lock
├── chefignore
├── .kitchen.yml
├── metadata.rb
├── README.md
├── recipes
│   └── default.rb
└── test
    └── integration
        ├── default
        │   └── serverspec
        │       ├── default_spec.rb
        │       └── spec_helper.rb
        └── roles
            └── demo.json

.kitchen.yml

---
driver:
  name: vagrant

provisioner:
  name: chef_zero

platforms:
  - name: ubuntu-14.04

suites:
  - name: default
    run_list:
      - role[demo]
    attributes:

Notes:

  • Provisioner is chef_zero
  • The runlist is configured to use a role

recipes/default.rb

file "/opt/helloworld.txt" do
  content "#{node['demo']['greeting']}"
end

attributes/default.rb

default['demo']['greeting'] = "hello world"

Notes:

  • Cookbook won't compile without a default

test/integration/default/serverspec/default_spec.rb

require 'spec_helper'

describe file('/opt/helloworld.txt') do

  it { should be_file }
  its(:content) { should match /this came from my role/ }

end

Notes:

  • Integration test is looking for the content that is set by the role attribute

test/integration/roles/demo.json

{
  "name": "demo",
  "default_attributes": {
    "demo": {
      "greeting": "this came from my role"
    }
  },
  "run_list": [
    "recipe[demo]"
  ]
}