diff options
-rw-r--r-- | Gemfile | 1 | ||||
-rw-r--r-- | chef.gemspec | 1 | ||||
-rw-r--r-- | spec/integration/recipes/lwrp_inline_resources_spec.rb | 2 | ||||
-rw-r--r-- | spec/integration/recipes/recipe_dsl_spec.rb | 277 | ||||
-rw-r--r-- | spec/support/shared/integration/integration_helper.rb | 11 |
5 files changed, 286 insertions, 6 deletions
@@ -10,6 +10,7 @@ end group(:development, :test) do gem "simplecov" gem 'rack', "~> 1.5.1" + gem 'cheffish', github: 'chef/cheffish', branch: 'jk/chef_run_additions' gem 'ruby-shadow', :platforms => :ruby unless RUBY_PLATFORM.downcase.match(/(aix|cygwin)/) end diff --git a/chef.gemspec b/chef.gemspec index 7cf6380062..2f8fabcec8 100644 --- a/chef.gemspec +++ b/chef.gemspec @@ -44,6 +44,7 @@ Gem::Specification.new do |s| s.add_dependency "syslog-logger", "~> 1.6" s.add_development_dependency "rack" + s.add_development_dependency "cheffish", "~> 1.1" # Rake 10.2 drops Ruby 1.8 support s.add_development_dependency "rake", "~> 10.1.0" diff --git a/spec/integration/recipes/lwrp_inline_resources_spec.rb b/spec/integration/recipes/lwrp_inline_resources_spec.rb index b4c4e6ca11..e70605d3d3 100644 --- a/spec/integration/recipes/lwrp_inline_resources_spec.rb +++ b/spec/integration/recipes/lwrp_inline_resources_spec.rb @@ -5,7 +5,7 @@ describe "LWRPs with inline resources" do include IntegrationSupport include Chef::Mixin::ShellOut - let(:chef_dir) { File.join(File.dirname(__FILE__), "..", "..", "..", "bin") } + let(:chef_dir) { File.expand_path("../../../../bin", __FILE__) } # Invoke `chef-client` as `ruby PATH/TO/chef-client`. This ensures the # following constraints are satisfied: diff --git a/spec/integration/recipes/recipe_dsl_spec.rb b/spec/integration/recipes/recipe_dsl_spec.rb new file mode 100644 index 0000000000..5442aeffc0 --- /dev/null +++ b/spec/integration/recipes/recipe_dsl_spec.rb @@ -0,0 +1,277 @@ +require 'support/shared/integration/integration_helper' + +describe "Recipe DSL methods" do + include IntegrationSupport + + context "With resource 'base_thingy' declared as BaseThingy" do + before(:context) { + + class BaseThingy < Chef::Resource + def initialize(*args, &block) + super + @resource_name = 'base_thingy' + @allowed_actions = [ :create ] + @action = :create + end + + class<<self + attr_accessor :created_resource + attr_accessor :created_provider + end + + def provider + Provider + end + class Provider < Chef::Provider + def load_current_resource + end + def action_create + BaseThingy.created_resource = new_resource.class + BaseThingy.created_provider = self.class + end + end + end + + # Modules to put stuff in + module Foo; end + module Foo::Bar; end + + } + + before :each do + BaseThingy.created_resource = nil + BaseThingy.created_provider = nil + end + + context "Automatic resource DSL" do + context "With a resource 'backcompat_thingy' declared in Chef::Resource and Chef::Provider" do + before(:context) { + + class Chef::Resource::BackcompatThingy < Chef::Resource + def initialize(*args, &block) + super + @resource_name = 'backcompat_thingy' + @allowed_actions = [ :create ] + @action = :create + end + end + class Chef::Provider::BackcompatThingy < Chef::Provider + def load_current_resource + end + def action_create + BaseThingy.created_resource = new_resource.class + BaseThingy.created_provider = self.class + end + end + + } + + it "backcompat_thingy creates a Chef::Resource::BackcompatThingy" do + expect_recipe { + backcompat_thingy 'blah' do; end + }.to emit_no_warnings_or_errors + expect(BaseThingy.created_resource).to eq Chef::Resource::BackcompatThingy + expect(BaseThingy.created_provider).to eq Chef::Provider::BackcompatThingy + end + + context "And another resource 'backcompat_thingy' in BackcompatThingy with 'provides'" do + before(:context) { + + class Foo::BackcompatThingy < BaseThingy; end + + } + + it "backcompat_thingy creates a BackcompatThingy and warns about ambiguity" do + recipe = converge { + backcompat_thingy 'blah' do; end + } + expect(recipe.logged_warnings).to match /ambiguous resource precedence/i + expect(BaseThingy.created_resource).not_to be_nil + end + end + end + + context "With a resource 'thingy' declared in Foo::Bar::Thingy2" do + before(:context) { + + class Foo::Bar::Thingy < BaseThingy; end + + } + + it "thingy creates a Foo::Bar::Thingy" do + expect_recipe { + thingy 'blah' do; end + }.to emit_no_warnings_or_errors + expect(BaseThingy.created_resource).to eq Foo::Bar::Thingy + end + end + + it "When resource 'thingy2' does not exist and is created during the recipe, it still works" do + expect_recipe { + class Foo::Thingy2 < BaseThingy; end + thingy2 'blah' do; end + }.to emit_no_warnings_or_errors + expect(BaseThingy.created_resource).to eq Foo::Thingy2 + end + end + + context "provides" do + context "When MySupplier provides :hemlock" do + before(:context) { + + class Foo::MySupplier < BaseThingy + provides :hemlock + end + + } + + it "my_supplier does not work in a recipe" do + expect_converge { + my_supplier 'blah' do; end + }.to raise_error(NoMethodError) + end + + it "hemlock works in a recipe" do + expect_recipe { + hemlock 'blah' do; end + }.to emit_no_warnings_or_errors + expect(BaseThingy.created_resource).to eq Foo::MySupplier + end + end + + context "When Thingy3 provides :thingy3" do + before(:context) { + + class Foo::Thingy3 < BaseThingy + provides :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 Foo::Thingy3 + end + + context "And Thingy4 provides :thingy3" do + before(:context) { + + class Foo::Thingy4 < Chef::Resource + provides :thingy3 + end + + } + + it "thingy3 works in a recipe and yields " do + recipe = converge { + thingy3 'blah' do; end + } + expect(recipe.logged_warnings).to match /ambiguous resource precedence/i + expect(BaseThingy.created_resource).not_to be_nil + end + + it "thingy4 does not work in a recipe" do + expect_converge { + thingy4 'blah' do; end + }.to raise_error(NoMethodError) + end + end + end + + context "When Thingy5 provides :thingy5, :twizzle and :twizzle2" do + before(:context) { + + class Foo::Thingy5 < BaseThingy + provides :thingy5 + provides :twizzle + provides :twizzle2 + end + + } + + it "thingy5 works in a recipe and yields Thingy5" do + expect_recipe { + thingy5 'blah' do; end + }.to emit_no_warnings_or_errors + expect(BaseThingy.created_resource).to eq Foo::Thingy5 + end + + it "twizzle works in a recipe and yields Thingy5" do + expect_recipe { + twizzle 'blah' do; end + }.to emit_no_warnings_or_errors + expect(BaseThingy.created_resource).to eq Foo::Thingy5 + end + + it "twizzle2 works in a recipe and yields Thingy5" do + expect_recipe { + twizzle2 'blah' do; end + }.to emit_no_warnings_or_errors + expect(BaseThingy.created_resource).to eq Foo::Thingy5 + end + end + + context "When Thingy6 uses provides_nothing" do + before(:context) { + + class Foo::Thingy6 < Chef::Resource + provides_nothing + end + + } + + it "thingy6 does not work in a recipe" do + expect_converge { + thingy6 'blah' do; end + }.to raise_error(NoMethodError) + end + end + + context "With platform-specific resources 'my_super_thingy_foo' and 'my_super_thingy_bar'" do + before(:context) { + class MySuperThingyFoo < BaseThingy + provides :my_super_thingy, platform: 'foo' + end + + class MySuperThingyBar < BaseThingy + provides :my_super_thingy, platform: 'bar' + end + } + + it "A run with platform 'foo' uses MySuperThingyFoo" do + r = Cheffish::ChefRun.new(chef_config) + r.client.run_context.node.automatic['platform'] = 'foo' + r.compile_recipe { + my_super_thingy 'blah' do; end + } + r.converge + expect(r).to emit_no_warnings_or_errors + expect(BaseThingy.created_resource).to eq MySuperThingyFoo + end + + it "A run with platform 'bar' uses MySuperThingyBar" do + r = Cheffish::ChefRun.new(chef_config) + r.client.run_context.node.automatic['platform'] = 'bar' + r.compile_recipe { + my_super_thingy 'blah' do; end + } + r.converge + expect(r).to emit_no_warnings_or_errors + expect(BaseThingy.created_resource).to eq MySuperThingyBar + end + + it "A run with platform 'x' reports that my_super_thingy is not supported" do + r = Cheffish::ChefRun.new(chef_config) + r.client.run_context.node.automatic['platform'] = 'x' + expect { + r.compile_recipe { + my_super_thingy 'blah' do; end + } + }.to raise_error(Chef::Exceptions::NoSuchResourceType) + end + end + end + end +end diff --git a/spec/support/shared/integration/integration_helper.rb b/spec/support/shared/integration/integration_helper.rb index e6942c62af..927ff2f42b 100644 --- a/spec/support/shared/integration/integration_helper.rb +++ b/spec/support/shared/integration/integration_helper.rb @@ -22,14 +22,19 @@ require 'fileutils' require 'chef/config' require 'chef/json_compat' require 'chef/server_api' -require 'chef_zero/rspec' require 'support/shared/integration/knife_support' require 'support/shared/integration/app_server_support' +require 'cheffish/rspec/chef_run_support' require 'spec_helper' module IntegrationSupport include ChefZero::RSpec + def self.included(includer_class) + includer_class.extend(Cheffish::RSpec::ChefRunSupport) + includer_class.extend(ClassMethods) + end + module ClassMethods include ChefZero::RSpec @@ -49,10 +54,6 @@ module IntegrationSupport end end - def self.included(includer_class) - includer_class.extend(ClassMethods) - end - def api Chef::ServerAPI.new end |