ChefSpec unit test for testing node attribute setting after node.rm?


#1

I have a cookbook where I reset an array-valued attribute at the “default” level of precedence, when it was already set in the environment at that same level of precedence.

Using the guidance under the section “Remove Precedence Level” in the doc “About Attributes” (https://docs.chef.io/attributes.html), I first “rm_default” the attribute , and then set it, to avoid having Chef “deep merge” the two values (and use the union of both). Here’s the code in my recipe that seems to work:

node.rm_default('foo', 'bar')
node.default['foo']['bar'] = [ 'a', 'b', 'c' ]

My question is: Is it possible to write a ChefSpec unit test example to test that this works? My ChefSpec example does not seem to work if I set the attribute with “node.default” in the SoloRunner block, to simulate the attribute’s having been set in the environment before the cookbook runs. That is, when my Chef run is set up like this:

      let(:chef_run) do                                                            
        ChefSpec::SoloRunner.new(platver) do |node|                                
          node.default['foo']['bar'] = ['d', 'e', 'f']                 
        end.converge(described_recipe)                                             
      end                                                                          

Then the example that tests for the updated node attribute fails: the node attribute does not appear to get set to the new value ([ ‘a’, ‘b’, ‘c’ ]) set by the recipe code at the top of this post; it stays at the value set in the SoloRunner block ([‘d’, ‘e’, ‘f’]).

However, it DOES seem to work if I use “node.force_default” to simulate the environment attribute:

      let(:chef_run) do                                                            
        ChefSpec::SoloRunner.new(platver) do |node|                                
          node.force_default['foo']['bar'] = ['d', 'e', 'f']                 
        end.converge(described_recipe)                                             
      end                                                                          

Can someone explain to my why “node.default” does not work here, and why “node.force_default” does? Also, maybe I’m just approaching this whole problem incorrectly, in which case I welcome your pointing me in the right direction.