Watch: Testing at the Edges

On March 1st, I presented a live webinar titled “Testing at the Edges”. Watch the recording below to hear me explain how to test resource guards that execute system commands or require specific system files. I also demonstrate enabling test coverage and working around recipes that rely on search results from the Chef Server.

In the presentation, I start by enabling test coverage but then explain how even when it reports 100% complete it is not exercising every logical branch in your recipes; specifically in your resource guards. I explore structuring your tests and creating the two scenarios when your resource guards execute commands. When it came time to implement a scenario that involved a resource guard with a file check in Ruby code I work around the pitfalls that come when you start to stub out core system library methods with a helpers methods. I finish with showing you how to stub the results of a Chef Server search query and verify the values were correctly used within a template.

During the presentation I was asked a few questions that I have included at the end of this post.


Q&A

What is the difference in in declaring the execute resource and expecting ‘do_nothing’ rather than expect(chef_run).to_not run_execute(…)?

When defining unit tests with ChefSpec you are defining the state of the resource collection. When you state that you expect a specific resource to_not take an action you are asking ChefSpec to examine the list of all the resources in the resource collection and ensure that this resource with this action is not present in that list.

A incorrectly specified resource or an incorrectly specified action on a resource that does exist in the resource collection will give you a false positive here. Because it obviously does not exist and obviously did not take that action. In this instance you are not checking for the presence of this unique resource but ensuring that it is absent. And as you can imagine there are a near infinite number of resources not present within the resource collection.

This is not the same as stating that you expect a resource is in the resource collection and it is taking no action. This approach is more correct because you are making a claim about the presence of a resource; not its absence.

How would you approach notifies and subscribes of other resources within a context scenario?

Resources may notify other resources to take action (or other resources subscribe to a resource). This chain of events is often important to evaluate because these resources reacting to other resources will take no action otherwise.

I did not demonstrate this during the webinar but the code repository that I demonstrated out of has a number of examples showing off this functionality. An example of several resources that notify one another in order to accomplish a complex task of pulling down a remote file, extracting its contents (only if a new file was retrieved), setting permissions (only if it was extracted), etc can be found here.

Can I set ServerRunner.new(platform: ‘windows’) – if I’m running Linux machine?

When using ChefSpec to unit test your cookbook you can definitely evaluate different platforms. ChefSpec employs a gem named Fauxhai. Fauxhai provides a large collection of sample Ohai data for multiple platforms. When I first started working with ChefSpec I had a hard time knowing which platforms were supported and the platform versions.

Author Franklin Webber

College dropout, turned instructor who found software development because everything else in his life was going too well. Forged by the fires of tech support, quality assurance and software development, he now brings technology to the hungry, sullied masses with raw energy, immeasurable empathy and a strong injection of humor.

  • Robert

    Hi Franklin,

    thanks a lot for this interesting webinar.

    In regards to searching by role in ServerRunner, I’ve found that the following works for me:

    “`
    server.create_node(‘node1’,
    automatic: { hostname: ‘node1’ },
    default: { cloud: { public_ipv4: ‘192.168.0.1’ } },
    run_list: [‘role[web]’]
    )
    “`