summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Keiser <john@johnkeiser.com>2015-06-16 16:27:52 -0700
committerJohn Keiser <john@johnkeiser.com>2015-06-18 15:07:48 -0700
commitdb59fd9392a97328df8d7ba7f1c2b1fc03058e76 (patch)
treea5ec9072139c642ffb39d80866512ad0150dfaf5
parent59717769a12768c62aa18270a51b91c820b67010 (diff)
downloadchef-db59fd9392a97328df8d7ba7f1c2b1fc03058e76.tar.gz
Sort identical "provides" alphabetically (for backcompat)
- Warn when multiple providers try to provide the same thing
-rw-r--r--lib/chef/chef_class.rb8
-rw-r--r--lib/chef/node_map.rb101
-rw-r--r--lib/chef/platform/priority_map.rb50
-rw-r--r--lib/chef/platform/provider_mapping.rb4
-rw-r--r--lib/chef/platform/provider_priority_map.rb24
-rw-r--r--lib/chef/platform/resource_priority_map.rb27
-rw-r--r--lib/chef/provider.rb2
-rw-r--r--lib/chef/provider/service/debian.rb2
-rw-r--r--lib/chef/provider/service/insserv.rb2
-rw-r--r--lib/chef/provider/service/invokercd.rb2
-rw-r--r--lib/chef/provider/service/redhat.rb2
-rw-r--r--lib/chef/provider/service/upstart.rb2
-rw-r--r--lib/chef/provider/user.rb2
-rw-r--r--lib/chef/resource.rb2
-rw-r--r--lib/chef/resource/macports_package.rb3
-rw-r--r--lib/chef/resource/package.rb5
-rw-r--r--spec/integration/recipes/recipe_dsl_spec.rb215
-rw-r--r--spec/unit/provider_resolver_spec.rb1
-rw-r--r--spec/unit/recipe_spec.rb16
-rw-r--r--spec/unit/resource_spec.rb6
20 files changed, 337 insertions, 139 deletions
diff --git a/lib/chef/chef_class.rb b/lib/chef/chef_class.rb
index f1dd797c04..a0c74f7aec 100644
--- a/lib/chef/chef_class.rb
+++ b/lib/chef/chef_class.rb
@@ -58,7 +58,7 @@ class Chef
# @return [Array<Class>] Priority Array of Provider Classes to use for the resource_name on the node
#
def get_provider_priority_array(resource_name)
- result = provider_priority_map.get_priority_array(node, resource_name)
+ result = provider_priority_map.get_priority_array(node, resource_name.to_sym)
result = result.dup if result
result
end
@@ -71,7 +71,7 @@ class Chef
# @return [Array<Class>] Priority Array of Resource Classes to use for the resource_name on the node
#
def get_resource_priority_array(resource_name)
- result = resource_priority_map.get_priority_array(node, resource_name)
+ result = resource_priority_map.get_priority_array(node, resource_name.to_sym)
result = result.dup if result
result
end
@@ -86,7 +86,7 @@ class Chef
# @return [Array<Class>] Modified Priority Array of Provider Classes to use for the resource_name on the node
#
def set_provider_priority_array(resource_name, priority_array, *filter, &block)
- result = provider_priority_map.set_priority_array(resource_name, priority_array, *filter, &block)
+ result = provider_priority_map.set_priority_array(resource_name.to_sym, priority_array, *filter, &block)
result = result.dup if result
result
end
@@ -101,7 +101,7 @@ class Chef
# @return [Array<Class>] Modified Priority Array of Resource Classes to use for the resource_name on the node
#
def set_resource_priority_array(resource_name, priority_array, *filter, &block)
- result = resource_priority_map.set_priority_array(resource_name, priority_array, *filter, &block)
+ result = resource_priority_map.set_priority_array(resource_name.to_sym, priority_array, *filter, &block)
result = result.dup if result
result
end
diff --git a/lib/chef/node_map.rb b/lib/chef/node_map.rb
index f547018a38..d5eed7c215 100644
--- a/lib/chef/node_map.rb
+++ b/lib/chef/node_map.rb
@@ -38,30 +38,35 @@ class Chef
#
# @return [NodeMap] Returns self for possible chaining
#
- def set(key, value, platform: nil, platform_version: nil, platform_family: nil, os: nil, on_platform: nil, on_platforms: nil, canonical: nil, &block)
+ def set(key, value, platform: nil, platform_version: nil, platform_family: nil, os: nil, on_platform: nil, on_platforms: nil, canonical: nil, override: nil, &block)
Chef::Log.deprecation "The on_platform option to node_map has been deprecated" if on_platform
Chef::Log.deprecation "The on_platforms option to node_map has been deprecated" if on_platforms
platform ||= on_platform || on_platforms
- filters = { platform: platform, platform_version: platform_version, platform_family: platform_family, os: os }
- new_matcher = { filters: filters, block: block, value: value, canonical: canonical }
- @map[key] ||= []
- # Decide where to insert the matcher; the new value is preferred over
- # anything more specific (see `priority_of`) and is preferred over older
- # values of the same specificity. (So all other things being equal,
- # newest wins.)
+ filters = {}
+ filters[:platform] = platform if platform
+ filters[:platform_version] = platform_version if platform_version
+ filters[:platform_family] = platform_family if platform_family
+ filters[:os] = os if os
+ new_matcher = { value: value, filters: filters }
+ new_matcher[:block] = block if block
+ new_matcher[:canonical] = canonical if canonical
+ new_matcher[:override] = override if override
+
+ # The map is sorted in order of preference already; we just need to find
+ # our place in it (just before the first value with the same preference level).
insert_at = nil
- @map[key].each_with_index do |matcher, index|
- if specificity(new_matcher) >= specificity(matcher)
- insert_at = index
- break
- end
+ @map[key] ||= []
+ @map[key].each_with_index do |matcher,index|
+ cmp = compare_matchers(key, new_matcher, matcher)
+ insert_at ||= index if cmp && cmp <= 0
end
if insert_at
@map[key].insert(insert_at, new_matcher)
else
@map[key] << new_matcher
end
- self
+ insert_at ||= @map[key].size - 1
+ @map
end
#
@@ -116,30 +121,7 @@ class Chef
remaining
end
- private
-
- #
- # Gives a value for "how specific" the matcher is.
- # Things which specify more specific filters get a higher number
- # (platform_version > platform > platform_family > os); things
- # with a block have higher specificity than similar things without
- # a block.
- #
- def specificity(matcher)
- if matcher[:filters][:platform_version]
- specificity = 8
- elsif matcher[:filters][:platform]
- specificity = 6
- elsif matcher[:filters][:platform_family]
- specificity = 4
- elsif matcher[:filters][:os]
- specificity = 2
- else
- specificity = 0
- end
- specificity += 1 if matcher[:block]
- specificity
- end
+ protected
#
# Succeeds if:
@@ -197,5 +179,48 @@ class Chef
return true if canonical.nil?
!!canonical == !!matcher[:canonical]
end
+
+ def compare_matchers(key, new_matcher, matcher)
+ cmp = compare_matcher_properties(new_matcher, matcher) { |m| m[:filters][:block] }
+ return cmp if cmp != 0
+ cmp = compare_matcher_properties(new_matcher, matcher) { |m| m[:filters][:platform_version] }
+ return cmp if cmp != 0
+ cmp = compare_matcher_properties(new_matcher, matcher) { |m| m[:filters][:platform] }
+ return cmp if cmp != 0
+ cmp = compare_matcher_properties(new_matcher, matcher) { |m| m[:filters][:platform_family] }
+ return cmp if cmp != 0
+ cmp = compare_matcher_properties(new_matcher, matcher) { |m| m[:filters][:os] }
+ return cmp if cmp != 0
+ cmp = compare_matcher_properties(new_matcher, matcher) { |m| m[:override] }
+ return cmp if cmp != 0
+ # If all things are identical, return 0
+ 0
+ end
+
+ def compare_matcher_properties(new_matcher, matcher)
+ a = yield(new_matcher)
+ b = yield(matcher)
+
+ # Check for blcacklists ('!windows'). Those always come *after* positive
+ # whitelists.
+ a_negated = Array(a).any? { |f| f.is_a?(String) && f.start_with?('!') }
+ b_negated = Array(b).any? { |f| f.is_a?(String) && f.start_with?('!') }
+ if a_negated != b_negated
+ return 1 if a_negated
+ return -1 if b_negated
+ end
+
+ # We treat false / true and nil / not-nil with the same comparison
+ a = nil if a == false
+ b = nil if b == false
+ cmp = a <=> b
+ # This is the case where one is non-nil, and one is nil. The one that is
+ # nil is "greater" (i.e. it should come last).
+ if cmp.nil?
+ return 1 if a.nil?
+ return -1 if b.nil?
+ end
+ cmp
+ end
end
end
diff --git a/lib/chef/platform/priority_map.rb b/lib/chef/platform/priority_map.rb
new file mode 100644
index 0000000000..3608975b51
--- /dev/null
+++ b/lib/chef/platform/priority_map.rb
@@ -0,0 +1,50 @@
+require 'chef/node_map'
+
+class Chef
+ class Platform
+ class PriorityMap < Chef::NodeMap
+ # @api private
+ def get_priority_array(node, key)
+ get(node, key)
+ end
+
+ # @api private
+ def set_priority_array(key, priority_array, *filter, &block)
+ priority_array = Array(priority_array)
+ set(key, priority_array, *filter, &block)
+ priority_array
+ end
+
+ # @api private
+ def list_handlers(node, key, **filters)
+ list(node, key, **filters).flatten(1).uniq
+ end
+
+ #
+ # Priority maps have one extra precedence: priority arrays override "provides,"
+ # and "provides" lines with identical filters sort by class name (ascending).
+ #
+ def compare_matchers(key, new_matcher, matcher)
+ # Priority arrays come before "provides"
+ if new_matcher[:value].is_a?(Array) != matcher[:value].is_a?(Array)
+ return new_matcher[:value].is_a?(Array) ? -1 : 1
+ end
+
+ cmp = super
+ if cmp == 0
+ # Sort by class name (ascending) as well, if all other properties
+ # are exactly equal
+ if new_matcher[:value].is_a?(Class) && !new_matcher[:override]
+ cmp = compare_matcher_properties(new_matcher, matcher) { |m| m[:value].name }
+ if cmp < 0
+ Chef::Log.warn "You are overriding #{key} on #{new_matcher[:filters].inspect} with #{new_matcher[:value].inspect}: used to be #{matcher[:value].inspect}. Use override: true if this is what you intended."
+ elsif cmp > 0
+ Chef::Log.warn "You declared a new resource #{new_matcher[:value].inspect} for resource #{key}, but it comes alphabetically after #{matcher[:value].inspect} and has the same filters (#{new_matcher[:filters].inspect}), so it will not be used. Use override: true if you want to use it for #{key}."
+ end
+ end
+ end
+ cmp
+ end
+ end
+ end
+end
diff --git a/lib/chef/platform/provider_mapping.rb b/lib/chef/platform/provider_mapping.rb
index e3a894c8ac..af17d8e1b4 100644
--- a/lib/chef/platform/provider_mapping.rb
+++ b/lib/chef/platform/provider_mapping.rb
@@ -201,8 +201,8 @@ class Chef
begin
result = Chef::Provider.const_get(class_name)
- Chef::Log.warn("Class Chef::Provider::#{class_name} does not declare 'provides #{convert_to_snake_case(class_name).to_sym.inspect}'.")
- Chef::Log.warn("This will no longer work in Chef 13: you must use 'provides' to provide DSL.")
+ Chef::Log.warn("Class Chef::Provider::#{class_name} does not declare 'resource_name #{convert_to_snake_case(class_name).to_sym.inspect}'.")
+ Chef::Log.warn("This will no longer work in Chef 13: you must use 'resource_name' to provide DSL.")
rescue NameError
end
end
diff --git a/lib/chef/platform/provider_priority_map.rb b/lib/chef/platform/provider_priority_map.rb
index 9d703c9178..5599c74c2d 100644
--- a/lib/chef/platform/provider_priority_map.rb
+++ b/lib/chef/platform/provider_priority_map.rb
@@ -1,29 +1,11 @@
require 'singleton'
+require 'chef/platform/priority_map'
class Chef
class Platform
- class ProviderPriorityMap
+ # @api private
+ class ProviderPriorityMap < Chef::Platform::PriorityMap
include Singleton
-
- def get_priority_array(node, resource_name)
- priority_map.get(node, resource_name.to_sym)
- end
-
- def set_priority_array(resource_name, priority_array, *filter, &block)
- priority_map.set(resource_name.to_sym, Array(priority_array), *filter, &block)
- end
-
- # @api private
- def list_handlers(node, resource_name)
- priority_map.list(node, resource_name.to_sym).flatten(1).uniq
- end
-
- private
-
- def priority_map
- require 'chef/node_map'
- @priority_map ||= Chef::NodeMap.new
- end
end
end
end
diff --git a/lib/chef/platform/resource_priority_map.rb b/lib/chef/platform/resource_priority_map.rb
index fb08debc53..aa57e3ddf0 100644
--- a/lib/chef/platform/resource_priority_map.rb
+++ b/lib/chef/platform/resource_priority_map.rb
@@ -1,34 +1,17 @@
require 'singleton'
+require 'chef/platform/priority_map'
class Chef
class Platform
- class ResourcePriorityMap
+ # @api private
+ class ResourcePriorityMap < Chef::Platform::PriorityMap
include Singleton
- def get_priority_array(node, resource_name, canonical: nil)
- priority_map.get(node, resource_name.to_sym, canonical: canonical)
- end
-
- def set_priority_array(resource_name, priority_array, *filter, &block)
- priority_map.set(resource_name.to_sym, Array(priority_array), *filter, &block)
- end
-
# @api private
- def delete_canonical(resource_name, resource_class)
- priority_map.delete_canonical(resource_name, resource_class)
- end
-
- # @api private
- def list_handlers(*args)
- priority_map.list(*args).flatten(1).uniq
+ def get_priority_array(node, resource_name, canonical: nil)
+ super(node, resource_name.to_sym, canonical: canonical)
end
- private
-
- def priority_map
- require 'chef/node_map'
- @priority_map ||= Chef::NodeMap.new
- end
end
end
end
diff --git a/lib/chef/provider.rb b/lib/chef/provider.rb
index e50e374804..131b72cd23 100644
--- a/lib/chef/provider.rb
+++ b/lib/chef/provider.rb
@@ -176,7 +176,7 @@ class Chef
end
def self.provides(short_name, opts={}, &block)
- Chef.set_provider_priority_array(short_name, self, opts, &block)
+ Chef.provider_priority_map.set(short_name, self, opts, &block)
end
def self.provides?(node, resource)
diff --git a/lib/chef/provider/service/debian.rb b/lib/chef/provider/service/debian.rb
index 01505924cb..c67f3f05da 100644
--- a/lib/chef/provider/service/debian.rb
+++ b/lib/chef/provider/service/debian.rb
@@ -25,8 +25,6 @@ class Chef
UPDATE_RC_D_ENABLED_MATCHES = /\/rc[\dS].d\/S|not installed/i
UPDATE_RC_D_PRIORITIES = /\/rc([\dS]).d\/([SK])(\d\d)/i
- provides :service, platform_family: "debian"
-
def self.provides?(node, resource)
super && Chef::Platform::ServiceHelpers.service_resource_providers.include?(:debian)
end
diff --git a/lib/chef/provider/service/insserv.rb b/lib/chef/provider/service/insserv.rb
index 31965a4bc6..4534e33f32 100644
--- a/lib/chef/provider/service/insserv.rb
+++ b/lib/chef/provider/service/insserv.rb
@@ -24,8 +24,6 @@ class Chef
class Service
class Insserv < Chef::Provider::Service::Init
- provides :service, os: "linux"
-
def self.provides?(node, resource)
super && Chef::Platform::ServiceHelpers.service_resource_providers.include?(:insserv)
end
diff --git a/lib/chef/provider/service/invokercd.rb b/lib/chef/provider/service/invokercd.rb
index 5ff24e0dbb..fdf4cbc256 100644
--- a/lib/chef/provider/service/invokercd.rb
+++ b/lib/chef/provider/service/invokercd.rb
@@ -23,8 +23,6 @@ class Chef
class Service
class Invokercd < Chef::Provider::Service::Init
- provides :service, platform_family: "debian"
-
def self.provides?(node, resource)
super && Chef::Platform::ServiceHelpers.service_resource_providers.include?(:invokercd)
end
diff --git a/lib/chef/provider/service/redhat.rb b/lib/chef/provider/service/redhat.rb
index 850953125e..a8deb13aec 100644
--- a/lib/chef/provider/service/redhat.rb
+++ b/lib/chef/provider/service/redhat.rb
@@ -26,8 +26,6 @@ class Chef
CHKCONFIG_ON = /\d:on/
CHKCONFIG_MISSING = /No such/
- provides :service, platform_family: [ "rhel", "fedora", "suse" ]
-
def self.provides?(node, resource)
super && Chef::Platform::ServiceHelpers.service_resource_providers.include?(:redhat)
end
diff --git a/lib/chef/provider/service/upstart.rb b/lib/chef/provider/service/upstart.rb
index 8d4aa41035..d8ce6af649 100644
--- a/lib/chef/provider/service/upstart.rb
+++ b/lib/chef/provider/service/upstart.rb
@@ -27,8 +27,6 @@ class Chef
class Upstart < Chef::Provider::Service::Simple
UPSTART_STATE_FORMAT = /\w+ \(?(\w+)\)?[\/ ](\w+)/
- provides :service, os: "linux"
-
def self.provides?(node, resource)
super && Chef::Platform::ServiceHelpers.service_resource_providers.include?(:upstart)
end
diff --git a/lib/chef/provider/user.rb b/lib/chef/provider/user.rb
index ad92a72a0a..244b11db98 100644
--- a/lib/chef/provider/user.rb
+++ b/lib/chef/provider/user.rb
@@ -23,8 +23,6 @@ require 'etc'
class Chef
class Provider
class User < Chef::Provider
- provides :user
-
include Chef::Mixin::Command
attr_accessor :user_exists, :locked
diff --git a/lib/chef/resource.rb b/lib/chef/resource.rb
index 10ad184506..418b0dc1ce 100644
--- a/lib/chef/resource.rb
+++ b/lib/chef/resource.rb
@@ -1143,7 +1143,7 @@ class Chef
remove_canonical_dsl
end
- result = Chef.set_resource_priority_array(name, self, options, &block)
+ result = Chef.resource_priority_map.set(name, self, options, &block)
Chef::DSL::Resources.add_resource_dsl(name)
result
end
diff --git a/lib/chef/resource/macports_package.rb b/lib/chef/resource/macports_package.rb
index 937839b6e1..5843016897 100644
--- a/lib/chef/resource/macports_package.rb
+++ b/lib/chef/resource/macports_package.rb
@@ -16,10 +16,11 @@
# limitations under the License.
#
+require 'chef/resource/package'
+
class Chef
class Resource
class MacportsPackage < Chef::Resource::Package
- provides :package, os: "darwin"
end
end
end
diff --git a/lib/chef/resource/package.rb b/lib/chef/resource/package.rb
index 1c6da75678..5be1c34b89 100644
--- a/lib/chef/resource/package.rb
+++ b/lib/chef/resource/package.rb
@@ -100,8 +100,3 @@ class Chef
end
end
end
-
-require 'chef/chef_class'
-require 'chef/resource/homebrew_package'
-
-Chef.set_resource_priority_array :package, Chef::Resource::HomebrewPackage, os: "darwin"
diff --git a/spec/integration/recipes/recipe_dsl_spec.rb b/spec/integration/recipes/recipe_dsl_spec.rb
index 03df3e7bb3..6bbb9a5c4c 100644
--- a/spec/integration/recipes/recipe_dsl_spec.rb
+++ b/spec/integration/recipes/recipe_dsl_spec.rb
@@ -91,7 +91,7 @@ describe "Recipe DSL methods" do
recipe = converge {
backcompat_thingy 'blah' do; end
}
- expect(recipe.logged_warnings).to eq ''
+ expect(recipe.logged_warnings).to match(/Class Chef::Provider::BackcompatThingy does not declare 'resource_name :backcompat_thingy'./)
expect(BaseThingy.created_resource).not_to be_nil
end
end
@@ -423,7 +423,7 @@ describe "Recipe DSL methods" do
end
EOM
}
- it "two_classes_one_dsl resolves to BlahModule::TwoClassesOneDsl (last declared)" do
+ it "two_classes_one_dsl resolves to BlahModule::TwoClassesOneDsl (alphabetical)" do
dsl_method = self.dsl_method
recipe = converge {
instance_eval("#{dsl_method} 'blah' do; end")
@@ -566,11 +566,11 @@ describe "Recipe DSL methods" do
}
- it "thingy3 works in a recipe and yields Foo::Thingy4 (the explicit one)" do
+ it "thingy3 works in a recipe and yields Thingy3 (the alphabetical one)" do
recipe = converge {
thingy3 'blah' do; end
}
- expect(BaseThingy.created_resource).to eq RecipeDSLSpecNamespace::Thingy4
+ expect(BaseThingy.created_resource).to eq RecipeDSLSpecNamespace::Thingy3
end
it "thingy4 does not work in a recipe" do
@@ -580,16 +580,19 @@ describe "Recipe DSL methods" do
end
it "resource_matching_short_name returns Thingy4" do
- expect(Chef::Resource.resource_matching_short_name(:thingy3)).to eq RecipeDSLSpecNamespace::Thingy4
+ expect(Chef::Resource.resource_matching_short_name(:thingy3)).to eq RecipeDSLSpecNamespace::Thingy3
end
end
end
- context "when Thingy5 has resource_name :thingy5" do
+ context "when Thingy5 has resource_name :thingy5 and provides :thingy5reverse, :thingy5_2 and :thingy5_2reverse" do
before(:context) {
class RecipeDSLSpecNamespace::Thingy5 < BaseThingy
resource_name :thingy5
+ provides :thingy5reverse
+ provides :thingy5_2
+ provides :thingy5_2reverse
end
}
@@ -618,17 +621,144 @@ describe "Recipe DSL methods" do
expect(BaseThingy.created_resource).to eq RecipeDSLSpecNamespace::Thingy6
end
- it "thingy5 works in a recipe and yields Foo::Thingy6 (the later one)" do
+ it "thingy5 works in a recipe and yields Foo::Thingy5 (the alphabetical one)" do
recipe = converge {
thingy5 'blah' do; end
}
- expect(BaseThingy.created_resource).to eq RecipeDSLSpecNamespace::Thingy6
+ expect(BaseThingy.created_resource).to eq RecipeDSLSpecNamespace::Thingy5
end
it "resource_matching_short_name returns Thingy5" do
expect(Chef::Resource.resource_matching_short_name(:thingy5)).to eq RecipeDSLSpecNamespace::Thingy5
end
+
+ context "and AThingy5 provides :thingy5reverse" do
+ before(:context) {
+
+ class RecipeDSLSpecNamespace::AThingy5 < BaseThingy
+ resource_name :thingy5reverse
+ end
+
+ }
+
+ it "thingy5reverse works in a recipe and yields AThingy5 (the alphabetical one)" do
+ recipe = converge {
+ thingy5reverse 'blah' do; end
+ }
+ expect(BaseThingy.created_resource).to eq RecipeDSLSpecNamespace::AThingy5
+ end
+ end
+
+ context "and ZRecipeDSLSpecNamespace::Thingy5 provides :thingy5_2" do
+ before(:context) {
+
+ module ZRecipeDSLSpecNamespace
+ class Thingy5 < BaseThingy
+ resource_name :thingy5_2
+ end
+ end
+
+ }
+
+ it "thingy5_2 works in a recipe and yields the RecipeDSLSpaceNamespace one (the alphabetical one)" do
+ recipe = converge {
+ thingy5_2 'blah' do; end
+ }
+ expect(BaseThingy.created_resource).to eq RecipeDSLSpecNamespace::Thingy5
+ end
+ end
+
+ context "and ARecipeDSLSpecNamespace::Thingy5 provides :thingy5_2" do
+ before(:context) {
+
+ module ARecipeDSLSpecNamespace
+ class Thingy5 < BaseThingy
+ resource_name :thingy5_2reverse
+ end
+ end
+
+ }
+
+ it "thingy5_2reverse works in a recipe and yields the ARecipeDSLSpaceNamespace one (the alphabetical one)" do
+ recipe = converge {
+ thingy5_2reverse 'blah' do; end
+ }
+ expect(BaseThingy.created_resource).to eq ARecipeDSLSpecNamespace::Thingy5
+ end
+ end
end
+
+ context "when Thingy3 has resource_name :thingy3" do
+ before(:context) {
+
+ class RecipeDSLSpecNamespace::Thingy3 < BaseThingy
+ resource_name :thingy3
+ end
+
+ }
+
+ it "thingy3 works in a recipe" do
+ expect_recipe {
+ thingy3 'blah' do; end
+ }.to emit_no_warnings_or_errors
+ expect(BaseThingy.created_resource).to eq RecipeDSLSpecNamespace::Thingy3
+ end
+
+ context "and Thingy4 has resource_name :thingy3" do
+ before(:context) {
+
+ class RecipeDSLSpecNamespace::Thingy4 < BaseThingy
+ resource_name :thingy3
+ end
+
+ }
+
+ it "thingy3 works in a recipe and yields Thingy3 (the alphabetical one)" do
+ recipe = converge {
+ thingy3 'blah' do; end
+ }
+ expect(BaseThingy.created_resource).to eq RecipeDSLSpecNamespace::Thingy3
+ end
+
+ it "thingy4 does not work in a recipe" do
+ expect_converge {
+ thingy4 'blah' do; end
+ }.to raise_error(NoMethodError)
+ end
+
+ it "resource_matching_short_name returns Thingy4" do
+ expect(Chef::Resource.resource_matching_short_name(:thingy3)).to eq RecipeDSLSpecNamespace::Thingy3
+ end
+ end
+
+ context "and Thingy4 has resource_name :thingy3" do
+ before(:context) {
+
+ class RecipeDSLSpecNamespace::Thingy4 < BaseThingy
+ resource_name :thingy3
+ end
+
+ }
+
+ it "thingy3 works in a recipe and yields Thingy3 (the alphabetical one)" do
+ recipe = converge {
+ thingy3 'blah' do; end
+ }
+ expect(BaseThingy.created_resource).to eq RecipeDSLSpecNamespace::Thingy3
+ end
+
+ it "thingy4 does not work in a recipe" do
+ expect_converge {
+ thingy4 'blah' do; end
+ }.to raise_error(NoMethodError)
+ end
+
+ it "resource_matching_short_name returns Thingy4" do
+ expect(Chef::Resource.resource_matching_short_name(:thingy3)).to eq RecipeDSLSpecNamespace::Thingy3
+ end
+ end
+ end
+
end
context "when Thingy7 provides :thingy8" do
@@ -657,11 +787,11 @@ describe "Recipe DSL methods" do
expect(BaseThingy.created_resource).to eq RecipeDSLSpecNamespace::Thingy7
end
- it "thingy8 works in a recipe and yields Thingy8 (the later one)" do
+ it "thingy8 works in a recipe and yields Thingy7 (alphabetical)" do
recipe = converge {
thingy8 'blah' do; end
}
- expect(BaseThingy.created_resource).to eq RecipeDSLSpecNamespace::Thingy8
+ expect(BaseThingy.created_resource).to eq RecipeDSLSpecNamespace::Thingy7
end
it "resource_matching_short_name returns Thingy8" do
@@ -670,36 +800,36 @@ describe "Recipe DSL methods" do
end
end
- context "when Thingy5 provides :thingy5, :twizzle and :twizzle2" do
+ context "when Thingy12 provides :thingy12, :twizzle and :twizzle2" do
before(:context) {
- class RecipeDSLSpecNamespace::Thingy5 < BaseThingy
- resource_name :thingy5
+ class RecipeDSLSpecNamespace::Thingy12 < BaseThingy
+ resource_name :thingy12
provides :twizzle
provides :twizzle2
end
}
- it "thingy5 works in a recipe and yields Thingy5" do
+ it "thingy12 works in a recipe and yields Thingy12" do
expect_recipe {
- thingy5 'blah' do; end
+ thingy12 'blah' do; end
}.to emit_no_warnings_or_errors
- expect(BaseThingy.created_resource).to eq RecipeDSLSpecNamespace::Thingy5
+ expect(BaseThingy.created_resource).to eq RecipeDSLSpecNamespace::Thingy12
end
- it "twizzle works in a recipe and yields Thingy5" do
+ it "twizzle works in a recipe and yields Thingy12" do
expect_recipe {
twizzle 'blah' do; end
}.to emit_no_warnings_or_errors
- expect(BaseThingy.created_resource).to eq RecipeDSLSpecNamespace::Thingy5
+ expect(BaseThingy.created_resource).to eq RecipeDSLSpecNamespace::Thingy12
end
- it "twizzle2 works in a recipe and yields Thingy5" do
+ it "twizzle2 works in a recipe and yields Thingy12" do
expect_recipe {
twizzle2 'blah' do; end
}.to emit_no_warnings_or_errors
- expect(BaseThingy.created_resource).to eq RecipeDSLSpecNamespace::Thingy5
+ expect(BaseThingy.created_resource).to eq RecipeDSLSpecNamespace::Thingy12
end
end
@@ -748,6 +878,51 @@ describe "Recipe DSL methods" do
}.to raise_error(Chef::Exceptions::NoSuchResourceType)
end
end
+
+ context "when Thingy9 provides :thingy9" do
+ before(:context) {
+ class RecipeDSLSpecNamespace::Thingy9 < BaseThingy
+ resource_name :thingy9
+ end
+ }
+
+ it "declaring a resource providing the same :thingy9 produces a warning" do
+ expect(Chef::Log).to receive(:warn).with("You declared a new resource RecipeDSLSpecNamespace::Thingy9AlternateProvider for resource thingy9, but it comes alphabetically after RecipeDSLSpecNamespace::Thingy9 and has the same filters ({}), so it will not be used. Use override: true if you want to use it for thingy9.")
+ class RecipeDSLSpecNamespace::Thingy9AlternateProvider < BaseThingy
+ resource_name :thingy9
+ end
+ end
+ end
+
+ context "when Thingy10 provides :thingy10" do
+ before(:context) {
+ class RecipeDSLSpecNamespace::Thingy10 < BaseThingy
+ resource_name :thingy10
+ end
+ }
+
+ it "declaring a resource providing the same :thingy10 with override: true does not produce a warning" do
+ expect(Chef::Log).not_to receive(:warn)
+ class RecipeDSLSpecNamespace::Thingy10AlternateProvider < BaseThingy
+ provides :thingy10, override: true
+ end
+ end
+ end
+
+ context "when Thingy11 provides :thingy11" do
+ before(:context) {
+ class RecipeDSLSpecNamespace::Thingy11 < BaseThingy
+ resource_name :thingy10
+ end
+ }
+
+ it "declaring a resource providing the same :thingy11 with os: 'linux' does not produce a warning" do
+ expect(Chef::Log).not_to receive(:warn)
+ class RecipeDSLSpecNamespace::Thingy11AlternateProvider < BaseThingy
+ provides :thingy11, os: 'linux'
+ end
+ end
+ end
end
end
diff --git a/spec/unit/provider_resolver_spec.rb b/spec/unit/provider_resolver_spec.rb
index e18d69bc19..cd3d7713a7 100644
--- a/spec/unit/provider_resolver_spec.rb
+++ b/spec/unit/provider_resolver_spec.rb
@@ -482,7 +482,6 @@ describe Chef::ProviderResolver do
python: Chef::Provider::Script,
remote_directory: Chef::Provider::RemoteDirectory,
route: Chef::Provider::Route,
- rpm_package: Chef::Provider::Package::Rpm,
ruby: Chef::Provider::Script,
ruby_block: Chef::Provider::RubyBlock,
script: Chef::Provider::Script,
diff --git a/spec/unit/recipe_spec.rb b/spec/unit/recipe_spec.rb
index 7579abf227..17ea498fe3 100644
--- a/spec/unit/recipe_spec.rb
+++ b/spec/unit/recipe_spec.rb
@@ -153,24 +153,24 @@ describe Chef::Recipe do
Object.send(:remove_const, :TottenhamHotspur)
end
- it "selects one if it is the last declared" do
- expect(Chef::Log).not_to receive(:warn)
+ it "selects the first one alphabetically" do
+ expect(Chef::Log).to receive(:warn).with("You declared a new resource TottenhamHotspur for resource football, but it comes alphabetically after Sounders and has the same filters ({:platform=>\"nbc_sports\"}), so it will not be used. Use override: true if you want to use it for football.")
Sounders.provides :football, platform: "nbc_sports"
TottenhamHotspur.provides :football, platform: "nbc_sports"
res1 = recipe.football "club world cup"
expect(res1.name).to eql("club world cup")
- expect(res1).to be_a_kind_of(TottenhamHotspur)
+ expect(res1).to be_a_kind_of(Sounders)
end
- it "selects the other one if it is given priority" do
- expect(Chef::Log).not_to receive(:warn)
+ it "selects the first one alphabetically even if the declaration order is reversed" do
+ expect(Chef::Log).to receive(:warn).with("You are overriding football2 on {:platform=>\"nbc_sports\"} with Sounders: used to be TottenhamHotspur. Use override: true if this is what you intended.")
- TottenhamHotspur.provides :football, platform: "nbc_sports"
- Sounders.provides :football, platform: "nbc_sports"
+ TottenhamHotspur.provides :football2, platform: "nbc_sports"
+ Sounders.provides :football2, platform: "nbc_sports"
- res1 = recipe.football "club world cup"
+ res1 = recipe.football2 "club world cup"
expect(res1.name).to eql("club world cup")
expect(res1).to be_a_kind_of(Sounders)
end
diff --git a/spec/unit/resource_spec.rb b/spec/unit/resource_spec.rb
index 87f7f8d929..8b0baff921 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).to receive(:set_resource_priority_array).with(
+ expect(Chef.resource_priority_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).to receive(:set_resource_priority_array).with(
+ expect(Chef.resource_priority_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).to receive(:set_resource_priority_array).with(
+ expect(Chef.resource_priority_map).to receive(:set).with(
:tape_deck, Chef::Resource::Klz, {}
)
klz.provides :tape_deck