Test Kitchen For Beginners

by Maksym Zinkevych

Greetings, readers! Today I would like to tell you about tools that facilitate cookbook testing. What seems to be the problem? As the infrastructure scale grows, it becomes increasingly harder to keep track of the dependencies and the aftermath of making changes in the cookbooks. That's when the issue with testing cookbooks arises. You can solve this issue with the help of such tools as Foodcritics, Chefspec, Minitest, Test Kitchen, etc. In this article, I'd like to share my experience of learning test kitchen in the proverbial "21 days". I tried to make this post as simple and comprehensible as possible to introduce Test Kitchen to you.

To get started, you need the following software: Vagrant, VirualBox and, of course, Test Kitchen itself.

As for an operating system, I chose MS Windows 7 x64. Why Windows? Let's just say it was part of the assignment.

This whole process took me three hours. So, if you want to go through all the steps single-handedly, it would make sense to reserve half of a day for this task.

Let's begin:

Step 1. Preparing the environment

VirtualBox & Vagrant

To begin with, you need to install VirtualBox and Vagrant.

After installing Vagrant, you need to restart your machine.


After the reboot, check the operability of Vagrant:

  • 1. Create a folder for your test instance:

    mkdir C:\vagrant && cd C:\vagrant
  • 2. Add a precise32 box:

    C:\vagrant>vagrant box add precise32 http://files.vagrantup.com/precise32.box
    Downloading box from URL: http://files.vagrantup.com/precise32.box
    Extracting box...ate: 3089k/s, Estimated time remaining: --:--:--)
    Successfully added box 'precise32' with provider 'virtualbox'!

  • 3. Initialize configuration. This command will create a Vagrantfile configuration file:

    C:\vagrant>vagrant init
  • 4. Edit the Vagrantfile file:

    -- config.vm.box = "base"
    ++ config.vm.box = "precise32"
  • 5. Now you're ready to launch your instance:

    C:\vagrant>vagrant up
  • 6. After the command execution is completed, connect to localhost:2222 via SSH:

    login as: vagrant
    vagrant@localhost's password: vagrant
    Welcome to Ubuntu 12.04 LTS (GNU/Linux 3.2.0-23-generic-pae i686)
    * Documentation: https://help.ubuntu.com/
    Welcome to your Vagrant-built virtual machine.

    If you did everything right, the connection will succeed.

Ruby & Ruby DevKit

Now you need to install ruby.

If you have an installed Chef-client, you should uninstall it, because you will use the one installed via Gem.

During installation, select the "Add Ruby executables to your PATH" option so that you can freely launch Ruby from the command prompt.

Next, you need to install DevKit, as it contains the necessary software package (the compiler, the libraries - in short, a DevKit). I would like to draw your attention to the fact that it would be best to install everything (both Ruby and DevKit) into the default catalog, otherwise problems may arise.

For the installation, take the following steps:

  • 1. Create a folder:

    mkdir C:\devkit && cd C:\devkit
  • 2. Download and save the archive into this folder, and un-zip the archive into the current directory:

    DevKit-tdm
    cd C:\devkit
  • 3. Begin installation:

    C:\devkit>ruby dk.rb init
    [INFO] found RubyInstaller v1.9.3 at C:/Ruby193
    Initialization complete! Please review and modify the auto-generated 'config.yml' file to ensure it contains the root directories to all of the installed Rubies you want enhanced by the DevKit.

    We can see that the version and the path to the installed ruby was detected

  • 4. Install:

    C:\DevKit>ruby dk.rb install
    [INFO] Updating convenience notice gem override for 'C:/Ruby193'
    [INFO] Installing 'C:/Ruby193/lib/ruby/site_ruby/devkit.rb'

    After ruby dk.rb install is executed, the path to DevKit must be added to PATH, unfortunatelly, this hasn't happened:

    C:\DevKit>echo %PATH%
    C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Ruby193\bin

    It means, we need to add the DevKit path manually. There are several ways to do it:

    • 1. Run the following command line command:

      setx PATH "C:\DevKit\mingw\bin\;C:\DevKit\bin\"

      This will add the PATH variable to the list of the users variables.

    • 2. Run cmd as Administrator and execute:

      setx PATH "%PATH%;C:\DevKit\mingw\bin\;C:\DevKit\bin\" /M

      In this case, the path to DevKit is added to the end of the PATH system variable.

    • 3. This way is recommended if you are not certain about the first two:

      Control Panel > System Properties > System Properties > Environment variables

      Edit the PATH variable and add C:\DevKit\bin\ ? C:\DevKit\mingw\bin\

      Open a new cmd and check:

      C:\Users\cc>echo %PATH%
      C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Ruby193\bin;C:\DevKit\mingw\bin\;C:\DevKit\bin\

Step 2. Installing Test Kitchen

