Skip steps in an InSpec integration test based on Chef attribute values

To speed up the test of some complex recipes, I use an attribute to skip certain long-running installations when I only need to test the rest of the recipe.

We will pass Chef Attribute values into an InSpec test using environment variables.

Declare an attribute in the atrributes.rb file with a safe default value, to allow the execution of all steps if the value is not overridden

# Set this to true in the .kitchen.yml file to skip long-running tasks during local test
default['quick_launch_for_test'] = false

Set the value in the suites: section of the kitchen.yml file to true to skip the long-running installations

  attributes:
    quick_launch_for_test: true

Save the attribute value in an environment variable in the recipe to pass it to InSpec

# Store the value in an environment variable for the integration test
env 'quick_launch_for_test' do
  value "#{node['quick_launch_for_test']}"
end

Make a decision in the recipe based on the value of the attribute

if ( node['quick_launch_for_test'] != true )
  #########################################
  #Microsoft Visual Studio Community 2017 #
  #########################################
  ...
end

Read the value of the environment variable into a local variable in the InSpec test file. If the environment variable does not exist, or the value is not “true”, the value of the local_execution variable will be “false”.

local_execution = ( os_env('quick_launch_for_test').content() == 'true')

Use the if statement to make the decision in your InSpec test file

if !local_execution
  describe package('Microsoft Visual Studio Community 2017') do
    it { should be_installed }
  end
end

 

Getting started with InSpec

InSpec is an open-source testing framework to verify your infrastructure satisfies the design requirements.

In this article, we will learn to install and use InSpec with Chef.

Install InSpec

  1. Navigate to https://downloads.chef.io/inspec, and download the installer for the operating system of your workstation,
  2. Execute the downloaded installer.

Allow InSpec to verify Red Hat Enterprise Linux instances

InSpec needs “sudo” access to execute the tests, but Red Hat Enterprise Linux prevents that access. Execute the following code on every instance when it runs in Test Kitchen:

if (node.chef_environment == "_default")
  # Running in Test Kitchen

  # Ensure sudo is installed
  package 'Install sudo' do
    package_name 'sudo'
    action :install
  end

  file '/etc/sudoers' do
    mode 0440
    owner 'root'
    group 'root'
    action :create
  end

  delete_lines 'remove hash-comments from /some/file' do
    path '/etc/sudoers'
    pattern '^.*requiretty'
  end

end

 

Start to use InSpec

To use InSpec as the default integration testing tool in Chef Test Kitchen

  1. Open the .kitchen.yml file of the cookbook,
  2. Delete the following lines from the platform section if exist:
    busser:
      sudo: true
  3. Add the following lines to the file between provisioner: and platforms:
    verifier:
      name: inspec
  4. Place the test files into the default location of the InSpec integration test. The “verify” command executes all files in the directory.
    test
    |--smoke
       |--default
          |--MY_RECIPE_NAME1_test.rb
          |--MY_RECIPE_NAME2_test.rb
    
  5. To execute the test file with the verify command, add these lines to every suite. This will execute all test files in the default folder.
        verifier:
          inspec_tests:
            - test/smoke/default
  6. To execute only one test file, specify the file name:
        verifier:
          inspec_tests:
            - test/smoke/default/MY_RECIPE_test.rb
  7. To execute the test file of another suite, use relative path, you can use tests from other cookbooks (../ANOTHER_COOKBOOK/test/recipes/ANOTHER_SUITE_NAME).
        verifier:
          inspec_tests:
            - ../ANOTHER_COOKBOOK/test/smoke/default
  8. Create an integration test for your recipe. Create a new file in the test/recipes/THE_SUITE_NAME folder. The name does not matter, if you are planning to create only one test file for the suite, name the file after the suite: default_test.rb,
  9. The following is a simple example of an InSpec integration test:
    # # encoding: utf-8
    
    # Inspec test for recipe my_cookbook::default
    
    # The Inspec reference, with examples and extensive documentation, can be
    # found at https://docs.chef.io/inspec_reference.html
    
    unless os.windows?
     describe user('root') do
     it { should exist }
     skip 'This is an example test, replace with your own test.'
     end
    end
    
    describe port(80) do
     it { should_not be_listening }
     skip 'This is an example test, replace with your own test.'
    end

As you can see, the syntax of InSpec is (intentionally) very similar to ServerSpec, that it replaces. It is very easy to convert existing ServerSpec integration tests to InSpec compliance tests.

Differences between ServerSpec and InSpec

ServerSpec “process”

changed from

 describe process('PROCESS_NAME') do
   it { should be_running }
 end

to

describe processes('PROCESS_NAME') do
  its('states') { should eq ['R<'] }
end

For more information

For more information on the Kitchen InSpec verifier visit https://github.com/chef/kitchen-inspec