diff options
author | John Keiser <john@johnkeiser.com> | 2015-06-03 12:04:34 -0700 |
---|---|---|
committer | John Keiser <john@johnkeiser.com> | 2015-06-03 12:04:34 -0700 |
commit | db703fe2e73ab7f783c860013cde836864de5e73 (patch) | |
tree | 098ef9c4e383288fb6c8e523375b1440198391a5 | |
parent | 27deff0d81499c9df32cfc0235792ea3a23834e4 (diff) | |
parent | 88857ae52f4bfb36d2aa3ca852cfbddd4fdff63b (diff) | |
download | chef-db703fe2e73ab7f783c860013cde836864de5e73.tar.gz |
Merge branch 'jk/3463'
-rw-r--r-- | lib/chef/resource.rb | 66 | ||||
-rw-r--r-- | lib/chef/resource/lwrp_base.rb | 2 | ||||
-rw-r--r-- | spec/unit/lwrp_spec.rb | 127 |
3 files changed, 173 insertions, 22 deletions
diff --git a/lib/chef/resource.rb b/lib/chef/resource.rb index b8bf53d6ec..ab955f5454 100644 --- a/lib/chef/resource.rb +++ b/lib/chef/resource.rb @@ -1274,31 +1274,61 @@ class Chef end end - # Implement deprecated LWRP class - module DeprecatedLWRPClass - # @api private - def register_deprecated_lwrp_class(resource_class, class_name) - if Chef::Resource.const_defined?(class_name, false) - Chef::Log.warn "#{class_name} already exists! Cannot create deprecation class for #{resource_class}" - else - deprecated_constants[class_name.to_sym] = resource_class - end + # @api private + def self.register_deprecated_lwrp_class(resource_class, class_name) + if Chef::Resource.const_defined?(class_name, false) + Chef::Log.warn "#{class_name} already exists! Deprecation class overwrites #{resource_class}" + Chef::Resource.send(:remove_const, class_name) end - def const_missing(class_name) - if deprecated_constants[class_name.to_sym] + # In order to generate deprecation warnings when you use Chef::Resource::MyLwrp, + # we make a special subclass (identical in nearly all respects) of the + # actual LWRP. When you say any of these, a deprecation warning will be + # generated: + # + # - Chef::Resource::MyLwrp.new(...) + # - resource.is_a?(Chef::Resource::MyLwrp) + # - resource.kind_of?(Chef::Resource::MyLwrp) + # - case resource + # when Chef::Resource::MyLwrp + # end + # + resource_subclass = class_eval <<-EOM, __FILE__, __LINE__+1 + class Chef::Resource::#{class_name} < resource_class + def initialize(*args, &block) + Chef::Log.deprecation("Using an LWRP by its name (#{class_name}) directly is no longer supported in Chef 13 and will be removed. Use Chef::Resource.resource_for_node(node, name) instead.") + super + end + self + end + EOM + # Make case, is_a and kind_of work with the new subclass, for backcompat. + # Any subclass of Chef::Resource::ResourceClass is already a subclass of resource_class + # Any subclass of resource_class is considered a subclass of Chef::Resource::ResourceClass + resource_class.class_eval do + define_method(:is_a?) do |other| + other.is_a?(Module) && other === self + end + define_method(:kind_of?) do |other| + other.is_a?(Module) && other === self + end + end + resource_subclass.class_eval do + define_singleton_method(:===) do |other| Chef::Log.deprecation("Using an LWRP by its name (#{class_name}) directly is no longer supported in Chef 13 and will be removed. Use Chef::Resource.resource_for_node(node, name) instead.") - deprecated_constants[class_name.to_sym] - else - raise NameError, "uninitialized constant Chef::Resource::#{class_name}" + # resource_subclass is a superclass of all resource_class descendants. + if self == resource_subclass && other.class <= resource_class + return true + end + super(other) end end + deprecated_constants[class_name.to_sym] = resource_subclass + end - def deprecated_constants - @deprecated_constants ||= {} - end + def self.deprecated_constants + @deprecated_constants ||= {} end - extend DeprecatedLWRPClass # @api private def lookup_provider_constant(name, action=:nothing) diff --git a/lib/chef/resource/lwrp_base.rb b/lib/chef/resource/lwrp_base.rb index 20d236a161..c486233020 100644 --- a/lib/chef/resource/lwrp_base.rb +++ b/lib/chef/resource/lwrp_base.rb @@ -69,8 +69,8 @@ class Chef LWRPBase.loaded_lwrps[filename] = true + # Create the deprecated Chef::Resource::LwrpFoo class Chef::Resource.register_deprecated_lwrp_class(resource_class, convert_to_class_name(resource_name)) - resource_class end diff --git a/spec/unit/lwrp_spec.rb b/spec/unit/lwrp_spec.rb index f83678308a..58cba27adf 100644 --- a/spec/unit/lwrp_spec.rb +++ b/spec/unit/lwrp_spec.rb @@ -160,8 +160,8 @@ describe "LWRP" do end end - it "should load the resource into a properly-named class and emit a warning about deprecation when accessing it" do - expect { Chef::Resource::LwrpFoo }.to raise_error(Chef::Exceptions::DeprecatedFeatureError) + it "should load the resource into a properly-named class and emit a warning when it is initialized" do + expect { Chef::Resource::LwrpFoo.new('hi') }.to raise_error(Chef::Exceptions::DeprecatedFeatureError) end it "should be resolvable with Chef::ResourceResolver.resolve(:lwrp_foo)" do @@ -211,6 +211,127 @@ describe "LWRP" do expect(cls.node[:penguin_name]).to eql("jackass") end + context "resource class created" do + before do + @old_treat_deprecation_warnings_as_errors = Chef::Config[:treat_deprecation_warnings_as_errors] + Chef::Config[:treat_deprecation_warnings_as_errors] = false + end + after do + Chef::Config[:treat_deprecation_warnings_as_errors] = @old_treat_deprecation_warnings_as_errors + end + + it "should load the resource into a properly-named class" do + expect(Chef::Resource::LwrpFoo).to be_kind_of(Class) + expect(Chef::Resource::LwrpFoo <= Chef::Resource::LWRPBase).to be_truthy + end + + it "get_lwrp(:lwrp_foo).new is a Chef::Resource::LwrpFoo" do + lwrp = get_lwrp(:lwrp_foo).new('hi') + expect(lwrp.kind_of?(Chef::Resource::LwrpFoo)).to be_truthy + expect(lwrp.is_a?(Chef::Resource::LwrpFoo)).to be_truthy + expect(get_lwrp(:lwrp_foo) === lwrp).to be_truthy + expect(Chef::Resource::LwrpFoo === lwrp).to be_truthy + end + + it "Chef::Resource::LwrpFoo.new is a get_lwrp(:lwrp_foo)" do + lwrp = Chef::Resource::LwrpFoo.new('hi') + expect(lwrp.kind_of?(get_lwrp(:lwrp_foo))).to be_truthy + expect(lwrp.is_a?(get_lwrp(:lwrp_foo))).to be_truthy + expect(get_lwrp(:lwrp_foo) === lwrp).to be_truthy + expect(Chef::Resource::LwrpFoo === lwrp).to be_truthy + end + + it "works even if LwrpFoo exists in the top level" do + module ::LwrpFoo + end + expect(Chef::Resource::LwrpFoo).not_to eq(::LwrpFoo) + end + + context "with a subclass of get_lwrp(:lwrp_foo)" do + let(:subclass) do + Class.new(get_lwrp(:lwrp_foo)) + end + + it "subclass.new is a subclass" do + lwrp = subclass.new('hi') + expect(lwrp.kind_of?(subclass)).to be_truthy + expect(lwrp.is_a?(subclass)).to be_truthy + expect(subclass === lwrp).to be_truthy + expect(lwrp.class === subclass) + end + it "subclass.new is a Chef::Resource::LwrpFoo" do + lwrp = subclass.new('hi') + expect(lwrp.kind_of?(Chef::Resource::LwrpFoo)).to be_truthy + expect(lwrp.is_a?(Chef::Resource::LwrpFoo)).to be_truthy + expect(Chef::Resource::LwrpFoo === lwrp).to be_truthy + expect(lwrp.class === Chef::Resource::LwrpFoo) + end + it "subclass.new is a get_lwrp(:lwrp_foo)" do + lwrp = subclass.new('hi') + expect(lwrp.kind_of?(get_lwrp(:lwrp_foo))).to be_truthy + expect(lwrp.is_a?(get_lwrp(:lwrp_foo))).to be_truthy + expect(get_lwrp(:lwrp_foo) === lwrp).to be_truthy + expect(lwrp.class === get_lwrp(:lwrp_foo)) + end + it "Chef::Resource::LwrpFoo.new is *not* a subclass" do + lwrp = Chef::Resource::LwrpFoo.new('hi') + expect(lwrp.kind_of?(subclass)).to be_falsey + expect(lwrp.is_a?(subclass)).to be_falsey + expect(subclass === lwrp.class).to be_falsey + expect(subclass === Chef::Resource::LwrpFoo).to be_falsey + end + it "get_lwrp(:lwrp_foo).new is *not* a subclass" do + lwrp = get_lwrp(:lwrp_foo).new('hi') + expect(lwrp.kind_of?(subclass)).to be_falsey + expect(lwrp.is_a?(subclass)).to be_falsey + expect(subclass === lwrp.class).to be_falsey + expect(subclass === get_lwrp(:lwrp_foo)).to be_falsey + end + end + + context "with a subclass of Chef::Resource::LwrpFoo" do + let(:subclass) do + Class.new(Chef::Resource::LwrpFoo) + end + + it "subclass.new is a subclass" do + lwrp = subclass.new('hi') + expect(lwrp.kind_of?(subclass)).to be_truthy + expect(lwrp.is_a?(subclass)).to be_truthy + expect(subclass === lwrp).to be_truthy + expect(lwrp.class === subclass) + end + it "subclass.new is a Chef::Resource::LwrpFoo" do + lwrp = subclass.new('hi') + expect(lwrp.kind_of?(Chef::Resource::LwrpFoo)).to be_truthy + expect(lwrp.is_a?(Chef::Resource::LwrpFoo)).to be_truthy + expect(Chef::Resource::LwrpFoo === lwrp).to be_truthy + expect(lwrp.class === Chef::Resource::LwrpFoo) + end + it "subclass.new is a get_lwrp(:lwrp_foo)" do + lwrp = subclass.new('hi') + expect(lwrp.kind_of?(get_lwrp(:lwrp_foo))).to be_truthy + expect(lwrp.is_a?(get_lwrp(:lwrp_foo))).to be_truthy + expect(get_lwrp(:lwrp_foo) === lwrp).to be_truthy + expect(lwrp.class === get_lwrp(:lwrp_foo)) + end + it "Chef::Resource::LwrpFoo.new is *not* a subclass" do + lwrp = Chef::Resource::LwrpFoo.new('hi') + expect(lwrp.kind_of?(subclass)).to be_falsey + expect(lwrp.is_a?(subclass)).to be_falsey + expect(subclass === lwrp.class).to be_falsey + expect(subclass === Chef::Resource::LwrpFoo).to be_falsey + end + it "get_lwrp(:lwrp_foo).new is *not* a subclass" do + lwrp = get_lwrp(:lwrp_foo).new('hi') + expect(lwrp.kind_of?(subclass)).to be_falsey + expect(lwrp.is_a?(subclass)).to be_falsey + expect(subclass === lwrp.class).to be_falsey + expect(subclass === get_lwrp(:lwrp_foo)).to be_falsey + end + end + end + context "resource_name" do let(:klass) { Class.new(Chef::Resource::LWRPBase) } @@ -355,7 +476,7 @@ describe "LWRP" do provider.action_twiddle_thumbs end - context "resource class created" do + context "provider class created" do before do @old_treat_deprecation_warnings_as_errors = Chef::Config[:treat_deprecation_warnings_as_errors] Chef::Config[:treat_deprecation_warnings_as_errors] = false |