Finally, you can install Test Kitchen:

  • 1. Create a folder for working with Test Kitchen:

    C:\>mkdir C:\kitchen && cd C:\kitchen
  • 2. Install Bundler:

    C:\DevKit>gem install bundler
    Fetching: bundler-1.5.2.gem (100%)
    Successfully installed bundler-1.5.2
    1 gem installed
    Installing ri documentation for bundler-1.5.2...
    Installing RDoc documentation for bundler-1.5.2...
  • 3. In a text editor, create a file named Gemfile with the following content:

    source 'https://rubygems.org'

    gem 'berkshelf', '~> 2.0.0' # use for manage cookbook dependencies
    gem 'chef', '~> 11.6.0'
    gem 'chef-zero'
    gem 'json', '1.7.7' # needed for conflict resolution
    gem 'kitchen-vagrant'
    gem 'test-kitchen'
  • 4. Begin installation:

    C:\kitchen>bundle install
    Fetching gem metadata from https://rubygems.org/.......
    Fetching additional metadata from https://rubygems.org/..
    Resolving dependencies...
    Installing i18n (0.6.9)
    Installing multi_json (1.8.4)
    Installing activesupport (3.2.16)
    ?
    Installing test-kitchen (1.0.0)
    Installing kitchen-vagrant (0.11.3)
    Using bundler (1.5.2)
    Your bundle is complete!
    Use `bundle show [gemname]` to see where a bundled gem is installed.
  • 5. Download and un-zip the cookbook into the current directory as a test (I used sendmail as an example):

    mkdir C:\kitchen\cookbooks && cd C:\kitchen\cookbooks && knife cookbook site download sendmail
  • 6. Initialize Test Kitchen configuration:

    C:\kitchen>kitchen init
    create .kitchen.yml
    create test/integration/default
    create .gitignore
    append .gitignore
    append .gitignore
  • 8. To launch one instance, make .kitchen.yml look like the following:

    ---
    driver_plugin: vagrant
    driver_config:
    require_chef_omnibus: true
    platforms:
    - name: ubuntu-12.04
    driver_config:
    box: opscode-ubuntu-12.04
    box_url: https://opscode-vm-bento.s3.amazonaws.com/vagrant/opscode_ubuntu-12.04_provisionerless.box

    suites:
    - name: default
    run_list: ["recipe[sendmail]"]
    attributes: {}
  • 9. Run the test:

    C:\kitchen>kitchen test
    .....................
    ←[0m[2014-01-11T10:17:15+00:00] INFO: *** Chef 11.8.2 ***←[36m
    ←[0m[2014-01-11T10:17:15+00:00] INFO: Chef-client pid: 1169←[36m
    ←[0m[2014-01-11T10:17:16+00:00] INFO: Setting the run_list to ["recipe[sendmail]"] from JSON←[36m
    ←[0m[2014-01-11T10:17:16+00:00] INFO: Run List is [recipe[sendmail]]←[36m
    ←[0m[2014-01-11T10:17:16+00:00] INFO: Run List expands to [sendmail]←[36m
    ←[0m[2014-01-11T10:17:16+00:00] INFO: Starting Chef Run for default-ubuntu-1204←[36m
    ←[0m[2014-01-11T10:17:16+00:00] INFO: Running start handlers←[36m
    ←[0m[2014-01-11T10:17:16+00:00] INFO: Start handlers complete.←[36m
    ←[0mCompiling Cookbooks...←[0m←[36m
    ←[0mConverging 2 resources←[0m←[36m
    ←[0mRecipe: sendmail::default←[0m←[36m
    ←[0m * package[sendmail] action install←[0m[2014-01-11T10:17:16+00:00] INFO: Processing package[sendmail] action install(sendmail::default line 1)←[36m
    ←[0m←[32m←[36m
    ←[0m - install version 8.14.4-2ubuntu2 of package sendmail←[0m←[36m
    ←[0m←[0m←[36m
    ←[0m * service[sendmail] action enable←[0m[2014-01-11T10:17:27+00:00] INFO: Processing service[sendmail] action enable (sendmail::default line 6)←[36m
    ←[0m[2014-01-11T10:17:27+00:00] INFO: service[sendmail] enabled←[36m
    ←[0m←[32m←[36m
    ←[0m - enable service service[sendmail]←[0m←[36m
    ←[0m←[0m←[36m
    ←[0m * service[sendmail] action start←[0m[2014-01-11T10:17:27+00:00] INFO: Processing service[sendmail] action start (sendmail::default line 6)←[36m
    ←[0m (up to date)←[0m←[36m
    ←[0m[2014-01-11T10:17:27+00:00] INFO: Chef Run complete in 11.695990777 seconds←[36m
    ←[0m[2014-01-11T10:17:27+00:00] INFO: Running report handlers←[36m
    ←[0m[2014-01-11T10:17:27+00:00] INFO: Report handlers complete←[36m
    ←[0mChef Client finished, 2 resources updated←[0m←[36m
    ←[0m←[36m Finished converging (0m29.54s).
    ←[0m←[36m-----> Setting up
    ←[0m←[36m Finished setting up (0m0.00s).
    ←[0m←[36m-----> Verifying
    ←[0m←[36m Finished verifying (0m0.00s).
    ←[0m←[36m-----> Destroying
    ←[0m←[36m [kitchen::driver::vagrant command] BEGIN (vagrant destroy -f)
    ←[0m←[36m [default] Forcing shutdown of VM...
    ←[0m←[36m [default] Destroying VM and associated drives...
    ←[0m←[36m [kitchen::driver::vagrant command] END (0m0.00s)
    ←[0m←[36m Vagrant instance destroyed.
    ←[0m←[36m Finished destroying (0m4.85s).
    ←[0m←[36m Finished testing (1m16.33s).
    ←[0m-----> Kitchen is finished. (1m16.69s)

Step 3. Berkshelf

We need Berkshelf to handle issues with cookbook dependencies.

Since you have already installed it in the previous step, proceed to configuration:

  • 1. Install the plug-in for Vagrant:

    C:\kitchen>vagrant plugin install vagrant-berkshelf
    Installing the 'vagrant-berkshelf' plugin. This can take a few minutes...
    Installed the plugin 'vagrant-berkshelf (1.3.7)'!
  • 2. Create the chef-cook project:

    C:\kitchen>berks init chef-cook
    create chef-cook/Berksfile
    create chef-cook/Thorfile
    create chef-cook/.gitignore
    run git init from "./chef-cook"
    C:/Ruby193/bin/berks: No such file or directory - git init
    create chef-cook/Gemfile
    create .kitchen.yml
    append Thorfile
    create test/integration/default
    append Gemfile
    append Gemfile
    You must run `bundle install' to fetch any new gems.
    create chef-cook/Vagrantfile
    Successfully initialized
  • 3. Begin installation (most likely, the gem data has been already installed):

    cd C:\kitchen\chef-cook && bundle install

  • 4. Create the cookbook:

    mkdir C:\kitchen\chef-cook\cookbooks && cd C:\kitchen\chef-cook\cookbooks && berks cookbook mytest
  • 5. Add your recipe to runlist .kitchen.yml:

    C:\kitchen\chef-cook\.kitchen.yml
    ---
    suites:
    - name: default
    run_list: ["recipe[mytest]"]
    attributes: {}
  • 6. Run the test:

    C:\kitchen\chef-cook>kitchen test

    And get an error:

    ERROR: Cookbook mytest not found. If you're loading mytest from another cookbook, make sure you configure the dependency in your metadata

    To fix it, add the following line to Berksfile:

    cookbook 'mytest', :path => 'cookbooks/mytest'

    The record indicates where Berkshelf can find the given cookbook

Then, let's make it more complicated by adding a dependency from a cookbook that you don't have locally, for example, sendmail.

  • 1. Add the following line to the C:\kitchen\chef-cook\mytest\default.rb recipe:

    include_recipe 'sendmail'
  • 2. Add a dependency to C:\kitchen\chef-cook\mytest\metadata.rb:

    depends 'sendmail'
  • 3. And, finally, edit Berksfile to make it look like the following:

    site :opscode
    cookbook 'sendmail'
    cookbook 'mytest', :path => 'cookbooks/mytest'

    We added the "'sendmail' cookbook". The record means that, if necessary, Berkshelf can download thesendmail cookbook from repository

  • 4. Check the operability of our cookbook:

    C:\kitchen\chef-cook>kitchen conerge
    ....
    ←[0m←[36m Resolving cookbook dependencies with Berkshelf...
    ←[0mInstalling sendmail (0.1.0) from site: 'http://cookbooks.opscode.com/api/v1/cookbooks'
    Using mytest (0.1.0) at './cookbooks/mytest'
    ....
    ←[0m * package[sendmail] action install←[0m[2014-01-15T08:00:44+00:00] INFO: Processing package[sendmail] action install (sendmail::default line 1)←[
    ...
    ←[0mChef Client finished, 2 resources updated←[0m←[36m
    ←[0m←[36m Finished converging (0m18.25s).
    ←[0m-----> Kitchen is finished. (0m18.68s)

From the log above, we can see that the sendmail cookbook was downloaded successfully, and the sendmail package was installed.

I'd like to repeat that this article targets complete newbies in this area, to show the very basics of the available tools. However, with the help of these tools, you will be able to manage a large number of cookbooks. In the future, I'll possibly write about Berkshelf with more details.

Useful links:

Chef HomePage

Test Kitchen HomePage

Berkshelf HomePage

Opscode community cookbooks

Here Ievgen Kabanets writes about Chef in greater details.