Contributors30 minutes | Test Kitchen enables you to run your cookbooks in a temporary environment that resembles production. With Test Kitchen, you confirm that things are working before you deploy your code to a test, preproduction, or production environment. Many users incorporate this kind of local development as part of their overall Chef workflow. |
In this part, you'll run through the Test Kitchen workflow to get the hang of things. You'll apply the web server cookbook you wrote in the _Manage a node with Chef server_ module on a local test instance.

 | In this step, Test Kitchen creates an instance of your virtual environment, for example, a CentOS virtual machine. |
 | In this step, Test Kitchen applies your cookbook to the virtual environment. |
 | In this step, Test Kitchen creates an SSH session into your virtual environment. |
 | In this step, you manually verify that your virtual environment is configured as you expect. |
 | In this step, Test Kitchen shuts down and destroys your virtual environment. |
In this module, you perform the verify step manually. In practice, you typically write tests that automatically verify whether your configuration works as you expect. You'll learn about local testing in a future module.
Here, you'll get a copy of the web server cookbook that you created in the earlier modules. Then you'll apply that cookbook on a CentOS virtual machine. Then you'll verify that everything's working. Finally, you'll destroy the instance.
1. Get the learn_chef_httpd cookbook from GitHub
In the Learn the Chef basics and Manage a node with Chef server modules, you wrote a cookbook named learn_chef_httpd that configures Apache web server. You'll run that cookbook on your test instance.
If you still have the learn_chef_httpd cookbook on your system, you're all set up. Otherwise, follow these steps to get it.
Start by creating the ~/learn-chef/cookbooks directory if it does not already exist.
Terminal: ~
$ | mkdir ~/learn-chef/cookbooks
|
Now cd there.
Terminal: ~
$ | cd ~/learn-chef/cookbooks
|
Next, clone the learn_chef_httpd cookbook from GitHub.
Terminal: ~/learn-chef/cookbooks
$ | git clone https://github.com/learn-chef/learn_chef_httpd.gitCloning into 'learn_chef_httpd'...
|
Now cd there.
Terminal: ~/learn-chef/cookbooks
$ | cd ~/learn-chef/cookbooks/learn_chef_httpd
|
The contents of ~/learn-chef/cookbooks/learn_chef_httpd is the same as what you built in the Manage a node with Chef server module. You can examine this directory to familiarize yourself with its contents.
| Remember that Chef Supermarket is also a place for the community to share cookbooks. You'll learn more about community cookbooks in later modules. |
2. Examine the Test Kitchen configuration file
When you use the chef generate cookbook command to create a cookbook, Chef creates a file named .kitchen.yml in the root directory of your cookbook. .kitchen.yml defines what's needed to run Test Kitchen, including which virtualization provider to use, how to run Chef, and what platforms to run your code on.
Here's what your .kitchen.yml file looks like.
Editor: ~/learn-chef/cookbooks/learn_chef_httpd/.kitchen.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| ---
driver:
name: vagrant
provisioner:
name: chef_zero
verifier:
name: inspec
platforms:
- name: centos-7
suites:
- name: default
run_list:
- recipe[learn_chef_httpd::default]
attributes: |
| On Linux and macOS, .kitchen.yml is a hidden file. Run ls -a if you want to see it from your terminal window. |
| In the latest releases of Test Kitchen, the .kitchen.yml file is named without the leading dot and will no longer be hidden. For example, kitchen.yml. However, the old format with the leading dot will remain backward compatible. |
Test Kitchen can manage more than one instance at a time to enable you to test your cookbooks on multiple platforms. The default configuration creates both an Ubuntu and a CentOS virtual machine. Since we want only CentOS, the platforms sections contains only centos-7.
Here's how the .kitchen.yml file breaks down.
- driver specifies the software that manages the machine. We're using the Vagrant Test Kitchen driver (list of other popular drivers). The Vagrant driver works with VirtualBox by default.
- provisioner specifies how to run Chef. We use
chef_zero because it enables you to mimic a Chef server environment on your local machine. This allows us to work with node attributes and other Chef server features. - transport specifies how to execute commands remotely on the test instance. WinRM is the default transport on Windows; SSH is the default on all other operating systems.
- verifier specifies which application to use when running automated tests. You'll learn more about automated testing in a future module.
- platforms specifies the target operating systems. We're targeting just one – CentOS 7.
- suites specifies what we want to apply to the virtual environment. You can have more than one suite. We define just one, named
default. This is where we provide the run-list, which defines which recipes to run and in the order to run them. Your run-list contains one recipe – the learn_chef_httpd cookbook's default recipe.
Recall that when Test Kitchen runs, it downloads the base virtual machine image, called a box, if the image does not already exist locally. Test Kitchen can infer the location for a set number of common configurations. For these common configurations, Test Kitchen downloads the Bento box from Vagrant Cloud. Bento is a Chef project that provides Vagrant boxes for many common platforms. In this example, centos-7 is the same as specifying bento/centos-7.
The Chef documentation explains the structure of the .kitchen.yml file in greater detail, and also explains more about the available settings.
3. Create the Test Kitchen instance
Now you'll provision a virtual machine to serve as your test environment. This is the kitchen create step in our workflow.

