Skip to content

Commit

Permalink
deep_merge_cache fixes for bugs in 12.0.0
Browse files Browse the repository at this point in the history
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].
  • Loading branch information
lamont-granquist committed Jan 14, 2015
1 parent 7b93aae commit d724763
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 4 deletions.
8 changes: 4 additions & 4 deletions lib/chef/node/attribute.rb
Expand Up @@ -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

Expand Down Expand Up @@ -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

Expand Down
31 changes: 31 additions & 0 deletions spec/unit/node_spec.rb
Expand Up @@ -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
Expand Down

0 comments on commit d724763

Please sign in to comment.