Mocking data in Test Kitchen (Part 2)

Thumbnail

Going beyond the easier use case of mocking attributes and databags, we sometimes want to fake some data about the system itself.

Ohai Attributes

Sometimes, you encounter systems where you want to make distrinctions based on Ohai attributes like the hostname or domain name. This is not very common, but worth noting that you can use similar techniques for mocking in those cases.

Let’s say we have a recipe which sets a specific networking configuration based on the hostname. Well, the problem with testing this, is that hostnames are automatic attributes and as you can see from the famous [Precedence Table], there is no way these can be overwritten.

There is a way, though - but first we have to look at an elusive concept in the Chef world: Fixture Cookbooks

Fixture Cookbook

This is a minimalist cookbook which helps you set up your machines so they can be tested with your unchanged recipe. This often involves some configuration which would normally happen outside of Chef. An example could be that in production your VMs are created based on images where another department made some changes. There could be base packages pre-installed or some DNS configuration done.

If we want to replicate this, we write a Fixture Cookbook. Not much effort in there, it is just meant for a pre-test setup. I prefer to put it into a directory test/integration/fixtures as they are clearly related to integration tests 1.

A fixture cookbook can exist out of only two files. A minimalistic metadata.rb:

name 'fixtures'

# depends 'other_cookbook', '~> 1.0'

There is no extra information needed, just the name and maybe some dependencies for your planned setup tasks.

Then, there is the default recipe recipe.rb. It sits right in the main directory, no need for a recipes/ subdirectory 2.

So how would we use this? Let’s look at our kitchen.yml:

suites:
 - name: standard
   provisioner:
     run_list:
        - recipe[fixtures]
        - recipe[sql_server::configure]

Of course, Chef does not yet know how to map this new cookbook and the path we created it in. This needs a slight adjustment to the Berksfile of your main cookbook:

source 'https://supermarket.chef.io'

metadata

cookbook 'fixtures', path: 'test/integration/fixtures', group: :integration

Test Kitchen starts tests with the :integration group, which tells Chef to add the path to our fixtures and the runlist then executes it.

Ohai Attributes with kitchen-ohai

Back to our example of overriding a hostname.

Now that we know how to tweak our environment with Fixture Cookbooks, we are only missing one piece of this puzzle: the knowledge about the kitchen-ohai cookbook.

This small gem allows us to override Ohai attributes. And now that we know how to set it up, our plan can come together.

As we already prepared our Berksfile and our kitchen.yml runlist, we only need to adjust the fixture cookbook contents.

metadata.rb:

name 'fixtures'
  
depends 'kitchen-ohai'

recipe.rb:

include_recipe 'kitchen-ohai'

And now we can override those attributes in the kitchen.yml:

suites:
  - name: standard
    provisioner:
      run_list:
        - recipe[fixtures]
        - recipe[sql_server::configure]
      attributes:
        kitchen_ohai:
          values:
            hostname: 'NEWHOSTNAME'

This is a pretty complex construct, so you should always ask yourself if using a Fixture Cookbook or overriding Ohai attributes is really the only way you can reach your goals. Try to avoid complexity, if possible. But know about your options, if you need them.


  1. Actually, this location is specifically mentioned to be used for fixtures in the Test Kitchen sources [return]
  2. This uses a concept called “Root Aliases” detailed in the RFC033-based documentation [return]