diff options
author | John Keiser <john@johnkeiser.com> | 2015-06-30 21:14:28 -0600 |
---|---|---|
committer | John Keiser <john@johnkeiser.com> | 2015-07-06 12:04:47 -0600 |
commit | 591b5599f5412faa382e45d035d76535cd93736a (patch) | |
tree | 3494785822024b7c4acc97adc4883c7a73e2eaaf /spec | |
parent | cfd2b1fa1b26e8b0aa92a5ba8bd294b96379b2fa (diff) | |
download | chef-591b5599f5412faa382e45d035d76535cd93736a.tar.gz |
Re-separate priority map and DSL handler map so that provides has veto power over priority
Diffstat (limited to 'spec')
-rw-r--r-- | spec/integration/recipes/recipe_dsl_spec.rb | 959 | ||||
-rw-r--r-- | spec/unit/lwrp_spec.rb | 8 | ||||
-rw-r--r-- | spec/unit/provider_resolver_spec.rb | 7 | ||||
-rw-r--r-- | spec/unit/resource_spec.rb | 6 |
4 files changed, 606 insertions, 374 deletions
diff --git a/spec/integration/recipes/recipe_dsl_spec.rb b/spec/integration/recipes/recipe_dsl_spec.rb index fa38808e3e..4e80c5a738 100644 --- a/spec/integration/recipes/recipe_dsl_spec.rb +++ b/spec/integration/recipes/recipe_dsl_spec.rb @@ -401,370 +401,6 @@ describe "Recipe DSL methods" do }.to raise_error(NoMethodError) end end - - context "with a resource named 'B' with resource name :two_classes_one_dsl" do - let(:two_classes_one_dsl) { :"two_classes_one_dsl#{Namer.current_index}" } - let(:resource_class) { - result = Class.new(BaseThingy) do - def self.name - "B" - end - def self.to_s; name; end - def self.inspect; name.inspect; end - end - result.resource_name two_classes_one_dsl - result - } - before { resource_class } # pull on it so it gets defined before the recipe runs - - context "and another resource named 'A' with resource_name :two_classes_one_dsl" do - let(:resource_class_a) { - result = Class.new(BaseThingy) do - def self.name - "A" - end - def self.to_s; name; end - def self.inspect; name.inspect; end - end - result.resource_name two_classes_one_dsl - result - } - before { resource_class_a } # pull on it so it gets defined before the recipe runs - - it "two_classes_one_dsl resolves to A (alphabetically earliest)" do - two_classes_one_dsl = self.two_classes_one_dsl - recipe = converge { - instance_eval("#{two_classes_one_dsl} 'blah'") - } - expect(recipe.logged_warnings).to eq '' - expect(BaseThingy.created_resource).to eq resource_class_a - end - - it "resource_matching_short_name returns B" do - expect(Chef::Resource.resource_matching_short_name(two_classes_one_dsl)).to eq resource_class_a - end - end - - context "and another resource named 'Z' with resource_name :two_classes_one_dsl" do - let(:resource_class_z) { - result = Class.new(BaseThingy) do - def self.name - "Z" - end - def self.to_s; name; end - def self.inspect; name.inspect; end - end - result.resource_name two_classes_one_dsl - result - } - before { resource_class_z } # pull on it so it gets defined before the recipe runs - - it "two_classes_one_dsl resolves to B (alphabetically earliest)" do - two_classes_one_dsl = self.two_classes_one_dsl - recipe = converge { - instance_eval("#{two_classes_one_dsl} 'blah'") - } - expect(recipe.logged_warnings).to eq '' - expect(BaseThingy.created_resource).to eq resource_class - end - - it "resource_matching_short_name returns B" do - expect(Chef::Resource.resource_matching_short_name(two_classes_one_dsl)).to eq resource_class - end - end - - context "and another resource Blarghle with provides :two_classes_one_dsl, os: 'blarghle'" do - let(:resource_class_blarghle) { - result = Class.new(BaseThingy) do - def self.name - "Blarghle" - end - def self.to_s; name; end - def self.inspect; name.inspect; end - end - result.resource_name two_classes_one_dsl - result.provides two_classes_one_dsl, os: 'blarghle' - result - } - before { resource_class_blarghle } # pull on it so it gets defined before the recipe runs - - it "on os = blarghle, two_classes_one_dsl resolves to Blarghle" do - two_classes_one_dsl = self.two_classes_one_dsl - recipe = converge { - # this is an ugly way to test, make Cheffish expose node attrs - run_context.node.automatic[:os] = 'blarghle' - instance_eval("#{two_classes_one_dsl} 'blah' do; end") - } - expect(recipe.logged_warnings).to eq '' - expect(BaseThingy.created_resource).to eq resource_class_blarghle - end - - it "on os = linux, two_classes_one_dsl resolves to B" do - two_classes_one_dsl = self.two_classes_one_dsl - recipe = converge { - # this is an ugly way to test, make Cheffish expose node attrs - run_context.node.automatic[:os] = 'linux' - instance_eval("#{two_classes_one_dsl} 'blah' do; end") - } - expect(recipe.logged_warnings).to eq '' - expect(BaseThingy.created_resource).to eq resource_class - end - end - end - - context "with a resource MyResource" do - let(:resource_class) { Class.new(BaseThingy) do - def self.called_provides - @called_provides - end - def to_s - "MyResource" - end - end } - let(:my_resource) { :"my_resource#{Namer.current_index}" } - let(:blarghle_blarghle_little_star) { :"blarghle_blarghle_little_star#{Namer.current_index}" } - - context "with resource_name :my_resource" do - before { - resource_class.resource_name my_resource - } - - context "with provides? returning true to my_resource" do - before { - my_resource = self.my_resource - resource_class.define_singleton_method(:provides?) do |node, resource_name| - @called_provides = true - resource_name == my_resource - end - } - - it "my_resource returns the resource and calls provides?, but does not emit a warning" do - dsl_name = self.my_resource - recipe = converge { - instance_eval("#{dsl_name} 'foo'") - } - expect(recipe.logged_warnings).to eq '' - expect(BaseThingy.created_resource).to eq resource_class - expect(resource_class.called_provides).to be_truthy - end - end - - context "with provides? returning true to blarghle_blarghle_little_star and not resource_name" do - before do - blarghle_blarghle_little_star = self.blarghle_blarghle_little_star - resource_class.define_singleton_method(:provides?) do |node, resource_name| - @called_provides = true - resource_name == blarghle_blarghle_little_star - end - end - - it "my_resource does not return the resource" do - dsl_name = self.my_resource - expect_converge { - instance_eval("#{dsl_name} 'foo'") - }.to raise_error(Chef::Exceptions::NoSuchResourceType) - expect(resource_class.called_provides).to be_truthy - end - - it "blarghle_blarghle_little_star 'foo' returns the resource and emits a warning" do - dsl_name = self.blarghle_blarghle_little_star - recipe = converge { - instance_eval("#{dsl_name} 'foo'") - } - expect(recipe.logged_warnings).to include "WARN: #{resource_class}.provides? returned true when asked if it provides DSL #{dsl_name}, but provides :#{dsl_name} was never called!" - expect(BaseThingy.created_resource).to eq resource_class - expect(resource_class.called_provides).to be_truthy - end - end - - context "and a provider" do - let(:provider_class) do - Class.new(BaseThingy::Provider) do - def self.name - "MyProvider" - end - def self.to_s; name; end - def self.inspect; name.inspect; end - def self.called_provides - @called_provides - end - end - end - - before do - resource_class.send(:define_method, :provider) { nil } - end - - context "that provides :my_resource" do - before do - provider_class.provides my_resource - end - - context "with supports? returning true" do - before do - provider_class.define_singleton_method(:supports?) { |resource,action| true } - end - - it "my_resource runs the provider and does not emit a warning" do - my_resource = self.my_resource - recipe = converge { - instance_eval("#{my_resource} 'foo'") - } - expect(recipe.logged_warnings).to eq '' - expect(BaseThingy.created_provider).to eq provider_class - end - - context "and another provider supporting :my_resource with supports? false" do - let(:provider_class2) do - Class.new(BaseThingy::Provider) do - def self.name - "MyProvider2" - end - def self.to_s; name; end - def self.inspect; name.inspect; end - def self.called_provides - @called_provides - end - provides my_resource - def self.supports?(resource, action) - false - end - end - end - - it "my_resource runs the first provider" do - my_resource = self.my_resource - recipe = converge { - instance_eval("#{my_resource} 'foo'") - } - expect(recipe.logged_warnings).to eq '' - expect(BaseThingy.created_provider).to eq provider_class - end - end - end - - context "with supports? returning false" do - before do - provider_class.define_singleton_method(:supports?) { |resource,action| false } - end - - # TODO no warning? ick - it "my_resource runs the provider anyway" do - my_resource = self.my_resource - recipe = converge { - instance_eval("#{my_resource} 'foo'") - } - expect(recipe.logged_warnings).to eq '' - expect(BaseThingy.created_provider).to eq provider_class - end - - context "and another provider supporting :my_resource with supports? true" do - let(:provider_class2) do - my_resource = self.my_resource - Class.new(BaseThingy::Provider) do - def self.name - "MyProvider2" - end - def self.to_s; name; end - def self.inspect; name.inspect; end - def self.called_provides - @called_provides - end - provides my_resource - def self.supports?(resource, action) - true - end - end - end - before { provider_class2 } # make sure the provider class shows up - - it "my_resource runs the other provider" do - my_resource = self.my_resource - recipe = converge { - instance_eval("#{my_resource} 'foo'") - } - expect(recipe.logged_warnings).to eq '' - expect(BaseThingy.created_provider).to eq provider_class2 - end - end - end - end - - context "with provides? returning true" do - before { - my_resource = self.my_resource - provider_class.define_singleton_method(:provides?) do |node, resource| - @called_provides = true - resource.declared_type == my_resource - end - } - - context "that provides :my_resource" do - before { - provider_class.provides my_resource - } - - it "my_resource calls the provider (and calls provides?), but does not emit a warning" do - my_resource = self.my_resource - recipe = converge { - instance_eval("#{my_resource} 'foo'") - } - expect(recipe.logged_warnings).to eq '' - expect(BaseThingy.created_provider).to eq provider_class - expect(provider_class.called_provides).to be_truthy - end - end - - context "that does not call provides :my_resource" do - it "my_resource calls the provider (and calls provides?), and emits a warning" do - my_resource = self.my_resource - recipe = converge { - instance_eval("#{my_resource} 'foo'") - } - expect(recipe.logged_warnings).to include("WARN: #{provider_class}.provides? returned true when asked if it provides DSL #{my_resource}, but provides :#{my_resource} was never called!") - expect(BaseThingy.created_provider).to eq provider_class - expect(provider_class.called_provides).to be_truthy - end - end - end - - context "with provides? returning false to my_resource" do - before { - my_resource = self.my_resource - provider_class.define_singleton_method(:provides?) do |node, resource| - @called_provides = true - false - end - } - - context "that provides :my_resource" do - before { - provider_class.provides my_resource - } - - it "my_resource fails to find a provider (and calls provides)" do - my_resource = self.my_resource - expect_converge { - instance_eval("#{my_resource} 'foo'") - }.to raise_error(Chef::Exceptions::ProviderNotFound) - expect(provider_class.called_provides).to be_truthy - end - end - - context "that does not provide :my_resource" do - it "my_resource fails to find a provider (and calls provides)" do - my_resource = self.my_resource - expect_converge { - instance_eval("#{my_resource} 'foo'") - }.to raise_error(Chef::Exceptions::ProviderNotFound) - expect(provider_class.called_provides).to be_truthy - end - end - end - end - end - end - end end @@ -1175,6 +811,601 @@ describe "Recipe DSL methods" do end end end + + context "with a resource named 'B' with resource name :two_classes_one_dsl" do + let(:two_classes_one_dsl) { :"two_classes_one_dsl#{Namer.current_index}" } + let(:resource_class) { + result = Class.new(BaseThingy) do + def self.name + "B" + end + def self.to_s; name; end + def self.inspect; name.inspect; end + end + result.resource_name two_classes_one_dsl + result + } + before { resource_class } # pull on it so it gets defined before the recipe runs + + context "and another resource named 'A' with resource_name :two_classes_one_dsl" do + let(:resource_class_a) { + result = Class.new(BaseThingy) do + def self.name + "A" + end + def self.to_s; name; end + def self.inspect; name.inspect; end + end + result.resource_name two_classes_one_dsl + result + } + before { resource_class_a } # pull on it so it gets defined before the recipe runs + + it "two_classes_one_dsl resolves to A (alphabetically earliest)" do + two_classes_one_dsl = self.two_classes_one_dsl + recipe = converge { + instance_eval("#{two_classes_one_dsl} 'blah'") + } + expect(recipe.logged_warnings).to eq '' + expect(BaseThingy.created_resource).to eq resource_class_a + end + + it "resource_matching_short_name returns B" do + expect(Chef::Resource.resource_matching_short_name(two_classes_one_dsl)).to eq resource_class_a + end + end + + context "and another resource named 'Z' with resource_name :two_classes_one_dsl" do + let(:resource_class_z) { + result = Class.new(BaseThingy) do + def self.name + "Z" + end + def self.to_s; name; end + def self.inspect; name.inspect; end + end + result.resource_name two_classes_one_dsl + result + } + before { resource_class_z } # pull on it so it gets defined before the recipe runs + + it "two_classes_one_dsl resolves to B (alphabetically earliest)" do + two_classes_one_dsl = self.two_classes_one_dsl + recipe = converge { + instance_eval("#{two_classes_one_dsl} 'blah'") + } + expect(recipe.logged_warnings).to eq '' + expect(BaseThingy.created_resource).to eq resource_class + end + + it "resource_matching_short_name returns B" do + expect(Chef::Resource.resource_matching_short_name(two_classes_one_dsl)).to eq resource_class + end + + context "and a priority array [ Z, B ]" do + before do + Chef.set_resource_priority_array(two_classes_one_dsl, [ resource_class_z, resource_class ]) + end + + it "two_classes_one_dsl resolves to Z (respects the priority array)" do + two_classes_one_dsl = self.two_classes_one_dsl + recipe = converge { + instance_eval("#{two_classes_one_dsl} 'blah'") + } + expect(recipe.logged_warnings).to eq '' + expect(BaseThingy.created_resource).to eq resource_class_z + end + + it "resource_matching_short_name returns B" do + expect(Chef::Resource.resource_matching_short_name(two_classes_one_dsl)).to eq resource_class + end + + context "when Z provides(:two_classes_one_dsl) { false }" do + before do + resource_class_z.provides(two_classes_one_dsl) { false } + end + + it "two_classes_one_dsl resolves to B (picks the next thing in the priority array)" do + two_classes_one_dsl = self.two_classes_one_dsl + recipe = converge { + instance_eval("#{two_classes_one_dsl} 'blah'") + } + expect(recipe.logged_warnings).to eq '' + expect(BaseThingy.created_resource).to eq resource_class + end + + it "resource_matching_short_name returns B" do + expect(Chef::Resource.resource_matching_short_name(two_classes_one_dsl)).to eq resource_class + end + end + end + + context "and priority arrays [ B ] and [ Z ]" do + before do + Chef.set_resource_priority_array(two_classes_one_dsl, [ resource_class ]) + Chef.set_resource_priority_array(two_classes_one_dsl, [ resource_class_z ]) + end + + it "two_classes_one_dsl resolves to Z (respects the most recent priority array)" do + two_classes_one_dsl = self.two_classes_one_dsl + recipe = converge { + instance_eval("#{two_classes_one_dsl} 'blah'") + } + expect(recipe.logged_warnings).to eq '' + expect(BaseThingy.created_resource).to eq resource_class_z + end + + it "resource_matching_short_name returns B" do + expect(Chef::Resource.resource_matching_short_name(two_classes_one_dsl)).to eq resource_class + end + + context "when Z provides(:two_classes_one_dsl) { false }" do + before do + resource_class_z.provides(two_classes_one_dsl) { false } + end + + it "two_classes_one_dsl resolves to B (picks the first match from the other priority array)" do + two_classes_one_dsl = self.two_classes_one_dsl + recipe = converge { + instance_eval("#{two_classes_one_dsl} 'blah'") + } + expect(recipe.logged_warnings).to eq '' + expect(BaseThingy.created_resource).to eq resource_class + end + + it "resource_matching_short_name returns B" do + expect(Chef::Resource.resource_matching_short_name(two_classes_one_dsl)).to eq resource_class + end + end + end + + context "and a priority array [ Z ]" do + before do + Chef.set_resource_priority_array(two_classes_one_dsl, [ resource_class_z ]) + end + + context "when Z provides(:two_classes_one_dsl) { false }" do + before do + resource_class_z.provides(two_classes_one_dsl) { false } + end + + it "two_classes_one_dsl resolves to B (picks the first match outside the priority array)" do + two_classes_one_dsl = self.two_classes_one_dsl + recipe = converge { + instance_eval("#{two_classes_one_dsl} 'blah'") + } + expect(recipe.logged_warnings).to eq '' + expect(BaseThingy.created_resource).to eq resource_class + end + + it "resource_matching_short_name returns B" do + expect(Chef::Resource.resource_matching_short_name(two_classes_one_dsl)).to eq resource_class + end + end + end + + end + + context "and a provider named 'B' which provides :two_classes_one_dsl" do + before do + resource_class.send(:define_method, :provider) { nil } + end + + let(:provider_class) { + result = Class.new(BaseThingy::Provider) do + def self.name + "B" + end + def self.to_s; name; end + def self.inspect; name.inspect; end + end + result.provides two_classes_one_dsl + result + } + before { provider_class } # pull on it so it gets defined before the recipe runs + + context "and another provider named 'A'" do + let(:provider_class_a) { + result = Class.new(BaseThingy::Provider) do + def self.name + "A" + end + def self.to_s; name; end + def self.inspect; name.inspect; end + end + result + } + context "which provides :two_classes_one_dsl" do + before { provider_class_a.provides two_classes_one_dsl } + + it "two_classes_one_dsl resolves to A (alphabetically earliest)" do + two_classes_one_dsl = self.two_classes_one_dsl + recipe = converge { + instance_eval("#{two_classes_one_dsl} 'blah'") + } + expect(recipe.logged_warnings).to eq '' + expect(BaseThingy.created_provider).to eq provider_class_a + end + end + context "which provides(:two_classes_one_dsl) { false }" do + before { provider_class_a.provides(two_classes_one_dsl) { false } } + + it "two_classes_one_dsl resolves to B (since A declined)" do + two_classes_one_dsl = self.two_classes_one_dsl + recipe = converge { + instance_eval("#{two_classes_one_dsl} 'blah'") + } + expect(recipe.logged_warnings).to eq '' + expect(BaseThingy.created_provider).to eq provider_class + end + end + end + + context "and another provider named 'Z'" do + let(:provider_class_z) { + result = Class.new(BaseThingy::Provider) do + def self.name + "Z" + end + def self.to_s; name; end + def self.inspect; name.inspect; end + end + result + } + before { provider_class_z } # pull on it so it gets defined before the recipe runs + + context "which provides :two_classes_one_dsl" do + before { provider_class_z.provides two_classes_one_dsl } + + it "two_classes_one_dsl resolves to B (alphabetically earliest)" do + two_classes_one_dsl = self.two_classes_one_dsl + recipe = converge { + instance_eval("#{two_classes_one_dsl} 'blah'") + } + expect(recipe.logged_warnings).to eq '' + expect(BaseThingy.created_provider).to eq provider_class + end + + context "with a priority array [ Z, B ]" do + before { Chef.set_provider_priority_array two_classes_one_dsl, [ provider_class_z, provider_class ] } + + it "two_classes_one_dsl resolves to Z (respects the priority map)" do + two_classes_one_dsl = self.two_classes_one_dsl + recipe = converge { + instance_eval("#{two_classes_one_dsl} 'blah'") + } + expect(recipe.logged_warnings).to eq '' + expect(BaseThingy.created_provider).to eq provider_class_z + end + end + end + + context "which provides(:two_classes_one_dsl) { false }" do + before { provider_class_z.provides(two_classes_one_dsl) { false } } + + context "with a priority array [ Z, B ]" do + before { Chef.set_provider_priority_array two_classes_one_dsl, [ provider_class_z, provider_class ] } + + it "two_classes_one_dsl resolves to B (the next one in the priority map)" do + two_classes_one_dsl = self.two_classes_one_dsl + recipe = converge { + instance_eval("#{two_classes_one_dsl} 'blah'") + } + expect(recipe.logged_warnings).to eq '' + expect(BaseThingy.created_provider).to eq provider_class + end + end + + context "with priority arrays [ B ] and [ Z ]" do + before { Chef.set_provider_priority_array two_classes_one_dsl, [ provider_class_z ] } + before { Chef.set_provider_priority_array two_classes_one_dsl, [ provider_class ] } + + it "two_classes_one_dsl resolves to B (the one in the next priority map)" do + two_classes_one_dsl = self.two_classes_one_dsl + recipe = converge { + instance_eval("#{two_classes_one_dsl} 'blah'") + } + expect(recipe.logged_warnings).to eq '' + expect(BaseThingy.created_provider).to eq provider_class + end + end + end + end + end + + context "and another resource Blarghle with provides :two_classes_one_dsl, os: 'blarghle'" do + let(:resource_class_blarghle) { + result = Class.new(BaseThingy) do + def self.name + "Blarghle" + end + def self.to_s; name; end + def self.inspect; name.inspect; end + end + result.resource_name two_classes_one_dsl + result.provides two_classes_one_dsl, os: 'blarghle' + result + } + before { resource_class_blarghle } # pull on it so it gets defined before the recipe runs + + it "on os = blarghle, two_classes_one_dsl resolves to Blarghle" do + two_classes_one_dsl = self.two_classes_one_dsl + recipe = converge { + # this is an ugly way to test, make Cheffish expose node attrs + run_context.node.automatic[:os] = 'blarghle' + instance_eval("#{two_classes_one_dsl} 'blah' do; end") + } + expect(recipe.logged_warnings).to eq '' + expect(BaseThingy.created_resource).to eq resource_class_blarghle + end + + it "on os = linux, two_classes_one_dsl resolves to B" do + two_classes_one_dsl = self.two_classes_one_dsl + recipe = converge { + # this is an ugly way to test, make Cheffish expose node attrs + run_context.node.automatic[:os] = 'linux' + instance_eval("#{two_classes_one_dsl} 'blah' do; end") + } + expect(recipe.logged_warnings).to eq '' + expect(BaseThingy.created_resource).to eq resource_class + end + end + end + + context "with a resource MyResource" do + let(:resource_class) { Class.new(BaseThingy) do + def self.called_provides + @called_provides + end + def to_s + "MyResource" + end + end } + let(:my_resource) { :"my_resource#{Namer.current_index}" } + let(:blarghle_blarghle_little_star) { :"blarghle_blarghle_little_star#{Namer.current_index}" } + + context "with resource_name :my_resource" do + before { + resource_class.resource_name my_resource + } + + context "with provides? returning true to my_resource" do + before { + my_resource = self.my_resource + resource_class.define_singleton_method(:provides?) do |node, resource_name| + @called_provides = true + resource_name == my_resource + end + } + + it "my_resource returns the resource and calls provides?, but does not emit a warning" do + dsl_name = self.my_resource + recipe = converge { + instance_eval("#{dsl_name} 'foo'") + } + expect(recipe.logged_warnings).to eq '' + expect(BaseThingy.created_resource).to eq resource_class + expect(resource_class.called_provides).to be_truthy + end + end + + context "with provides? returning true to blarghle_blarghle_little_star and not resource_name" do + before do + blarghle_blarghle_little_star = self.blarghle_blarghle_little_star + resource_class.define_singleton_method(:provides?) do |node, resource_name| + @called_provides = true + resource_name == blarghle_blarghle_little_star + end + end + + it "my_resource does not return the resource" do + dsl_name = self.my_resource + expect_converge { + instance_eval("#{dsl_name} 'foo'") + }.to raise_error(Chef::Exceptions::NoSuchResourceType) + expect(resource_class.called_provides).to be_truthy + end + + it "blarghle_blarghle_little_star 'foo' returns the resource and emits a warning" do + Chef::Config[:treat_deprecation_warnings_as_errors] = false + dsl_name = self.blarghle_blarghle_little_star + recipe = converge { + instance_eval("#{dsl_name} 'foo'") + } + expect(recipe.logged_warnings).to include "WARN: #{resource_class}.provides? returned true when asked if it provides DSL #{dsl_name}, but provides :#{dsl_name} was never called!" + expect(BaseThingy.created_resource).to eq resource_class + expect(resource_class.called_provides).to be_truthy + end + end + + context "and a provider" do + let(:provider_class) do + Class.new(BaseThingy::Provider) do + def self.name + "MyProvider" + end + def self.to_s; name; end + def self.inspect; name.inspect; end + def self.called_provides + @called_provides + end + end + end + + before do + resource_class.send(:define_method, :provider) { nil } + end + + context "that provides :my_resource" do + before do + provider_class.provides my_resource + end + + context "with supports? returning true" do + before do + provider_class.define_singleton_method(:supports?) { |resource,action| true } + end + + it "my_resource runs the provider and does not emit a warning" do + my_resource = self.my_resource + recipe = converge { + instance_eval("#{my_resource} 'foo'") + } + expect(recipe.logged_warnings).to eq '' + expect(BaseThingy.created_provider).to eq provider_class + end + + context "and another provider supporting :my_resource with supports? false" do + let(:provider_class2) do + Class.new(BaseThingy::Provider) do + def self.name + "MyProvider2" + end + def self.to_s; name; end + def self.inspect; name.inspect; end + def self.called_provides + @called_provides + end + provides my_resource + def self.supports?(resource, action) + false + end + end + end + + it "my_resource runs the first provider" do + my_resource = self.my_resource + recipe = converge { + instance_eval("#{my_resource} 'foo'") + } + expect(recipe.logged_warnings).to eq '' + expect(BaseThingy.created_provider).to eq provider_class + end + end + end + + context "with supports? returning false" do + before do + provider_class.define_singleton_method(:supports?) { |resource,action| false } + end + + # TODO no warning? ick + it "my_resource runs the provider anyway" do + my_resource = self.my_resource + recipe = converge { + instance_eval("#{my_resource} 'foo'") + } + expect(recipe.logged_warnings).to eq '' + expect(BaseThingy.created_provider).to eq provider_class + end + + context "and another provider supporting :my_resource with supports? true" do + let(:provider_class2) do + my_resource = self.my_resource + Class.new(BaseThingy::Provider) do + def self.name + "MyProvider2" + end + def self.to_s; name; end + def self.inspect; name.inspect; end + def self.called_provides + @called_provides + end + provides my_resource + def self.supports?(resource, action) + true + end + end + end + before { provider_class2 } # make sure the provider class shows up + + it "my_resource runs the other provider" do + my_resource = self.my_resource + recipe = converge { + instance_eval("#{my_resource} 'foo'") + } + expect(recipe.logged_warnings).to eq '' + expect(BaseThingy.created_provider).to eq provider_class2 + end + end + end + end + + context "with provides? returning true" do + before { + my_resource = self.my_resource + provider_class.define_singleton_method(:provides?) do |node, resource| + @called_provides = true + resource.declared_type == my_resource + end + } + + context "that provides :my_resource" do + before { + provider_class.provides my_resource + } + + it "my_resource calls the provider (and calls provides?), but does not emit a warning" do + my_resource = self.my_resource + recipe = converge { + instance_eval("#{my_resource} 'foo'") + } + expect(recipe.logged_warnings).to eq '' + expect(BaseThingy.created_provider).to eq provider_class + expect(provider_class.called_provides).to be_truthy + end + end + + context "that does not call provides :my_resource" do + it "my_resource calls the provider (and calls provides?), and emits a warning" do + Chef::Config[:treat_deprecation_warnings_as_errors] = false + my_resource = self.my_resource + recipe = converge { + instance_eval("#{my_resource} 'foo'") + } + expect(recipe.logged_warnings).to include("WARN: #{provider_class}.provides? returned true when asked if it provides DSL #{my_resource}, but provides :#{my_resource} was never called!") + expect(BaseThingy.created_provider).to eq provider_class + expect(provider_class.called_provides).to be_truthy + end + end + end + + context "with provides? returning false to my_resource" do + before { + my_resource = self.my_resource + provider_class.define_singleton_method(:provides?) do |node, resource| + @called_provides = true + false + end + } + + context "that provides :my_resource" do + before { + provider_class.provides my_resource + } + + it "my_resource fails to find a provider (and calls provides)" do + my_resource = self.my_resource + expect_converge { + instance_eval("#{my_resource} 'foo'") + }.to raise_error(Chef::Exceptions::ProviderNotFound) + expect(provider_class.called_provides).to be_truthy + end + end + + context "that does not provide :my_resource" do + it "my_resource fails to find a provider (and calls provides)" do + my_resource = self.my_resource + expect_converge { + instance_eval("#{my_resource} 'foo'") + }.to raise_error(Chef::Exceptions::ProviderNotFound) + expect(provider_class.called_provides).to be_truthy + end + end + end + end + end + end end before(:all) { Namer.current_index = 0 } diff --git a/spec/unit/lwrp_spec.rb b/spec/unit/lwrp_spec.rb index 545524eb10..bcb64cb21e 100644 --- a/spec/unit/lwrp_spec.rb +++ b/spec/unit/lwrp_spec.rb @@ -439,7 +439,7 @@ describe "LWRP" do end it "sets itself as a provider for a resource of the same name" do - found_providers = Chef::Platform::ProviderPriorityMap.instance.list_handlers(node, :lwrp_buck_passer) + found_providers = Chef::Platform::ProviderHandlerMap.instance.list(node, :lwrp_buck_passer) # we bypass the per-file loading to get the file to load each time, # which creates the LWRP class repeatedly. New things get prepended to # the list of providers. @@ -451,7 +451,7 @@ describe "LWRP" do let(:lwrp_cookbok_name) { "l_w_r_p" } it "sets itself as a provider for a resource of the same name" do - found_providers = Chef::Platform::ProviderPriorityMap.instance.list_handlers(node, :l_w_r_p_buck_passer) + found_providers = Chef::Platform::ProviderHandlerMap.instance.list(node, :l_w_r_p_buck_passer) expect(found_providers.size).to eq(1) expect(found_providers.last).to eq(get_lwrp_provider(:l_w_r_p_buck_passer)) end @@ -462,10 +462,10 @@ describe "LWRP" do let(:lwrp_cookbok_name) { "l-w-r-p" } it "sets itself as a provider for a resource of the same name" do - incorrect_providers = Chef::Platform::ProviderPriorityMap.instance.list_handlers(node, :'l-w-r-p_buck_passer') + incorrect_providers = Chef::Platform::ProviderHandlerMap.instance.list(node, :'l-w-r-p_buck_passer') expect(incorrect_providers).to eq([]) - found_providers = Chef::Platform::ProviderPriorityMap.instance.list_handlers(node, :l_w_r_p_buck_passer) + found_providers = Chef::Platform::ProviderHandlerMap.instance.list(node, :l_w_r_p_buck_passer) expect(found_providers.first).to eq(get_lwrp_provider(:l_w_r_p_buck_passer)) end end diff --git a/spec/unit/provider_resolver_spec.rb b/spec/unit/provider_resolver_spec.rb index e09b12a20a..88df4a20cc 100644 --- a/spec/unit/provider_resolver_spec.rb +++ b/spec/unit/provider_resolver_spec.rb @@ -90,13 +90,14 @@ describe Chef::ProviderResolver do end def self.expect_providers(**providers) - providers.each do |name, expected_provider| + providers.each do |name, expected| describe name.to_s do let(:resource_name) { name } tags = [] + expected_provider = nil expected_resource = nil - Array(expected_provider).each do |p| + Array(expected).each do |p| if p.is_a?(Class) && p <= Chef::Provider expected_provider = p elsif p.is_a?(Class) && p <= Chef::Resource @@ -525,8 +526,8 @@ describe Chef::ProviderResolver do # We want to check that these are unsupported: apt_package: nil, bff_package: nil, - dsc_script: nil, dpkg_package: nil, + dsc_script: nil, ips_package: nil, pacman_package: nil, paludis_package: nil, diff --git a/spec/unit/resource_spec.rb b/spec/unit/resource_spec.rb index 1377950c99..b9ba80068b 100644 --- a/spec/unit/resource_spec.rb +++ b/spec/unit/resource_spec.rb @@ -810,21 +810,21 @@ describe Chef::Resource do end it 'adds mappings for a single platform' do - expect(Chef.resource_priority_map).to receive(:set).with( + expect(Chef.resource_handler_map).to receive(:set).with( :dinobot, Chef::Resource::Klz, { platform: ['autobots'] } ) klz.provides :dinobot, platform: ['autobots'] end it 'adds mappings for multiple platforms' do - expect(Chef.resource_priority_map).to receive(:set).with( + expect(Chef.resource_handler_map).to receive(:set).with( :energy, Chef::Resource::Klz, { platform: ['autobots', 'decepticons']} ) klz.provides :energy, platform: ['autobots', 'decepticons'] end it 'adds mappings for all platforms' do - expect(Chef.resource_priority_map).to receive(:set).with( + expect(Chef.resource_handler_map).to receive(:set).with( :tape_deck, Chef::Resource::Klz, {} ) klz.provides :tape_deck |