summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Keiser <john@johnkeiser.com>2015-06-30 11:35:33 -0600
committerJohn Keiser <john@johnkeiser.com>2015-06-30 11:35:33 -0600
commit480d18f26f17c289889ed65d3f8a50e5b336053f (patch)
tree4aa5d541a6a2f06c84ac6be9f742e8d1e8477687
parentf0e9b2ffe7ec0904456b50ee26913cb42c0ca258 (diff)
parente1e1e1331a4e87c662dae72acdeff00230e74a3c (diff)
downloadchef-480d18f26f17c289889ed65d3f8a50e5b336053f.tar.gz
Merge branch 'jk/call_provides_when_resolving'
-rw-r--r--lib/chef/exceptions.rb4
-rw-r--r--lib/chef/node_map.rb30
-rw-r--r--lib/chef/platform/priority_map.rb8
-rw-r--r--lib/chef/platform/provider_mapping.rb4
-rw-r--r--lib/chef/provider/dsc_resource.rb4
-rw-r--r--lib/chef/provider/dsc_script.rb2
-rw-r--r--lib/chef/provider/mount/aix.rb2
-rw-r--r--lib/chef/provider/package/openbsd.rb1
-rw-r--r--lib/chef/provider_resolver.rb100
-rw-r--r--lib/chef/resource.rb8
-rw-r--r--lib/chef/resource/dsc_script.rb2
-rw-r--r--lib/chef/resource/ips_package.rb1
-rw-r--r--lib/chef/resource/mount.rb8
-rw-r--r--lib/chef/resource/openbsd_package.rb11
-rw-r--r--lib/chef/resource/solaris_package.rb5
-rw-r--r--lib/chef/resource_resolver.rb69
-rw-r--r--spec/functional/resource/package_spec.rb2
-rw-r--r--spec/integration/recipes/recipe_dsl_spec.rb429
-rw-r--r--spec/spec_helper.rb32
-rw-r--r--spec/unit/platform_spec.rb2
-rw-r--r--spec/unit/provider/dsc_resource_spec.rb6
-rw-r--r--spec/unit/provider/dsc_script_spec.rb4
-rw-r--r--spec/unit/provider_resolver_spec.rb302
-rw-r--r--spec/unit/resource_resolver_spec.rb12
24 files changed, 676 insertions, 372 deletions
diff --git a/lib/chef/exceptions.rb b/lib/chef/exceptions.rb
index dd0bac3cf9..1b726d654c 100644
--- a/lib/chef/exceptions.rb
+++ b/lib/chef/exceptions.rb
@@ -97,6 +97,8 @@ class Chef
class ConflictingMembersInGroup < ArgumentError; end
class InvalidResourceReference < RuntimeError; end
class ResourceNotFound < RuntimeError; end
+ class ProviderNotFound < RuntimeError; end
+ NoProviderAvailable = ProviderNotFound
class VerificationNotFound < RuntimeError; end
# Can't find a Resource of this type that is valid on this platform.
@@ -218,8 +220,6 @@ class Chef
class ChildConvergeError < RuntimeError; end
- class NoProviderAvailable < RuntimeError; end
-
class DeprecatedFeatureError < RuntimeError;
def initalize(message)
super("#{message} (raising error due to treat_deprecation_warnings_as_errors being set)")
diff --git a/lib/chef/node_map.rb b/lib/chef/node_map.rb
index edf0fd689a..d905c8779e 100644
--- a/lib/chef/node_map.rb
+++ b/lib/chef/node_map.rb
@@ -20,13 +20,6 @@ class Chef
class NodeMap
#
- # Create a new NodeMap
- #
- def initialize
- @map = {}
- end
-
- #
# Set a key/value pair on the map with a filter. The filter must be true
# when applied to the node in order to retrieve the value.
#
@@ -55,18 +48,17 @@ class Chef
# 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] ||= []
- @map[key].each_with_index do |matcher,index|
+ 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)
+ map[key].insert(insert_at, new_matcher)
else
- @map[key] << new_matcher
+ map[key] << new_matcher
end
- insert_at ||= @map[key].size - 1
- @map
+ map
end
#
@@ -100,8 +92,8 @@ class Chef
#
def list(node, key, canonical: nil)
raise ArgumentError, "first argument must be a Chef::Node" unless node.is_a?(Chef::Node) || node.nil?
- return [] unless @map.has_key?(key)
- @map[key].select do |matcher|
+ return [] unless map.has_key?(key)
+ map[key].select do |matcher|
node_matches?(node, matcher) && canonical_matches?(canonical, matcher)
end.map { |matcher| matcher[:value] }
end
@@ -110,11 +102,11 @@ class Chef
# @return remaining
# @api private
def delete_canonical(key, value)
- remaining = @map[key]
+ remaining = map[key]
if remaining
remaining.delete_if { |matcher| matcher[:canonical] && Array(matcher[:value]) == Array(value) }
if remaining.empty?
- @map.delete(key)
+ map.delete(key)
remaining = nil
end
end
@@ -222,5 +214,9 @@ class Chef
end
cmp
end
+
+ def map
+ @map ||= {}
+ end
end
end
diff --git a/lib/chef/platform/priority_map.rb b/lib/chef/platform/priority_map.rb
index d559eece78..73554eafe1 100644
--- a/lib/chef/platform/priority_map.rb
+++ b/lib/chef/platform/priority_map.rb
@@ -6,7 +6,7 @@ class Chef
def priority(resource_name, priority_array, *filter)
set_priority_array(resource_name.to_sym, priority_array, *filter)
end
-
+
# @api private
def get_priority_array(node, key)
get(node, key)
@@ -24,6 +24,12 @@ class Chef
list(node, key, **filters).flatten(1).uniq
end
+ # @api private
+ def includes_handler?(key, handler)
+ return false if !map.has_key?(key)
+ map[key].any? { |m| h = m[:value]; h.is_a?(Array) ? h.include?(handler) : h == handler }
+ end
+
#
# Priority maps have one extra precedence: priority arrays override "provides,"
# and "provides" lines with identical filters sort by class name (ascending).
diff --git a/lib/chef/platform/provider_mapping.rb b/lib/chef/platform/provider_mapping.rb
index 4278b8d24f..38dd0e38af 100644
--- a/lib/chef/platform/provider_mapping.rb
+++ b/lib/chef/platform/provider_mapping.rb
@@ -176,7 +176,7 @@ class Chef
platform_provider(platform, version, resource_type) ||
resource_matching_provider(platform, version, resource_type)
- raise ArgumentError, "Cannot find a provider for #{resource_type} on #{platform} version #{version}" if provider_klass.nil?
+ raise Chef::Exceptions::ProviderNotFound, "Cannot find a provider for #{resource_type} on #{platform} version #{version}" if provider_klass.nil?
provider_klass
end
@@ -197,7 +197,7 @@ class Chef
def resource_matching_provider(platform, version, resource_type)
if resource_type.kind_of?(Chef::Resource)
- class_name = resource_type.class.name ? resource_type.class.name.split('::').last :
+ class_name = resource_type.class.name ? resource_type.class.name.split('::').last :
convert_to_class_name(resource_type.resource_name.to_s)
begin
diff --git a/lib/chef/provider/dsc_resource.rb b/lib/chef/provider/dsc_resource.rb
index 5fa84a21e9..379369ba6e 100644
--- a/lib/chef/provider/dsc_resource.rb
+++ b/lib/chef/provider/dsc_resource.rb
@@ -53,7 +53,7 @@ class Chef
requirements.assert(:run) do |a|
a.assertion { supports_dsc_invoke_resource? }
err = ["You must have Powershell version >= 5.0.10018.0 to use dsc_resource."]
- a.failure_message Chef::Exceptions::NoProviderAvailable,
+ a.failure_message Chef::Exceptions::ProviderNotFound,
err
a.whyrun err + ["Assuming a previous resource installs Powershell 5.0.10018.0 or higher."]
a.block_action!
@@ -63,7 +63,7 @@ class Chef
meta_configuration['RefreshMode'] == 'Disabled'
}
err = ["The LCM must have its RefreshMode set to Disabled. "]
- a.failure_message Chef::Exceptions::NoProviderAvailable, err.join(' ')
+ a.failure_message Chef::Exceptions::ProviderNotFound, err.join(' ')
a.whyrun err + ["Assuming a previous resource sets the RefreshMode."]
a.block_action!
end
diff --git a/lib/chef/provider/dsc_script.rb b/lib/chef/provider/dsc_script.rb
index a75e68a475..b2432132b7 100644
--- a/lib/chef/provider/dsc_script.rb
+++ b/lib/chef/provider/dsc_script.rb
@@ -70,7 +70,7 @@ class Chef
"Powershell 4.0 or higher was not detected on your system and is required to use the dsc_script resource.",
]
a.assertion { supports_dsc? }
- a.failure_message Chef::Exceptions::NoProviderAvailable, err.join(' ')
+ a.failure_message Chef::Exceptions::ProviderNotFound, err.join(' ')
a.whyrun err + ["Assuming a previous resource installs Powershell 4.0 or higher."]
a.block_action!
end
diff --git a/lib/chef/provider/mount/aix.rb b/lib/chef/provider/mount/aix.rb
index 4ad7b24c15..510dfde46d 100644
--- a/lib/chef/provider/mount/aix.rb
+++ b/lib/chef/provider/mount/aix.rb
@@ -32,7 +32,7 @@ class Chef
@new_resource.options.clear
end
if @new_resource.fstype == "auto"
- @new_resource.fstype = nil
+ @new_resource.send(:clear_fstype)
end
end
diff --git a/lib/chef/provider/package/openbsd.rb b/lib/chef/provider/package/openbsd.rb
index f231101390..83fc09c8ae 100644
--- a/lib/chef/provider/package/openbsd.rb
+++ b/lib/chef/provider/package/openbsd.rb
@@ -31,6 +31,7 @@ class Chef
class Openbsd < Chef::Provider::Package
provides :package, os: "openbsd"
+ provides :openbsd_package
include Chef::Mixin::ShellOut
include Chef::Mixin::GetSourceFromPackage
diff --git a/lib/chef/provider_resolver.rb b/lib/chef/provider_resolver.rb
index 5bfee343d1..8e731ff96a 100644
--- a/lib/chef/provider_resolver.rb
+++ b/lib/chef/provider_resolver.rb
@@ -17,7 +17,7 @@
#
require 'chef/exceptions'
-require 'chef/platform/provider_priority_map'
+require 'chef/platform/priority_map'
class Chef
#
@@ -62,12 +62,35 @@ class Chef
maybe_chef_platform_lookup(resource)
end
+ # Does NOT call provides? on the resource (it is assumed this is being
+ # called *from* provides?).
def provided_by?(provider_class)
- prioritized_handlers.include?(provider_class)
+ potential_handlers.include?(provider_class)
+ end
+
+ def self.includes_handler?(resource_name, provider_class)
+ priority_map.includes_handler?(resource_name, provider_class)
+ end
+
+ def enabled_handlers
+ @enabled_handlers ||=
+ potential_handlers.select { |handler| !overrode_provides?(handler) || handler.provides?(node, resource) }
+ end
+
+ # TODO deprecate this and allow actions to be passed as a filter to
+ # `provides` so we don't have to have two separate things.
+ # @api private
+ def supported_handlers
+ @supported_handlers ||=
+ enabled_handlers.select { |handler| handler.supports?(resource, action) }
end
private
+ def potential_handlers
+ priority_map.list_handlers(node, resource.resource_name)
+ end
+
# if resource.provider is set, just return one of those objects
def maybe_explicit_provider(resource)
return nil unless resource.provider
@@ -78,28 +101,16 @@ class Chef
def maybe_dynamic_provider_resolution(resource, action)
Chef::Log.debug "Providers for generic #{resource.resource_name} resource enabled on node include: #{enabled_handlers}"
- # Get all the handlers in the priority bucket
- handlers = prioritized_handlers
-
- # Narrow it down to handlers that return `true` to `provides?`
- # TODO deprecate this and don't bother calling--the fact that they said
- # `provides` should be enough. But we need to do it right now because
- # some classes implement additional handling.
- enabled_handlers = prioritized_handlers.select { |handler| handler.provides?(node, resource) }
-
- # Narrow it down to handlers that return `true` to `supports?`
- # TODO deprecate this and allow actions to be passed as a filter to
- # `provides` so we don't have to have two separate things.
- supported_handlers = enabled_handlers.select { |handler| handler.supports?(resource, action) }
- if supported_handlers.empty?
+ handlers = supported_handlers
+ if handlers.empty?
# if none of the providers specifically support the resource, we still need to pick one of the providers that are
# enabled on the node to handle the why-run use case. FIXME we should only do this in why-run mode then.
Chef::Log.debug "No providers responded true to `supports?` for action #{action} on resource #{resource}, falling back to enabled handlers so we can return something anyway."
- handler = enabled_handlers.first
- else
- handler = supported_handlers.first
+ handlers = enabled_handlers
end
+ handler = handlers.first
+
if handler
Chef::Log.debug "Provider for action #{action} on resource #{resource} is #{handler}"
else
@@ -114,13 +125,16 @@ class Chef
Chef::Platform.find_provider_for_node(node, resource)
end
- def provider_priority_map
- Chef::Platform::ProviderPriorityMap.instance
+ def self.priority_map
+ Chef.provider_priority_map
end
- def prioritized_handlers
- @prioritized_handlers ||=
- provider_priority_map.list_handlers(node, resource.resource_name).flatten(1).uniq
+ def priority_map
+ Chef.provider_priority_map
+ end
+
+ def overrode_provides?(handler)
+ handler.method(:provides?).owner != Chef::Provider.method(:provides?).owner
end
module Deprecated
@@ -129,33 +143,21 @@ class Chef
@providers ||= Chef::Provider.descendants
end
- # this cut looks at if the provider can handle the resource type on the node
def enabled_handlers
- @enabled_handlers ||=
- providers.select do |klass|
- # NB: this is different from resource_resolver which must pass a resource_name
- # FIXME: deprecate this and normalize on passing resource_name here
- klass.provides?(node, resource)
- end.sort {|a,b| a.to_s <=> b.to_s }
- end
-
- # this cut looks at if the provider can handle the specific resource and action
- def supported_handlers
- @supported_handlers ||=
- enabled_handlers.select do |klass|
- klass.supports?(resource, action)
- end
- end
-
- # If there are no providers for a DSL, we search through the
- def prioritized_handlers
- @prioritized_handlers ||= super || begin
- result = providers.select { |handler| handler.provides?(node, resource) }.sort_by(:name)
- if !result.empty?
- Chef::Log.deprecation("#{resource.resource_name.to_sym} is marked as providing DSL #{method_symbol}, but provides #{resource.resource_name.to_sym.inspect} was never called!")
- Chef::Log.deprecation("In Chef 13, this will break: you must call provides to mark the names you provide, even if you also override provides? yourself.")
+ @enabled_handlers ||= begin
+ handlers = super
+ if handlers.empty?
+ # Look through all providers, and find ones that return true to provides.
+ # Don't bother with ones that don't override provides?, since they
+ # would have been in enabled_handlers already if that were so. (It's a
+ # perf concern otherwise.)
+ handlers = providers.select { |handler| overrode_provides?(handler) && handler.provides?(node, resource) }
+ handlers.each do |handler|
+ Chef::Log.deprecation("#{handler}.provides? returned true when asked if it provides DSL #{resource.resource_name}, but provides #{resource.resource_name.inspect} was never called!")
+ Chef::Log.deprecation("In Chef 13, this will break: you must call provides to mark the names you provide, even if you also override provides? yourself.")
+ end
end
- result
+ handlers
end
end
end
diff --git a/lib/chef/resource.rb b/lib/chef/resource.rb
index 704490e748..7965068037 100644
--- a/lib/chef/resource.rb
+++ b/lib/chef/resource.rb
@@ -1017,7 +1017,7 @@ class Chef
if name
name = name.to_sym
# If our class is not already providing this name, provide it.
- if !Chef::ResourceResolver.list(name).include?(self)
+ if !Chef::ResourceResolver.includes_handler?(name, self)
provides name, canonical: true
end
@resource_name = name
@@ -1297,7 +1297,7 @@ class Chef
end
def self.inherited(child)
super
- @sorted_descendants = nil
+ @@sorted_descendants = nil
# set resource_name automatically if it's not set
if child.name && !child.resource_name
if child.name =~ /^Chef::Resource::(\w+)$/
@@ -1340,8 +1340,8 @@ class Chef
result
end
- def self.provides?(node, resource)
- Chef::ResourceResolver.resolve(resource, node: node).provided_by?(self)
+ def self.provides?(node, resource_name)
+ Chef::ResourceResolver.new(node, resource_name).provided_by?(self)
end
# Helper for #notifies
diff --git a/lib/chef/resource/dsc_script.rb b/lib/chef/resource/dsc_script.rb
index 2fcf183375..2877f61eb4 100644
--- a/lib/chef/resource/dsc_script.rb
+++ b/lib/chef/resource/dsc_script.rb
@@ -22,7 +22,7 @@ class Chef
class Resource
class DscScript < Chef::Resource
- provides :dsc_script, platform: "windows"
+ provides :dsc_script, os: "windows"
default_action :run
diff --git a/lib/chef/resource/ips_package.rb b/lib/chef/resource/ips_package.rb
index 8d720dd411..2bf8e1dba8 100644
--- a/lib/chef/resource/ips_package.rb
+++ b/lib/chef/resource/ips_package.rb
@@ -23,6 +23,7 @@ class Chef
class Resource
class IpsPackage < ::Chef::Resource::Package
+ provides :package, os: "solaris2"
provides :ips_package, os: "solaris2"
allowed_actions :install, :remove, :upgrade
diff --git a/lib/chef/resource/mount.rb b/lib/chef/resource/mount.rb
index 79986d127f..a5da0ba329 100644
--- a/lib/chef/resource/mount.rb
+++ b/lib/chef/resource/mount.rb
@@ -174,6 +174,14 @@ class Chef
)
end
+ private
+
+ # Used by the AIX provider to set fstype to nil.
+ # TODO use property to make nil a valid value for fstype
+ def clear_fstype
+ @fstype = nil
+ end
+
end
end
end
diff --git a/lib/chef/resource/openbsd_package.rb b/lib/chef/resource/openbsd_package.rb
index f91fdb37e0..9ae8813d69 100644
--- a/lib/chef/resource/openbsd_package.rb
+++ b/lib/chef/resource/openbsd_package.rb
@@ -29,17 +29,6 @@ class Chef
include Chef::Mixin::ShellOut
provides :package, os: "openbsd"
-
- def after_created
- assign_provider
- end
-
- private
-
- def assign_provider
- @provider = Chef::Provider::Package::Openbsd
- end
-
end
end
end
diff --git a/lib/chef/resource/solaris_package.rb b/lib/chef/resource/solaris_package.rb
index 2dc72d5c47..a98fb8b4fa 100644
--- a/lib/chef/resource/solaris_package.rb
+++ b/lib/chef/resource/solaris_package.rb
@@ -24,10 +24,7 @@ class Chef
class Resource
class SolarisPackage < Chef::Resource::Package
provides :package, os: "solaris2", platform_family: "nexentacore"
- provides :package, os: "solaris2", platform_family: "solaris2" do |node|
- # on >= Solaris 11 we default to IPS packages instead
- node[:platform_version].to_f <= 5.10
- end
+ provides :package, os: "solaris2", platform_family: "solaris2", platform_version: "<= 5.10"
end
end
end
diff --git a/lib/chef/resource_resolver.rb b/lib/chef/resource_resolver.rb
index 9df627beb2..2f27e93a3b 100644
--- a/lib/chef/resource_resolver.rb
+++ b/lib/chef/resource_resolver.rb
@@ -83,9 +83,9 @@ class Chef
# @api private use Chef::ResourceResolver.resolve instead.
def resolve
# log this so we know what resources will work for the generic resource on the node (early cut)
- Chef::Log.debug "Resources for generic #{resource_name} resource enabled on node include: #{prioritized_handlers}"
+ Chef::Log.debug "Resources for generic #{resource_name} resource enabled on node include: #{enabled_handlers}"
- handler = prioritized_handlers.first
+ handler = enabled_handlers.first
if handler
Chef::Log.debug "Resource for #{resource_name} is #{handler}"
@@ -98,59 +98,70 @@ class Chef
# @api private
def list
- Chef::Log.debug "Resources for generic #{resource_name} resource enabled on node include: #{prioritized_handlers}"
- prioritized_handlers
+ Chef::Log.debug "Resources for generic #{resource_name} resource enabled on node include: #{enabled_handlers}"
+ enabled_handlers
end
#
# Whether this DSL is provided by the given resource_class.
#
+ # Does NOT call provides? on the resource (it is assumed this is being
+ # called *from* provides?).
+ #
# @api private
def provided_by?(resource_class)
- !prioritized_handlers.include?(resource_class)
+ potential_handlers.include?(resource_class)
+ end
+
+ #
+ # Whether the given handler attempts to provide the resource class at all.
+ #
+ # @api private
+ def self.includes_handler?(resource_name, resource_class)
+ priority_map.includes_handler?(resource_name, resource_class)
end
protected
+ def self.priority_map
+ Chef.resource_priority_map
+ end
+
def priority_map
- Chef::Platform::ResourcePriorityMap.instance
+ Chef.resource_priority_map
end
- def prioritized_handlers
- @prioritized_handlers ||=
- priority_map.list_handlers(node, resource_name, canonical: canonical)
+ # @api private
+ def potential_handlers
+ priority_map.list_handlers(node, resource_name, canonical: canonical)
+ end
+
+ def enabled_handlers
+ potential_handlers.select { |handler| !overrode_provides?(handler) || handler.provides?(node, resource_name) }
+ end
+
+ def overrode_provides?(handler)
+ handler.method(:provides?).owner != Chef::Resource.method(:provides?).owner
end
module Deprecated
# return a deterministically sorted list of Chef::Resource subclasses
- # @deprecated Now prioritized_handlers does its own work (more efficiently)
def resources
Chef::Resource.sorted_descendants
end
- # A list of all handlers
- # @deprecated Now prioritized_handlers does its own work
def enabled_handlers
- Chef::Log.deprecation("enabled_handlers is deprecated. If you are implementing a ResourceResolver, use provided_handlers. If you are not, use Chef::ResourceResolver.list(#{resource_name.inspect}, node: <node>)")
- resources.select { |klass| klass.provides?(node, resource_name) }
- end
-
- protected
-
- # A list of all handlers for the given DSL. If there are no handlers in
- # the map, we still check all descendants of Chef::Resource for backwards
- # compatibility purposes.
- def prioritized_handlers
- @prioritized_handlers ||= super ||
- resources.select do |klass|
- # Don't bother calling provides? unless it's overridden. We already
- # know prioritized_handlers
- if klass.method(:provides?).owner != Chef::Resource && klass.provides?(node, resource_name)
- Chef::Log.deprecation("Resources #{provided.join(", ")} are marked as providing DSL #{resource_name}, but provides #{resource_name.inspect} was never called!")
+ @enabled_handlers ||= begin
+ handlers = super
+ if handlers.empty?
+ handlers = resources.select { |handler| overrode_provides?(handler) && handler.provides?(node, resource_name) }
+ handlers.each do |handler|
+ Chef::Log.deprecation("#{handler}.provides? returned true when asked if it provides DSL #{resource_name}, but provides #{resource_name.inspect} was never called!")
Chef::Log.deprecation("In Chef 13, this will break: you must call provides to mark the names you provide, even if you also override provides? yourself.")
- true
end
end
+ handlers
+ end
end
end
prepend Deprecated
diff --git a/spec/functional/resource/package_spec.rb b/spec/functional/resource/package_spec.rb
index 5c17ca0107..8d37b072e8 100644
--- a/spec/functional/resource/package_spec.rb
+++ b/spec/functional/resource/package_spec.rb
@@ -386,5 +386,3 @@ describe Chef::Resource::Package, metadata do
end
end
-
-
diff --git a/spec/integration/recipes/recipe_dsl_spec.rb b/spec/integration/recipes/recipe_dsl_spec.rb
index 5426dce080..fa38808e3e 100644
--- a/spec/integration/recipes/recipe_dsl_spec.rb
+++ b/spec/integration/recipes/recipe_dsl_spec.rb
@@ -11,7 +11,7 @@ describe "Recipe DSL methods" do
before(:all) { Namer.current_index = 1 }
before { Namer.current_index += 1 }
- context "With resource 'base_thingy' declared as BaseThingy" do
+ context "with resource 'base_thingy' declared as BaseThingy" do
before(:context) {
class BaseThingy < Chef::Resource
@@ -52,7 +52,7 @@ describe "Recipe DSL methods" do
Chef::Config[:treat_deprecation_warnings_as_errors] = false
end
- context "With a resource 'backcompat_thingy' declared in Chef::Resource and Chef::Provider" do
+ context "with a resource 'backcompat_thingy' declared in Chef::Resource and Chef::Provider" do
before(:context) {
class Chef::Resource::BackcompatThingy < Chef::Resource
@@ -97,7 +97,7 @@ describe "Recipe DSL methods" do
end
end
- context "With a resource named RecipeDSLSpecNamespace::Bar::BarThingy" do
+ context "with a resource named RecipeDSLSpecNamespace::Bar::BarThingy" do
before(:context) {
class RecipeDSLSpecNamespace::Bar::BarThingy < BaseThingy
@@ -112,7 +112,7 @@ describe "Recipe DSL methods" do
end
end
- context "With a resource named Chef::Resource::NoNameThingy with resource_name nil" do
+ context "with a resource named Chef::Resource::NoNameThingy with resource_name nil" do
before(:context) {
class Chef::Resource::NoNameThingy < BaseThingy
@@ -128,7 +128,7 @@ describe "Recipe DSL methods" do
end
end
- context "With a resource named AnotherNoNameThingy with resource_name :another_thingy_name" do
+ context "with a resource named AnotherNoNameThingy with resource_name :another_thingy_name" do
before(:context) {
class AnotherNoNameThingy < BaseThingy
@@ -152,7 +152,7 @@ describe "Recipe DSL methods" do
end
end
- context "With a resource named AnotherNoNameThingy2 with resource_name :another_thingy_name2; resource_name :another_thingy_name3" do
+ context "with a resource named AnotherNoNameThingy2 with resource_name :another_thingy_name2; resource_name :another_thingy_name3" do
before(:context) {
class AnotherNoNameThingy2 < BaseThingy
@@ -184,7 +184,7 @@ describe "Recipe DSL methods" do
end
context "provides overriding resource_name" do
- context "With a resource named AnotherNoNameThingy3 with provides :another_no_name_thingy3, os: 'blarghle'" do
+ context "with a resource named AnotherNoNameThingy3 with provides :another_no_name_thingy3, os: 'blarghle'" do
before(:context) {
class AnotherNoNameThingy3 < BaseThingy
@@ -213,7 +213,7 @@ describe "Recipe DSL methods" do
end
end
- context "With a resource named AnotherNoNameThingy4 with two provides" do
+ context "with a resource named AnotherNoNameThingy4 with two provides" do
before(:context) {
class AnotherNoNameThingy4 < BaseThingy
@@ -253,7 +253,7 @@ describe "Recipe DSL methods" do
end
end
- context "With a resource named AnotherNoNameThingy5, a different resource_name, and a provides with the original resource_name" do
+ context "with a resource named AnotherNoNameThingy5, a different resource_name, and a provides with the original resource_name" do
before(:context) {
class AnotherNoNameThingy5 < BaseThingy
@@ -290,7 +290,7 @@ describe "Recipe DSL methods" do
end
end
- context "With a resource named AnotherNoNameThingy6, a provides with the original resource name, and a different resource_name" do
+ context "with a resource named AnotherNoNameThingy6, a provides with the original resource name, and a different resource_name" do
before(:context) {
class AnotherNoNameThingy6 < BaseThingy
@@ -327,7 +327,7 @@ describe "Recipe DSL methods" do
end
end
- context "With a resource named AnotherNoNameThingy7, a new resource_name, and provides with that new resource name" do
+ context "with a resource named AnotherNoNameThingy7, a new resource_name, and provides with that new resource name" do
before(:context) {
class AnotherNoNameThingy7 < BaseThingy
@@ -365,7 +365,7 @@ describe "Recipe DSL methods" do
end
# opposite order from the previous test (provides, then resource_name)
- context "With a resource named AnotherNoNameThingy8, a provides with a new resource name, and resource_name with that new resource name" do
+ context "with a resource named AnotherNoNameThingy8, a provides with a new resource name, and resource_name with that new resource name" do
before(:context) {
class AnotherNoNameThingy8 < BaseThingy
@@ -402,118 +402,369 @@ describe "Recipe DSL methods" do
end
end
- context "With a resource TwoClassesOneDsl" do
- let(:class_name) { "TwoClassesOneDsl#{Namer.current_index}" }
- let(:dsl_method) { :"two_classes_one_dsl#{Namer.current_index}" }
-
- before {
- eval <<-EOM, nil, __FILE__, __LINE__+1
- class #{class_name} < BaseThingy
- resource_name #{dsl_method.inspect}
+ 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
- EOM
- }
- context "and resource BlahModule::TwoClassesOneDsl" do
- before {
- eval <<-EOM, nil, __FILE__, __LINE__+1
- module BlahModule
- class #{class_name} < BaseThingy
- resource_name #{dsl_method.inspect}
- end
- end
- EOM
- }
- 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")
- }
- expect(recipe.logged_warnings).to eq ''
- expect(BaseThingy.created_resource).to eq eval("BlahModule::#{class_name}")
+ def self.to_s; name; end
+ def self.inspect; name.inspect; end
end
- it "resource_matching_short_name returns BlahModule::TwoClassesOneDsl" do
- expect(Chef::Resource.resource_matching_short_name(dsl_method)).to eq eval("BlahModule::#{class_name}")
- end
- end
- context "and resource BlahModule::TwoClassesOneDsl with resource_name nil" do
- before {
- eval <<-EOM, nil, __FILE__, __LINE__+1
- module BlahModule
- class BlahModule::#{class_name} < BaseThingy
- resource_name nil
- 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
- EOM
+ def self.to_s; name; end
+ def self.inspect; name.inspect; end
+ end
+ result.resource_name two_classes_one_dsl
+ result
}
- it "two_classes_one_dsl resolves to ::TwoClassesOneDsl" do
- dsl_method = self.dsl_method
+ 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("#{dsl_method} 'blah' do; end")
+ instance_eval("#{two_classes_one_dsl} 'blah'")
}
expect(recipe.logged_warnings).to eq ''
- expect(BaseThingy.created_resource).to eq eval("::#{class_name}")
+ expect(BaseThingy.created_resource).to eq resource_class_a
end
- it "resource_matching_short_name returns ::TwoClassesOneDsl" do
- expect(Chef::Resource.resource_matching_short_name(dsl_method)).to eq eval("::#{class_name}")
+
+ 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 resource BlahModule::TwoClassesOneDsl with resource_name :argh" do
- before {
- eval <<-EOM, nil, __FILE__, __LINE__+1
- module BlahModule
- class BlahModule::#{class_name} < BaseThingy
- resource_name :argh
- 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
- EOM
+ def self.to_s; name; end
+ def self.inspect; name.inspect; end
+ end
+ result.resource_name two_classes_one_dsl
+ result
}
- it "two_classes_one_dsl resolves to ::TwoClassesOneDsl" do
- dsl_method = self.dsl_method
+ 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("#{dsl_method} 'blah' do; end")
+ instance_eval("#{two_classes_one_dsl} 'blah'")
}
expect(recipe.logged_warnings).to eq ''
- expect(BaseThingy.created_resource).to eq eval("::#{class_name}")
+ expect(BaseThingy.created_resource).to eq resource_class
end
- it "resource_matching_short_name returns ::TwoClassesOneDsl" do
- expect(Chef::Resource.resource_matching_short_name(dsl_method)).to eq eval("::#{class_name}")
+
+ 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 resource BlahModule::TwoClassesOneDsl with provides :two_classes_one_dsl, os: 'blarghle'" do
- before {
- eval <<-EOM, nil, __FILE__, __LINE__+1
- module BlahModule
- class BlahModule::#{class_name} < BaseThingy
- resource_name #{dsl_method.inspect}
- provides #{dsl_method.inspect}, os: 'blarghle'
- 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
- EOM
+ 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 "and os = blarghle, two_classes_one_dsl resolves to BlahModule::TwoClassesOneDsl" do
- dsl_method = self.dsl_method
+ 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("#{dsl_method} 'blah' do; end")
+ instance_eval("#{two_classes_one_dsl} 'blah' do; end")
}
expect(recipe.logged_warnings).to eq ''
- expect(BaseThingy.created_resource).to eq eval("BlahModule::#{class_name}")
+ expect(BaseThingy.created_resource).to eq resource_class_blarghle
end
- it "and os = linux, two_classes_one_dsl resolves to ::TwoClassesOneDsl" do
- dsl_method = self.dsl_method
+ 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("#{dsl_method} 'blah' do; end")
+ instance_eval("#{two_classes_one_dsl} 'blah' do; end")
}
expect(recipe.logged_warnings).to eq ''
- expect(BaseThingy.created_resource).to eq eval("::#{class_name}")
+ 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
@@ -833,7 +1084,7 @@ describe "Recipe DSL methods" do
end
end
- context "With platform-specific resources 'my_super_thingy_foo' and 'my_super_thingy_bar'" do
+ context "with platform-specific resources 'my_super_thingy_foo' and 'my_super_thingy_bar'" do
before(:context) {
class MySuperThingyFoo < BaseThingy
resource_name :my_super_thingy_foo
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index dcf244c3cc..8e24e03e9f 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -87,12 +87,14 @@ Dir["spec/support/**/*.rb"].
OHAI_SYSTEM = Ohai::System.new
OHAI_SYSTEM.all_plugins("platform")
-TEST_PLATFORM =
- (OHAI_SYSTEM['platform'] ||
- 'unknown_test_platform').dup.freeze
-TEST_PLATFORM_VERSION =
- (OHAI_SYSTEM['platform_version'] ||
- 'unknown_platform_version').dup.freeze
+test_node = Chef::Node.new
+test_node.automatic['os'] = (OHAI_SYSTEM['os'] || 'unknown_os').dup.freeze
+test_node.automatic['platform_family'] = (OHAI_SYSTEM['platform_family'] || 'unknown_platform_family').dup.freeze
+test_node.automatic['platform'] = (OHAI_SYSTEM['platform'] || 'unknown_platform').dup.freeze
+test_node.automatic['platform_version'] = (OHAI_SYSTEM['platform_version'] || 'unknown_platform_version').dup.freeze
+TEST_NODE = test_node.freeze
+TEST_PLATFORM = TEST_NODE['platform']
+TEST_PLATFORM_VERSION = TEST_NODE['platform_version']
RSpec.configure do |config|
config.include(Matchers)
@@ -162,13 +164,17 @@ RSpec.configure do |config|
config.filter_run_excluding :provider => lambda {|criteria|
type, target_provider = criteria.first
- platform = TEST_PLATFORM.dup
- platform_version = TEST_PLATFORM_VERSION.dup
-
- begin
- provider_for_running_platform = Chef::Platform.find_provider(platform, platform_version, type)
- provider_for_running_platform != target_provider
- rescue ArgumentError # no provider for platform
+ node = TEST_NODE.dup
+ resource_class = Chef::ResourceResolver.resolve(type, node: node)
+ if resource_class
+ resource = resource_class.new('test', Chef::RunContext.new(node, nil, nil))
+ begin
+ provider = resource.provider_for_action(Array(resource_class.default_action).first)
+ provider.class != target_provider
+ rescue Chef::Exceptions::ProviderNotFound # no provider for platform
+ true
+ end
+ else
true
end
}
diff --git a/spec/unit/platform_spec.rb b/spec/unit/platform_spec.rb
index 36325d5411..34b46f657f 100644
--- a/spec/unit/platform_spec.rb
+++ b/spec/unit/platform_spec.rb
@@ -103,7 +103,7 @@ describe Chef::Platform do
end
it "should raise an exception if a provider cannot be found for a resource type" do
- expect { Chef::Platform.find_provider("Darwin", "9.2.2", :coffee) }.to raise_error(ArgumentError)
+ expect { Chef::Platform.find_provider("Darwin", "9.2.2", :coffee) }.to raise_error(Chef::Exceptions::ProviderNotFound)
end
it "should look up a provider for a resource with a Chef::Resource object" do
diff --git a/spec/unit/provider/dsc_resource_spec.rb b/spec/unit/provider/dsc_resource_spec.rb
index 0a6c22bdcf..65c1c019f0 100644
--- a/spec/unit/provider/dsc_resource_spec.rb
+++ b/spec/unit/provider/dsc_resource_spec.rb
@@ -35,10 +35,10 @@ describe Chef::Provider::DscResource do
node
}
- it 'raises a NoProviderAvailable exception' do
+ it 'raises a ProviderNotFound exception' do
expect(provider).not_to receive(:meta_configuration)
expect{provider.run_action(:run)}.to raise_error(
- Chef::Exceptions::NoProviderAvailable, /5\.0\.10018\.0/)
+ Chef::Exceptions::ProviderNotFound, /5\.0\.10018\.0/)
end
end
@@ -56,7 +56,7 @@ describe Chef::Provider::DscResource do
expect(provider).to receive(:meta_configuration).and_return(
meta_configuration)
expect { provider.run_action(:run) }.to raise_error(
- Chef::Exceptions::NoProviderAvailable, /Disabled/)
+ Chef::Exceptions::ProviderNotFound, /Disabled/)
end
end
diff --git a/spec/unit/provider/dsc_script_spec.rb b/spec/unit/provider/dsc_script_spec.rb
index d4b2eb3b22..76589e71c1 100644
--- a/spec/unit/provider/dsc_script_spec.rb
+++ b/spec/unit/provider/dsc_script_spec.rb
@@ -158,14 +158,14 @@ describe Chef::Provider::DscScript do
expect {
provider.run_action(:run)
- }.to raise_error(Chef::Exceptions::NoProviderAvailable)
+ }.to raise_error(Chef::Exceptions::ProviderNotFound)
end
end
it 'raises an exception if Powershell is not present' do
expect {
provider.run_action(:run)
- }.to raise_error(Chef::Exceptions::NoProviderAvailable)
+ }.to raise_error(Chef::Exceptions::ProviderNotFound)
end
end
diff --git a/spec/unit/provider_resolver_spec.rb b/spec/unit/provider_resolver_spec.rb
index cd3d7713a7..e09b12a20a 100644
--- a/spec/unit/provider_resolver_spec.rb
+++ b/spec/unit/provider_resolver_spec.rb
@@ -28,30 +28,37 @@ include Chef::Mixin::ConvertToClassName
describe Chef::ProviderResolver do
+ let(:resource_name) { :service }
+ let(:provider) { nil }
+ let(:action) { :start }
+
let(:node) do
node = Chef::Node.new
- allow(node).to receive(:[]).with(:os).and_return(os)
- allow(node).to receive(:[]).with(:platform_family).and_return(platform_family)
- allow(node).to receive(:[]).with(:platform).and_return(platform)
- allow(node).to receive(:[]).with(:platform_version).and_return(platform_version)
- allow(node).to receive(:is_a?).and_return(Chef::Node)
+ node.automatic[:os] = os
+ node.automatic[:platform_family] = platform_family
+ node.automatic[:platform] = platform
+ node.automatic[:platform_version] = platform_version
+ node.automatic[:kernel] = { machine: 'i386' }
node
end
+ let(:run_context) { Chef::RunContext.new(node, nil, nil) }
let(:provider_resolver) { Chef::ProviderResolver.new(node, resource, action) }
+ let(:resolved_provider) do
+ begin
+ resource ? resource.provider_for_action(action).class : nil
+ rescue Chef::Exceptions::ProviderNotFound
+ nil
+ end
+ end
- let(:action) { :start }
-
- let(:resolved_provider) { provider_resolver.resolve }
-
- let(:provider) { nil }
-
- let(:resource_name) { :service }
-
- let(:resource) { double(Chef::Resource, provider: provider, resource_name: resource_name) }
-
- before do
- allow(resource).to receive(:is_a?).with(Chef::Resource).and_return(true)
+ let(:resource) do
+ resource_class = Chef::ResourceResolver.resolve(resource_name, node: node)
+ if resource_class
+ resource = resource_class.new('test', run_context)
+ resource.provider = provider if provider
+ end
+ resource
end
def self.on_platform(platform, *tags,
@@ -83,16 +90,40 @@ describe Chef::ProviderResolver do
end
def self.expect_providers(**providers)
- providers.each do |name, provider|
+ providers.each do |name, expected_provider|
describe name.to_s do
let(:resource_name) { name }
- if provider
- it "resolves to a #{provider}" do
- expect(resolved_provider).to eql(provider)
+
+ tags = []
+ expected_resource = nil
+ Array(expected_provider).each do |p|
+ if p.is_a?(Class) && p <= Chef::Provider
+ expected_provider = p
+ elsif p.is_a?(Class) && p <= Chef::Resource
+ expected_resource = p
+ else
+ tags << p
+ end
+ end
+
+ if expected_resource && expected_provider
+ it "'#{name}' resolves to resource #{expected_resource} and provider #{expected_provider}", *tags do
+ expect(resource.class).to eql(expected_resource)
+ provider = double(expected_provider, class: expected_provider)
+ expect(provider).to receive(:action=).with(action)
+ expect(expected_provider).to receive(:new).with(resource, run_context).and_return(provider)
+ expect(resolved_provider).to eql(expected_provider)
+ end
+ elsif expected_provider
+ it "'#{name}' resolves to provider #{expected_provider}", *tags do
+ provider = double(expected_provider)
+ expect(provider).to receive(:action=).with(action)
+ expect(expected_provider).to receive(:new).with(resource, run_context).and_return(provider)
+ expect(resolved_provider).to eql(expected_provider)
end
else
- it "Fails to resolve (since #{name.inspect} is unsupported on #{platform} #{platform_version})" do
- expect { resolved_provider }.to raise_error /Cannot find a provider/
+ it "'#{name}' fails to resolve (since #{name.inspect} is unsupported on #{platform} #{platform_version})", *tags do
+ expect(resolved_provider).to be_nil
end
end
end
@@ -454,42 +485,42 @@ describe Chef::ProviderResolver do
PROVIDERS =
{
- bash: Chef::Provider::Script,
- breakpoint: Chef::Provider::Breakpoint,
- chef_gem: Chef::Provider::Package::Rubygems,
- cookbook_file: Chef::Provider::CookbookFile,
- csh: Chef::Provider::Script,
- deploy: Chef::Provider::Deploy::Timestamped,
- deploy_revision: Chef::Provider::Deploy::Revision,
- directory: Chef::Provider::Directory,
- easy_install_package: Chef::Provider::Package::EasyInstall,
- erl_call: Chef::Provider::ErlCall,
- execute: Chef::Provider::Execute,
- file: Chef::Provider::File,
- gem_package: Chef::Provider::Package::Rubygems,
- git: Chef::Provider::Git,
- group: Chef::Provider::Group::Gpasswd,
- homebrew_package: Chef::Provider::Package::Homebrew,
- http_request: Chef::Provider::HttpRequest,
- ifconfig: Chef::Provider::Ifconfig,
- link: Chef::Provider::Link,
- log: Chef::Provider::Log::ChefLog,
- macports_package: Chef::Provider::Package::Macports,
- mdadm: Chef::Provider::Mdadm,
- mount: Chef::Provider::Mount::Mount,
- perl: Chef::Provider::Script,
- portage_package: Chef::Provider::Package::Portage,
- python: Chef::Provider::Script,
- remote_directory: Chef::Provider::RemoteDirectory,
- route: Chef::Provider::Route,
- ruby: Chef::Provider::Script,
- ruby_block: Chef::Provider::RubyBlock,
- script: Chef::Provider::Script,
- subversion: Chef::Provider::Subversion,
- template: Chef::Provider::Template,
- timestamped_deploy: Chef::Provider::Deploy::Timestamped,
- user: Chef::Provider::User::Useradd,
- whyrun_safe_ruby_block: Chef::Provider::WhyrunSafeRubyBlock,
+ bash: [ Chef::Resource::Bash, Chef::Provider::Script ],
+ breakpoint: [ Chef::Resource::Breakpoint, Chef::Provider::Breakpoint ],
+ chef_gem: [ Chef::Resource::ChefGem, Chef::Provider::Package::Rubygems ],
+ cookbook_file: [ Chef::Resource::CookbookFile, Chef::Provider::CookbookFile ],
+ csh: [ Chef::Resource::Csh, Chef::Provider::Script ],
+ deploy: [ Chef::Resource::Deploy, Chef::Provider::Deploy::Timestamped ],
+ deploy_revision: [ Chef::Resource::DeployRevision, Chef::Provider::Deploy::Revision ],
+ directory: [ Chef::Resource::Directory, Chef::Provider::Directory ],
+ easy_install_package: [ Chef::Resource::EasyInstallPackage, Chef::Provider::Package::EasyInstall ],
+ erl_call: [ Chef::Resource::ErlCall, Chef::Provider::ErlCall ],
+ execute: [ Chef::Resource::Execute, Chef::Provider::Execute ],
+ file: [ Chef::Resource::File, Chef::Provider::File ],
+ gem_package: [ Chef::Resource::GemPackage, Chef::Provider::Package::Rubygems ],
+ git: [ Chef::Resource::Git, Chef::Provider::Git ],
+ group: [ Chef::Resource::Group, Chef::Provider::Group::Gpasswd ],
+ homebrew_package: [ Chef::Resource::HomebrewPackage, Chef::Provider::Package::Homebrew ],
+ http_request: [ Chef::Resource::HttpRequest, Chef::Provider::HttpRequest ],
+ ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig ],
+ link: [ Chef::Resource::Link, Chef::Provider::Link ],
+ log: [ Chef::Resource::Log, Chef::Provider::Log::ChefLog ],
+ macports_package: [ Chef::Resource::MacportsPackage, Chef::Provider::Package::Macports ],
+ mdadm: [ Chef::Resource::Mdadm, Chef::Provider::Mdadm ],
+ mount: [ Chef::Resource::Mount, Chef::Provider::Mount::Mount ],
+ perl: [ Chef::Resource::Perl, Chef::Provider::Script ],
+ portage_package: [ Chef::Resource::PortagePackage, Chef::Provider::Package::Portage ],
+ python: [ Chef::Resource::Python, Chef::Provider::Script ],
+ remote_directory: [ Chef::Resource::RemoteDirectory, Chef::Provider::RemoteDirectory ],
+ route: [ Chef::Resource::Route, Chef::Provider::Route ],
+ ruby: [ Chef::Resource::Ruby, Chef::Provider::Script ],
+ ruby_block: [ Chef::Resource::RubyBlock, Chef::Provider::RubyBlock ],
+ script: [ Chef::Resource::Script, Chef::Provider::Script ],
+ subversion: [ Chef::Resource::Subversion, Chef::Provider::Subversion ],
+ template: [ Chef::Resource::Template, Chef::Provider::Template ],
+ timestamped_deploy: [ Chef::Resource::TimestampedDeploy, Chef::Provider::Deploy::Timestamped ],
+ user: [ Chef::Resource::User, Chef::Provider::User::Useradd ],
+ whyrun_safe_ruby_block: [ Chef::Resource::WhyrunSafeRubyBlock, Chef::Provider::WhyrunSafeRubyBlock ],
# We want to check that these are unsupported:
apt_package: nil,
@@ -507,61 +538,62 @@ describe Chef::ProviderResolver do
windows_service: nil,
"linux" => {
- apt_package: Chef::Provider::Package::Apt,
- dpkg_package: Chef::Provider::Package::Dpkg,
- pacman_package: Chef::Provider::Package::Pacman,
- paludis_package: Chef::Provider::Package::Paludis,
- rpm_package: Chef::Provider::Package::Rpm,
- yum_package: Chef::Provider::Package::Yum,
+ apt_package: [ Chef::Resource::AptPackage, Chef::Provider::Package::Apt ],
+ dpkg_package: [ Chef::Resource::DpkgPackage, Chef::Provider::Package::Dpkg ],
+ pacman_package: [ Chef::Resource::PacmanPackage, Chef::Provider::Package::Pacman ],
+ paludis_package: [ Chef::Resource::PaludisPackage, Chef::Provider::Package::Paludis ],
+ rpm_package: [ Chef::Resource::RpmPackage, Chef::Provider::Package::Rpm ],
+ yum_package: [ Chef::Resource::YumPackage, Chef::Provider::Package::Yum ],
"debian" => {
- ifconfig: Chef::Provider::Ifconfig::Debian,
- package: Chef::Provider::Package::Apt,
-# service: Chef::Provider::Service::Debian,
+ ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig::Debian ],
+ package: [ Chef::Resource::AptPackage, Chef::Provider::Package::Apt ],
+# service: [ Chef::Resource::DebianService, Chef::Provider::Service::Debian ],
"debian" => {
"7.0" => {
},
"6.0" => {
- ifconfig: Chef::Provider::Ifconfig,
-# service: Chef::Provider::Service::Insserv,
+ ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig ],
+# service: [ Chef::Resource::InsservService, Chef::Provider::Service::Insserv ],
},
"5.0" => {
- ifconfig: Chef::Provider::Ifconfig,
+ ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig ],
},
},
"gcel" => {
"3.1.4" => {
- ifconfig: Chef::Provider::Ifconfig,
+ ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig ],
},
},
"linaro" => {
"3.1.4" => {
- ifconfig: Chef::Provider::Ifconfig,
+ ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig ],
},
},
"linuxmint" => {
"3.1.4" => {
- ifconfig: Chef::Provider::Ifconfig,
-# service: Chef::Provider::Service::Upstart,
+ ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig ],
+# service: [ Chef::Resource::UpstartService, Chef::Provider::Service::Upstart ],
},
},
"raspbian" => {
"3.1.4" => {
- ifconfig: Chef::Provider::Ifconfig,
+ ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig ],
},
},
"ubuntu" => {
"11.10" => {
},
"10.04" => {
- ifconfig: Chef::Provider::Ifconfig,
+ ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig ],
},
},
},
"arch" => {
- package: Chef::Provider::Package::Pacman,
+ # TODO should be Chef::Resource::PacmanPackage
+ package: [ Chef::Resource::Package, Chef::Provider::Package::Pacman ],
"arch" => {
"3.1.4" => {
@@ -570,8 +602,8 @@ describe Chef::ProviderResolver do
},
"freebsd" => {
- group: Chef::Provider::Group::Pw,
- user: Chef::Provider::User::Pw,
+ group: [ Chef::Resource::Group, Chef::Provider::Group::Pw ],
+ user: [ Chef::Resource::User, Chef::Provider::User::Pw ],
"freebsd" => {
"3.1.4" => {
@@ -579,30 +611,31 @@ describe Chef::ProviderResolver do
},
},
"suse" => {
- group: Chef::Provider::Group::Gpasswd,
+ group: [ Chef::Resource::Group, Chef::Provider::Group::Gpasswd ],
"suse" => {
"12.0" => {
},
%w(11.1 11.2 11.3) => {
- group: Chef::Provider::Group::Suse,
+ group: [ Chef::Resource::Group, Chef::Provider::Group::Suse ],
},
},
"opensuse" => {
-# service: Chef::Provider::Service::Redhat,
- package: Chef::Provider::Package::Zypper,
- group: Chef::Provider::Group::Usermod,
+# service: [ Chef::Resource::RedhatService, Chef::Provider::Service::Redhat ],
+ package: [ Chef::Resource::ZypperPackage, Chef::Provider::Package::Zypper ],
+ group: [ Chef::Resource::Group, Chef::Provider::Group::Usermod ],
"12.3" => {
},
"12.2" => {
- group: Chef::Provider::Group::Suse,
+ group: [ Chef::Resource::Group, Chef::Provider::Group::Suse ],
},
},
},
"gentoo" => {
- package: Chef::Provider::Package::Portage,
- portage_package: Chef::Provider::Package::Portage,
-# service: Chef::Provider::Service::Gentoo,
+ # TODO should be Chef::Resource::PortagePackage
+ package: [ Chef::Resource::Package, Chef::Provider::Package::Portage ],
+ portage_package: [ Chef::Resource::PortagePackage, Chef::Provider::Package::Portage ],
+# service: [ Chef::Resource::GentooService, Chef::Provider::Service::Gentoo ],
"gentoo" => {
"3.1.4" => {
@@ -611,27 +644,27 @@ describe Chef::ProviderResolver do
},
"rhel" => {
-# service: Chef::Provider::Service::Systemd,
- package: Chef::Provider::Package::Yum,
- ifconfig: Chef::Provider::Ifconfig::Redhat,
+# service: [ Chef::Resource::SystemdService, Chef::Provider::Service::Systemd ],
+ package: [ Chef::Resource::YumPackage, Chef::Provider::Package::Yum ],
+ ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig::Redhat ],
%w(amazon xcp xenserver ibm_powerkvm cloudlinux parallels) => {
"3.1.4" => {
-# service: Chef::Provider::Service::Redhat,
+# service: [ Chef::Resource::RedhatService, Chef::Provider::Service::Redhat ],
},
},
%w(redhat centos scientific oracle) => {
"7.0" => {
},
"6.0" => {
-# service: Chef::Provider::Service::Redhat,
+# service: [ Chef::Resource::RedhatService, Chef::Provider::Service::Redhat ],
},
},
"fedora" => {
"15.0" => {
},
"14.0" => {
-# service: Chef::Provider::Service::Redhat,
+# service: [ Chef::Resource::RedhatService, Chef::Provider::Service::Redhat ],
},
},
},
@@ -640,9 +673,9 @@ describe Chef::ProviderResolver do
"darwin" => {
%w(mac_os_x mac_os_x_server) => {
- group: Chef::Provider::Group::Dscl,
- package: Chef::Provider::Package::Homebrew,
- user: Chef::Provider::User::Dscl,
+ group: [ Chef::Resource::Group, Chef::Provider::Group::Dscl ],
+ package: [ Chef::Resource::HomebrewPackage, Chef::Provider::Package::Homebrew ],
+ user: [ Chef::Resource::User, Chef::Provider::User::Dscl ],
"mac_os_x" => {
"10.9.2" => {
@@ -652,17 +685,17 @@ describe Chef::ProviderResolver do
},
"windows" => {
- batch: Chef::Provider::Batch,
- dsc_script: Chef::Provider::DscScript,
- env: Chef::Provider::Env::Windows,
- group: Chef::Provider::Group::Windows,
- mount: Chef::Provider::Mount::Windows,
- package: Chef::Provider::Package::Windows,
- powershell_script: Chef::Provider::PowershellScript,
- service: Chef::Provider::Service::Windows,
- user: Chef::Provider::User::Windows,
- windows_package: Chef::Provider::Package::Windows,
- windows_service: Chef::Provider::Service::Windows,
+ batch: [ Chef::Resource::Batch, Chef::Provider::Batch ],
+ dsc_script: [ Chef::Resource::DscScript, Chef::Provider::DscScript ],
+ env: [ Chef::Resource::Env, Chef::Provider::Env::Windows ],
+ group: [ Chef::Resource::Group, Chef::Provider::Group::Windows ],
+ mount: [ Chef::Resource::Mount, Chef::Provider::Mount::Windows ],
+ package: [ Chef::Resource::WindowsPackage, Chef::Provider::Package::Windows ],
+ powershell_script: [ Chef::Resource::PowershellScript, Chef::Provider::PowershellScript ],
+ service: [ Chef::Resource::WindowsService, Chef::Provider::Service::Windows ],
+ user: [ Chef::Resource::User, Chef::Provider::User::Windows ],
+ windows_package: [ Chef::Resource::WindowsPackage, Chef::Provider::Package::Windows ],
+ windows_service: [ Chef::Resource::WindowsService, Chef::Provider::Service::Windows ],
"windows" => {
%w(mswin mingw32 windows) => {
@@ -673,15 +706,16 @@ describe Chef::ProviderResolver do
},
"aix" => {
- bff_package: Chef::Provider::Package::Aix,
- cron: Chef::Provider::Cron::Aix,
- group: Chef::Provider::Group::Aix,
- ifconfig: Chef::Provider::Ifconfig::Aix,
- mount: Chef::Provider::Mount::Aix,
- package: Chef::Provider::Package::Aix,
- rpm_package: Chef::Provider::Package::Rpm,
- user: Chef::Provider::User::Aix,
-# service: Chef::Provider::Service::Aix,
+ bff_package: [ Chef::Resource::BffPackage, Chef::Provider::Package::Aix ],
+ cron: [ Chef::Resource::Cron, Chef::Provider::Cron::Aix ],
+ group: [ Chef::Resource::Group, Chef::Provider::Group::Aix ],
+ ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig::Aix ],
+ mount: [ Chef::Resource::Mount, Chef::Provider::Mount::Aix ],
+ # TODO should be Chef::Resource::BffPackage
+ package: [ Chef::Resource::Package, Chef::Provider::Package::Aix ],
+ rpm_package: [ Chef::Resource::RpmPackage, Chef::Provider::Package::Rpm ],
+ user: [ Chef::Resource::User, Chef::Provider::User::Aix ],
+# service: [ Chef::Resource::AixService, Chef::Provider::Service::Aix ],
"aix" => {
"aix" => {
@@ -695,7 +729,7 @@ describe Chef::ProviderResolver do
"hpux" => {
"hpux" => {
"3.1.4" => {
- group: Chef::Provider::Group::Usermod
+ group: [ Chef::Resource::Group, Chef::Provider::Group::Usermod ]
}
}
}
@@ -705,15 +739,15 @@ describe Chef::ProviderResolver do
"netbsd" => {
"netbsd" => {
"3.1.4" => {
- group: Chef::Provider::Group::Groupmod,
+ group: [ Chef::Resource::Group, Chef::Provider::Group::Groupmod ],
},
},
},
},
"openbsd" => {
- group: Chef::Provider::Group::Usermod,
- package: Chef::Provider::Package::Openbsd,
+ group: [ Chef::Resource::Group, Chef::Provider::Group::Usermod ],
+ package: [ Chef::Resource::OpenbsdPackage, Chef::Provider::Package::Openbsd ],
"openbsd" => {
"openbsd" => {
@@ -724,15 +758,15 @@ describe Chef::ProviderResolver do
},
"solaris2" => {
- group: Chef::Provider::Group::Usermod,
- ips_package: Chef::Provider::Package::Ips,
- package: Chef::Provider::Package::Ips,
- mount: Chef::Provider::Mount::Solaris,
- solaris_package: Chef::Provider::Package::Solaris,
+ group: [ Chef::Resource::Group, Chef::Provider::Group::Usermod ],
+ ips_package: [ Chef::Resource::IpsPackage, Chef::Provider::Package::Ips ],
+ package: [ Chef::Resource::SolarisPackage, Chef::Provider::Package::Solaris ],
+ mount: [ Chef::Resource::Mount, Chef::Provider::Mount::Solaris ],
+ solaris_package: [ Chef::Resource::SolarisPackage, Chef::Provider::Package::Solaris ],
"smartos" => {
- smartos_package: Chef::Provider::Package::SmartOS,
- package: Chef::Provider::Package::SmartOS,
+ smartos_package: [ Chef::Resource::SmartosPackage, Chef::Provider::Package::SmartOS ],
+ package: [ Chef::Resource::SmartosPackage, Chef::Provider::Package::SmartOS ],
"smartos" => {
"3.1.4" => {
@@ -743,12 +777,11 @@ describe Chef::ProviderResolver do
"solaris2" => {
"nexentacore" => {
"3.1.4" => {
- package: Chef::Provider::Package::Solaris,
},
},
"omnios" => {
"3.1.4" => {
- user: Chef::Provider::User::Solaris,
+ user: [ Chef::Resource::User, Chef::Provider::User::Solaris ],
}
},
"openindiana" => {
@@ -760,11 +793,11 @@ describe Chef::ProviderResolver do
},
},
"solaris2" => {
- user: Chef::Provider::User::Solaris,
+ user: [ Chef::Resource::User, Chef::Provider::User::Solaris ],
"5.11" => {
+ package: [ Chef::Resource::IpsPackage, Chef::Provider::Package::Ips ],
},
"5.9" => {
- package: Chef::Provider::Package::Solaris,
},
},
},
@@ -784,7 +817,8 @@ describe Chef::ProviderResolver do
"exherbo" => {
"exherbo" => {
"3.1.4" => {
- package: Chef::Provider::Package::Paludis
+ # TODO should be Chef::Resource::PaludisPackage
+ package: [ Chef::Resource::Package, Chef::Provider::Package::Paludis ]
}
}
}
diff --git a/spec/unit/resource_resolver_spec.rb b/spec/unit/resource_resolver_spec.rb
index 09ff026575..b3bda9d945 100644
--- a/spec/unit/resource_resolver_spec.rb
+++ b/spec/unit/resource_resolver_spec.rb
@@ -31,19 +31,23 @@ describe Chef::ResourceResolver do
context 'instance methods' do
let(:resolver) do
- described_class.new(Chef::Node.new, 'execute[echo]')
+ described_class.new(Chef::Node.new, 'execute')
end
it '#resolve' do
- expect(resolver.resolve).to be_nil
+ expect(resolver.resolve).to eq Chef::Resource::Execute
end
it '#list' do
- expect(resolver.list).to be_empty
+ expect(resolver.list).to eq [ Chef::Resource::Execute ]
end
- it '#provided_by?' do
+ it '#provided_by? returns true when resource class is in the list' do
expect(resolver.provided_by?(Chef::Resource::Execute)).to be_truthy
end
+
+ it '#provided_by? returns false when resource class is not in the list' do
+ expect(resolver.provided_by?(Chef::Resource::File)).to be_falsey
+ end
end
end