summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordanielsdeleo <dan@opscode.com>2013-01-29 18:10:28 -0800
committerdanielsdeleo <dan@opscode.com>2013-01-29 18:10:28 -0800
commitafd031b09c90e373da3f64365b6406c3d0d48c2c (patch)
tree71cf184908b864caba51ea1214430d489917c560
parent1f03cb4604b1944d20afd0faf292686fcb0f012b (diff)
parentb4fbb9bd3a6aeae9d3ff218f877da1ade1bba101 (diff)
downloadchef-afd031b09c90e373da3f64365b6406c3d0d48c2c.tar.gz
Merge branch 'set-unless-fix'
-rw-r--r--lib/chef/node.rb5
-rw-r--r--lib/chef/node/attribute.rb29
-rw-r--r--spec/unit/node/attribute_spec.rb31
-rw-r--r--spec/unit/node_spec.rb45
4 files changed, 110 insertions, 0 deletions
diff --git a/lib/chef/node.rb b/lib/chef/node.rb
index 0caf6602fe..b301045b28 100644
--- a/lib/chef/node.rb
+++ b/lib/chef/node.rb
@@ -123,6 +123,7 @@ class Chef
# Set a normal attribute of this node, but auto-vivify any Mashes that
# might be missing
def normal
+ attributes.set_unless_value_present = false
attributes.normal
end
@@ -139,12 +140,14 @@ class Chef
# Set a default of this node, but auto-vivify any Mashes that might
# be missing
def default
+ attributes.set_unless_value_present = false
attributes.default
end
# Set a force default attribute. Intermediate mashes will be created by
# auto-vivify if necessary.
def default!
+ attributes.set_unless_value_present = false
attributes.default!
end
@@ -158,12 +161,14 @@ class Chef
# Set an override attribute of this node, but auto-vivify any Mashes that
# might be missing
def override
+ attributes.set_unless_value_present = false
attributes.override
end
# Set a force override attribute. Intermediate mashes will be created by
# auto-vivify if needed.
def override!
+ attributes.set_unless_value_present = false
attributes.override!
end
diff --git a/lib/chef/node/attribute.rb b/lib/chef/node/attribute.rb
index eb6a0372d5..a417406721 100644
--- a/lib/chef/node/attribute.rb
+++ b/lib/chef/node/attribute.rb
@@ -209,6 +209,34 @@ class Chef
@combined_default = nil
end
+ # Debug what's going on with an attribute. +args+ is a path spec to the
+ # attribute you're interested in. For example, to debug where the value
+ # of `node[:network][:default_interface]` is coming from, use:
+ # debug_value(:network, :default_interface).
+ # The return value is an Array of Arrays. The first element is
+ # `["set_unless_enabled?", Boolean]`, which describes whether the
+ # attribute collection is in "set_unless" mode. The rest of the Arrays
+ # are pairs of `["precedence_level", value]`, where precedence level is
+ # the component, such as role default, normal, etc. and value is the
+ # attribute value set at that precedence level. If there is no value at
+ # that precedence level, +value+ will be the symbol +:not_present+.
+ def debug_value(*args)
+ components = COMPONENTS.map do |component|
+ ivar = instance_variable_get(component)
+ value = args.inject(ivar) do |so_far, key|
+ if so_far == :not_present
+ :not_present
+ elsif so_far.has_key?(key)
+ so_far[key]
+ else
+ :not_present
+ end
+ end
+ [component.to_s.sub(/^@/,""), value]
+ end
+ [["set_unless_enabled?", @set_unless_present]] + components
+ end
+
# Enables or disables `||=`-like attribute setting. See, e.g., Node#set_unless
def set_unless_value_present=(setting)
@set_unless_present = setting
@@ -220,6 +248,7 @@ class Chef
@merged_attributes = nil
@combined_default = nil
@combined_override = nil
+ @set_unless_present = false
end
alias :reset :reset_cache
diff --git a/spec/unit/node/attribute_spec.rb b/spec/unit/node/attribute_spec.rb
index 435dc3230c..5aa563aedf 100644
--- a/spec/unit/node/attribute_spec.rb
+++ b/spec/unit/node/attribute_spec.rb
@@ -247,6 +247,37 @@ describe Chef::Node::Attribute do
end
+ describe "when debugging attributes" do
+ before do
+ @attributes.default[:foo][:bar] = "default"
+ @attributes.env_default[:foo][:bar] = "env_default"
+ @attributes.role_default[:foo][:bar] = "role_default"
+ @attributes.force_default[:foo][:bar] = "force_default"
+ @attributes.normal[:foo][:bar] = "normal"
+ @attributes.override[:foo][:bar] = "override"
+ @attributes.role_override[:foo][:bar] = "role_override"
+ @attributes.env_override[:foo][:bar] = "env_override"
+ @attributes.force_override[:foo][:bar] = "force_override"
+ @attributes.automatic[:foo][:bar] = "automatic"
+ end
+
+ it "gives the value at each level of precedence for a path spec" do
+ expected = [["set_unless_enabled?", false],
+ ["default", "default"],
+ ["env_default", "env_default"],
+ ["role_default", "role_default"],
+ ["force_default", "force_default"],
+ ["normal", "normal"],
+ ["override", "override"],
+ ["role_override", "role_override"],
+ ["env_override", "env_override"],
+ ["force_override", "force_override"],
+ ["automatic", "automatic"]
+ ]
+ @attributes.debug_value(:foo, :bar).should == expected
+ end
+ end
+
describe "when fetching values based on precedence" do
before do
@attributes.default["default"] = "cookbook default"
diff --git a/spec/unit/node_spec.rb b/spec/unit/node_spec.rb
index d785f84c73..3d32902b94 100644
--- a/spec/unit/node_spec.rb
+++ b/spec/unit/node_spec.rb
@@ -177,6 +177,21 @@ describe Chef::Node do
node[:snoopy][:is_a_puppy].should == true
end
+ it "should allow you to set a value after a set_unless" do
+ # this tests for set_unless_present state bleeding between statements CHEF-3806
+ node.set_unless[:snoopy][:is_a_puppy] = false
+ node.set[:snoopy][:is_a_puppy] = true
+ node[:snoopy][:is_a_puppy].should == true
+ end
+
+ it "should let you set a value after a 'dangling' set_unless" do
+ # this tests for set_unless_present state bleeding between statements CHEF-3806
+ node.set[:snoopy][:is_a_puppy] = "what"
+ node.set_unless[:snoopy][:is_a_puppy]
+ node.set[:snoopy][:is_a_puppy] = true
+ node[:snoopy][:is_a_puppy].should == true
+ end
+
it "auto-vivifies attributes created via method syntax" do
node.set.fuu.bahrr.baz = "qux"
node.fuu.bahrr.baz.should == "qux"
@@ -201,6 +216,21 @@ describe Chef::Node do
node[:snoopy][:is_a_puppy].should == true
end
+ it "should allow you to set a value after a default_unless" do
+ # this tests for set_unless_present state bleeding between statements CHEF-3806
+ node.default_unless[:snoopy][:is_a_puppy] = false
+ node.default[:snoopy][:is_a_puppy] = true
+ node[:snoopy][:is_a_puppy].should == true
+ end
+
+ it "should allow you to set a value after a 'dangling' default_unless" do
+ # this tests for set_unless_present state bleeding between statements CHEF-3806
+ node.default[:snoopy][:is_a_puppy] = "what"
+ node.default_unless[:snoopy][:is_a_puppy]
+ node.default[:snoopy][:is_a_puppy] = true
+ node[:snoopy][:is_a_puppy].should == true
+ end
+
it "auto-vivifies attributes created via method syntax" do
node.default.fuu.bahrr.baz = "qux"
node.fuu.bahrr.baz.should == "qux"
@@ -231,6 +261,21 @@ describe Chef::Node do
node[:snoopy][:is_a_puppy].should == true
end
+ it "should allow you to set a value after an override_unless" do
+ # this tests for set_unless_present state bleeding between statements CHEF-3806
+ node.override_unless[:snoopy][:is_a_puppy] = false
+ node.override[:snoopy][:is_a_puppy] = true
+ node[:snoopy][:is_a_puppy].should == true
+ end
+
+ it "should allow you to set a value after a 'dangling' override_unless" do
+ # this tests for set_unless_present state bleeding between statements CHEF-3806
+ node.override_unless[:snoopy][:is_a_puppy] = "what"
+ node.override_unless[:snoopy][:is_a_puppy]
+ node.override[:snoopy][:is_a_puppy] = true
+ node[:snoopy][:is_a_puppy].should == true
+ end
+
it "auto-vivifies attributes created via method syntax" do
node.override.fuu.bahrr.baz = "qux"
node.fuu.bahrr.baz.should == "qux"