We often call the set of virtual environments that's created by Test Kitchen simply a kitchen.
From the ~/learn-chef/cookbooks/learn_chef_httpd directory, run kitchen list to see what's in the kitchen.
Terminal: ~/learn-chef/cookbooks/learn_chef_httpd
$ | kitchen listInstance Driver Provisioner Verifier Transport Last Action Last Errordefault-centos-7 Vagrant ChefZero Inspec Ssh <Not Created> <None>
|
Our kitchen includes just one instance – a CentOS 7 virtual machine that's configured to run the default suite. The Last Action column shows that the virtual machine is not yet created.
Create the instance now by running kitchen create.
Terminal: ~/learn-chef/cookbooks/learn_chef_httpd
$ | kitchen create-----> Starting Kitchen (v1.20.0)-----> Creating <default-centos-7>... Bringing machine 'default' up with 'virtualbox' provider... ==> default: Box 'bento/centos-7' could not be found. Attempting to find and install... default: Box Provider: virtualbox default: Box Version: >= 0 ==> default: Loading metadata for box 'bento/centos-7' default: URL: https://vagrantcloud.com/bento/centos-7 ==> default: Adding box 'bento/centos-7' (v201803.24.0) for provider: virtualbox default: Downloading: https://vagrantcloud.com/bento/boxes/centos-7/versions/201803.24.0/providers/virtualbox.box ==> default: Importing base box 'bento/centos-7'... ==> default: Checking if box 'bento/centos-7' is up to date... ==> default: Setting the name of the VM: default-centos-7_default_1524855825851_52073 Vagrant is currently configured to create VirtualBox synced folders with the `SharedFoldersEnableSymlinksCreate` option enabled. If the Vagrant guest is not trusted, you may want to disable this option. For more information on this option, please refer to the VirtualBox manual: https://www.virtualbox.org/manual/ch04.html#sharedfolders This option can be disabled globally with an environment variable: VAGRANT_DISABLE_VBOXSYMLINKCREATE=1 or on a per folder basis within the Vagrantfile: config.vm.synced_folder '/host/path', '/guest/path', SharedFoldersEnableSymlinksCreate: false ==> default: Clearing any previously set network interfaces... ==> default: Preparing network interfaces based on configuration... default: Adapter 1: nat ==> default: Forwarding ports... default: 22 (guest) => 2222 (host) (adapter 1) ==> default: Booting VM... ==> default: Waiting for machine to boot. This may take a few minutes... default: SSH address: 127.0.0.1:2222 default: SSH username: vagrant default: SSH auth method: private key default: default: Vagrant insecure key detected. Vagrant will automatically replace default: this with a newly generated keypair for better security. default: default: Inserting generated public key within guest... default: Removing insecure key from the guest if it's present... default: Key inserted! Disconnecting and reconnecting using new SSH key... ==> default: Machine booted and ready! ==> default: Checking for guest additions in VM... ==> default: Setting hostname... ==> default: Mounting shared folders... default: /tmp/omnibus/cache => /root/.kitchen/cache ==> default: Machine not provisioned because `--no-provision` is specified. [SSH] Established Vagrant instance <default-centos-7> created. Finished creating <default-centos-7> (11m46.62s).-----> Kitchen is finished. (11m47.86s)
|
| If you need to destroy your instance before you complete this module, run kitchen destroy. You can later run kitchen create to pick back up where you left off on a fresh instance. |
| If you receive a VERR_PATH_NOT_FOUND error, this might indicate that path name of your VirtualBox VM exceeds the maximum path length of your filesystem. In that case, move your learn-chef directory to a location higher in your directory structure (for example, C: on Windows) and run kitchen create a second time. |
This command will take longer the first time you run it because Vagrant needs to download the base image, or box. After the base box is downloaded, kitchen create will complete much more quickly.
Now run kitchen list again.
Terminal: ~/learn-chef/cookbooks/learn_chef_httpd
$ | kitchen listInstance Driver Provisioner Verifier Transport Last Action Last Errordefault-centos-7 Vagrant ChefZero Inspec Ssh Created <None>
|
The Last Action column now shows that the virtual machine has been created.
4. Apply the learn_chef_httpd cookbook to your Test Kitchen instance
Now run kitchen converge to apply the cookbook to the CentOS virtual machine.

