From d724763623b9593f61e2df083e576d1ed8406aae Mon Sep 17 00:00:00 2001 From: Lamont Granquist Date: Wed, 14 Jan 2015 10:51:32 -0800 Subject: [PATCH] deep_merge_cache fixes for bugs in 12.0.0 In 12.0.0 we introduced a cache for the merged attributes for the top-level node attribute keys. This fixes this so that node['foo'] and node[:foo] are not cached separately. This also showed up in bugs as issues between node['foo'] access and node.foo access because node.foo is translated into node[:foo]. --- lib/chef/node/attribute.rb | 8 ++++---- spec/unit/node_spec.rb | 31 +++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/lib/chef/node/attribute.rb b/lib/chef/node/attribute.rb index 3c48f653eb4..80f5ac4f8d0 100644 --- a/lib/chef/node/attribute.rb +++ b/lib/chef/node/attribute.rb @@ -253,7 +253,7 @@ def reset_cache(path = nil) if path.nil? @deep_merge_cache = {} else - deep_merge_cache.delete(path) + deep_merge_cache.delete(path.to_s) end end @@ -436,12 +436,12 @@ def combined_default(*path) end def [](key) - if deep_merge_cache.has_key?(key) + if deep_merge_cache.has_key?(key.to_s) # return the cache of the deep merged values by top-level key - deep_merge_cache[key] + deep_merge_cache[key.to_s] else # save all the work of computing node[key] - deep_merge_cache[key] = merged_attributes(key) + deep_merge_cache[key.to_s] = merged_attributes(key) end end diff --git a/spec/unit/node_spec.rb b/spec/unit/node_spec.rb index 0bc76db2727..5939403ce6e 100644 --- a/spec/unit/node_spec.rb +++ b/spec/unit/node_spec.rb @@ -611,6 +611,37 @@ end end + # In Chef-12.0 there is a deep_merge cache on the top level attribute which had a bug + # where it cached node[:foo] separate from node['foo']. These tests exercise those edge conditions. + # + # https://github.com/opscode/chef/issues/2700 + # https://github.com/opscode/chef/issues/2712 + # https://github.com/opscode/chef/issues/2745 + # + describe "deep merge attribute cache edge conditions" do + it "does not error with complicated attribute substitution" do + node.default['chef_attribute_hell']['attr1'] = "attribute1" + node.default['chef_attribute_hell']['attr2'] = "#{node.chef_attribute_hell.attr1}/attr2" + expect { node.default['chef_attribute_hell']['attr3'] = "#{node.chef_attribute_hell.attr2}/attr3" }.not_to raise_error + end + + it "caches both strings and symbols correctly" do + node.force_default[:solr][:version] = '4.10.2' + node.force_default[:solr][:data_dir] = "/opt/solr-#{node['solr'][:version]}/example/solr" + node.force_default[:solr][:xms] = "512M" + expect(node[:solr][:xms]).to eql("512M") + expect(node['solr'][:xms]).to eql("512M") + end + + it "method interpolation syntax also works" do + node.default['passenger']['version'] = '4.0.57' + node.default['passenger']['root_path'] = "passenger-#{node['passenger']['version']}" + node.default['passenger']['root_path_2'] = "passenger-#{node.passenger['version']}" + expect(node['passenger']['root_path_2']).to eql("passenger-4.0.57") + expect(node[:passenger]['root_path_2']).to eql("passenger-4.0.57") + end + end + it "should raise an ArgumentError if you ask for an attribute that doesn't exist via method_missing" do expect { node.sunshine }.to raise_error(NoMethodError) end