Trying to understand this code


#1

I have been given a cookbook and told to write tests for it. I am fairly new to chef and new to chef testing. I have done some testing before for Node.js but that’s it. The code block below is the one I am having trouble writing a test for. If I understand it right it is taking the usr/local… and replacing it’s contents with the source listed on the second line. Then reloads the Nginx service shortly after a delay. How do you write tests for that?

template ‘usr/local/nginx/conf/modsecurity.conf’ do
source ‘modsecurity.conf.erb’
notifies :reload, “service[nginx]”, :delayed
end


#2

Hello,

Testing Chef resources is achieved with ChefSpec. You may find it helpful to run through the Learn Chef module for unit testing.

Learn Chef:

https://learn.chef.io/modules/unit-test-with-chefspec

ChefSpec:

https://github.com/chefspec/chefspec

https://github.com/chefspec/chefspec/tree/master/examples/template

I think you’ll likely have more questions, but this should get you started.

Brandon


#3

Thanks, I have gone through the learn.chef.io but still am not 100% on it. Been looking at the docs but they only seem to show how to write the cookbooks or write certain types of tests. I can’t find any that are specific to the template styling. That’s why I came here to ask.


#4

Hi @jkwysdom, welcome to the community!

The examples directory in the chefspec repo is a wealth of info for chefspec tests, which are considered a type of ‘unit’ test in Chef, with the unit being an individual resource.

For the template resource you pasted:

template ‘/usr/local/nginx/conf/modsecurity.conf’ do
    source ‘modsecurity.conf.erb’
    notifies :reload, “service[nginx]”, :delayed
end

You are telling chef-client to render the modsecurity.conf file at that path, using the template source modsecurity.conf.erb and to send a delayed (executed at the end of the chef-client run) notification to the chef service resource named ‘nginx’ telling it to run the :reload action.

You would need a chefspec statement like:

it 'some description of resource under test here' do
  expect(chef_run).to create_template('/usr/local/nginx/conf/modsecurity.conf').with(
    source 'modsecurity.conf.erb'
   )
  expect(chef_run).to notify('service[nginx]').to(:reload).delayed
end

There’s some more boilerplate to making this work, like ensuring chef_run is an instance of ChefSpec::SoloRunner or ChefSpec::ServerRunner but you can find these examples in the repo.

I’d also encourage you to look at test-kitchen and inspec testing, which is how integration testing is performed for chef cookbooks. Test-kitchen creates temporary machines and converges your recipe, inspec verifies the resutls.

An inspec test for this resource could look like:

describe file('/usr/local/nginx/conf/modsecurity.conf') do
  it { should exist }
  its('mode') { should cmp '0644' }
end

You can test other properties as well, this is documented with examples on the inspec file resource page

Hope that is clear.


#5

Thanks, the inspec test is the one that helped. I am using inspec to write the tests so far. Noted the chefspec one down too for future use.