Terminal: ~/learn-chef/cookbooks/learn_chef_httpd
$ | kitchen converge-----> Starting Kitchen (v1.20.0)-----> Converging <default-centos-7>... Preparing files for transfer Preparing dna.json Resolving cookbook dependencies with Berkshelf 6.3.1... Removing non-cookbook files before transfer Preparing validation.pem Preparing client.rb-----> Installing Chef Omnibus (install only if missing) Downloading https://omnitruck.chef.io/install.sh to file /tmp/install.sh Trying wget... Download complete. el 7 x86_64 Getting information for chef stable for el... downloading https://omnitruck.chef.io/stable/chef/metadata?v=&p=el&pv=7&m=x86_64 to file /tmp/install.sh.2603/metadata.txt trying wget... sha1 dedf02c8ac06a6e6927b5fef64c0ff50e4cba154 sha256 14ca797942b9a5b4e9c7b0abdb4dada1c2a2c783e5f264b422f36a8993439d78 url https://packages.chef.io/files/stable/chef/14.0.202/el/7/chef-14.0.202-1.el7.x86_64.rpm version 14.0.202 downloaded metadata file looks valid... downloading https://packages.chef.io/files/stable/chef/14.0.202/el/7/chef-14.0.202-1.el7.x86_64.rpm to file /tmp/omnibus/cache/chef-14.0.202-1.el7.x86_64.rpm trying wget... Comparing checksum with sha256sum... WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING You are installing an omnibus package without a version pin. If you are installing on production servers via an automated process this is DANGEROUS and you will be upgraded without warning on new releases, even to new major releases. Letting the version float is only appropriate in desktop, test, development or CI/CD environments. WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING Installing chef installing with rpm... warning: /tmp/omnibus/cache/chef-14.0.202-1.el7.x86_64.rpm: Header V4 DSA/SHA1 Signature, key ID 83ef826a: NOKEY Updating / installing... Thank you for installing Chef! Transferring files to <default-centos-7> Starting Chef Client, version 14.0.202 Creating a new client identity for default-centos-7 using the validator key. resolving cookbooks for run list: ["learn_chef_httpd::default"] Synchronizing Cookbooks: - learn_chef_httpd (0.1.0) Installing Cookbook Gems: Compiling Cookbooks... Converging 3 resources Recipe: learn_chef_httpd::default * yum_package[httpd] action install - install version 0:2.4.6-67.el7.centos.6.x86_64 of package httpd * service[httpd] action enable - enable service service[httpd] * service[httpd] action start - start service service[httpd] * template[/var/www/html/index.html] action create - create new file /var/www/html/index.html - update content in file /var/www/html/index.html from none to ef4ffd --- /var/www/html/index.html 2018-04-27 19:05:37.425211928 +0000 +++ /var/www/html/.chef-index20180427-2730-ux9n7b.html 2018-04-27 19:05:37.425211928 +0000 @@ -1 +1,6 @@ +<html> + <body> + <h1>hello world</h1> + </body> +</html> - restore selinux security context Running handlers: Running handlers complete Chef Client finished, 4/4 resources updated in 28 seconds Downloading files from <default-centos-7> Finished converging <default-centos-7> (1m10.41s).-----> Kitchen is finished. (1m11.61s)
|
| We use the term converge to describe the process of bringing a system closer to its desired state. When you see the word converge, think test and repair. |
| In practice, if you had more than one platform specified in your .kitchen.yml file, then you should specify the platform/instance you want to test your cookbook on when you run kitchen converge. For example, kitchen converge default-windows-2012r2. Otherwise, Test Kitchen would test your cookbook on all the platforms specified in your .kitchen.yml file. Incidentally, the platform specification is a concatenation of the suites name and the platform name in your .kitchen.yml. Therefore, default-windows-2012r2 is derived from this exerpt from your .kitchen.yml: |
Terminal: Example
| platforms: - name: windows-2012r2 suites: - name: default
|
Test Kitchen runs chef-client on the instance. When the chef-client run completes successfully, Test Kitchen exits with exit code 0. Run the following to check the exit code.
Terminal: ~/learn-chef/cookbooks/learn_chef_httpd
If you receive a result other than 0, fix the errors that were reported. Then run kitchen converge to apply the changes and again check the exit code.
Run kitchen list to see the latest status.
Terminal: ~/learn-chef/cookbooks/learn_chef_httpd
$ | kitchen listInstance Driver Provisioner Verifier Transport Last Action Last Errordefault-centos-7 Vagrant ChefZero Inspec Ssh Converged <None>
|
kitchen converge takes longer the first time you run it on a new instance because Test Kitchen needs to install the Chef tools. Run kitchen converge a second time to see how much faster it is.
Terminal: ~/learn-chef/cookbooks/learn_chef_httpd
$ | kitchen converge-----> Starting Kitchen (v1.20.0)-----> Converging <default-centos-7>... Preparing files for transfer Preparing dna.json Resolving cookbook dependencies with Berkshelf 6.3.1... Removing non-cookbook files before transfer Preparing validation.pem Preparing client.rb-----> Chef Omnibus installation detected (install only if missing) Transferring files to <default-centos-7> Starting Chef Client, version 14.0.202 resolving cookbooks for run list: ["learn_chef_httpd::default"] Synchronizing Cookbooks: - learn_chef_httpd (0.1.0) Installing Cookbook Gems: Compiling Cookbooks... Converging 3 resources Recipe: learn_chef_httpd::default * yum_package[httpd] action install (up to date) * service[httpd] action enable (up to date) * service[httpd] action start (up to date) * template[/var/www/html/index.html] action create (up to date) Running handlers: Running handlers complete Chef Client finished, 0/4 resources updated in 02 seconds Downloading files from <default-centos-7> Finished converging <default-centos-7> (0m3.93s).-----> Kitchen is finished. (0m5.23s)
|
This run was faster not only because the instance already had the Chef tools installed, but also because it was already in the desired state, so Chef had no work to do.
5. Verify that your Test Kitchen instance is configured as expected
The next step in the Test Kitchen workflow is to verify the configuration.

