Skip to content

Writing Specs

Mike Lapshin edited this page Nov 8, 2013 · 7 revisions

In this topic we will explain different aspects of writing Foodtaster specs.

What is a spec

Spec (spec file) is a program written in Ruby language using RSpec library. In order to write specs you should have basic Ruby and RSpec knowledge. Spec files are usually located inside spec folder in root of your repository and have filename pattern *_spec.rb (end with "_spec" and have ".rb" extension).

If you're not familiar with RSpec, lookup some RSpec tutorials.

Structure of a spec

Each spec file should begin with requiring a spec_helper file following one describe block:

require 'spec_helper'

describe "my cookbook" do
  # ...
end

Running Chef

Foodtaster is a library for testing Chef cookbooks. So before performing any tests we need to start Chef on our VMs. To tell Foodtaster to run Chef, use run_chef_on method:

describe "my cookbook" do
  run_chef_on :vm0 do |c|
    c.json = { some_attribute: 42 }
    c.add_recipe 'my_cookbook::server'
  end

  run_chef_on :vm1 do |c|
    c.add_recipe 'my_cookbook::client'
  end
end

In this example, :vm0 is converged with my_cookbook::server recipe and :vm1 with my_cookbook::client.

NB Before Chef Run Foodtaster rollbacks VM into initial (so-called "clean") state. You can (and should) use one VM for different specs.

VM objects

When you declared a Chef Run on some VM with run_chef_on method, you can access this VM in any place of your spec:

describe "my cookbook" do
  run_chef_on :vm0 do |c|
    c.add_recipe 'my_cookbook::default'
  end

  before :all { vm0.execute("rm -rf /tmp/*") }

  it "should have nobody user" do
    vm0.should have_user("nobody")
  end
end

Read RDoc documentation for list of available methods of VM objects.

Access VM without running Chef

Sometimes you need VM for your specs, but don't need to run Chef on it. In such case, use require_vm method:

describe "my cookbook" do
  run_chef_on :vm0 do |c|
    c.add_recipe 'my_cookbook::default'
  end

  require_vm :vm1

  example do
    vm1.execute("ping #{vm0.ip}").should be_successful
  end
end

NB require_vm don't do rollback. If you need a clean VM, rollback it explicitly with Vm#rollback method.