Going beyond the easier use case of mocking attributes and databags, we sometimes want to fake some data about the system itself.
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
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
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
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.
name 'fixtures' depends 'kitchen-ohai'
And now we can override those attributes in the
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.