In practice, you typically write automated tests that verify whether your instance is configured as you expect. Having automated tests enables you to quickly verify that your configuration works as you add features to your cookbook. In fact, many Chef users take a test-driven approach, where you write your tests first before you write any Chef code.
You'll learn more about automated testing in a future module. For now, let's verify the configuration manually. Recall that the learn_chef_httpd cookbook configures Apache and sets the home page to display "hello world". An easy way to verify this is to log into your test instance and run curl localhost.
The kitchen login command is the most common way to access your test instance. This command creates an SSH connection into your instance and enables you to explore your test instance and verify its configuration.
Because you only want to run curl localhost, you can run kitchen exec to run a single command.
Run the following command to verify the contents of your web server's home page.
Terminal: ~/learn-chef/cookbooks/learn_chef_httpd
$ | kitchen exec -c 'curl localhost'-----> Execute command on default-centos-7. <html> <body> <h1>hello world</h1> </body> </html>
|
You see that the web page contains "hello world" as expected.
| When you use the Vagrant driver, you can also assign a static IP address to your instance. This enables you to verify the configuration externally, such as from your workstation's web browser. You'll do so in the next module. |
6. Delete the Test Kitchen instance
We're all done with our virtual machine, so now run the kitchen destroy command to delete it.

Terminal: ~/learn-chef/cookbooks/learn_chef_httpd
$ | kitchen destroy-----> Starting Kitchen (v1.20.0)-----> Destroying <default-centos-7>... ==> default: Forcing shutdown of VM... ==> default: Destroying VM and associated drives... Vagrant instance <default-centos-7> destroyed. Finished destroying <default-centos-7> (0m4.05s).-----> Kitchen is finished. (0m5.34s)
|
Run kitchen list and you'll see that the Last Action column shows that the virtual machine no longer exists.
Terminal: ~/learn-chef/cookbooks/learn_chef_httpd
$ | kitchen listInstance Driver Provisioner Verifier Transport Last Action Last Errordefault-centos-7 Vagrant ChefZero Inspec Ssh <Not Created> <None>
|