diff options
Diffstat (limited to 'spec')
75 files changed, 4384 insertions, 1267 deletions
diff --git a/spec/data/recipes.tgz b/spec/data/recipes.tgz Binary files differnew file mode 100644 index 0000000000..a6c172a001 --- /dev/null +++ b/spec/data/recipes.tgz diff --git a/spec/functional/audit/rspec_formatter_spec.rb b/spec/functional/audit/rspec_formatter_spec.rb index 43d3c2f6dd..009374db68 100644 --- a/spec/functional/audit/rspec_formatter_spec.rb +++ b/spec/functional/audit/rspec_formatter_spec.rb @@ -19,9 +19,10 @@ # require 'spec_helper' -require 'spec/support/audit_helper' +require 'rspec/core/sandbox' require 'chef/audit/runner' require 'rspec/support/spec/in_sub_process' +require 'rspec/support/spec/stderr_splitter' require 'chef/audit/rspec_formatter' describe Chef::Audit::RspecFormatter do @@ -37,7 +38,7 @@ describe Chef::Audit::RspecFormatter do let!(:formatter) { Chef::Audit::RspecFormatter.new(output) } around(:each) do |ex| - Sandboxing.sandboxed { ex.run } + RSpec::Core::Sandbox.sandboxed { ex.run } end it "should not close the output using our formatter" do diff --git a/spec/functional/audit/runner_spec.rb b/spec/functional/audit/runner_spec.rb index aa35548f2f..494942889a 100644 --- a/spec/functional/audit/runner_spec.rb +++ b/spec/functional/audit/runner_spec.rb @@ -17,9 +17,10 @@ # require 'spec_helper' -require 'spec/support/audit_helper' +require 'rspec/core/sandbox' require 'chef/audit/runner' require 'rspec/support/spec/in_sub_process' +require 'rspec/support/spec/stderr_splitter' require 'tempfile' ## @@ -42,7 +43,7 @@ describe Chef::Audit::Runner do let(:stdout) { StringIO.new } around(:each) do |ex| - Sandboxing.sandboxed { ex.run } + RSpec::Core::Sandbox.sandboxed { ex.run } end before do @@ -53,7 +54,7 @@ describe Chef::Audit::Runner do let(:audits) { {} } let(:run_context) { instance_double(Chef::RunContext, :events => events, :audits => audits) } - let(:controls_name) { "controls_name" } + let(:control_group_name) { "control_group_name" } it "Correctly runs an empty controls block" do in_sub_process do @@ -68,7 +69,7 @@ describe Chef::Audit::Runner do expect(2 - 2).to eq(0) end end - { controls_name => Struct.new(:args, :block).new([controls_name], should_pass)} + { control_group_name => Struct.new(:args, :block).new([control_group_name], should_pass)} end end @@ -79,7 +80,7 @@ describe Chef::Audit::Runner do expect(2 - 1).to eq(0) end end - { controls_name => Struct.new(:args, :block).new([controls_name], should_fail)} + { control_group_name => Struct.new(:args, :block).new([control_group_name], should_fail)} end end @@ -102,7 +103,7 @@ describe Chef::Audit::Runner do expect(stdout.string).to match(/Failure\/Error: expect\(2 - 1\)\.to eq\(0\)/) expect(stdout.string).to match(/1 example, 1 failure/) - expect(stdout.string).to match(/# controls_name should fail/) + expect(stdout.string).to match(/# control_group_name should fail/) end end end @@ -126,7 +127,7 @@ describe Chef::Audit::Runner do contents = tmpfile.read expect(contents).to match(/Failure\/Error: expect\(2 - 1\)\.to eq\(0\)/) expect(contents).to match(/1 example, 1 failure/) - expect(contents).to match(/# controls_name should fail/) + expect(contents).to match(/# control_group_name should fail/) end end end diff --git a/spec/functional/file_content_management/deploy_strategies_spec.rb b/spec/functional/file_content_management/deploy_strategies_spec.rb index bcd171eb73..03a6c504c1 100644 --- a/spec/functional/file_content_management/deploy_strategies_spec.rb +++ b/spec/functional/file_content_management/deploy_strategies_spec.rb @@ -20,15 +20,6 @@ require 'spec_helper' shared_examples_for "a content deploy strategy" do - # Ruby 1.8 has no binread - def binread(file) - if IO.respond_to?(:binread) - IO.binread(file) - else - IO.read(file) - end - end - def normalize_mode(mode_int) ( mode_int & 07777).to_s(8) end @@ -160,7 +151,7 @@ shared_examples_for "a content deploy strategy" do it "updates the target with content from staged" do content_deployer.deploy(staging_file_path, target_file_path) - expect(binread(target_file_path)).to eq(staging_file_content) + expect(IO.binread(target_file_path)).to eq(staging_file_content) end context "when the owner of the target file is not the owner of the staging file", :requires_root do diff --git a/spec/functional/knife/exec_spec.rb b/spec/functional/knife/exec_spec.rb index 0a9177b5e8..6262094a9f 100644 --- a/spec/functional/knife/exec_spec.rb +++ b/spec/functional/knife/exec_spec.rb @@ -41,9 +41,7 @@ describe Chef::Knife::Exec do @server.stop end - skip "executes a script in the context of the chef-shell main context", :ruby_18_only - - it "executes a script in the context of the chef-shell main context", :ruby_gte_19_only do + it "executes a script in the context of the chef-shell main context" do @node = Chef::Node.new @node.name("ohai-world") response = {"rows" => [@node],"start" => 0,"total" => 1} diff --git a/spec/functional/resource/execute_spec.rb b/spec/functional/resource/execute_spec.rb index 020814fcd6..aaa1c772b7 100644 --- a/spec/functional/resource/execute_spec.rb +++ b/spec/functional/resource/execute_spec.rb @@ -35,6 +35,32 @@ describe Chef::Resource::Execute do end end + describe "when why_run is enabled" do + before do + Chef::Config[:why_run] = true + end + + let(:guard) { "ruby -e 'exit 0'" } + let!(:guard_resource) { + interpreter = Chef::GuardInterpreter::ResourceGuardInterpreter.new(resource, guard, nil) + interpreter.send(:get_interpreter_resource, resource) + } + + it "executes the guard and not the regular resource" do + expect_any_instance_of(Chef::GuardInterpreter::ResourceGuardInterpreter).to receive(:get_interpreter_resource).and_return(guard_resource) + + # why_run mode doesn't disable the updated_by_last_action logic, so we really have to look at the provider action + # to see if why_run correctly disabled the resource. It should shell_out! for the guard but not the resource. + expect_any_instance_of(Chef::Provider::Execute).to receive(:shell_out!).once + + resource.only_if guard + resource.run_action(:run) + + expect(resource).to be_updated_by_last_action + expect(guard_resource).to be_updated_by_last_action + end + end + describe "when parent resource sets :cwd" do let(:guard) { %{ruby -e 'exit 1 unless File.exists?("./big_json_plus_one.json")'} } diff --git a/spec/functional/resource/powershell_spec.rb b/spec/functional/resource/powershell_spec.rb index 033f34e256..1b3ac844e0 100644 --- a/spec/functional/resource/powershell_spec.rb +++ b/spec/functional/resource/powershell_spec.rb @@ -56,6 +56,21 @@ describe Chef::Resource::WindowsScript::PowershellScript, :windows_only do resource.run_action(:run) end + it "returns the -27 for a powershell script that exits with -27" do + file = Tempfile.new(['foo', '.ps1']) + begin + file.write "exit -27" + file.close + resource.code(". \"#{file.path}\"") + resource.returns(-27) + resource.run_action(:run) + ensure + file.close + file.unlink + end + end + + it "returns the process exit code" do resource.code(arbitrary_nonzero_process_exit_code_content) resource.returns(arbitrary_nonzero_process_exit_code) diff --git a/spec/functional/resource/user/useradd_spec.rb b/spec/functional/resource/user/useradd_spec.rb index 6b962c19aa..9ac88d7b60 100644 --- a/spec/functional/resource/user/useradd_spec.rb +++ b/spec/functional/resource/user/useradd_spec.rb @@ -82,12 +82,25 @@ describe Chef::Provider::User::Useradd, metadata do end after do - begin - pw_entry # will raise if the user doesn't exist - shell_out!("userdel", "-r", username, :returns => [0,12]) - rescue UserNotFound - # nothing to remove + max_retries = 3 + while max_retries > 0 + begin + pw_entry # will raise if the user doesn't exist + status = shell_out!("userdel", "-r", username, :returns => [0,8,12]) + + # Error code 8 during userdel indicates that the user is logged in. + # This occurs randomly because the accounts daemon holds a lock due to which userdel fails. + # The work around is to retry userdel for 3 times. + break if status.exitstatus != 8 + + sleep 1 + max_retries = max_retries -1 + rescue UserNotFound + break + end end + + status.error! if max_retries == 0 end let(:node) do diff --git a/spec/integration/client/client_spec.rb b/spec/integration/client/client_spec.rb index 62660bb852..8afb52e29a 100644 --- a/spec/integration/client/client_spec.rb +++ b/spec/integration/client/client_spec.rb @@ -1,5 +1,34 @@ require 'support/shared/integration/integration_helper' require 'chef/mixin/shell_out' +require 'tiny_server' +require 'tmpdir' + +def recipes_filename + File.join(CHEF_SPEC_DATA, 'recipes.tgz') +end + +def start_tiny_server(server_opts={}) + recipes_size = File::Stat.new(recipes_filename).size + @server = TinyServer::Manager.new(server_opts) + @server.start + @api = TinyServer::API.instance + @api.clear + # + # trivial endpoints + # + # just a normal file + # (expected_content should be uncompressed) + @api.get("/recipes.tgz", 200) { + File.open(recipes_filename, "rb") do |f| + f.read + end + } +end + +def stop_tiny_server + @server.stop + @server = @api = nil +end describe "chef-client" do include IntegrationSupport @@ -252,7 +281,7 @@ EOM it "should exit with a zero code when there is not an audit failure" do file 'cookbooks/audit_test/recipes/succeed.rb', <<-RECIPE -controls "control group without top level control" do +control_group "control group without top level control" do it "should succeed" do expect(2 - 2).to eq(0) end @@ -261,12 +290,12 @@ end result = shell_out("#{chef_client} -c \"#{path_to('config/client.rb')}\" -o 'audit_test::succeed'", :cwd => chef_dir) expect(result.error?).to be_falsey - expect(result.stdout).to include("Successfully executed all `controls` blocks and contained examples") + expect(result.stdout).to include("Successfully executed all `control_group` blocks and contained examples") end it "should exit with a non-zero code when there is an audit failure" do file 'cookbooks/audit_test/recipes/fail.rb', <<-RECIPE -controls "control group without top level control" do +control_group "control group without top level control" do it "should fail" do expect(2 - 2).to eq(1) end @@ -279,4 +308,28 @@ end end end + context "when using recipe-url" do + before(:all) do + start_tiny_server + end + + after(:all) do + stop_tiny_server + end + + let(:tmp_dir) { Dir.mktmpdir("recipe-url") } + + it "should complete with success when passed -z and --recipe-url" do + file 'config/client.rb', <<EOM +chef_repo_path "#{tmp_dir}" +EOM + result = shell_out("#{chef_client} -c \"#{path_to('config/client.rb')}\" --recipe-url=http://localhost:9000/recipes.tgz -o 'x::default' -z", :cwd => tmp_dir) + result.error! + end + + it 'should fail when passed --recipe-url and not passed -z' do + result = shell_out("#{chef_client} --recipe-url=http://localhost:9000/recipes.tgz", :cwd => tmp_dir) + expect(result.exitstatus).to eq(1) + end + end end diff --git a/spec/integration/knife/chef_fs_data_store_spec.rb b/spec/integration/knife/chef_fs_data_store_spec.rb index eb02db5384..c1f2c7134f 100644 --- a/spec/integration/knife/chef_fs_data_store_spec.rb +++ b/spec/integration/knife/chef_fs_data_store_spec.rb @@ -138,6 +138,7 @@ EOM context 'PUT /TYPE/NAME' do before do file 'empty.json', {} + file 'dummynode.json', { "name" => "x", "chef_environment" => "rspec" , "json_class" => "Chef::Node", "normal" => {"foo" => "bar"}} file 'rolestuff.json', '{"description":"hi there","name":"x"}' file 'cookbooks_to_upload/x/metadata.rb', cookbook_x_100_metadata_rb end @@ -165,9 +166,10 @@ EOM knife('list --local /environments').should_succeed "/environments/x.json\n" end - it 'knife raw -z -i empty.json -m PUT /nodes/x' do - knife("raw -z -i #{path_to('empty.json')} -m PUT /nodes/x").should_succeed( /"x"/ ) + it 'knife raw -z -i dummynode.json -m PUT /nodes/x' do + knife("raw -z -i #{path_to('dummynode.json')} -m PUT /nodes/x").should_succeed( /"x"/ ) knife('list --local /nodes').should_succeed "/nodes/x.json\n" + knife('show -z /nodes/x.json --verbose').should_succeed /"bar"/ end it 'knife raw -z -i empty.json -m PUT /roles/x' do @@ -196,6 +198,7 @@ EOM context 'POST /TYPE/NAME' do before do file 'empty.json', { 'name' => 'z' } + file 'dummynode.json', { "name" => "z", "chef_environment" => "rspec" , "json_class" => "Chef::Node", "normal" => {"foo" => "bar"}} file 'empty_x.json', { 'name' => 'x' } file 'empty_id.json', { 'id' => 'z' } file 'rolestuff.json', '{"description":"hi there","name":"x"}' @@ -231,9 +234,10 @@ EOM knife('list --local /environments').should_succeed "/environments/z.json\n" end - it 'knife raw -z -i empty.json -m POST /nodes' do - knife("raw -z -i #{path_to('empty.json')} -m POST /nodes").should_succeed( /uri/ ) + it 'knife raw -z -i dummynode.json -m POST /nodes' do + knife("raw -z -i #{path_to('dummynode.json')} -m POST /nodes").should_succeed( /uri/ ) knife('list --local /nodes').should_succeed "/nodes/z.json\n" + knife('show -z /nodes/z.json').should_succeed /"bar"/ end it 'knife raw -z -i empty.json -m POST /roles' do diff --git a/spec/integration/knife/download_spec.rb b/spec/integration/knife/download_spec.rb index cf1e4fcf0f..c87e6fe20a 100644 --- a/spec/integration/knife/download_spec.rb +++ b/spec/integration/knife/download_spec.rb @@ -1069,7 +1069,7 @@ EOM end when_the_repository 'is empty' do - it 'knife download /cookbooks/x signs all requests', :ruby_gte_19_only do + it 'knife download /cookbooks/x signs all requests' do # Check that BasicClient.request() always gets called with X-OPS-USERID original_new = Chef::HTTP::BasicClient.method(:new) diff --git a/spec/integration/solo/solo_spec.rb b/spec/integration/solo/solo_spec.rb index cc9ba1abb2..41f5f5506f 100644 --- a/spec/integration/solo/solo_spec.rb +++ b/spec/integration/solo/solo_spec.rb @@ -83,8 +83,7 @@ end EOM end - # Ruby 1.8.7 doesn't have Process.spawn :( - it "while running solo concurrently", :ruby_gte_19_only => true do + it "while running solo concurrently" do file 'config/solo.rb', <<EOM cookbook_path "#{path_to('cookbooks')}" file_cache_path "#{path_to('config/cache')}" diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 995be5060b..8888efc424 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -83,8 +83,13 @@ Dir["spec/support/**/*.rb"]. OHAI_SYSTEM = Ohai::System.new OHAI_SYSTEM.all_plugins("platform") -TEST_PLATFORM = OHAI_SYSTEM["platform"].dup.freeze -TEST_PLATFORM_VERSION = OHAI_SYSTEM["platform_version"].dup.freeze + +TEST_PLATFORM = + (OHAI_SYSTEM['platform'] || + 'unknown_test_platform').dup.freeze +TEST_PLATFORM_VERSION = + (OHAI_SYSTEM['platform_version'] || + 'unknown_platform_version').dup.freeze RSpec.configure do |config| config.include(Matchers) @@ -124,11 +129,7 @@ RSpec.configure do |config| config.filter_run_excluding :aix_only => true unless aix? config.filter_run_excluding :supports_cloexec => true unless supports_cloexec? config.filter_run_excluding :selinux_only => true unless selinux_enabled? - config.filter_run_excluding :ruby_18_only => true unless ruby_18? - config.filter_run_excluding :ruby_19_only => true unless ruby_19? - config.filter_run_excluding :ruby_gte_19_only => true unless ruby_gte_19? config.filter_run_excluding :ruby_20_only => true unless ruby_20? - config.filter_run_excluding :ruby_gte_20_only => true unless ruby_gte_20? # chef_gte_XX_only and chef_lt_XX_only pair up correctly with the same XX # number. please conserve this pattern & resist filling out all the operators config.filter_run_excluding :chef_gte_13_only => true unless chef_gte_13? @@ -137,9 +138,8 @@ RSpec.configure do |config| config.filter_run_excluding :requires_root_or_running_windows => true unless (root? || windows?) config.filter_run_excluding :requires_unprivileged_user => true if root? config.filter_run_excluding :uses_diff => true unless has_diff? - config.filter_run_excluding :ruby_gte_20_and_openssl_gte_101 => true unless (ruby_gte_20? && openssl_gte_101?) + config.filter_run_excluding :openssl_gte_101 => true unless openssl_gte_101? config.filter_run_excluding :openssl_lt_101 => true unless openssl_lt_101? - config.filter_run_excluding :ruby_lt_20 => true unless ruby_lt_20? config.filter_run_excluding :aes_256_gcm_only => true unless aes_256_gcm? config.filter_run_excluding :broken => true @@ -169,6 +169,12 @@ RSpec.configure do |config| config.before(:each) do Chef::Config.reset + + # By default, treat deprecation warnings as errors in tests. + Chef::Config.treat_deprecation_warnings_as_errors(true) + + # Set environment variable so the setting persists in child processes + ENV['CHEF_TREAT_DEPRECATION_WARNINGS_AS_ERRORS'] = "1" end config.before(:suite) do diff --git a/spec/stress/win32/file_spec.rb b/spec/stress/win32/file_spec.rb index dd1dcd305e..6c4b26b05c 100644 --- a/spec/stress/win32/file_spec.rb +++ b/spec/stress/win32/file_spec.rb @@ -24,12 +24,12 @@ describe 'Chef::ReservedNames::Win32::File', :windows_only do @path = File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "data", "old_home_dir", "my-dot-emacs")) end - it "should not leak significant memory" do + it "should not leak significant memory", :volatile do test = lambda { Chef::ReservedNames::Win32::File.symlink?(@path) } expect(test).not_to leak_memory(:warmup => 50000, :iterations => 50000) end - it "should not leak handles" do + it "should not leak handles", :volatile do test = lambda { Chef::ReservedNames::Win32::File.symlink?(@path) } expect(test).not_to leak_handles(:warmup => 50, :iterations => 100) end diff --git a/spec/support/audit_helper.rb b/spec/support/audit_helper.rb deleted file mode 100644 index 8fd3f4d719..0000000000 --- a/spec/support/audit_helper.rb +++ /dev/null @@ -1,65 +0,0 @@ -# This code comes from https://github.com/rspec/rspec-core/blob/master/spec/spec_helper.rb and -# https://github.com/rspec/rspec-core/blob/master/spec/support/sandboxing.rb - -# To leverage the sandboxing use an `around` block: -# around(:each) do |ex| -# Sandboxing.sandboxed { ex.run } -# end - -# rspec-core did not include a license on Github -# TODO when this API is exposed publicly from rspec-core, get rid of this copy pasta - -# Adding these as writers is necessary, otherwise we cannot set the new configuration. -# Only want to do this in the specs. -class << RSpec - attr_writer :configuration, :world -end - -class NullObject - private - def method_missing(method, *args, &block) - # ignore - end -end - -# TODO remove this when RSPec exposes this functionality publically -# https://github.com/rspec/rspec-core/pull/1808 -module Sandboxing - def self.sandboxed(&block) - orig_load_path = $LOAD_PATH.dup - orig_config = RSpec.configuration - orig_world = RSpec.world - orig_example = RSpec.current_example - new_config = RSpec::Core::Configuration.new - new_config.expose_dsl_globally = false - new_config.expecting_with_rspec = true - new_world = RSpec::Core::World.new(new_config) - RSpec.configuration = new_config - RSpec.world = new_world - object = Object.new - object.extend(RSpec::Core::SharedExampleGroup) - - (class << RSpec::Core::ExampleGroup; self; end).class_exec do - alias_method :orig_run, :run - def run(reporter=nil) - RSpec.current_example = nil - orig_run(reporter || NullObject.new) - end - end - - RSpec::Mocks.with_temporary_scope do - object.instance_exec(&block) - end - ensure - (class << RSpec::Core::ExampleGroup; self; end).class_exec do - remove_method :run - alias_method :run, :orig_run - remove_method :orig_run - end - - RSpec.configuration = orig_config - RSpec.world = orig_world - RSpec.current_example = orig_example - $LOAD_PATH.replace(orig_load_path) - end -end diff --git a/spec/support/platform_helpers.rb b/spec/support/platform_helpers.rb index 959580c953..a412fe38e1 100644 --- a/spec/support/platform_helpers.rb +++ b/spec/support/platform_helpers.rb @@ -6,10 +6,6 @@ class ShellHelpers extend Chef::Mixin::ShellOut end -def ruby_gte_20? - RUBY_VERSION.to_f >= 2.0 -end - def ruby_lt_20? !ruby_gte_20? end @@ -30,14 +26,6 @@ def ruby_20? !!(RUBY_VERSION =~ /^2.0/) end -def ruby_19? - !!(RUBY_VERSION =~ /^1.9/) -end - -def ruby_18? - !!(RUBY_VERSION =~ /^1.8/) -end - def windows? !!(RUBY_PLATFORM =~ /mswin|mingw|windows/) end diff --git a/spec/unit/api_client_spec.rb b/spec/unit/api_client_spec.rb index 7f8687e2b9..7668e31f5a 100644 --- a/spec/unit/api_client_spec.rb +++ b/spec/unit/api_client_spec.rb @@ -129,43 +129,83 @@ describe Chef::ApiClient do end end - describe "when deserializing from JSON" do - before(:each) do - client = { - "name" => "black", - "public_key" => "crowes", - "private_key" => "monkeypants", - "admin" => true, - "validator" => true, - "json_class" => "Chef::ApiClient" - } - @client = Chef::JSONCompat.from_json(Chef::JSONCompat.to_json(client)) + describe "when deserializing from JSON (string) using ApiClient#from_json" do + let(:client_string) do + "{\"name\":\"black\",\"public_key\":\"crowes\",\"private_key\":\"monkeypants\",\"admin\":true,\"validator\":true}" + end + + let(:client) do + Chef::ApiClient.from_json(client_string) + end + + it "does not require a 'json_class' string" do + expect(Chef::JSONCompat.parse(client_string)["json_class"]).to eq(nil) end it "should deserialize to a Chef::ApiClient object" do - expect(@client).to be_a_kind_of(Chef::ApiClient) + expect(client).to be_a_kind_of(Chef::ApiClient) end it "preserves the name" do - expect(@client.name).to eq("black") + expect(client.name).to eq("black") end it "preserves the public key" do - expect(@client.public_key).to eq("crowes") + expect(client.public_key).to eq("crowes") end it "preserves the admin status" do - expect(@client.admin).to be_truthy + expect(client.admin).to be_truthy end it "preserves the 'validator' status" do - expect(@client.validator).to be_truthy + expect(client.validator).to be_truthy end it "includes the private key if present" do - expect(@client.private_key).to eq("monkeypants") + expect(client.private_key).to eq("monkeypants") + end + end + + describe "when deserializing from JSON (hash) using JSONCompat#from_json" do + let(:client_hash) do + { + "name" => "black", + "public_key" => "crowes", + "private_key" => "monkeypants", + "admin" => true, + "validator" => true, + "json_class" => "Chef::ApiClient" + } end + let(:client) do + Chef::JSONCompat.from_json(Chef::JSONCompat.to_json(client_hash)) + end + + it "should deserialize to a Chef::ApiClient object" do + expect(client).to be_a_kind_of(Chef::ApiClient) + end + + it "preserves the name" do + expect(client.name).to eq("black") + end + + it "preserves the public key" do + expect(client.public_key).to eq("crowes") + end + + it "preserves the admin status" do + expect(client.admin).to be_truthy + end + + it "preserves the 'validator' status" do + expect(client.validator).to be_truthy + end + + it "includes the private key if present" do + expect(client.private_key).to eq("monkeypants") + end end describe "when loading from JSON" do @@ -306,5 +346,3 @@ describe Chef::ApiClient do end end end - - diff --git a/spec/unit/application/apply_spec.rb b/spec/unit/application/apply_spec.rb index 5a6366281f..f6cd0bae03 100644 --- a/spec/unit/application/apply_spec.rb +++ b/spec/unit/application/apply_spec.rb @@ -91,4 +91,20 @@ describe Chef::Application::Apply do end end + describe "when the json_attribs configuration option is specified" do + let(:json_attribs) { {"a" => "b"} } + let(:config_fetcher) { double(Chef::ConfigFetcher, :fetch_json => json_attribs) } + let(:json_source) { "https://foo.com/foo.json" } + + before do + Chef::Config[:json_attribs] = json_source + expect(Chef::ConfigFetcher).to receive(:new).with(json_source). + and_return(config_fetcher) + end + + it "reads the JSON attributes from the specified source" do + @app.reconfigure + expect(@app.json_attribs).to eq(json_attribs) + end + end end diff --git a/spec/unit/application/client_spec.rb b/spec/unit/application/client_spec.rb index 33af9bc5c1..ea2ad473e5 100644 --- a/spec/unit/application/client_spec.rb +++ b/spec/unit/application/client_spec.rb @@ -26,6 +26,7 @@ describe Chef::Application::Client, "reconfigure" do before do allow(Kernel).to receive(:trap).and_return(:ok) + allow(::File).to receive(:read).with(Chef::Config.platform_specific_path("/etc/chef/client.rb")).and_return("") @original_argv = ARGV.dup ARGV.clear @@ -41,6 +42,13 @@ describe Chef::Application::Client, "reconfigure" do ARGV.replace(@original_argv) end + describe 'parse cli_arguments' do + it 'should call set_specific_recipes' do + expect(app).to receive(:set_specific_recipes).and_return(true) + app.reconfigure + end + end + describe "when configured to not fork the client process" do before do Chef::Config[:client_fork] = false @@ -215,8 +223,21 @@ Enable chef-client interval runs by setting `:client_fork = true` in your config end end end + + describe "when both the pidfile and lockfile opts are set to the same value" do + + before do + Chef::Config[:pid_file] = "/path/to/file" + Chef::Config[:lockfile] = "/path/to/file" + end + + it "should throw an exception" do + expect { @app.reconfigure }.to raise_error + end + end end + describe Chef::Application::Client, "setup_application" do before do @app = Chef::Application::Client.new @@ -236,11 +257,13 @@ describe Chef::Application::Client, "setup_application" do end describe Chef::Application::Client, "configure_chef" do + let(:app) { Chef::Application::Client.new } + before do @original_argv = ARGV.dup ARGV.clear - @app = Chef::Application::Client.new - @app.configure_chef + allow(::File).to receive(:read).with(Chef::Config.platform_specific_path("/etc/chef/client.rb")).and_return("") + app.configure_chef end after do diff --git a/spec/unit/application/solo_spec.rb b/spec/unit/application/solo_spec.rb index 2a07ff38ad..1785ecfc86 100644 --- a/spec/unit/application/solo_spec.rb +++ b/spec/unit/application/solo_spec.rb @@ -34,6 +34,11 @@ describe Chef::Application::Solo do end describe "configuring the application" do + it 'should call set_specific_recipes' do + expect(app).to receive(:set_specific_recipes) + app.reconfigure + end + it "should set solo mode to true" do app.reconfigure expect(Chef::Config[:solo]).to be_truthy diff --git a/spec/unit/application_spec.rb b/spec/unit/application_spec.rb index 210f875fbe..f5a2c72aa0 100644 --- a/spec/unit/application_spec.rb +++ b/spec/unit/application_spec.rb @@ -56,6 +56,11 @@ describe Chef::Application do expect(@app).to receive(:configure_proxy_environment_variables).and_return(true) @app.reconfigure end + + it 'should not receive set_specific_recipes' do + expect(@app).to_not receive(:set_specific_recipes) + @app.reconfigure + end end describe Chef::Application do @@ -473,6 +478,36 @@ describe Chef::Application do end end + describe 'run_chef_client' do + context 'with an application' do + let(:app) { Chef::Application.new } + + context 'when called with an invalid argument' do + before do + allow(app).to receive(:fork_chef_client).and_return(true) + allow(app).to receive(:run_with_graceful_exit_option).and_return(true) + end + + it 'should raise an argument error detailing the problem' do + specific_recipes_regexp = Regexp.new 'received non-Array like specific_recipes argument' + expect { app.run_chef_client(nil) }.to raise_error(ArgumentError, specific_recipes_regexp) + end + end + + context 'when called with an Array-like argument (#size)' do + before do + allow(app).to receive(:fork_chef_client).and_return(true) + allow(app).to receive(:run_with_graceful_exit_option).and_return(true) + end + + it 'should be cool' do + expect { app.run_chef_client([]) }.not_to raise_error + end + end + end + + end + describe "configuration errors" do before do expect(Process).to receive(:exit) diff --git a/spec/unit/audit/audit_event_proxy_spec.rb b/spec/unit/audit/audit_event_proxy_spec.rb index 899ba468b1..17a5d3d771 100644 --- a/spec/unit/audit/audit_event_proxy_spec.rb +++ b/spec/unit/audit/audit_event_proxy_spec.rb @@ -44,7 +44,7 @@ describe Chef::Audit::AuditEventProxy do it "notifies control_group_started event" do expect(Chef::Log).to receive(:debug). - with("Entered \`controls\` block named poots") + with("Entered \`control_group\` block named poots") expect(events).to receive(:control_group_started). with(description) audit_event_proxy.example_group_started(notification) @@ -76,7 +76,7 @@ describe Chef::Audit::AuditEventProxy do end it "sends a message that audits completed" do - expect(Chef::Log).to receive(:info).with("Successfully executed all \`controls\` blocks and contained examples") + expect(Chef::Log).to receive(:info).with("Successfully executed all \`control_group\` blocks and contained examples") audit_event_proxy.stop(notification) end diff --git a/spec/unit/audit/runner_spec.rb b/spec/unit/audit/runner_spec.rb index 67590fecf9..801147bdb9 100644 --- a/spec/unit/audit/runner_spec.rb +++ b/spec/unit/audit/runner_spec.rb @@ -17,11 +17,13 @@ # require 'spec_helper' -require 'spec/support/audit_helper' +require 'rspec/core/sandbox' require 'chef/audit/runner' require 'chef/audit/audit_event_proxy' require 'chef/audit/rspec_formatter' require 'rspec/support/spec/in_sub_process' +require 'rspec/support/spec/stderr_splitter' + describe Chef::Audit::Runner do include RSpec::Support::InSubProcess @@ -31,7 +33,7 @@ describe Chef::Audit::Runner do let(:runner) { Chef::Audit::Runner.new(run_context) } around(:each) do |ex| - Sandboxing.sandboxed { ex.run } + RSpec::Core::Sandbox.sandboxed { ex.run } end describe "#initialize" do @@ -76,14 +78,14 @@ describe Chef::Audit::Runner do end end - describe "#register_controls" do + describe "#register_control_groups" do let(:audits) { [] } let(:run_context) { instance_double(Chef::RunContext, :audits => audits) } it "adds the control group aliases" do - runner.send(:register_controls) + runner.send(:register_control_groups) - expect(RSpec::Core::DSL.example_group_aliases).to include(:__controls__) + expect(RSpec::Core::DSL.example_group_aliases).to include(:__control_group__) expect(RSpec::Core::DSL.example_group_aliases).to include(:control) end @@ -92,7 +94,7 @@ describe Chef::Audit::Runner do let(:group) {Struct.new(:args, :block).new(["group_name"], nil)} it "sends the audits to the world" do - runner.send(:register_controls) + runner.send(:register_control_groups) expect(RSpec.world.example_groups.size).to eq(1) # For whatever reason, `kind_of` is not working diff --git a/spec/unit/chef_fs/config_spec.rb b/spec/unit/chef_fs/config_spec.rb index 031da6c4b5..c7c47ad8ab 100644 --- a/spec/unit/chef_fs/config_spec.rb +++ b/spec/unit/chef_fs/config_spec.rb @@ -55,4 +55,56 @@ describe Chef::ChefFS::Config do Chef::ChefFS::Config.new(base_config, Dir.pwd, {}, ui) end end + + describe "local FS configuration" do + + let(:chef_config) do + Mash.new({ + client_path: "/base_path/clients", + cookbook_path: "/base_path/cookbooks", + data_bag_path: "/base_path/data_bags", + environment_path: "/base_path/environments", + node_path: "/base_path/nodes", + role_path: "/base_path/roles", + user_path: "/base_path/users", + policy_path: "/base_path/policies" + }) + end + + let(:chef_fs_config) { Chef::ChefFS::Config.new(chef_config, Dir.pwd) } + + subject(:local_fs) { chef_fs_config.local_fs } + + def platform_path(*args) + File.expand_path(*args) + end + + it "sets the correct nodes path on the local FS object" do + expect(local_fs.child_paths["nodes"]).to eq([platform_path("/base_path/nodes")]) + end + + it "sets the correct cookbook path on the local FS object" do + expect(local_fs.child_paths["cookbooks"]).to eq([platform_path("/base_path/cookbooks")]) + end + + it "sets the correct data bag path on the local FS object" do + expect(local_fs.child_paths["data_bags"]).to eq([platform_path("/base_path/data_bags")]) + end + + it "sets the correct environment path on the local FS object" do + expect(local_fs.child_paths["environments"]).to eq([platform_path("/base_path/environments")]) + end + + it "sets the correct role path on the local FS object" do + expect(local_fs.child_paths["roles"]).to eq([platform_path("/base_path/roles")]) + end + + it "sets the correct user path on the local FS object" do + expect(local_fs.child_paths["users"]).to eq([platform_path("/base_path/users")]) + end + + it "sets the correct policy path on the local FS object" do + expect(local_fs.child_paths["policies"]).to eq([platform_path("/base_path/policies")]) + end + end end diff --git a/spec/unit/chef_fs/file_pattern_spec.rb b/spec/unit/chef_fs/file_pattern_spec.rb index cdf506225a..a9f06e8424 100644 --- a/spec/unit/chef_fs/file_pattern_spec.rb +++ b/spec/unit/chef_fs/file_pattern_spec.rb @@ -355,7 +355,7 @@ describe Chef::ChefFS::FilePattern do it 'could_match_children? /abc** returns false for /xyz' do pending 'Make could_match_children? more rigorous' # At the moment, we return false for this, but in the end it would be nice to return true: - pattern.could_match_children?('/xyz').should be_falsey + expect(pattern.could_match_children?('/xyz')).to be_falsey end it 'exact_child_name_under' do expect(pattern.exact_child_name_under('/')).to eq(nil) diff --git a/spec/unit/config_spec.rb b/spec/unit/config_spec.rb index ed2003e8bf..06178f7733 100644 --- a/spec/unit/config_spec.rb +++ b/spec/unit/config_spec.rb @@ -508,4 +508,43 @@ describe Chef::Config do end end end + + describe "Treating deprecation warnings as errors" do + + context "when using our default RSpec configuration" do + + it "defaults to treating deprecation warnings as errors" do + expect(Chef::Config[:treat_deprecation_warnings_as_errors]).to be(true) + end + + it "sets CHEF_TREAT_DEPRECATION_WARNINGS_AS_ERRORS environment variable" do + expect(ENV['CHEF_TREAT_DEPRECATION_WARNINGS_AS_ERRORS']).to eq("1") + end + + it "treats deprecation warnings as errors in child processes when testing" do + # Doing a full integration test where we launch a child process is slow + # and liable to break for weird reasons (bundler env stuff, etc.), so + # we're just checking that the presence of the environment variable + # causes treat_deprecation_warnings_as_errors to be set to true after a + # config reset. + Chef::Config.reset + expect(Chef::Config[:treat_deprecation_warnings_as_errors]).to be(true) + end + + end + + context "outside of our test environment" do + + before do + ENV.delete('CHEF_TREAT_DEPRECATION_WARNINGS_AS_ERRORS') + Chef::Config.reset + end + + it "defaults to NOT treating deprecation warnings as errors" do + expect(Chef::Config[:treat_deprecation_warnings_as_errors]).to be(false) + end + end + + + end end diff --git a/spec/unit/cookbook_loader_spec.rb b/spec/unit/cookbook_loader_spec.rb index 51532778e4..45a985bafd 100644 --- a/spec/unit/cookbook_loader_spec.rb +++ b/spec/unit/cookbook_loader_spec.rb @@ -190,6 +190,11 @@ describe Chef::CookbookLoader do end describe "loading only one cookbook" do + + let(:openldap_cookbook) { cookbook_loader["openldap"] } + + let(:cookbook_as_hash) { Chef::CookbookManifest.new(openldap_cookbook).to_hash } + before(:each) do cookbook_loader.load_cookbook("openldap") end @@ -205,12 +210,11 @@ describe Chef::CookbookLoader do it "should not duplicate keys when serialized to JSON" do # Chef JSON serialization will generate duplicate keys if given # a Hash containing matching string and symbol keys. See CHEF-4571. - aa = cookbook_loader["openldap"] - expect(aa.to_hash["metadata"].recipes.keys).not_to include(:openldap) - expect(aa.to_hash["metadata"].recipes.keys).to include("openldap") + expect(cookbook_as_hash["metadata"].recipes.keys).not_to include(:openldap) + expect(cookbook_as_hash["metadata"].recipes.keys).to include("openldap") expected_desc = "Main Open LDAP configuration" - expect(aa.to_hash["metadata"].recipes["openldap"]).to eq(expected_desc) - raw = Chef::JSONCompat.to_json(aa.to_hash["metadata"].recipes) + expect(cookbook_as_hash["metadata"].recipes["openldap"]).to eq(expected_desc) + raw = Chef::JSONCompat.to_json(cookbook_as_hash["metadata"].recipes) search_str = "\"openldap\":\"" key_idx = raw.index(search_str) expect(key_idx).to be > 0 diff --git a/spec/unit/cookbook_manifest_spec.rb b/spec/unit/cookbook_manifest_spec.rb index 8b50b040c2..938f72c743 100644 --- a/spec/unit/cookbook_manifest_spec.rb +++ b/spec/unit/cookbook_manifest_spec.rb @@ -1,7 +1,6 @@ # -# Author:: Tim Hinderliter (<tim@opscode.com>) -# Author:: Christopher Walters (<cw@opscode.com>) -# Copyright:: Copyright (c) 2010 Opscode, Inc. +# Author:: Daniel DeLeo (<dan@chef.io>) +# Copyright:: Copyright (c) 2015 Opscode, Inc. # License:: Apache License, Version 2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,540 +14,214 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -# require 'spec_helper' +require 'chef/cookbook_manifest' +require 'chef/digester' +require 'pathname' -describe "Chef::CookbookVersion manifest" do - before(:each) do - @cookbook = Chef::CookbookVersion.new "test-cookbook" - @cookbook.manifest = { - "files" => - [ - # afile.rb - { - :name => "afile.rb", - :path => "files/host-examplehost.example.org/afile.rb", - :checksum => "csum-host", - :specificity => "host-examplehost.example.org" - }, - { - :name => "afile.rb", - :path => "files/ubuntu-9.10/afile.rb", - :checksum => "csum-platver-full", - :specificity => "ubuntu-9.10" - }, - { - :name => "afile.rb", - :path => "files/newubuntu-9/afile.rb", - :checksum => "csum-platver-partial", - :specificity => "newubuntu-9" - }, - { - :name => "afile.rb", - :path => "files/ubuntu/afile.rb", - :checksum => "csum-plat", - :specificity => "ubuntu" - }, - { - :name => "afile.rb", - :path => "files/default/afile.rb", - :checksum => "csum-default", - :specificity => "default" - }, - - # for different/odd platform_versions - { - :name => "bfile.rb", - :path => "files/fakeos-2.0.rc.1/bfile.rb", - :checksum => "csum2-platver-full", - :specificity => "fakeos-2.0.rc.1" - }, - { - :name => "bfile.rb", - :path => "files/newfakeos-2.0.rc/bfile.rb", - :checksum => "csum2-platver-partial", - :specificity => "newfakeos-2.0.rc" - }, - { - :name => "bfile.rb", - :path => "files/fakeos-maple tree/bfile.rb", - :checksum => "csum3-platver-full", - :specificity => "maple tree" - }, - { - :name => "bfile.rb", - :path => "files/fakeos-1/bfile.rb", - :checksum => "csum4-platver-full", - :specificity => "fakeos-1" - }, - - # directory adirectory - { - :name => "anotherfile1.rb", - :path => "files/host-examplehost.example.org/adirectory/anotherfile1.rb.host", - :checksum => "csum-host-1", - :specificity => "host-examplehost.example.org" - }, - { - :name => "anotherfile2.rb", - :path => "files/host-examplehost.example.org/adirectory/anotherfile2.rb.host", - :checksum => "csum-host-2", - :specificity => "host-examplehost.example.org" - }, - - { - :name => "anotherfile1.rb", - :path => "files/ubuntu-9.10/adirectory/anotherfile1.rb.platform-full-version", - :checksum => "csum-platver-full-1", - :specificity => "ubuntu-9.10" - }, - { - :name => "anotherfile2.rb", - :path => "files/ubuntu-9.10/adirectory/anotherfile2.rb.platform-full-version", - :checksum => "csum-platver-full-2", - :specificity => "ubuntu-9.10" - }, - - { - :name => "anotherfile1.rb", - :path => "files/newubuntu-9/adirectory/anotherfile1.rb.platform-partial-version", - :checksum => "csum-platver-partial-1", - :specificity => "newubuntu-9" - }, - { - :name => "anotherfile2.rb", - :path => "files/newubuntu-9/adirectory/anotherfile2.rb.platform-partial-version", - :checksum => "csum-platver-partial-2", - :specificity => "nweubuntu-9" - }, - - { - :name => "anotherfile1.rb", - :path => "files/ubuntu/adirectory/anotherfile1.rb.platform", - :checksum => "csum-plat-1", - :specificity => "ubuntu" - }, - { - :name => "anotherfile2.rb", - :path => "files/ubuntu/adirectory/anotherfile2.rb.platform", - :checksum => "csum-plat-2", - :specificity => "ubuntu" - }, - - { - :name => "anotherfile1.rb", - :path => "files/default/adirectory/anotherfile1.rb.default", - :checksum => "csum-default-1", - :specificity => "default" - }, - { - :name => "anotherfile2.rb", - :path => "files/default/adirectory/anotherfile2.rb.default", - :checksum => "csum-default-2", - :specificity => "default" - }, - # for different/odd platform_versions - { - :name => "anotherfile1.rb", - :path => "files/fakeos-2.0.rc.1/adirectory/anotherfile1.rb.platform-full-version", - :checksum => "csum2-platver-full-1", - :specificity => "fakeos-2.0.rc.1" - }, - { - :name => "anotherfile2.rb", - :path => "files/fakeos-2.0.rc.1/adirectory/anotherfile2.rb.platform-full-version", - :checksum => "csum2-platver-full-2", - :specificity => "fakeos-2.0.rc.1" - }, - { - :name => "anotherfile1.rb", - :path => "files/newfakeos-2.0.rc.1/adirectory/anotherfile1.rb.platform-partial-version", - :checksum => "csum2-platver-partial-1", - :specificity => "newfakeos-2.0.rc" - }, - { - :name => "anotherfile2.rb", - :path => "files/newfakeos-2.0.rc.1/adirectory/anotherfile2.rb.platform-partial-version", - :checksum => "csum2-platver-partial-2", - :specificity => "newfakeos-2.0.rc" - }, - { - :name => "anotherfile1.rb", - :path => "files/fakeos-maple tree/adirectory/anotherfile1.rb.platform-full-version", - :checksum => "csum3-platver-full-1", - :specificity => "fakeos-maple tree" - }, - { - :name => "anotherfile2.rb", - :path => "files/fakeos-maple tree/adirectory/anotherfile2.rb.platform-full-version", - :checksum => "csum3-platver-full-2", - :specificity => "fakeos-maple tree" - }, - { - :name => "anotherfile1.rb", - :path => "files/fakeos-1/adirectory/anotherfile1.rb.platform-full-version", - :checksum => "csum4-platver-full-1", - :specificity => "fakeos-1" - }, - { - :name => "anotherfile2.rb", - :path => "files/fakeos-1/adirectory/anotherfile2.rb.platform-full-version", - :checksum => "csum4-platver-full-2", - :specificity => "fakeos-1" - }, - ] - } - - end - - - it "should return a manifest record based on priority preference: host" do - node = Chef::Node.new - node.automatic_attrs[:platform] = "ubuntu" - node.automatic_attrs[:platform_version] = "9.10" - node.automatic_attrs[:fqdn] = "examplehost.example.org" - - manifest_record = @cookbook.preferred_manifest_record(node, :files, "afile.rb") - expect(manifest_record).not_to be_nil - expect(manifest_record[:checksum]).to eq("csum-host") - end - - it "should return a manifest record based on priority preference: platform & full version" do - node = Chef::Node.new - node.automatic_attrs[:platform] = "ubuntu" - node.automatic_attrs[:platform_version] = "9.10" - node.automatic_attrs[:fqdn] = "differenthost.example.org" - - manifest_record = @cookbook.preferred_manifest_record(node, :files, "afile.rb") - expect(manifest_record).not_to be_nil - expect(manifest_record[:checksum]).to eq("csum-platver-full") - end - - it "should return a manifest record based on priority preference: platform & partial version" do - node = Chef::Node.new - node.automatic_attrs[:platform] = "newubuntu" - node.automatic_attrs[:platform_version] = "9.10" - node.automatic_attrs[:fqdn] = "differenthost.example.org" - - manifest_record = @cookbook.preferred_manifest_record(node, :files, "afile.rb") - expect(manifest_record).not_to be_nil - expect(manifest_record[:checksum]).to eq("csum-platver-partial") - end +describe Chef::CookbookManifest do - it "should return a manifest record based on priority preference: platform only" do - node = Chef::Node.new - node.automatic_attrs[:platform] = "ubuntu" - node.automatic_attrs[:platform_version] = "1.0" - node.automatic_attrs[:fqdn] = "differenthost.example.org" + let(:version) { "1.2.3" } - manifest_record = @cookbook.preferred_manifest_record(node, :files, "afile.rb") - expect(manifest_record).not_to be_nil - expect(manifest_record[:checksum]).to eq("csum-plat") - end - - it "should return a manifest record based on priority preference: default" do - node = Chef::Node.new - node.automatic_attrs[:platform] = "notubuntu" - node.automatic_attrs[:platform_version] = "1.0" - node.automatic_attrs[:fqdn] = "differenthost.example.org" - - manifest_record = @cookbook.preferred_manifest_record(node, :files, "afile.rb") - expect(manifest_record).not_to be_nil - expect(manifest_record[:checksum]).to eq("csum-default") + let(:metadata) do + Chef::Cookbook::Metadata.new.tap do |m| + m.version(version) + end end - it "should return a manifest record based on priority preference: platform & full version - platform_version variant 1" do - node = Chef::Node.new - node.automatic_attrs[:platform] = "fakeos" - node.automatic_attrs[:platform_version] = "2.0.rc.1" - node.automatic_attrs[:fqdn] = "differenthost.example.org" + let(:cookbook_root) { '/tmp/blah' } - manifest_record = @cookbook.preferred_manifest_record(node, :files, "bfile.rb") - expect(manifest_record).not_to be_nil - expect(manifest_record[:checksum]).to eq("csum2-platver-full") + let(:cookbook_version) do + Chef::CookbookVersion.new("tatft", cookbook_root).tap do |c| + c.metadata = metadata + end end - it "should return a manifest record based on priority preference: platform & partial version - platform_version variant 1" do - node = Chef::Node.new - node.automatic_attrs[:platform] = "newfakeos" - node.automatic_attrs[:platform_version] = "2.0.rc.1" - node.automatic_attrs[:fqdn] = "differenthost.example.org" + let(:policy_mode) { false } - manifest_record = @cookbook.preferred_manifest_record(node, :files, "bfile.rb") - expect(manifest_record).not_to be_nil - expect(manifest_record[:checksum]).to eq("csum2-platver-partial") - end + subject(:cookbook_manifest) { Chef::CookbookManifest.new(cookbook_version, policy_mode: policy_mode) } - it "should return a manifest record based on priority preference: platform & full version - platform_version variant 2" do - node = Chef::Node.new - node.automatic_attrs[:platform] = "fakeos" - node.automatic_attrs[:platform_version] = "maple tree" - node.automatic_attrs[:fqdn] = "differenthost.example.org" + context "when policy mode is not specified" do - manifest_record = @cookbook.preferred_manifest_record(node, :files, "bfile.rb") - expect(manifest_record).not_to be_nil - expect(manifest_record[:checksum]).to eq("csum3-platver-full") - end + subject(:cookbook_manifest) { Chef::CookbookManifest.new(cookbook_version) } - it "should return a manifest record based on priority preference: platform & full version - platform_version variant 3" do - node = Chef::Node.new - node.automatic_attrs[:platform] = "fakeos" - node.automatic_attrs[:platform_version] = "1" - node.automatic_attrs[:fqdn] = "differenthost.example.org" + it "defaults to policies disabled" do + expect(cookbook_manifest.policy_mode?).to be(false) + end - manifest_record = @cookbook.preferred_manifest_record(node, :files, "bfile.rb") - expect(manifest_record).not_to be_nil - expect(manifest_record[:checksum]).to eq("csum4-platver-full") end - describe "when fetching the contents of a directory by file specificity" do - - it "should return a directory of manifest records based on priority preference: host" do - node = Chef::Node.new - node.automatic_attrs[:platform] = "ubuntu" - node.automatic_attrs[:platform_version] = "9.10" - node.automatic_attrs[:fqdn] = "examplehost.example.org" + describe "collecting cookbook data from the cookbook version object" do - manifest_records = @cookbook.preferred_manifest_records_for_directory(node, :files, "adirectory") - expect(manifest_records).not_to be_nil - expect(manifest_records.size).to eq(2) - - checksums = manifest_records.map{ |manifest_record| manifest_record[:checksum] } - expect(checksums.sort).to eq(["csum-host-1", "csum-host-2"]) + it "delegates `name' to cookbook_version" do + expect(cookbook_manifest.name).to eq("tatft") end - it "should return a directory of manifest records based on priority preference: platform & full version" do - node = Chef::Node.new - node.automatic_attrs[:platform] = "ubuntu" - node.automatic_attrs[:platform_version] = "9.10" - node.automatic_attrs[:fqdn] = "differenthost.example.org" - - manifest_records = @cookbook.preferred_manifest_records_for_directory(node, :files, "adirectory") - expect(manifest_records).not_to be_nil - expect(manifest_records.size).to eq(2) - - checksums = manifest_records.map{ |manifest_record| manifest_record[:checksum] } - expect(checksums.sort).to eq(["csum-platver-full-1", "csum-platver-full-2"]) + it "delegates `root_paths' to cookbook_version" do + expect(cookbook_manifest.root_paths).to eq(['/tmp/blah']) end - it "should return a directory of manifest records based on priority preference: platform & partial version" do - node = Chef::Node.new - node.automatic_attrs[:platform] = "newubuntu" - node.automatic_attrs[:platform_version] = "9.10" - node.automatic_attrs[:fqdn] = "differenthost.example.org" - - manifest_records = @cookbook.preferred_manifest_records_for_directory(node, :files, "adirectory") - expect(manifest_records).not_to be_nil - expect(manifest_records.size).to eq(2) - - checksums = manifest_records.map{ |manifest_record| manifest_record[:checksum] } - expect(checksums.sort).to eq(["csum-platver-partial-1", "csum-platver-partial-2"]) + it "delegates `metadata' to cookbook_version" do + expect(cookbook_manifest.metadata).to eq(metadata) end - it "should return a directory of manifest records based on priority preference: platform only" do - node = Chef::Node.new - node.automatic_attrs[:platform] = "ubuntu" - node.automatic_attrs[:platform_version] = "1.0" - node.automatic_attrs[:fqdn] = "differenthost.example.org" - - manifest_records = @cookbook.preferred_manifest_records_for_directory(node, :files, "adirectory") - expect(manifest_records).not_to be_nil - expect(manifest_records.size).to eq(2) - - checksums = manifest_records.map{ |manifest_record| manifest_record[:checksum] } - expect(checksums.sort).to eq(["csum-plat-1", "csum-plat-2"]) + it "delegates `full_name' to cookbook_version" do + expect(cookbook_manifest.full_name).to eq("tatft-1.2.3") end - it "should return a directory of manifest records based on priority preference: default" do - node = Chef::Node.new - node.automatic_attrs[:platform] = "notubuntu" - node.automatic_attrs[:platform_version] = "1.0" - node.automatic_attrs[:fqdn] = "differenthost.example.org" - - manifest_records = @cookbook.preferred_manifest_records_for_directory(node, :files, "adirectory") - expect(manifest_records).not_to be_nil - expect(manifest_records.size).to eq(2) - - checksums = manifest_records.map{ |manifest_record| manifest_record[:checksum] } - expect(checksums.sort).to eq(["csum-default-1", "csum-default-2"]) + it "delegates `version' to cookbook_version" do + expect(cookbook_manifest.version).to eq(version) end - it "should return a manifest record based on priority preference: platform & full version - platform_version variant 1" do - node = Chef::Node.new - node.automatic_attrs[:platform] = "fakeos" - node.automatic_attrs[:platform_version] = "2.0.rc.1" - node.automatic_attrs[:fqdn] = "differenthost.example.org" - - manifest_records = @cookbook.preferred_manifest_records_for_directory(node, :files, "adirectory") - expect(manifest_records).not_to be_nil - expect(manifest_records.size).to eq(2) + it "delegates `frozen_version?' to cookbook_version" do + expect(cookbook_manifest.frozen_version?).to be(false) + end - checksums = manifest_records.map{ |manifest_record| manifest_record[:checksum] } - expect(checksums.sort).to eq(["csum2-platver-full-1", "csum2-platver-full-2"]) + it "delegates `segment_filenames' to cookbook_version" do + expect(cookbook_version).to receive(:segment_filenames).with(:recipes).and_return([]) + expect(cookbook_manifest.segment_filenames(:recipes)).to eq([]) end - it "should return a manifest record based on priority preference: platform & partial version - platform_version variant 1" do - node = Chef::Node.new - node.automatic_attrs[:platform] = "newfakeos" - node.automatic_attrs[:platform_version] = "2.0.rc.1" - node.automatic_attrs[:fqdn] = "differenthost.example.org" + end - manifest_records = @cookbook.preferred_manifest_records_for_directory(node, :files, "adirectory") - expect(manifest_records).not_to be_nil - expect(manifest_records.size).to eq(2) + context "when given an empty cookbook" do - checksums = manifest_records.map{ |manifest_record| manifest_record[:checksum] } - expect(checksums.sort).to eq(["csum2-platver-partial-1", "csum2-platver-partial-2"]) - end + let(:expected_hash) do + { + "chef_type" => "cookbook_version", - it "should return a manifest record based on priority preference: platform & full version - platform_version variant 2" do - node = Chef::Node.new - node.automatic_attrs[:platform] = "fakeos" - node.automatic_attrs[:platform_version] = "maple tree" - node.automatic_attrs[:fqdn] = "differenthost.example.org" + "name" => "tatft-1.2.3", + "version" => "1.2.3", + "cookbook_name" => "tatft", + "metadata" => metadata, - manifest_records = @cookbook.preferred_manifest_records_for_directory(node, :files, "adirectory") - expect(manifest_records).not_to be_nil - expect(manifest_records.size).to eq(2) + "frozen?" => false, - checksums = manifest_records.map{ |manifest_record| manifest_record[:checksum] } - expect(checksums.sort).to eq(["csum3-platver-full-1", "csum3-platver-full-2"]) + "recipes" =>[], + "definitions" =>[], + "libraries" =>[], + "attributes" =>[], + "files" =>[], + "templates" =>[], + "resources" =>[], + "providers" =>[], + "root_files" =>[], + } end - it "should return a manifest record based on priority preference: platform & full version - platform_version variant 3" do - node = Chef::Node.new - node.automatic_attrs[:platform] = "fakeos" - node.automatic_attrs[:platform_version] = "1" - node.automatic_attrs[:fqdn] = "differenthost.example.org" - - manifest_records = @cookbook.preferred_manifest_records_for_directory(node, :files, "adirectory") - expect(manifest_records).not_to be_nil - expect(manifest_records.size).to eq(2) - - checksums = manifest_records.map{ |manifest_record| manifest_record[:checksum] } - expect(checksums.sort).to eq(["csum4-platver-full-1", "csum4-platver-full-2"]) + it "converts the CookbookVersion to a ruby Hash representation" do + expect(cookbook_manifest.to_hash).to eq(expected_hash) end + end - ## Globbing the relative paths out of the manifest records ## + context "when given a cookbook with files" do - describe "when globbing for relative file paths based on filespecificity" do - it "should return a list of relative paths based on priority preference: host" do - node = Chef::Node.new - node.automatic_attrs[:platform] = "ubuntu" - node.automatic_attrs[:platform_version] = "9.10" - node.automatic_attrs[:fqdn] = "examplehost.example.org" + let(:cookbook_root) { File.join(CHEF_SPEC_DATA, 'cb_version_cookbooks', 'tatft') } - filenames = @cookbook.relative_filenames_in_preferred_directory(node, :files, "adirectory") - expect(filenames).not_to be_nil - expect(filenames.size).to eq(2) + let(:attribute_filenames) { Dir[File.join(cookbook_root, 'attributes', '**', '*.rb')] } + let(:definition_filenames) { Dir[File.join(cookbook_root, 'definitions', '**', '*.rb')] } + let(:file_filenames) { Dir[File.join(cookbook_root, 'files', '**', '*.tgz')] } + let(:recipe_filenames) { Dir[File.join(cookbook_root, 'recipes', '**', '*.rb')] } + let(:template_filenames) { Dir[File.join(cookbook_root, 'templates', '**', '*.erb')] } + let(:library_filenames) { Dir[File.join(cookbook_root, 'libraries', '**', '*.rb')] } + let(:resource_filenames) { Dir[File.join(cookbook_root, 'resources', '**', '*.rb')] } + let(:provider_filenames) { Dir[File.join(cookbook_root, 'providers', '**', '*.rb')] } + let(:root_filenames) { Array(File.join(cookbook_root, 'README.rdoc')) } + let(:metadata_filenames) { Array(File.join(cookbook_root, 'metadata.json')) } - expect(filenames.sort).to eq(['anotherfile1.rb.host', 'anotherfile2.rb.host']) - end + let(:match_md5) { /[0-9a-f]{32}/ } - it "should return a list of relative paths based on priority preference: platform & full version" do - node = Chef::Node.new - node.automatic_attrs[:platform] = "ubuntu" - node.automatic_attrs[:platform_version] = "9.10" - node.automatic_attrs[:fqdn] = "differenthost.example.org" + def map_to_file_specs(paths) + paths.map do |path| - filenames = @cookbook.relative_filenames_in_preferred_directory(node, :files, "adirectory") - expect(filenames).not_to be_nil - expect(filenames.size).to eq(2) + relative_path = Pathname.new(path).relative_path_from(Pathname.new(cookbook_root)).to_s - expect(filenames.sort).to eq(['anotherfile1.rb.platform-full-version', 'anotherfile2.rb.platform-full-version']) + { + "name" => File.basename(path), + "path" => relative_path, + "checksum" => Chef::Digester.generate_md5_checksum_for_file(path), + "specificity" => "default", + } + end end - it "should return a list of relative paths based on priority preference: platform & partial version" do - node = Chef::Node.new - node.automatic_attrs[:platform] = "newubuntu" - node.automatic_attrs[:platform_version] = "9.10" - node.automatic_attrs[:fqdn] = "differenthost.example.org" - - filenames = @cookbook.relative_filenames_in_preferred_directory(node, :files, "adirectory") - expect(filenames).not_to be_nil - expect(filenames.size).to eq(2) + let(:expected_hash) do + { + "chef_type" => "cookbook_version", - expect(filenames.sort).to eq(['anotherfile1.rb.platform-partial-version', 'anotherfile2.rb.platform-partial-version']) - end - - it "should return a list of relative paths based on priority preference: platform only" do - node = Chef::Node.new - node.automatic_attrs[:platform] = "ubuntu" - node.automatic_attrs[:platform_version] = "1.0" - node.automatic_attrs[:fqdn] = "differenthost.example.org" + "name" => "tatft-1.2.3", + "version" => "1.2.3", + "cookbook_name" => "tatft", + "metadata" => metadata, - filenames = @cookbook.relative_filenames_in_preferred_directory(node, :files, "adirectory") - expect(filenames).not_to be_nil - expect(filenames.size).to eq(2) + "frozen?" => false, - expect(filenames.sort).to eq(['anotherfile1.rb.platform', 'anotherfile2.rb.platform']) + "recipes" => map_to_file_specs(recipe_filenames), + "definitions" => map_to_file_specs(definition_filenames), + "libraries" => map_to_file_specs(library_filenames), + "attributes" => map_to_file_specs(attribute_filenames), + "files" => map_to_file_specs(file_filenames), + "templates" => map_to_file_specs(template_filenames), + "resources" => map_to_file_specs(resource_filenames), + "providers" => map_to_file_specs(provider_filenames), + "root_files" => map_to_file_specs(root_filenames), + } end - it "should return a list of relative paths based on priority preference: default" do - node = Chef::Node.new - node.automatic_attrs[:platform] = "notubuntu" - node.automatic_attrs[:platform_version] = "1.0" - node.automatic_attrs[:fqdn] = "differenthost.example.org" + before do + cookbook_version.attribute_filenames = attribute_filenames + cookbook_version.definition_filenames = definition_filenames + cookbook_version.file_filenames = file_filenames + cookbook_version.recipe_filenames = recipe_filenames + cookbook_version.template_filenames = template_filenames + cookbook_version.library_filenames = library_filenames + cookbook_version.resource_filenames = resource_filenames + cookbook_version.provider_filenames = provider_filenames + cookbook_version.root_filenames = root_filenames + cookbook_version.metadata_filenames = metadata_filenames + end - filenames = @cookbook.relative_filenames_in_preferred_directory(node, :files, "adirectory") - expect(filenames).not_to be_nil - expect(filenames.size).to eq(2) + it "converts the CookbookVersion to a ruby Hash representation" do + cookbook_manifest_hash = cookbook_manifest.to_hash - expect(filenames.sort).to eq(['anotherfile1.rb.default', 'anotherfile2.rb.default']) + expect(cookbook_manifest_hash.keys).to match_array(expected_hash.keys) + cookbook_manifest_hash.each do |key, value| + expect(cookbook_manifest_hash[key]).to eq(expected_hash[key]) + end end - it "should return a list of relative paths based on priority preference: platform & full version - platform_version variant 1" do - node = Chef::Node.new - node.automatic_attrs[:platform] = "fakeos" - node.automatic_attrs[:platform_version] = "2.0.rc.1" - node.automatic_attrs[:fqdn] = "differenthost.example.org" + end - filenames = @cookbook.relative_filenames_in_preferred_directory(node, :files, "adirectory") - expect(filenames).not_to be_nil - expect(filenames.size).to eq(2) + describe "providing upstream URLs for save" do - expect(filenames.sort).to eq(['anotherfile1.rb.platform-full-version', 'anotherfile2.rb.platform-full-version']) - end + context "and policy mode is disabled" do - it "should return a list of relative paths based on priority preference: platform & partial version - platform_version variant 1" do - node = Chef::Node.new - node.automatic_attrs[:platform] = "newfakeos" - node.automatic_attrs[:platform_version] = "2.0.rc.1" - node.automatic_attrs[:fqdn] = "differenthost.example.org" + it "gives the save URL" do + expect(cookbook_manifest.save_url).to eq("cookbooks/tatft/1.2.3") + end - filenames = @cookbook.relative_filenames_in_preferred_directory(node, :files, "adirectory") - expect(filenames).not_to be_nil - expect(filenames.size).to eq(2) + it "gives the force save URL" do + expect(cookbook_manifest.force_save_url).to eq("cookbooks/tatft/1.2.3?force=true") + end - expect(filenames.sort).to eq(['anotherfile1.rb.platform-partial-version', 'anotherfile2.rb.platform-partial-version']) end - it "should return a list of relative paths based on priority preference: platform & full version - platform_version variant 2" do - node = Chef::Node.new - node.automatic_attrs[:platform] = "fakeos" - node.automatic_attrs[:platform_version] = "maple tree" - node.automatic_attrs[:fqdn] = "differenthost.example.org" - - filenames = @cookbook.relative_filenames_in_preferred_directory(node, :files, "adirectory") - expect(filenames).not_to be_nil - expect(filenames.size).to eq(2) + context "and policy mode is enabled" do - expect(filenames.sort).to eq(['anotherfile1.rb.platform-full-version', 'anotherfile2.rb.platform-full-version']) - end + let(:policy_mode) { true } - it "should return a list of relative paths based on priority preference: platform & full version - platform_version variant 3" do - node = Chef::Node.new - node.automatic_attrs[:platform] = "fakeos" - node.automatic_attrs[:platform_version] = "1" - node.automatic_attrs[:fqdn] = "differenthost.example.org" + it "gives the save URL" do + expect(cookbook_manifest.save_url).to eq("cookbook_artifacts/tatft/1.2.3") + end - filenames = @cookbook.relative_filenames_in_preferred_directory(node, :files, "adirectory") - expect(filenames).not_to be_nil - expect(filenames.size).to eq(2) + it "gives the force save URL" do + expect(cookbook_manifest.force_save_url).to eq("cookbook_artifacts/tatft/1.2.3?force=true") + end - expect(filenames.sort).to eq(['anotherfile1.rb.platform-full-version', 'anotherfile2.rb.platform-full-version']) end end + end + diff --git a/spec/unit/cookbook_uploader_spec.rb b/spec/unit/cookbook_uploader_spec.rb index af25baff13..152e5373f0 100644 --- a/spec/unit/cookbook_uploader_spec.rb +++ b/spec/unit/cookbook_uploader_spec.rb @@ -45,7 +45,13 @@ describe Chef::CookbookUploader do let(:sandbox_commit_uri) { "https://chef.example.org/sandboxes/abc123" } - let(:uploader) { described_class.new(cookbooks_to_upload, :rest => http_client) } + let(:policy_mode) { false } + + let(:uploader) { described_class.new(cookbooks_to_upload, rest: http_client, policy_mode: policy_mode) } + + it "defaults to not enabling policy mode" do + expect(described_class.new(cookbooks_to_upload, rest: http_client).policy_mode?).to be(false) + end it "has a list of cookbooks to upload" do expect(uploader.cookbooks).to eq(cookbooks_to_upload) @@ -61,7 +67,7 @@ describe Chef::CookbookUploader do describe "uploading cookbooks" do def url_for(cksum) - "https://storage.example.com/#{cksum}" + "https://storage.example.com/#{cksum}" end let(:sandbox_response) do @@ -94,6 +100,10 @@ describe Chef::CookbookUploader do end end + def expected_save_url(cookbook) + "cookbooks/#{cookbook.name}/#{cookbook.version}" + end + def expect_sandbox_commit expect(http_client).to receive(:put).with(sandbox_commit_uri, {:is_completed => true}) end @@ -102,7 +112,7 @@ describe Chef::CookbookUploader do cookbooks_to_upload.each do |cookbook| expect(http_client).to receive(:put). - with(cookbook.save_url, cookbook) + with(expected_save_url(cookbook), cookbook) end end @@ -155,6 +165,30 @@ describe Chef::CookbookUploader do end end + + context "when policy_mode is specified" do + + let(:cksums_not_on_remote) do + checksums_of_cookbook_files.keys + end + + let(:policy_mode) { true } + + def expected_save_url(cookbook) + "cookbook_artifacts/#{cookbook.name}/#{cookbook.version}" + end + + it "uploads all files in a sandbox transaction, then creates cookbooks on the server using cookbook_artifacts API" do + expect_sandbox_create + expect_checksum_upload + expect_sandbox_commit + expect_cookbook_create + + uploader.upload_cookbooks + end + + + end end end diff --git a/spec/unit/cookbook_version_file_specificity_spec.rb b/spec/unit/cookbook_version_file_specificity_spec.rb new file mode 100644 index 0000000000..73b10899d4 --- /dev/null +++ b/spec/unit/cookbook_version_file_specificity_spec.rb @@ -0,0 +1,554 @@ +# +# Author:: Tim Hinderliter (<tim@opscode.com>) +# Author:: Christopher Walters (<cw@opscode.com>) +# Copyright:: Copyright (c) 2010 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require 'spec_helper' + +describe Chef::CookbookVersion, "file specificity" do + before(:each) do + @cookbook = Chef::CookbookVersion.new "test-cookbook" + @cookbook.manifest = { + "files" => + [ + # afile.rb + { + :name => "afile.rb", + :path => "files/host-examplehost.example.org/afile.rb", + :checksum => "csum-host", + :specificity => "host-examplehost.example.org" + }, + { + :name => "afile.rb", + :path => "files/ubuntu-9.10/afile.rb", + :checksum => "csum-platver-full", + :specificity => "ubuntu-9.10" + }, + { + :name => "afile.rb", + :path => "files/newubuntu-9/afile.rb", + :checksum => "csum-platver-partial", + :specificity => "newubuntu-9" + }, + { + :name => "afile.rb", + :path => "files/ubuntu/afile.rb", + :checksum => "csum-plat", + :specificity => "ubuntu" + }, + { + :name => "afile.rb", + :path => "files/default/afile.rb", + :checksum => "csum-default", + :specificity => "default" + }, + + # for different/odd platform_versions + { + :name => "bfile.rb", + :path => "files/fakeos-2.0.rc.1/bfile.rb", + :checksum => "csum2-platver-full", + :specificity => "fakeos-2.0.rc.1" + }, + { + :name => "bfile.rb", + :path => "files/newfakeos-2.0.rc/bfile.rb", + :checksum => "csum2-platver-partial", + :specificity => "newfakeos-2.0.rc" + }, + { + :name => "bfile.rb", + :path => "files/fakeos-maple tree/bfile.rb", + :checksum => "csum3-platver-full", + :specificity => "maple tree" + }, + { + :name => "bfile.rb", + :path => "files/fakeos-1/bfile.rb", + :checksum => "csum4-platver-full", + :specificity => "fakeos-1" + }, + + # directory adirectory + { + :name => "anotherfile1.rb", + :path => "files/host-examplehost.example.org/adirectory/anotherfile1.rb.host", + :checksum => "csum-host-1", + :specificity => "host-examplehost.example.org" + }, + { + :name => "anotherfile2.rb", + :path => "files/host-examplehost.example.org/adirectory/anotherfile2.rb.host", + :checksum => "csum-host-2", + :specificity => "host-examplehost.example.org" + }, + + { + :name => "anotherfile1.rb", + :path => "files/ubuntu-9.10/adirectory/anotherfile1.rb.platform-full-version", + :checksum => "csum-platver-full-1", + :specificity => "ubuntu-9.10" + }, + { + :name => "anotherfile2.rb", + :path => "files/ubuntu-9.10/adirectory/anotherfile2.rb.platform-full-version", + :checksum => "csum-platver-full-2", + :specificity => "ubuntu-9.10" + }, + + { + :name => "anotherfile1.rb", + :path => "files/newubuntu-9/adirectory/anotherfile1.rb.platform-partial-version", + :checksum => "csum-platver-partial-1", + :specificity => "newubuntu-9" + }, + { + :name => "anotherfile2.rb", + :path => "files/newubuntu-9/adirectory/anotherfile2.rb.platform-partial-version", + :checksum => "csum-platver-partial-2", + :specificity => "nweubuntu-9" + }, + + { + :name => "anotherfile1.rb", + :path => "files/ubuntu/adirectory/anotherfile1.rb.platform", + :checksum => "csum-plat-1", + :specificity => "ubuntu" + }, + { + :name => "anotherfile2.rb", + :path => "files/ubuntu/adirectory/anotherfile2.rb.platform", + :checksum => "csum-plat-2", + :specificity => "ubuntu" + }, + + { + :name => "anotherfile1.rb", + :path => "files/default/adirectory/anotherfile1.rb.default", + :checksum => "csum-default-1", + :specificity => "default" + }, + { + :name => "anotherfile2.rb", + :path => "files/default/adirectory/anotherfile2.rb.default", + :checksum => "csum-default-2", + :specificity => "default" + }, + # for different/odd platform_versions + { + :name => "anotherfile1.rb", + :path => "files/fakeos-2.0.rc.1/adirectory/anotherfile1.rb.platform-full-version", + :checksum => "csum2-platver-full-1", + :specificity => "fakeos-2.0.rc.1" + }, + { + :name => "anotherfile2.rb", + :path => "files/fakeos-2.0.rc.1/adirectory/anotherfile2.rb.platform-full-version", + :checksum => "csum2-platver-full-2", + :specificity => "fakeos-2.0.rc.1" + }, + { + :name => "anotherfile1.rb", + :path => "files/newfakeos-2.0.rc.1/adirectory/anotherfile1.rb.platform-partial-version", + :checksum => "csum2-platver-partial-1", + :specificity => "newfakeos-2.0.rc" + }, + { + :name => "anotherfile2.rb", + :path => "files/newfakeos-2.0.rc.1/adirectory/anotherfile2.rb.platform-partial-version", + :checksum => "csum2-platver-partial-2", + :specificity => "newfakeos-2.0.rc" + }, + { + :name => "anotherfile1.rb", + :path => "files/fakeos-maple tree/adirectory/anotherfile1.rb.platform-full-version", + :checksum => "csum3-platver-full-1", + :specificity => "fakeos-maple tree" + }, + { + :name => "anotherfile2.rb", + :path => "files/fakeos-maple tree/adirectory/anotherfile2.rb.platform-full-version", + :checksum => "csum3-platver-full-2", + :specificity => "fakeos-maple tree" + }, + { + :name => "anotherfile1.rb", + :path => "files/fakeos-1/adirectory/anotherfile1.rb.platform-full-version", + :checksum => "csum4-platver-full-1", + :specificity => "fakeos-1" + }, + { + :name => "anotherfile2.rb", + :path => "files/fakeos-1/adirectory/anotherfile2.rb.platform-full-version", + :checksum => "csum4-platver-full-2", + :specificity => "fakeos-1" + }, + ] + } + + end + + + it "should return a manifest record based on priority preference: host" do + node = Chef::Node.new + node.automatic_attrs[:platform] = "ubuntu" + node.automatic_attrs[:platform_version] = "9.10" + node.automatic_attrs[:fqdn] = "examplehost.example.org" + + manifest_record = @cookbook.preferred_manifest_record(node, :files, "afile.rb") + expect(manifest_record).not_to be_nil + expect(manifest_record[:checksum]).to eq("csum-host") + end + + it "should return a manifest record based on priority preference: platform & full version" do + node = Chef::Node.new + node.automatic_attrs[:platform] = "ubuntu" + node.automatic_attrs[:platform_version] = "9.10" + node.automatic_attrs[:fqdn] = "differenthost.example.org" + + manifest_record = @cookbook.preferred_manifest_record(node, :files, "afile.rb") + expect(manifest_record).not_to be_nil + expect(manifest_record[:checksum]).to eq("csum-platver-full") + end + + it "should return a manifest record based on priority preference: platform & partial version" do + node = Chef::Node.new + node.automatic_attrs[:platform] = "newubuntu" + node.automatic_attrs[:platform_version] = "9.10" + node.automatic_attrs[:fqdn] = "differenthost.example.org" + + manifest_record = @cookbook.preferred_manifest_record(node, :files, "afile.rb") + expect(manifest_record).not_to be_nil + expect(manifest_record[:checksum]).to eq("csum-platver-partial") + end + + it "should return a manifest record based on priority preference: platform only" do + node = Chef::Node.new + node.automatic_attrs[:platform] = "ubuntu" + node.automatic_attrs[:platform_version] = "1.0" + node.automatic_attrs[:fqdn] = "differenthost.example.org" + + manifest_record = @cookbook.preferred_manifest_record(node, :files, "afile.rb") + expect(manifest_record).not_to be_nil + expect(manifest_record[:checksum]).to eq("csum-plat") + end + + it "should return a manifest record based on priority preference: default" do + node = Chef::Node.new + node.automatic_attrs[:platform] = "notubuntu" + node.automatic_attrs[:platform_version] = "1.0" + node.automatic_attrs[:fqdn] = "differenthost.example.org" + + manifest_record = @cookbook.preferred_manifest_record(node, :files, "afile.rb") + expect(manifest_record).not_to be_nil + expect(manifest_record[:checksum]).to eq("csum-default") + end + + it "should return a manifest record based on priority preference: platform & full version - platform_version variant 1" do + node = Chef::Node.new + node.automatic_attrs[:platform] = "fakeos" + node.automatic_attrs[:platform_version] = "2.0.rc.1" + node.automatic_attrs[:fqdn] = "differenthost.example.org" + + manifest_record = @cookbook.preferred_manifest_record(node, :files, "bfile.rb") + expect(manifest_record).not_to be_nil + expect(manifest_record[:checksum]).to eq("csum2-platver-full") + end + + it "should return a manifest record based on priority preference: platform & partial version - platform_version variant 1" do + node = Chef::Node.new + node.automatic_attrs[:platform] = "newfakeos" + node.automatic_attrs[:platform_version] = "2.0.rc.1" + node.automatic_attrs[:fqdn] = "differenthost.example.org" + + manifest_record = @cookbook.preferred_manifest_record(node, :files, "bfile.rb") + expect(manifest_record).not_to be_nil + expect(manifest_record[:checksum]).to eq("csum2-platver-partial") + end + + it "should return a manifest record based on priority preference: platform & full version - platform_version variant 2" do + node = Chef::Node.new + node.automatic_attrs[:platform] = "fakeos" + node.automatic_attrs[:platform_version] = "maple tree" + node.automatic_attrs[:fqdn] = "differenthost.example.org" + + manifest_record = @cookbook.preferred_manifest_record(node, :files, "bfile.rb") + expect(manifest_record).not_to be_nil + expect(manifest_record[:checksum]).to eq("csum3-platver-full") + end + + it "should return a manifest record based on priority preference: platform & full version - platform_version variant 3" do + node = Chef::Node.new + node.automatic_attrs[:platform] = "fakeos" + node.automatic_attrs[:platform_version] = "1" + node.automatic_attrs[:fqdn] = "differenthost.example.org" + + manifest_record = @cookbook.preferred_manifest_record(node, :files, "bfile.rb") + expect(manifest_record).not_to be_nil + expect(manifest_record[:checksum]).to eq("csum4-platver-full") + end + + describe "when fetching the contents of a directory by file specificity" do + + it "should return a directory of manifest records based on priority preference: host" do + node = Chef::Node.new + node.automatic_attrs[:platform] = "ubuntu" + node.automatic_attrs[:platform_version] = "9.10" + node.automatic_attrs[:fqdn] = "examplehost.example.org" + + manifest_records = @cookbook.preferred_manifest_records_for_directory(node, :files, "adirectory") + expect(manifest_records).not_to be_nil + expect(manifest_records.size).to eq(2) + + checksums = manifest_records.map{ |manifest_record| manifest_record[:checksum] } + expect(checksums.sort).to eq(["csum-host-1", "csum-host-2"]) + end + + it "should return a directory of manifest records based on priority preference: platform & full version" do + node = Chef::Node.new + node.automatic_attrs[:platform] = "ubuntu" + node.automatic_attrs[:platform_version] = "9.10" + node.automatic_attrs[:fqdn] = "differenthost.example.org" + + manifest_records = @cookbook.preferred_manifest_records_for_directory(node, :files, "adirectory") + expect(manifest_records).not_to be_nil + expect(manifest_records.size).to eq(2) + + checksums = manifest_records.map{ |manifest_record| manifest_record[:checksum] } + expect(checksums.sort).to eq(["csum-platver-full-1", "csum-platver-full-2"]) + end + + it "should return a directory of manifest records based on priority preference: platform & partial version" do + node = Chef::Node.new + node.automatic_attrs[:platform] = "newubuntu" + node.automatic_attrs[:platform_version] = "9.10" + node.automatic_attrs[:fqdn] = "differenthost.example.org" + + manifest_records = @cookbook.preferred_manifest_records_for_directory(node, :files, "adirectory") + expect(manifest_records).not_to be_nil + expect(manifest_records.size).to eq(2) + + checksums = manifest_records.map{ |manifest_record| manifest_record[:checksum] } + expect(checksums.sort).to eq(["csum-platver-partial-1", "csum-platver-partial-2"]) + end + + it "should return a directory of manifest records based on priority preference: platform only" do + node = Chef::Node.new + node.automatic_attrs[:platform] = "ubuntu" + node.automatic_attrs[:platform_version] = "1.0" + node.automatic_attrs[:fqdn] = "differenthost.example.org" + + manifest_records = @cookbook.preferred_manifest_records_for_directory(node, :files, "adirectory") + expect(manifest_records).not_to be_nil + expect(manifest_records.size).to eq(2) + + checksums = manifest_records.map{ |manifest_record| manifest_record[:checksum] } + expect(checksums.sort).to eq(["csum-plat-1", "csum-plat-2"]) + end + + it "should return a directory of manifest records based on priority preference: default" do + node = Chef::Node.new + node.automatic_attrs[:platform] = "notubuntu" + node.automatic_attrs[:platform_version] = "1.0" + node.automatic_attrs[:fqdn] = "differenthost.example.org" + + manifest_records = @cookbook.preferred_manifest_records_for_directory(node, :files, "adirectory") + expect(manifest_records).not_to be_nil + expect(manifest_records.size).to eq(2) + + checksums = manifest_records.map{ |manifest_record| manifest_record[:checksum] } + expect(checksums.sort).to eq(["csum-default-1", "csum-default-2"]) + end + + it "should return a manifest record based on priority preference: platform & full version - platform_version variant 1" do + node = Chef::Node.new + node.automatic_attrs[:platform] = "fakeos" + node.automatic_attrs[:platform_version] = "2.0.rc.1" + node.automatic_attrs[:fqdn] = "differenthost.example.org" + + manifest_records = @cookbook.preferred_manifest_records_for_directory(node, :files, "adirectory") + expect(manifest_records).not_to be_nil + expect(manifest_records.size).to eq(2) + + checksums = manifest_records.map{ |manifest_record| manifest_record[:checksum] } + expect(checksums.sort).to eq(["csum2-platver-full-1", "csum2-platver-full-2"]) + end + + it "should return a manifest record based on priority preference: platform & partial version - platform_version variant 1" do + node = Chef::Node.new + node.automatic_attrs[:platform] = "newfakeos" + node.automatic_attrs[:platform_version] = "2.0.rc.1" + node.automatic_attrs[:fqdn] = "differenthost.example.org" + + manifest_records = @cookbook.preferred_manifest_records_for_directory(node, :files, "adirectory") + expect(manifest_records).not_to be_nil + expect(manifest_records.size).to eq(2) + + checksums = manifest_records.map{ |manifest_record| manifest_record[:checksum] } + expect(checksums.sort).to eq(["csum2-platver-partial-1", "csum2-platver-partial-2"]) + end + + it "should return a manifest record based on priority preference: platform & full version - platform_version variant 2" do + node = Chef::Node.new + node.automatic_attrs[:platform] = "fakeos" + node.automatic_attrs[:platform_version] = "maple tree" + node.automatic_attrs[:fqdn] = "differenthost.example.org" + + manifest_records = @cookbook.preferred_manifest_records_for_directory(node, :files, "adirectory") + expect(manifest_records).not_to be_nil + expect(manifest_records.size).to eq(2) + + checksums = manifest_records.map{ |manifest_record| manifest_record[:checksum] } + expect(checksums.sort).to eq(["csum3-platver-full-1", "csum3-platver-full-2"]) + end + + it "should return a manifest record based on priority preference: platform & full version - platform_version variant 3" do + node = Chef::Node.new + node.automatic_attrs[:platform] = "fakeos" + node.automatic_attrs[:platform_version] = "1" + node.automatic_attrs[:fqdn] = "differenthost.example.org" + + manifest_records = @cookbook.preferred_manifest_records_for_directory(node, :files, "adirectory") + expect(manifest_records).not_to be_nil + expect(manifest_records.size).to eq(2) + + checksums = manifest_records.map{ |manifest_record| manifest_record[:checksum] } + expect(checksums.sort).to eq(["csum4-platver-full-1", "csum4-platver-full-2"]) + end + end + + ## Globbing the relative paths out of the manifest records ## + + describe "when globbing for relative file paths based on filespecificity" do + it "should return a list of relative paths based on priority preference: host" do + node = Chef::Node.new + node.automatic_attrs[:platform] = "ubuntu" + node.automatic_attrs[:platform_version] = "9.10" + node.automatic_attrs[:fqdn] = "examplehost.example.org" + + filenames = @cookbook.relative_filenames_in_preferred_directory(node, :files, "adirectory") + expect(filenames).not_to be_nil + expect(filenames.size).to eq(2) + + expect(filenames.sort).to eq(['anotherfile1.rb.host', 'anotherfile2.rb.host']) + end + + it "should return a list of relative paths based on priority preference: platform & full version" do + node = Chef::Node.new + node.automatic_attrs[:platform] = "ubuntu" + node.automatic_attrs[:platform_version] = "9.10" + node.automatic_attrs[:fqdn] = "differenthost.example.org" + + filenames = @cookbook.relative_filenames_in_preferred_directory(node, :files, "adirectory") + expect(filenames).not_to be_nil + expect(filenames.size).to eq(2) + + expect(filenames.sort).to eq(['anotherfile1.rb.platform-full-version', 'anotherfile2.rb.platform-full-version']) + end + + it "should return a list of relative paths based on priority preference: platform & partial version" do + node = Chef::Node.new + node.automatic_attrs[:platform] = "newubuntu" + node.automatic_attrs[:platform_version] = "9.10" + node.automatic_attrs[:fqdn] = "differenthost.example.org" + + filenames = @cookbook.relative_filenames_in_preferred_directory(node, :files, "adirectory") + expect(filenames).not_to be_nil + expect(filenames.size).to eq(2) + + expect(filenames.sort).to eq(['anotherfile1.rb.platform-partial-version', 'anotherfile2.rb.platform-partial-version']) + end + + it "should return a list of relative paths based on priority preference: platform only" do + node = Chef::Node.new + node.automatic_attrs[:platform] = "ubuntu" + node.automatic_attrs[:platform_version] = "1.0" + node.automatic_attrs[:fqdn] = "differenthost.example.org" + + filenames = @cookbook.relative_filenames_in_preferred_directory(node, :files, "adirectory") + expect(filenames).not_to be_nil + expect(filenames.size).to eq(2) + + expect(filenames.sort).to eq(['anotherfile1.rb.platform', 'anotherfile2.rb.platform']) + end + + it "should return a list of relative paths based on priority preference: default" do + node = Chef::Node.new + node.automatic_attrs[:platform] = "notubuntu" + node.automatic_attrs[:platform_version] = "1.0" + node.automatic_attrs[:fqdn] = "differenthost.example.org" + + filenames = @cookbook.relative_filenames_in_preferred_directory(node, :files, "adirectory") + expect(filenames).not_to be_nil + expect(filenames.size).to eq(2) + + expect(filenames.sort).to eq(['anotherfile1.rb.default', 'anotherfile2.rb.default']) + end + + it "should return a list of relative paths based on priority preference: platform & full version - platform_version variant 1" do + node = Chef::Node.new + node.automatic_attrs[:platform] = "fakeos" + node.automatic_attrs[:platform_version] = "2.0.rc.1" + node.automatic_attrs[:fqdn] = "differenthost.example.org" + + filenames = @cookbook.relative_filenames_in_preferred_directory(node, :files, "adirectory") + expect(filenames).not_to be_nil + expect(filenames.size).to eq(2) + + expect(filenames.sort).to eq(['anotherfile1.rb.platform-full-version', 'anotherfile2.rb.platform-full-version']) + end + + it "should return a list of relative paths based on priority preference: platform & partial version - platform_version variant 1" do + node = Chef::Node.new + node.automatic_attrs[:platform] = "newfakeos" + node.automatic_attrs[:platform_version] = "2.0.rc.1" + node.automatic_attrs[:fqdn] = "differenthost.example.org" + + filenames = @cookbook.relative_filenames_in_preferred_directory(node, :files, "adirectory") + expect(filenames).not_to be_nil + expect(filenames.size).to eq(2) + + expect(filenames.sort).to eq(['anotherfile1.rb.platform-partial-version', 'anotherfile2.rb.platform-partial-version']) + end + + it "should return a list of relative paths based on priority preference: platform & full version - platform_version variant 2" do + node = Chef::Node.new + node.automatic_attrs[:platform] = "fakeos" + node.automatic_attrs[:platform_version] = "maple tree" + node.automatic_attrs[:fqdn] = "differenthost.example.org" + + filenames = @cookbook.relative_filenames_in_preferred_directory(node, :files, "adirectory") + expect(filenames).not_to be_nil + expect(filenames.size).to eq(2) + + expect(filenames.sort).to eq(['anotherfile1.rb.platform-full-version', 'anotherfile2.rb.platform-full-version']) + end + + it "should return a list of relative paths based on priority preference: platform & full version - platform_version variant 3" do + node = Chef::Node.new + node.automatic_attrs[:platform] = "fakeos" + node.automatic_attrs[:platform_version] = "1" + node.automatic_attrs[:fqdn] = "differenthost.example.org" + + filenames = @cookbook.relative_filenames_in_preferred_directory(node, :files, "adirectory") + expect(filenames).not_to be_nil + expect(filenames.size).to eq(2) + + expect(filenames.sort).to eq(['anotherfile1.rb.platform-full-version', 'anotherfile2.rb.platform-full-version']) + end + end +end diff --git a/spec/unit/cookbook_version_spec.rb b/spec/unit/cookbook_version_spec.rb index 6dd3429ffc..440dd9da6c 100644 --- a/spec/unit/cookbook_version_spec.rb +++ b/spec/unit/cookbook_version_spec.rb @@ -68,32 +68,10 @@ describe Chef::CookbookVersion do expect(@cookbook_version).to be_frozen_version end - it "is \"ready\"" do - # WTF is this? what are the valid states? and why aren't they set with encapsulating methods? - # [Dan 15-Jul-2010] - expect(@cookbook_version.status).to eq(:ready) - end - it "has empty metadata" do expect(@cookbook_version.metadata).to eq(Chef::Cookbook::Metadata.new) end - it "creates a manifest hash of its contents" do - expected = {"recipes"=>[], - "definitions"=>[], - "libraries"=>[], - "attributes"=>[], - "files"=>[], - "templates"=>[], - "resources"=>[], - "providers"=>[], - "root_files"=>[], - "cookbook_name"=>"tatft", - "metadata"=>Chef::Cookbook::Metadata.new, - "version"=>"0.0.0", - "name"=>"tatft-0.0.0"} - expect(@cookbook_version.manifest).to eq(expected) - end end describe "with a cookbook directory named tatft" do @@ -141,85 +119,6 @@ describe Chef::CookbookVersion do @node.name("testing") end - it "generates a manifest containing the cookbook's files" do - manifest = @cookbook_version.manifest - - expect(manifest["metadata"]).to eq(Chef::Cookbook::Metadata.new) - expect(manifest["cookbook_name"]).to eq("tatft") - - expect(manifest["recipes"].size).to eq(1) - - recipe = manifest["recipes"].first - expect(recipe["name"]).to eq("default.rb") - expect(recipe["path"]).to eq("recipes/default.rb") - expect(recipe["checksum"]).to match(MD5) - expect(recipe["specificity"]).to eq("default") - - expect(manifest["definitions"].size).to eq(1) - - definition = manifest["definitions"].first - expect(definition["name"]).to eq("runit_service.rb") - expect(definition["path"]).to eq("definitions/runit_service.rb") - expect(definition["checksum"]).to match(MD5) - expect(definition["specificity"]).to eq("default") - - expect(manifest["libraries"].size).to eq(1) - - library = manifest["libraries"].first - expect(library["name"]).to eq("ownage.rb") - expect(library["path"]).to eq("libraries/ownage.rb") - expect(library["checksum"]).to match(MD5) - expect(library["specificity"]).to eq("default") - - expect(manifest["attributes"].size).to eq(1) - - attribute_file = manifest["attributes"].first - expect(attribute_file["name"]).to eq("default.rb") - expect(attribute_file["path"]).to eq("attributes/default.rb") - expect(attribute_file["checksum"]).to match(MD5) - expect(attribute_file["specificity"]).to eq("default") - - expect(manifest["files"].size).to eq(1) - - cookbook_file = manifest["files"].first - expect(cookbook_file["name"]).to eq("giant_blob.tgz") - expect(cookbook_file["path"]).to eq("files/default/giant_blob.tgz") - expect(cookbook_file["checksum"]).to match(MD5) - expect(cookbook_file["specificity"]).to eq("default") - - expect(manifest["templates"].size).to eq(1) - - template = manifest["templates"].first - expect(template["name"]).to eq("configuration.erb") - expect(template["path"]).to eq("templates/default/configuration.erb") - expect(template["checksum"]).to match(MD5) - expect(template["specificity"]).to eq("default") - - expect(manifest["resources"].size).to eq(1) - - lwr = manifest["resources"].first - expect(lwr["name"]).to eq("lwr.rb") - expect(lwr["path"]).to eq("resources/lwr.rb") - expect(lwr["checksum"]).to match(MD5) - expect(lwr["specificity"]).to eq("default") - - expect(manifest["providers"].size).to eq(1) - - lwp = manifest["providers"].first - expect(lwp["name"]).to eq("lwp.rb") - expect(lwp["path"]).to eq("providers/lwp.rb") - expect(lwp["checksum"]).to match(MD5) - expect(lwp["specificity"]).to eq("default") - - expect(manifest["root_files"].size).to eq(1) - - readme = manifest["root_files"].first - expect(readme["name"]).to eq("README.rdoc") - expect(readme["path"]).to eq("README.rdoc") - expect(readme["checksum"]).to match(MD5) - expect(readme["specificity"]).to eq("default") - end - it "determines whether a template is available for a given node" do expect(@cookbook_version).to have_template_for_node(@node, "configuration.erb") expect(@cookbook_version).not_to have_template_for_node(@node, "missing.erb") @@ -253,102 +152,6 @@ describe Chef::CookbookVersion do end end - describe "and a cookbook_version with a different name" do - before do - # Currently the cookbook loader finds all the files then tells CookbookVersion - # where they are. - @cookbook_version = Chef::CookbookVersion.new("blarghle", @cookbook_root) - @cookbook_version.attribute_filenames = @cookbook[:attribute_filenames] - @cookbook_version.definition_filenames = @cookbook[:definition_filenames] - @cookbook_version.recipe_filenames = @cookbook[:recipe_filenames] - @cookbook_version.template_filenames = @cookbook[:template_filenames] - @cookbook_version.file_filenames = @cookbook[:file_filenames] - @cookbook_version.library_filenames = @cookbook[:library_filenames] - @cookbook_version.resource_filenames = @cookbook[:resource_filenames] - @cookbook_version.provider_filenames = @cookbook[:provider_filenames] - @cookbook_version.root_filenames = @cookbook[:root_filenames] - @cookbook_version.metadata_filenames = @cookbook[:metadata_filenames] - end - - it "generates a manifest containing the cookbook's files" do - manifest = @cookbook_version.manifest - - expect(manifest["metadata"]).to eq(Chef::Cookbook::Metadata.new) - expect(manifest["cookbook_name"]).to eq("blarghle") - - expect(manifest["recipes"].size).to eq(1) - - recipe = manifest["recipes"].first - expect(recipe["name"]).to eq("default.rb") - expect(recipe["path"]).to eq("recipes/default.rb") - expect(recipe["checksum"]).to match(MD5) - expect(recipe["specificity"]).to eq("default") - - expect(manifest["definitions"].size).to eq(1) - - definition = manifest["definitions"].first - expect(definition["name"]).to eq("runit_service.rb") - expect(definition["path"]).to eq("definitions/runit_service.rb") - expect(definition["checksum"]).to match(MD5) - expect(definition["specificity"]).to eq("default") - - expect(manifest["libraries"].size).to eq(1) - - library = manifest["libraries"].first - expect(library["name"]).to eq("ownage.rb") - expect(library["path"]).to eq("libraries/ownage.rb") - expect(library["checksum"]).to match(MD5) - expect(library["specificity"]).to eq("default") - - expect(manifest["attributes"].size).to eq(1) - - attribute_file = manifest["attributes"].first - expect(attribute_file["name"]).to eq("default.rb") - expect(attribute_file["path"]).to eq("attributes/default.rb") - expect(attribute_file["checksum"]).to match(MD5) - expect(attribute_file["specificity"]).to eq("default") - - expect(manifest["files"].size).to eq(1) - - cookbook_file = manifest["files"].first - expect(cookbook_file["name"]).to eq("giant_blob.tgz") - expect(cookbook_file["path"]).to eq("files/default/giant_blob.tgz") - expect(cookbook_file["checksum"]).to match(MD5) - expect(cookbook_file["specificity"]).to eq("default") - - expect(manifest["templates"].size).to eq(1) - - template = manifest["templates"].first - expect(template["name"]).to eq("configuration.erb") - expect(template["path"]).to eq("templates/default/configuration.erb") - expect(template["checksum"]).to match(MD5) - expect(template["specificity"]).to eq("default") - - expect(manifest["resources"].size).to eq(1) - - lwr = manifest["resources"].first - expect(lwr["name"]).to eq("lwr.rb") - expect(lwr["path"]).to eq("resources/lwr.rb") - expect(lwr["checksum"]).to match(MD5) - expect(lwr["specificity"]).to eq("default") - - expect(manifest["providers"].size).to eq(1) - - lwp = manifest["providers"].first - expect(lwp["name"]).to eq("lwp.rb") - expect(lwp["path"]).to eq("providers/lwp.rb") - expect(lwp["checksum"]).to match(MD5) - expect(lwp["specificity"]).to eq("default") - - expect(manifest["root_files"].size).to eq(1) - - readme = manifest["root_files"].first - expect(readme["name"]).to eq("README.rdoc") - expect(readme["path"]).to eq("README.rdoc") - expect(readme["checksum"]).to match(MD5) - expect(readme["specificity"]).to eq("default") - end - end end describe 'with a cookbook directory named cookbook2 that has unscoped files' do @@ -499,8 +302,63 @@ describe Chef::CookbookVersion do end - include_examples "to_json equalivent to Chef::JSONCompat.to_json" do - let(:jsonable) { Chef::CookbookVersion.new("tatft", '/tmp/blah') } + describe "when deprecation warnings are errors" do + + subject(:cbv) { Chef::CookbookVersion.new("version validation", '/tmp/blah') } + + describe "HTTP Resource behaviors", pending: "will be deprected when CookbookManifest API is stablized" do + + it "errors on #save_url" do + expect { cbv.save_url }.to raise_error(Chef::Exceptions::DeprecatedFeatureError) + end + + it "errors on #force_save_url" do + expect { cbv.force_save_url }.to raise_error(Chef::Exceptions::DeprecatedFeatureError) + end + + it "errors on #to_hash" do + expect { cbv.to_hash }.to raise_error(Chef::Exceptions::DeprecatedFeatureError) + end + + it "errors on #to_json" do + expect { cbv.to_json }.to raise_error(Chef::Exceptions::DeprecatedFeatureError) + end + + end + + it "errors on #status and #status=" do + expect { cbv.status = :wat }.to raise_error(Chef::Exceptions::DeprecatedFeatureError) + expect { cbv.status }.to raise_error(Chef::Exceptions::DeprecatedFeatureError) + end + end + describe "deprecated features" do + + subject(:cbv) { Chef::CookbookVersion.new("tatft", '/tmp/blah').tap { |c| c.version = "1.2.3" } } + + before do + Chef::Config[:treat_deprecation_warnings_as_errors] = false + end + + it "gives a save URL for the standard cookbook API" do + expect(cbv.save_url).to eq("cookbooks/tatft/1.2.3") + end + + it "gives a force save URL for the standard cookbook API" do + expect(cbv.force_save_url).to eq("cookbooks/tatft/1.2.3?force=true") + end + + it "is \"ready\"" do + # WTF is this? what are the valid states? and why aren't they set with encapsulating methods? + # [Dan 15-Jul-2010] + expect(cbv.status).to eq(:ready) + end + + + include_examples "to_json equalivent to Chef::JSONCompat.to_json" do + let(:jsonable) { Chef::CookbookVersion.new("tatft", '/tmp/blah') } + end + + end end diff --git a/spec/unit/data_bag_item_spec.rb b/spec/unit/data_bag_item_spec.rb index 4cf6e59242..4348252388 100644 --- a/spec/unit/data_bag_item_spec.rb +++ b/spec/unit/data_bag_item_spec.rb @@ -20,86 +20,86 @@ require 'spec_helper' require 'chef/data_bag_item' describe Chef::DataBagItem do - before(:each) do - @data_bag_item = Chef::DataBagItem.new - end + let(:data_bag_item) { Chef::DataBagItem.new } describe "initialize" do it "should be a Chef::DataBagItem" do - expect(@data_bag_item).to be_a_kind_of(Chef::DataBagItem) + expect(data_bag_item).to be_a_kind_of(Chef::DataBagItem) end end describe "data_bag" do it "should let you set the data_bag to a string" do - expect(@data_bag_item.data_bag("clowns")).to eq("clowns") + expect(data_bag_item.data_bag("clowns")).to eq("clowns") end it "should return the current data_bag type" do - @data_bag_item.data_bag "clowns" - expect(@data_bag_item.data_bag).to eq("clowns") + data_bag_item.data_bag "clowns" + expect(data_bag_item.data_bag).to eq("clowns") end it "should not accept spaces" do - expect { @data_bag_item.data_bag "clown masters" }.to raise_error(ArgumentError) + expect { data_bag_item.data_bag "clown masters" }.to raise_error(ArgumentError) end it "should throw an ArgumentError if you feed it anything but a string" do - expect { @data_bag_item.data_bag Hash.new }.to raise_error(ArgumentError) + expect { data_bag_item.data_bag Hash.new }.to raise_error(ArgumentError) end end describe "raw_data" do it "should let you set the raw_data with a hash" do - expect { @data_bag_item.raw_data = { "id" => "octahedron" } }.not_to raise_error + expect { data_bag_item.raw_data = { "id" => "octahedron" } }.not_to raise_error end it "should let you set the raw_data from a mash" do - expect { @data_bag_item.raw_data = Mash.new({ "id" => "octahedron" }) }.not_to raise_error + expect { data_bag_item.raw_data = Mash.new({ "id" => "octahedron" }) }.not_to raise_error end it "should raise an exception if you set the raw data without a key" do - expect { @data_bag_item.raw_data = { "monkey" => "pants" } }.to raise_error(ArgumentError) + expect { data_bag_item.raw_data = { "monkey" => "pants" } }.to raise_error(ArgumentError) end it "should raise an exception if you set the raw data to something other than a hash" do - expect { @data_bag_item.raw_data = "katie rules" }.to raise_error(ArgumentError) + expect { data_bag_item.raw_data = "katie rules" }.to raise_error(ArgumentError) end it "should accept alphanum/-/_ for the id" do - expect { @data_bag_item.raw_data = { "id" => "h1-_" } }.not_to raise_error + expect { data_bag_item.raw_data = { "id" => "h1-_" } }.not_to raise_error end it "should accept alphanum.alphanum for the id" do - expect { @data_bag_item.raw_data = { "id" => "foo.bar" } }.not_to raise_error + expect { data_bag_item.raw_data = { "id" => "foo.bar" } }.not_to raise_error end it "should accept .alphanum for the id" do - expect { @data_bag_item.raw_data = { "id" => ".bozo" } }.not_to raise_error + expect { data_bag_item.raw_data = { "id" => ".bozo" } }.not_to raise_error end it "should raise an exception if the id contains anything but alphanum/-/_" do - expect { @data_bag_item.raw_data = { "id" => "!@#" } }.to raise_error(ArgumentError) + expect { data_bag_item.raw_data = { "id" => "!@#" } }.to raise_error(ArgumentError) end it "should return the raw data" do - @data_bag_item.raw_data = { "id" => "highway_of_emptiness" } - expect(@data_bag_item.raw_data).to eq({ "id" => "highway_of_emptiness" }) + data_bag_item.raw_data = { "id" => "highway_of_emptiness" } + expect(data_bag_item.raw_data).to eq({ "id" => "highway_of_emptiness" }) end it "should be a Mash by default" do - expect(@data_bag_item.raw_data).to be_a_kind_of(Mash) + expect(data_bag_item.raw_data).to be_a_kind_of(Mash) end end describe "object_name" do - before(:each) do - @data_bag_item.data_bag("dreams") - @data_bag_item.raw_data = { "id" => "the_beatdown" } - end + let(:data_bag_item) { + data_bag_item = Chef::DataBagItem.new + data_bag_item.data_bag("dreams") + data_bag_item.raw_data = { "id" => "the_beatdown" } + data_bag_item + } it "should return an object name based on the bag name and the raw_data id" do - expect(@data_bag_item.object_name).to eq("data_bag_item_dreams_the_beatdown") + expect(data_bag_item.object_name).to eq("data_bag_item_dreams_the_beatdown") end end @@ -110,17 +110,19 @@ describe Chef::DataBagItem do end describe "when used like a Hash" do - before(:each) do - @data_bag_item.raw_data = { "id" => "journey", "trials" => "been through" } - end + let(:data_bag_item) { + data_bag_item = Chef::DataBagItem.new + data_bag_item.raw_data = { "id" => "journey", "trials" => "been through" } + data_bag_item + } it "responds to keys" do - expect(@data_bag_item.keys).to include("id") - expect(@data_bag_item.keys).to include("trials") + expect(data_bag_item.keys).to include("id") + expect(data_bag_item.keys).to include("trials") end it "supports element reference with []" do - expect(@data_bag_item["id"]).to eq("journey") + expect(data_bag_item["id"]).to eq("journey") end it "implements all the methods of Hash" do @@ -131,100 +133,113 @@ describe Chef::DataBagItem do :invert, :update, :replace, :merge!, :merge, :has_key?, :has_value?, :key?, :value?] methods.each do |m| - expect(@data_bag_item).to respond_to(m) + expect(data_bag_item).to respond_to(m) end end - end describe "to_hash" do - before(:each) do - @data_bag_item.data_bag("still_lost") - @data_bag_item.raw_data = { "id" => "whoa", "i_know" => "kung_fu" } - @to_hash = @data_bag_item.to_hash - end + let(:data_bag_item) { + data_bag_item = Chef::DataBagItem.new + data_bag_item.data_bag("still_lost") + data_bag_item.raw_data = { "id" => "whoa", "i_know" => "kung_fu" } + data_bag_item + } + + let(:to_hash) { data_bag_item.to_hash } it "should return a hash" do - expect(@to_hash).to be_a_kind_of(Hash) + expect(to_hash).to be_a_kind_of(Hash) end it "should have the raw_data keys as top level keys" do - expect(@to_hash["id"]).to eq("whoa") - expect(@to_hash["i_know"]).to eq("kung_fu") + expect(to_hash["id"]).to eq("whoa") + expect(to_hash["i_know"]).to eq("kung_fu") end it "should have the chef_type of data_bag_item" do - expect(@to_hash["chef_type"]).to eq("data_bag_item") + expect(to_hash["chef_type"]).to eq("data_bag_item") end it "should have the data_bag set" do - expect(@to_hash["data_bag"]).to eq("still_lost") + expect(to_hash["data_bag"]).to eq("still_lost") end end describe "when deserializing from JSON" do - before(:each) do - @data_bag_item.data_bag('mars_volta') - @data_bag_item.raw_data = { "id" => "octahedron", "snooze" => { "finally" => :world_will }} - @deserial = Chef::JSONCompat.from_json(Chef::JSONCompat.to_json(@data_bag_item)) - end + let(:data_bag_item) { + data_bag_item = Chef::DataBagItem.new + data_bag_item.data_bag('mars_volta') + data_bag_item.raw_data = { "id" => "octahedron", "snooze" => { "finally" => :world_will } } + data_bag_item + } + + let(:deserial) { Chef::JSONCompat.from_json(Chef::JSONCompat.to_json(data_bag_item)) } + it "should deserialize to a Chef::DataBagItem object" do - expect(@deserial).to be_a_kind_of(Chef::DataBagItem) + expect(deserial).to be_a_kind_of(Chef::DataBagItem) end it "should have a matching 'data_bag' value" do - expect(@deserial.data_bag).to eq(@data_bag_item.data_bag) + expect(deserial.data_bag).to eq(data_bag_item.data_bag) end it "should have a matching 'id' key" do - expect(@deserial["id"]).to eq("octahedron") + expect(deserial["id"]).to eq("octahedron") end it "should have a matching 'snooze' key" do - expect(@deserial["snooze"]).to eq({ "finally" => "world_will" }) + expect(deserial["snooze"]).to eq({ "finally" => "world_will" }) end include_examples "to_json equalivent to Chef::JSONCompat.to_json" do - let(:jsonable) { @data_bag_item } + let(:jsonable) { data_bag_item } end end describe "when converting to a string" do it "converts to a string in the form data_bag_item[ID]" do - @data_bag_item['id'] = "heart of darkness" - expect(@data_bag_item.to_s).to eq('data_bag_item[heart of darkness]') + data_bag_item['id'] = "heart of darkness" + expect(data_bag_item.to_s).to eq('data_bag_item[heart of darkness]') end it "inspects as data_bag_item[BAG, ID, RAW_DATA]" do raw_data = {"id" => "heart_of_darkness", "author" => "Conrad"} - @data_bag_item.raw_data = raw_data - @data_bag_item.data_bag("books") + data_bag_item.raw_data = raw_data + data_bag_item.data_bag("books") - expect(@data_bag_item.inspect).to eq("data_bag_item[\"books\", \"heart_of_darkness\", #{raw_data.inspect}]") + expect(data_bag_item.inspect).to eq("data_bag_item[\"books\", \"heart_of_darkness\", #{raw_data.inspect}]") end end describe "save" do + let(:server) { instance_double(Chef::REST) } + + let(:data_bag_item) { + data_bag_item = Chef::DataBagItem.new + data_bag_item['id'] = "heart of darkness" + data_bag_item.raw_data = {"id" => "heart_of_darkness", "author" => "Conrad"} + data_bag_item.data_bag("books") + data_bag_item + } + before do - @rest = double("Chef::REST") - allow(Chef::REST).to receive(:new).and_return(@rest) - @data_bag_item['id'] = "heart of darkness" - raw_data = {"id" => "heart_of_darkness", "author" => "Conrad"} - @data_bag_item.raw_data = raw_data - @data_bag_item.data_bag("books") + expect(Chef::REST).to receive(:new).and_return(server) end + it "should update the item when it already exists" do - expect(@rest).to receive(:put_rest).with("data/books/heart_of_darkness", @data_bag_item) - @data_bag_item.save + expect(server).to receive(:put_rest).with("data/books/heart_of_darkness", data_bag_item) + data_bag_item.save end it "should create if the item is not found" do exception = double("404 error", :code => "404") - expect(@rest).to receive(:put_rest).and_raise(Net::HTTPServerException.new("foo", exception)) - expect(@rest).to receive(:post_rest).with("data/books", @data_bag_item) - @data_bag_item.save + expect(server).to receive(:put_rest).and_raise(Net::HTTPServerException.new("foo", exception)) + expect(server).to receive(:post_rest).with("data/books", data_bag_item) + data_bag_item.save end + describe "when whyrun mode is enabled" do before do Chef::Config[:why_run] = true @@ -232,41 +247,60 @@ describe Chef::DataBagItem do after do Chef::Config[:why_run] = false end + it "should not save" do - expect(@rest).not_to receive(:put_rest) - expect(@rest).not_to receive(:post_rest) - @data_bag_item.data_bag("books") - @data_bag_item.save + expect(server).not_to receive(:put_rest) + expect(server).not_to receive(:post_rest) + data_bag_item.data_bag("books") + data_bag_item.save end end + end + + describe "destroy" do + let(:server) { instance_double(Chef::REST) } + + let(:data_bag_item) { + data_bag_item = Chef::DataBagItem.new + data_bag_item.data_bag('a_baggy_bag') + data_bag_item.raw_data = { "id" => "some_id" } + data_bag_item + } + it "should set default parameters" do + expect(Chef::REST).to receive(:new).and_return(server) + expect(server).to receive(:delete_rest).with("data/a_baggy_bag/data_bag_item_a_baggy_bag_some_id") + + data_bag_item.destroy + end end describe "when loading" do before do - @data_bag_item.raw_data = {"id" => "charlie", "shell" => "zsh", "ssh_keys" => %w{key1 key2}} - @data_bag_item.data_bag("users") + data_bag_item.raw_data = {"id" => "charlie", "shell" => "zsh", "ssh_keys" => %w{key1 key2}} + data_bag_item.data_bag("users") end describe "from an API call" do + let(:http_client) { double("Chef::REST") } + before do - @http_client = double("Chef::REST") - allow(Chef::REST).to receive(:new).and_return(@http_client) + allow(Chef::REST).to receive(:new).and_return(http_client) end it "converts raw data to a data bag item" do - expect(@http_client).to receive(:get_rest).with("data/users/charlie").and_return(@data_bag_item.to_hash) + expect(http_client).to receive(:get_rest).with("data/users/charlie").and_return(data_bag_item.to_hash) item = Chef::DataBagItem.load(:users, "charlie") expect(item).to be_a_kind_of(Chef::DataBagItem) - expect(item).to eq(@data_bag_item) + expect(item).to eq(data_bag_item) end it "does not convert when a DataBagItem is returned from the API call" do - expect(@http_client).to receive(:get_rest).with("data/users/charlie").and_return(@data_bag_item) + expect(http_client).to receive(:get_rest).with("data/users/charlie").and_return(data_bag_item) item = Chef::DataBagItem.load(:users, "charlie") expect(item).to be_a_kind_of(Chef::DataBagItem) - expect(item).to equal(@data_bag_item) + expect(item).to equal(data_bag_item) end end @@ -280,13 +314,11 @@ describe Chef::DataBagItem do end it "converts the raw data to a data bag item" do - expect(Chef::DataBag).to receive(:load).with('users').and_return({'charlie' => @data_bag_item.to_hash}) + expect(Chef::DataBag).to receive(:load).with('users').and_return({'charlie' => data_bag_item.to_hash}) item = Chef::DataBagItem.load('users', 'charlie') expect(item).to be_a_kind_of(Chef::DataBagItem) - expect(item).to eq(@data_bag_item) + expect(item).to eq(data_bag_item) end end - end - end diff --git a/spec/unit/deprecation_spec.rb b/spec/unit/deprecation_spec.rb index 9bd081a6c4..f824cb7c76 100644 --- a/spec/unit/deprecation_spec.rb +++ b/spec/unit/deprecation_spec.rb @@ -59,27 +59,40 @@ describe Chef::Deprecation do end end - context 'deprecation warning messages' do - before(:each) do - @warning_output = [ ] - allow(Chef::Log).to receive(:warn) { |msg| @warning_output << msg } + context 'when Chef::Config[:treat_deprecation_warnings_as_errors] is off' do + before do + Chef::Config[:treat_deprecation_warnings_as_errors] = false end - it 'should be enabled for deprecated methods' do - TestClass.new.deprecated_method(10) - expect(@warning_output).not_to be_empty + context 'deprecation warning messages' do + before(:each) do + @warning_output = [ ] + allow(Chef::Log).to receive(:warn) { |msg| @warning_output << msg } + end + + it 'should be enabled for deprecated methods' do + TestClass.new.deprecated_method(10) + expect(@warning_output).not_to be_empty + end + + it 'should contain stack trace' do + TestClass.new.deprecated_method(10) + expect(@warning_output.join("").include?(".rb")).to be_truthy + end end - it 'should contain stack trace' do - TestClass.new.deprecated_method(10) - expect(@warning_output.join("").include?(".rb")).to be_truthy + it 'deprecated methods should still be called' do + test_instance = TestClass.new + test_instance.deprecated_method(10) + expect(test_instance.get_value).to eq(10) end end - it 'deprecated methods should still be called' do + it 'should raise when deprecation warnings are treated as errors' do + # rspec should set this + expect(Chef::Config[:treat_deprecation_warnings_as_errors]).to be true test_instance = TestClass.new - test_instance.deprecated_method(10) - expect(test_instance.get_value).to eq(10) + expect { test_instance.deprecated_method(10) }.to raise_error(Chef::Exceptions::DeprecatedFeatureError) end end diff --git a/spec/unit/dsl/audit_spec.rb b/spec/unit/dsl/audit_spec.rb index 38707127f0..28b28e0a7c 100644 --- a/spec/unit/dsl/audit_spec.rb +++ b/spec/unit/dsl/audit_spec.rb @@ -17,18 +17,18 @@ describe Chef::DSL::Audit do let(:cookbook_collection) { {} } it "raises an error when a block of audits is not provided" do - expect{ auditor.controls "name" }.to raise_error(Chef::Exceptions::NoAuditsProvided) + expect{ auditor.control_group "name" }.to raise_error(Chef::Exceptions::NoAuditsProvided) end it "raises an error when no audit name is given" do - expect{ auditor.controls do end }.to raise_error(Chef::Exceptions::AuditNameMissing) + expect{ auditor.control_group do end }.to raise_error(Chef::Exceptions::AuditNameMissing) end context "audits already populated" do let(:audits) { {"unique" => {} } } it "raises an error if the audit name is a duplicate" do - expect { auditor.controls "unique" do end }.to raise_error(Chef::Exceptions::AuditControlGroupDuplicate) + expect { auditor.control_group "unique" do end }.to raise_error(Chef::Exceptions::AuditControlGroupDuplicate) end end @@ -36,7 +36,7 @@ describe Chef::DSL::Audit do let(:auditor) { BadAuditDSLTester.new } it "fails because it relies on the recipe DSL existing" do - expect { auditor.controls "unique" do end }.to raise_error(NoMethodError, /undefined method `cookbook_name'/) + expect { auditor.control_group "unique" do end }.to raise_error(NoMethodError, /undefined method `cookbook_name'/) end end diff --git a/spec/unit/encrypted_data_bag_item_spec.rb b/spec/unit/encrypted_data_bag_item_spec.rb index 14afea507c..0a4306727b 100644 --- a/spec/unit/encrypted_data_bag_item_spec.rb +++ b/spec/unit/encrypted_data_bag_item_spec.rb @@ -124,14 +124,6 @@ describe Chef::EncryptedDataBagItem::Encryptor do context "on unsupported platforms" do let(:aead_algorithm) { Chef::EncryptedDataBagItem::AEAD_ALGORITHM } - it "throws an error warning about the Ruby version if it has no GCM support" do - # Force OpenSSL with AEAD support - allow(OpenSSL::Cipher).to receive(:ciphers).and_return([ aead_algorithm ]) - # Ruby without AEAD support - expect(OpenSSL::Cipher).to receive(:method_defined?).with(:auth_data=).and_return(false) - expect { encryptor }.to raise_error(Chef::EncryptedDataBagItem::EncryptedDataBagRequirementsFailure, /requires Ruby/) - end - it "throws an error warning about the OpenSSL version if it has no GCM support" do # Force Ruby with AEAD support allow(OpenSSL::Cipher).to receive(:method_defined?).with(:auth_data=).and_return(true) @@ -140,14 +132,6 @@ describe Chef::EncryptedDataBagItem::Encryptor do expect { encryptor }.to raise_error(Chef::EncryptedDataBagItem::EncryptedDataBagRequirementsFailure, /requires an OpenSSL/) end - context "on platforms with old Ruby", :ruby_lt_20 do - - it "throws an error warning about the Ruby version" do - expect { encryptor }.to raise_error(Chef::EncryptedDataBagItem::EncryptedDataBagRequirementsFailure, /requires Ruby/) - end - - end # context on platforms with old Ruby - context "on platforms with old OpenSSL", :openssl_lt_101 do it "throws an error warning about the OpenSSL version" do @@ -214,14 +198,6 @@ describe Chef::EncryptedDataBagItem::Decryptor do } end - context "on platforms with old Ruby", :ruby_lt_20 do - - it "throws an error warning about the Ruby version" do - expect { decryptor }.to raise_error(Chef::EncryptedDataBagItem::EncryptedDataBagRequirementsFailure, /requires Ruby/) - end - - end # context on platforms with old Ruby - context "on platforms with old OpenSSL", :openssl_lt_101 do it "throws an error warning about the OpenSSL version" do diff --git a/spec/unit/knife/client_create_spec.rb b/spec/unit/knife/client_create_spec.rb index 8e7cc4a5e3..10d386b5ff 100644 --- a/spec/unit/knife/client_create_spec.rb +++ b/spec/unit/knife/client_create_spec.rb @@ -21,82 +21,96 @@ require 'spec_helper' Chef::Knife::ClientCreate.load_deps describe Chef::Knife::ClientCreate do + let(:stderr) { StringIO.new } + + let(:default_client_hash) do + { + "name" => "adam", + "validator" => false, + "admin" => false + } + end + + let(:client) do + c = double("Chef::ApiClient") + allow(c).to receive(:save).and_return({"private_key" => ""}) + allow(c).to receive(:to_s).and_return("client[adam]") + c + end + + let(:knife) do + k = Chef::Knife::ClientCreate.new + k.name_args = [ "adam" ] + k.ui.config[:disable_editing] = true + allow(k.ui).to receive(:stderr).and_return(stderr) + allow(k.ui).to receive(:stdout).and_return(stderr) + k + end + before(:each) do Chef::Config[:node_name] = "webmonkey.example.com" - @knife = Chef::Knife::ClientCreate.new - @knife.config = { - :file => nil, - :admin => false, - :validator => false - } - @knife.name_args = [ "adam" ] - @client = Chef::ApiClient.new - allow(@client).to receive(:save).and_return({ 'private_key' => '' }) - allow(@knife).to receive(:edit_data).and_return(@client) - allow(@knife).to receive(:puts) - allow(Chef::ApiClient).to receive(:new).and_return(@client) - @stderr = StringIO.new - allow(@knife.ui).to receive(:stderr).and_return(@stderr) end describe "run" do - it "should create a new Client" do - expect(Chef::ApiClient).to receive(:new).and_return(@client) - @knife.run - expect(@stderr.string).to match /created client.+adam/i + it "should create and save the ApiClient" do + expect(Chef::ApiClient).to receive(:from_hash).and_return(client) + expect(client).to receive(:save) + knife.run + end + + it "should print a message upon creation" do + expect(Chef::ApiClient).to receive(:from_hash).and_return(client) + expect(client).to receive(:save) + knife.run + expect(stderr.string).to match /Created client.*adam/i end it "should set the Client name" do - expect(@client).to receive(:name).with("adam") - @knife.run + expect(Chef::ApiClient).to receive(:from_hash).with(hash_including("name" => "adam")).and_return(client) + knife.run end it "by default it is not an admin" do - expect(@client).to receive(:admin).with(false) - @knife.run + expect(Chef::ApiClient).to receive(:from_hash).with(hash_including("admin" => false)).and_return(client) + knife.run end it "by default it is not a validator" do - expect(@client).to receive(:validator).with(false) - @knife.run + expect(Chef::ApiClient).to receive(:from_hash).with(hash_including("validator" => false)).and_return(client) + knife.run end it "should allow you to edit the data" do - expect(@knife).to receive(:edit_data).with(@client) - @knife.run - end - - it "should save the Client" do - expect(@client).to receive(:save) - @knife.run + expect(knife).to receive(:edit_hash).with(default_client_hash).and_return(default_client_hash) + allow(Chef::ApiClient).to receive(:from_hash).and_return(client) + knife.run end describe "with -f or --file" do it "should write the private key to a file" do - @knife.config[:file] = "/tmp/monkeypants" - allow(@client).to receive(:save).and_return({ 'private_key' => "woot" }) + knife.config[:file] = "/tmp/monkeypants" + allow_any_instance_of(Chef::ApiClient).to receive(:save).and_return({ 'private_key' => "woot" }) filehandle = double("Filehandle") expect(filehandle).to receive(:print).with('woot') expect(File).to receive(:open).with("/tmp/monkeypants", "w").and_yield(filehandle) - @knife.run + knife.run end end describe "with -a or --admin" do it "should create an admin client" do - @knife.config[:admin] = true - expect(@client).to receive(:admin).with(true) - @knife.run + knife.config[:admin] = true + expect(Chef::ApiClient).to receive(:from_hash).with(hash_including("admin" => true)).and_return(client) + knife.run end end describe "with --validator" do it "should create an validator client" do - @knife.config[:validator] = true - expect(@client).to receive(:validator).with(true) - @knife.run + knife.config[:validator] = true + expect(Chef::ApiClient).to receive(:from_hash).with(hash_including("validator" => true)).and_return(client) + knife.run end end - end end diff --git a/spec/unit/knife/cookbook_site_share_spec.rb b/spec/unit/knife/cookbook_site_share_spec.rb index 0f97261ad4..515a1603ad 100644 --- a/spec/unit/knife/cookbook_site_share_spec.rb +++ b/spec/unit/knife/cookbook_site_share_spec.rb @@ -108,11 +108,20 @@ describe Chef::Knife::CookbookSiteShare do expect { @knife.run }.to raise_error(SystemExit) end - it 'should make a tarball of the cookbook' do - expect(@knife).to receive(:shell_out!) do |args| - expect(args.to_s).to match(/tar -czf/) + if File.exists?('/usr/bin/gnutar') || File.exists?('/bin/gnutar') + it 'should use gnutar to make a tarball of the cookbook' do + expect(@knife).to receive(:shell_out!) do |args| + expect(args.to_s).to match(/gnutar -czf/) + end + @knife.run + end + else + it 'should make a tarball of the cookbook' do + expect(@knife).to receive(:shell_out!) do |args| + expect(args.to_s).to match(/tar -czf/) + end + @knife.run end - @knife.run end it 'should exit and log to error when the tarball creation fails' do diff --git a/spec/unit/knife/cookbook_upload_spec.rb b/spec/unit/knife/cookbook_upload_spec.rb index 5dbd456ad8..fb94886cad 100644 --- a/spec/unit/knife/cookbook_upload_spec.rb +++ b/spec/unit/knife/cookbook_upload_spec.rb @@ -246,28 +246,62 @@ E describe 'with -a or --all' do before(:each) do knife.config[:all] = true - @test_cookbook1 = Chef::CookbookVersion.new('test_cookbook1', '/tmp/blah') - @test_cookbook2 = Chef::CookbookVersion.new('test_cookbook2', '/tmp/blah') - allow(cookbook_loader).to receive(:each).and_yield("test_cookbook1", @test_cookbook1).and_yield("test_cookbook2", @test_cookbook2) - allow(cookbook_loader).to receive(:cookbook_names).and_return(["test_cookbook1", "test_cookbook2"]) end - it 'should upload all cookbooks' do - expect(knife).to receive(:upload).once - knife.run - end + context 'when cookbooks exist in the cookbook path' do + before(:each) do + @test_cookbook1 = Chef::CookbookVersion.new('test_cookbook1', '/tmp/blah') + @test_cookbook2 = Chef::CookbookVersion.new('test_cookbook2', '/tmp/blah') + allow(cookbook_loader).to receive(:each).and_yield("test_cookbook1", @test_cookbook1).and_yield("test_cookbook2", @test_cookbook2) + allow(cookbook_loader).to receive(:cookbook_names).and_return(["test_cookbook1", "test_cookbook2"]) + end - it 'should report on success' do - expect(knife).to receive(:upload).once - expect(knife.ui).to receive(:info).with(/Uploaded all cookbooks/) - knife.run + it 'should upload all cookbooks' do + expect(knife).to receive(:upload).once + knife.run + end + + it 'should report on success' do + expect(knife).to receive(:upload).once + expect(knife.ui).to receive(:info).with(/Uploaded all cookbooks/) + knife.run + end + + it 'should update the version constraints for an environment' do + allow(knife).to receive(:assert_environment_valid!).and_return(true) + knife.config[:environment] = "production" + expect(knife).to receive(:update_version_constraints).once + knife.run + end end - it 'should update the version constraints for an environment' do - allow(knife).to receive(:assert_environment_valid!).and_return(true) - knife.config[:environment] = "production" - expect(knife).to receive(:update_version_constraints).once - knife.run + context 'when no cookbooks exist in the cookbook path' do + before(:each) do + allow(cookbook_loader).to receive(:each) + end + + it 'should not upload any cookbooks' do + expect(knife).to_not receive(:upload) + knife.run + end + + context 'when cookbook path is an array' do + it 'should warn users that no cookbooks exist' do + knife.config[:cookbook_path] = ['/chef-repo/cookbooks', '/home/user/cookbooks'] + expect(knife.ui).to receive(:warn).with( + /Could not find any cookbooks in your cookbook path: #{knife.config[:cookbook_path].join(', ')}\. Use --cookbook-path to specify the desired path\./) + knife.run + end + end + + context 'when cookbook path is a string' do + it 'should warn users that no cookbooks exist' do + knife.config[:cookbook_path] = '/chef-repo/cookbooks' + expect(knife.ui).to receive(:warn).with( + /Could not find any cookbooks in your cookbook path: #{knife.config[:cookbook_path]}\. Use --cookbook-path to specify the desired path\./) + knife.run + end + end end end diff --git a/spec/unit/knife/raw_spec.rb b/spec/unit/knife/raw_spec.rb new file mode 100644 index 0000000000..ab929abd39 --- /dev/null +++ b/spec/unit/knife/raw_spec.rb @@ -0,0 +1,43 @@ +# +# Author:: Steven Danna (<steve@getchef.com>) +# Copyright:: Copyright (c) 2014 Chef Software, Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require 'spec_helper' + +describe Chef::Knife::Raw do + let(:rest) do + r = double('Chef::Knife::Raw::RawInputServerAPI') + allow(Chef::Knife::Raw::RawInputServerAPI).to receive(:new).and_return(r) + r + end + + let(:knife) do + k = Chef::Knife::Raw.new + k.config[:method] = "GET" + k.name_args = [ "/nodes" ] + k + end + + describe "run" do + it "should set the x-ops-request-source header when --proxy-auth is set" do + knife.config[:proxy_auth] = true + expect(rest).to receive(:request).with(:GET, "/nodes", + { 'Content-Type' => 'application/json', + 'x-ops-request-source' => 'web'}, false) + knife.run + end + end +end diff --git a/spec/unit/knife/role_env_run_list_add_spec.rb b/spec/unit/knife/role_env_run_list_add_spec.rb new file mode 100644 index 0000000000..f286d5fd0d --- /dev/null +++ b/spec/unit/knife/role_env_run_list_add_spec.rb @@ -0,0 +1,217 @@ +# +# Author:: Adam Jacob (<adam@opscode.com>) +# Author:: Will Albenzi (<walbenzi@gmail.com>) +# Copyright:: Copyright (c) 2008 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require 'spec_helper' + +describe Chef::Knife::RoleEnvRunListAdd do + before(:each) do +# Chef::Config[:role_name] = "websimian" +# Chef::Config[:env_name] = "QA" + @knife = Chef::Knife::RoleEnvRunListAdd.new + @knife.config = { + :after => nil + } + @knife.name_args = [ "will", "QA", "role[monkey]" ] + allow(@knife).to receive(:output).and_return(true) + @role = Chef::Role.new() + allow(@role).to receive(:save).and_return(true) + allow(Chef::Role).to receive(:load).and_return(@role) + end + + describe "run" do + +# it "should display all the things" do +# @knife.run +# @role.to_json.should == 'show all the things' +# end + + it "should have an empty default run list" do + @knife.run + expect(@role.run_list[0]).to be_nil + end + + it "should have a QA environment" do + @knife.run + expect(@role.active_run_list_for('QA')).to eq('QA') + end + + it "should load the role named will" do + expect(Chef::Role).to receive(:load).with("will") + @knife.run + end + + it "should be able to add an environment specific run list" do + @knife.run + expect(@role.run_list_for('QA')[0]).to eq('role[monkey]') + end + + it "should save the role" do + expect(@role).to receive(:save) + @knife.run + end + + it "should print the run list" do + expect(@knife).to receive(:output).and_return(true) + @knife.run + end + + describe "with -a or --after specified" do + it "should not create a change if the specified 'after' never comes" do + @role.run_list_for("_default") << "role[acorns]" + @role.run_list_for("_default") << "role[barn]" + @knife.config[:after] = "role[acorns]" + @knife.name_args = [ "will", "QA", "role[pad]" ] + @knife.run + expect(@role.run_list_for("QA")[0]).to be_nil + expect(@role.run_list[0]).to eq("role[acorns]") + expect(@role.run_list[1]).to eq("role[barn]") + expect(@role.run_list[2]).to be_nil + end + + it "should add to the run list after the specified entries in the QA run list" do + #Setup + @role.run_list_for("_default") << "role[acorns]" + @role.run_list_for("_default") << "role[barn]" + @knife.run + @role.run_list_for("QA") << "role[pencil]" + @role.run_list_for("QA") << "role[pen]" + #Configuration we are testing + @knife.config[:after] = "role[pencil]" + @knife.name_args = [ "will", "QA", "role[pad]", "role[whackadoo]" ] + @knife.run + #The actual tests + expect(@role.run_list_for("QA")[0]).to eq("role[monkey]") + expect(@role.run_list_for("QA")[1]).to eq("role[pencil]") + expect(@role.run_list_for("QA")[2]).to eq("role[pad]") + expect(@role.run_list_for("QA")[3]).to eq("role[whackadoo]") + expect(@role.run_list_for("QA")[4]).to eq("role[pen]") + expect(@role.run_list[0]).to eq("role[acorns]") + expect(@role.run_list[1]).to eq("role[barn]") + expect(@role.run_list[2]).to be_nil + end + end + + describe "with more than one role or recipe" do + it "should add to the QA run list all the entries" do + @knife.name_args = [ "will", "QA", "role[monkey],role[duck]" ] + @role.run_list_for("_default") << "role[acorns]" + @knife.run + expect(@role.run_list_for("QA")[0]).to eq("role[monkey]") + expect(@role.run_list_for("QA")[1]).to eq("role[duck]") + expect(@role.run_list[0]).to eq("role[acorns]") + expect(@role.run_list[1]).to be_nil + end + end + + describe "with more than one role or recipe with space between items" do + it "should add to the run list all the entries" do + @knife.name_args = [ "will", "QA", "role[monkey], role[duck]" ] + @role.run_list_for("_default") << "role[acorns]" + @knife.run + expect(@role.run_list_for("QA")[0]).to eq("role[monkey]") + expect(@role.run_list_for("QA")[1]).to eq("role[duck]") + expect(@role.run_list[0]).to eq("role[acorns]") + expect(@role.run_list[1]).to be_nil + end + end + + describe "with more than one role or recipe as different arguments" do + it "should add to the run list all the entries" do + @knife.name_args = [ "will", "QA", "role[monkey]", "role[duck]" ] + @role.run_list_for("_default") << "role[acorns]" + @knife.run + expect(@role.run_list_for("QA")[0]).to eq("role[monkey]") + expect(@role.run_list_for("QA")[1]).to eq("role[duck]") + expect(@role.run_list[0]).to eq("role[acorns]") + expect(@role.run_list[1]).to be_nil + end + end + + describe "with more than one role or recipe as different arguments and list separated by comas" do + it "should add to the run list all the entries" do + @knife.name_args = [ "will", "QA", "role[monkey]", "role[duck],recipe[bird::fly]" ] + @role.run_list_for("_default") << "role[acorns]" + @knife.run + expect(@role.run_list_for("QA")[0]).to eq("role[monkey]") + expect(@role.run_list_for("QA")[1]).to eq("role[duck]") + expect(@role.run_list_for("QA")[2]).to eq("recipe[bird::fly]") + expect(@role.run_list[0]).to eq("role[acorns]") + expect(@role.run_list[1]).to be_nil + end + end + + describe "Recipe with version number is allowed" do + it "should add to the run list all the entries including the versioned recipe" do + @knife.name_args = [ "will", "QA", "role[monkey]", "role[duck],recipe[bird::fly@1.1.3]" ] + @role.run_list_for("_default") << "role[acorns]" + @knife.run + expect(@role.run_list_for("QA")[0]).to eq("role[monkey]") + expect(@role.run_list_for("QA")[1]).to eq("role[duck]") + expect(@role.run_list_for("QA")[2]).to eq("recipe[bird::fly@1.1.3]") + expect(@role.run_list[0]).to eq("role[acorns]") + expect(@role.run_list[1]).to be_nil + end + end + + describe "with one role or recipe but with an extraneous comma" do + it "should add to the run list one item" do + @role.run_list_for("_default") << "role[acorns]" + @knife.name_args = [ "will", "QA", "role[monkey]," ] + @knife.run + expect(@role.run_list_for("QA")[0]).to eq("role[monkey]") + expect(@role.run_list_for("QA")[1]).to be_nil + expect(@role.run_list[0]).to eq("role[acorns]") + expect(@role.run_list[1]).to be_nil + end + end + + describe "with more than one command" do + it "should be able to the environment run list by running multiple knife commands" do + @knife.name_args = [ "will", "QA", "role[blue]," ] + @knife.run + @knife.name_args = [ "will", "QA", "role[black]," ] + @knife.run + expect(@role.run_list_for("QA")[0]).to eq("role[blue]") + expect(@role.run_list_for("QA")[1]).to eq("role[black]") + expect(@role.run_list[0]).to be_nil + end + end + + describe "with more than one environment" do + it "should add to the run list a second environment in the specific run list" do + @role.run_list_for("_default") << "role[acorns]" + @knife.name_args = [ "will", "QA", "role[blue]," ] + @knife.run + @role.run_list_for("QA") << "role[walnuts]" + + @knife.name_args = [ "will", "PRD", "role[ball]," ] + @knife.run + @role.run_list_for("PRD") << "role[pen]" + + expect(@role.run_list_for("QA")[0]).to eq("role[blue]") + expect(@role.run_list_for("PRD")[0]).to eq("role[ball]") + expect(@role.run_list_for("QA")[1]).to eq("role[walnuts]") + expect(@role.run_list_for("PRD")[1]).to eq("role[pen]") + expect(@role.run_list[0]).to eq("role[acorns]") + expect(@role.run_list[1]).to be_nil + end + end + + end +end diff --git a/spec/unit/knife/role_env_run_list_clear_spec.rb b/spec/unit/knife/role_env_run_list_clear_spec.rb new file mode 100644 index 0000000000..525376c358 --- /dev/null +++ b/spec/unit/knife/role_env_run_list_clear_spec.rb @@ -0,0 +1,100 @@ +# +# Author:: Adam Jacob (<adam@opscode.com>) +# Author:: Will Albenzi (<walbenzi@gmail.com>) +# Copyright:: Copyright (c) 2008 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require 'spec_helper' + +describe Chef::Knife::RoleEnvRunListClear do + before(:each) do + Chef::Config[:role_name] = "will" + Chef::Config[:env_name] = "QA" + @setup = Chef::Knife::RoleEnvRunListAdd.new + @setup.name_args = [ "will", "QA", "role[monkey]", "role[person]" ] + + @knife = Chef::Knife::RoleEnvRunListClear.new + @knife.config = { + :print_after => nil + } + @knife.name_args = [ "will", "QA" ] + allow(@knife).to receive(:output).and_return(true) + + @role = Chef::Role.new() + @role.name("will") + allow(@role).to receive(:save).and_return(true) + + allow(@knife.ui).to receive(:confirm).and_return(true) + allow(Chef::Role).to receive(:load).and_return(@role) + + end + + + + describe "run" do + + +# it "should display all the things" do +# @knife.run +# @role.to_json.should == 'show all the things' +# end + + it "should load the node" do + expect(Chef::Role).to receive(:load).with("will").and_return(@role) + @knife.run + end + + it "should remove the item from the run list" do + @setup.run + @knife.run + expect(@role.run_list_for('QA')[0]).to be_nil + expect(@role.run_list[0]).to be_nil + end + + it "should save the node" do + expect(@role).to receive(:save).and_return(true) + @knife.run + end + + it "should print the run list" do + expect(@knife).to receive(:output).and_return(true) + @knife.config[:print_after] = true + @setup.run + @knife.run + end + + describe "should clear an environmental run list of roles and recipes" do + it "should remove the items from the run list" do + @setup.name_args = [ "will", "QA", "recipe[orange::chicken]", "role[monkey]", "recipe[duck::type]", "role[person]", "role[bird]", "role[town]" ] + @setup.run + @setup.name_args = [ "will", "PRD", "recipe[orange::chicken]", "role[monkey]", "recipe[duck::type]", "role[person]", "role[bird]", "role[town]" ] + @setup.run + @knife.name_args = [ 'will', 'QA' ] + @knife.run + expect(@role.run_list_for('QA')[0]).to be_nil + expect(@role.run_list_for('PRD')[0]).to eq('recipe[orange::chicken]') + expect(@role.run_list_for('PRD')[1]).to eq('role[monkey]') + expect(@role.run_list_for('PRD')[2]).to eq('recipe[duck::type]') + expect(@role.run_list_for('PRD')[3]).to eq('role[person]') + expect(@role.run_list_for('PRD')[4]).to eq('role[bird]') + expect(@role.run_list_for('PRD')[5]).to eq('role[town]') + end + end + end +end + + + diff --git a/spec/unit/knife/role_env_run_list_remove_spec.rb b/spec/unit/knife/role_env_run_list_remove_spec.rb new file mode 100644 index 0000000000..a15d0af691 --- /dev/null +++ b/spec/unit/knife/role_env_run_list_remove_spec.rb @@ -0,0 +1,108 @@ +# +# Author:: Adam Jacob (<adam@opscode.com>) +# Author:: Will Albenzi (<walbenzi@gmail.com>) +# Copyright:: Copyright (c) 2008 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require 'spec_helper' + +describe Chef::Knife::RoleEnvRunListRemove do + before(:each) do + Chef::Config[:role_name] = "will" + Chef::Config[:env_name] = "QA" + @setup = Chef::Knife::RoleEnvRunListAdd.new + @setup.name_args = [ "will", "QA", "role[monkey]", "role[person]" ] + + @knife = Chef::Knife::RoleEnvRunListRemove.new + @knife.config = { + :print_after => nil + } + @knife.name_args = [ "will", "QA", "role[monkey]" ] + allow(@knife).to receive(:output).and_return(true) + + @role = Chef::Role.new() + @role.name("will") + allow(@role).to receive(:save).and_return(true) + + allow(@knife.ui).to receive(:confirm).and_return(true) + allow(Chef::Role).to receive(:load).and_return(@role) + + end + + + + describe "run" do + + +# it "should display all the things" do +# @knife.run +# @role.to_json.should == 'show all the things' +# end + + it "should load the node" do + expect(Chef::Role).to receive(:load).with("will").and_return(@role) + @knife.run + end + + it "should remove the item from the run list" do + @setup.run + @knife.run + expect(@role.run_list_for('QA')[0]).not_to eq('role[monkey]') + expect(@role.run_list_for('QA')[0]).to eq('role[person]') + expect(@role.run_list[0]).to be_nil + end + + it "should save the node" do + expect(@role).to receive(:save).and_return(true) + @knife.run + end + + it "should print the run list" do + expect(@knife).to receive(:output).and_return(true) + @knife.config[:print_after] = true + @setup.run + @knife.run + end + + describe "run with a list of roles and recipes" do + it "should remove the items from the run list" do + @setup.name_args = [ "will", "QA", "recipe[orange::chicken]", "role[monkey]", "recipe[duck::type]", "role[person]", "role[bird]", "role[town]" ] + @setup.run + @setup.name_args = [ "will", "PRD", "recipe[orange::chicken]", "role[monkey]", "recipe[duck::type]", "role[person]", "role[bird]", "role[town]" ] + @setup.run + @knife.name_args = [ 'will', 'QA', 'role[monkey]' ] + @knife.run + @knife.name_args = [ 'will', 'QA', 'recipe[duck::type]' ] + @knife.run + expect(@role.run_list_for('QA')).not_to include('role[monkey]') + expect(@role.run_list_for('QA')).not_to include('recipe[duck::type]') + expect(@role.run_list_for('QA')[0]).to eq('recipe[orange::chicken]') + expect(@role.run_list_for('QA')[1]).to eq('role[person]') + expect(@role.run_list_for('QA')[2]).to eq('role[bird]') + expect(@role.run_list_for('QA')[3]).to eq('role[town]') + expect(@role.run_list_for('PRD')[0]).to eq('recipe[orange::chicken]') + expect(@role.run_list_for('PRD')[1]).to eq('role[monkey]') + expect(@role.run_list_for('PRD')[2]).to eq('recipe[duck::type]') + expect(@role.run_list_for('PRD')[3]).to eq('role[person]') + expect(@role.run_list_for('PRD')[4]).to eq('role[bird]') + expect(@role.run_list_for('PRD')[5]).to eq('role[town]') + end + end + end +end + + + diff --git a/spec/unit/knife/role_env_run_list_replace_spec.rb b/spec/unit/knife/role_env_run_list_replace_spec.rb new file mode 100644 index 0000000000..ea48601b8d --- /dev/null +++ b/spec/unit/knife/role_env_run_list_replace_spec.rb @@ -0,0 +1,108 @@ +# +# Author:: Adam Jacob (<adam@opscode.com>) +# Author:: Will Albenzi (<walbenzi@gmail.com>) +# Copyright:: Copyright (c) 2008 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require 'spec_helper' + +describe Chef::Knife::RoleEnvRunListReplace do + before(:each) do + Chef::Config[:role_name] = "will" + Chef::Config[:env_name] = "QA" + @setup = Chef::Knife::RoleEnvRunListAdd.new + @setup.name_args = [ "will", "QA", "role[monkey]", "role[dude]", "role[fixer]" ] + + @knife = Chef::Knife::RoleEnvRunListReplace.new + @knife.config = { + :print_after => nil + } + @knife.name_args = [ "will", "QA", "role[dude]", "role[person]" ] + allow(@knife).to receive(:output).and_return(true) + + @role = Chef::Role.new() + @role.name("will") + allow(@role).to receive(:save).and_return(true) + + allow(@knife.ui).to receive(:confirm).and_return(true) + allow(Chef::Role).to receive(:load).and_return(@role) + + end + + + + describe "run" do + + +# it "should display all the things" do +# @knife.run +# @role.to_json.should == 'show all the things' +# end + + it "should load the node" do + expect(Chef::Role).to receive(:load).with("will").and_return(@role) + @knife.run + end + + it "should remove the item from the run list" do + @setup.run + @knife.run + expect(@role.run_list_for('QA')[1]).not_to eq('role[dude]') + expect(@role.run_list_for('QA')[1]).to eq('role[person]') + expect(@role.run_list[0]).to be_nil + end + + it "should save the node" do + expect(@role).to receive(:save).and_return(true) + @knife.run + end + + it "should print the run list" do + expect(@knife).to receive(:output).and_return(true) + @knife.config[:print_after] = true + @setup.run + @knife.run + end + + describe "run with a list of roles and recipes" do + it "should replace the items from the run list" do + @setup.name_args = [ "will", "QA", "recipe[orange::chicken]", "role[monkey]", "recipe[duck::type]", "role[person]", "role[bird]", "role[town]" ] + @setup.run + @setup.name_args = [ "will", "PRD", "recipe[orange::chicken]", "role[monkey]", "recipe[duck::type]", "role[person]", "role[bird]", "role[town]" ] + @setup.run + @knife.name_args = [ 'will', 'QA', 'role[monkey]', 'role[gibbon]' ] + @knife.run + @knife.name_args = [ 'will', 'QA', 'recipe[duck::type]', 'recipe[duck::mallard]' ] + @knife.run + expect(@role.run_list_for('QA')).not_to include('role[monkey]') + expect(@role.run_list_for('QA')).not_to include('recipe[duck::type]') + expect(@role.run_list_for('QA')[0]).to eq('recipe[orange::chicken]') + expect(@role.run_list_for('QA')[1]).to eq('role[gibbon]') + expect(@role.run_list_for('QA')[2]).to eq('recipe[duck::mallard]') + expect(@role.run_list_for('QA')[3]).to eq('role[person]') + expect(@role.run_list_for('QA')[4]).to eq('role[bird]') + expect(@role.run_list_for('QA')[5]).to eq('role[town]') + expect(@role.run_list_for('PRD')[0]).to eq('recipe[orange::chicken]') + expect(@role.run_list_for('PRD')[1]).to eq('role[monkey]') + expect(@role.run_list_for('PRD')[2]).to eq('recipe[duck::type]') + expect(@role.run_list_for('PRD')[3]).to eq('role[person]') + expect(@role.run_list_for('PRD')[4]).to eq('role[bird]') + expect(@role.run_list_for('PRD')[5]).to eq('role[town]') + expect(@role.run_list[0]).to be_nil + end + end + end +end diff --git a/spec/unit/knife/role_env_run_list_set_spec.rb b/spec/unit/knife/role_env_run_list_set_spec.rb new file mode 100644 index 0000000000..f3abb86fcf --- /dev/null +++ b/spec/unit/knife/role_env_run_list_set_spec.rb @@ -0,0 +1,102 @@ +# +# Author:: Adam Jacob (<adam@opscode.com>) +# Author:: Will Albenzi (<walbenzi@gmail.com>) +# Copyright:: Copyright (c) 2008 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require 'spec_helper' + +describe Chef::Knife::RoleEnvRunListSet do + before(:each) do + Chef::Config[:role_name] = "will" + Chef::Config[:env_name] = "QA" + @setup = Chef::Knife::RoleEnvRunListAdd.new + @setup.name_args = [ "will", "QA", "role[monkey]", "role[person]", "role[bucket]" ] + + @knife = Chef::Knife::RoleEnvRunListSet.new + @knife.config = { + :print_after => nil + } + @knife.name_args = [ "will", "QA", "role[owen]", "role[mauntel]" ] + allow(@knife).to receive(:output).and_return(true) + + @role = Chef::Role.new() + @role.name("will") + allow(@role).to receive(:save).and_return(true) + + allow(@knife.ui).to receive(:confirm).and_return(true) + allow(Chef::Role).to receive(:load).and_return(@role) + + end + + + + describe "run" do + + +# it "should display all the things" do +# @knife.run +# @role.to_json.should == 'show all the things' +# end + + it "should load the node" do + expect(Chef::Role).to receive(:load).with("will").and_return(@role) + @knife.run + end + + it "should replace all the items in the runlist with what is specified" do + @setup.run + @knife.run + expect(@role.run_list_for('QA')[0]).to eq("role[owen]") + expect(@role.run_list_for('QA')[1]).to eq("role[mauntel]") + expect(@role.run_list_for('QA')[2]).to be_nil + expect(@role.run_list[0]).to be_nil + end + + it "should save the node" do + expect(@role).to receive(:save).and_return(true) + @knife.run + end + + it "should print the run list" do + expect(@knife).to receive(:output).and_return(true) + @knife.config[:print_after] = true + @setup.run + @knife.run + end + + describe "should clear an environmental run list of roles and recipes" do + it "should remove the items from the run list" do + @setup.name_args = [ "will", "QA", "recipe[orange::chicken]", "role[monkey]", "recipe[duck::type]", "role[person]", "role[bird]", "role[town]" ] + @setup.run + @setup.name_args = [ "will", "PRD", "recipe[orange::chicken]", "role[monkey]", "recipe[duck::type]", "role[person]", "role[bird]", "role[town]" ] + @setup.run + @knife.name_args = [ "will", "QA", "role[coke]", "role[pepsi]" ] + @knife.run + expect(@role.run_list_for('QA')[0]).to eq("role[coke]") + expect(@role.run_list_for('QA')[1]).to eq("role[pepsi]") + expect(@role.run_list_for('QA')[2]).to be_nil + expect(@role.run_list_for('PRD')[0]).to eq('recipe[orange::chicken]') + expect(@role.run_list_for('PRD')[1]).to eq('role[monkey]') + expect(@role.run_list_for('PRD')[2]).to eq('recipe[duck::type]') + expect(@role.run_list_for('PRD')[3]).to eq('role[person]') + expect(@role.run_list_for('PRD')[4]).to eq('role[bird]') + expect(@role.run_list_for('PRD')[5]).to eq('role[town]') + expect(@role.run_list[0]).to be_nil + end + end + end +end diff --git a/spec/unit/knife/role_run_list_add_spec.rb b/spec/unit/knife/role_run_list_add_spec.rb new file mode 100644 index 0000000000..d61c114912 --- /dev/null +++ b/spec/unit/knife/role_run_list_add_spec.rb @@ -0,0 +1,179 @@ +# +# Author:: Adam Jacob (<adam@opscode.com>) +# Author:: Will Albenzi (<walbenzi@gmail.com>) +# Copyright:: Copyright (c) 2008 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require 'spec_helper' + +describe Chef::Knife::RoleRunListAdd do + before(:each) do +# Chef::Config[:role_name] = "websimian" +# Chef::Config[:env_name] = "QA" + @knife = Chef::Knife::RoleRunListAdd.new + @knife.config = { + :after => nil + } + @knife.name_args = [ "will", "role[monkey]" ] + allow(@knife).to receive(:output).and_return(true) + @role = Chef::Role.new() + allow(@role).to receive(:save).and_return(true) + allow(Chef::Role).to receive(:load).and_return(@role) + end + + describe "run" do + +# it "should display all the things" do +# @knife.run +# @role.to_json.should == 'show all the things' +# end + + it "should have a run list with the monkey role" do + @knife.run + expect(@role.run_list[0]).to eq("role[monkey]") + end + + it "should load the role named will" do + expect(Chef::Role).to receive(:load).with("will") + @knife.run + end + + it "should save the role" do + expect(@role).to receive(:save) + @knife.run + end + + it "should print the run list" do + expect(@knife).to receive(:output).and_return(true) + @knife.run + end + + describe "with -a or --after specified" do + it "should not create a change if the specified 'after' never comes" do + @role.run_list_for("_default") << "role[acorns]" + @role.run_list_for("_default") << "role[barn]" + @knife.config[:after] = "role[tree]" + @knife.name_args = [ "will", "role[pad]" ] + @knife.run + expect(@role.run_list[0]).to eq("role[acorns]") + expect(@role.run_list[1]).to eq("role[barn]") + expect(@role.run_list[2]).to be_nil + end + + it "should add to the run list after the specified entries in the default run list" do + #Setup + @role.run_list_for("_default") << "role[acorns]" + @role.run_list_for("_default") << "role[barn]" + #Configuration we are testing + @knife.config[:after] = "role[acorns]" + @knife.name_args = [ "will", "role[pad]", "role[whackadoo]" ] + @knife.run + #The actual tests + expect(@role.run_list[0]).to eq("role[acorns]") + expect(@role.run_list[1]).to eq("role[pad]") + expect(@role.run_list[2]).to eq("role[whackadoo]") + expect(@role.run_list[3]).to eq("role[barn]") + expect(@role.run_list[4]).to be_nil + end + end + + describe "with more than one role or recipe" do + it "should add to the QA run list all the entries" do + @knife.name_args = [ "will", "role[monkey],role[duck]" ] + @role.run_list_for("_default") << "role[acorns]" + @knife.run + expect(@role.run_list[0]).to eq("role[acorns]") + expect(@role.run_list[1]).to eq("role[monkey]") + expect(@role.run_list[2]).to eq("role[duck]") + expect(@role.run_list[3]).to be_nil + end + end + + describe "with more than one role or recipe with space between items" do + it "should add to the run list all the entries" do + @knife.name_args = [ "will", "role[monkey], role[duck]" ] + @role.run_list_for("_default") << "role[acorns]" + @knife.run + expect(@role.run_list[0]).to eq("role[acorns]") + expect(@role.run_list[1]).to eq("role[monkey]") + expect(@role.run_list[2]).to eq("role[duck]") + expect(@role.run_list[3]).to be_nil + end + end + + describe "with more than one role or recipe as different arguments" do + it "should add to the run list all the entries" do + @knife.name_args = [ "will", "role[monkey]", "role[duck]" ] + @role.run_list_for("_default") << "role[acorns]" + @knife.run + expect(@role.run_list[0]).to eq("role[acorns]") + expect(@role.run_list[1]).to eq("role[monkey]") + expect(@role.run_list[2]).to eq("role[duck]") + expect(@role.run_list[3]).to be_nil + end + end + + describe "with more than one role or recipe as different arguments and list separated by comas" do + it "should add to the run list all the entries" do + @knife.name_args = [ "will", "role[monkey]", "role[duck],recipe[bird::fly]" ] + @role.run_list_for("_default") << "role[acorns]" + @knife.run + expect(@role.run_list[0]).to eq("role[acorns]") + expect(@role.run_list[1]).to eq("role[monkey]") + expect(@role.run_list[2]).to eq("role[duck]") + expect(@role.run_list[3]).to eq("recipe[bird::fly]") + expect(@role.run_list[4]).to be_nil + end + end + + describe "Recipe with version number is allowed" do + it "should add to the run list all the entries including the versioned recipe" do + @knife.name_args = [ "will", "role[monkey]", "role[duck],recipe[bird::fly@1.1.3]" ] + @role.run_list_for("_default") << "role[acorns]" + @knife.run + expect(@role.run_list[0]).to eq("role[acorns]") + expect(@role.run_list[1]).to eq("role[monkey]") + expect(@role.run_list[2]).to eq("role[duck]") + expect(@role.run_list[3]).to eq("recipe[bird::fly@1.1.3]") + expect(@role.run_list[4]).to be_nil + end + end + + describe "with one role or recipe but with an extraneous comma" do + it "should add to the run list one item" do + @role.run_list_for("_default") << "role[acorns]" + @knife.name_args = [ "will", "role[monkey]," ] + @knife.run + expect(@role.run_list[0]).to eq("role[acorns]") + expect(@role.run_list[1]).to eq("role[monkey]") + expect(@role.run_list[2]).to be_nil + end + end + + describe "with more than one command" do + it "should be able to the environment run list by running multiple knife commands" do + @knife.name_args = [ "will", "role[blue]," ] + @knife.run + @knife.name_args = [ "will", "role[black]," ] + @knife.run + expect(@role.run_list[0]).to eq("role[blue]") + expect(@role.run_list[1]).to eq("role[black]") + expect(@role.run_list[2]).to be_nil + end + end + + end +end diff --git a/spec/unit/knife/role_run_list_clear_spec.rb b/spec/unit/knife/role_run_list_clear_spec.rb new file mode 100644 index 0000000000..e5a6e18673 --- /dev/null +++ b/spec/unit/knife/role_run_list_clear_spec.rb @@ -0,0 +1,90 @@ +# +# Author:: Adam Jacob (<adam@opscode.com>) +# Author:: Will Albenzi (<walbenzi@gmail.com>) +# Copyright:: Copyright (c) 2008 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require 'spec_helper' + +describe Chef::Knife::RoleRunListClear do + before(:each) do + Chef::Config[:role_name] = "will" + @setup = Chef::Knife::RoleRunListAdd.new + @setup.name_args = [ "will", "role[monkey]", "role[person]" ] + + @knife = Chef::Knife::RoleRunListClear.new + @knife.config = { + :print_after => nil + } + @knife.name_args = [ "will" ] + allow(@knife).to receive(:output).and_return(true) + + @role = Chef::Role.new() + @role.name("will") + allow(@role).to receive(:save).and_return(true) + + allow(@knife.ui).to receive(:confirm).and_return(true) + allow(Chef::Role).to receive(:load).and_return(@role) + + end + + + + describe "run" do + + +# it "should display all the things" do +# @knife.run +# @role.to_json.should == 'show all the things' +# end + + it "should load the node" do + expect(Chef::Role).to receive(:load).with("will").and_return(@role) + @knife.run + end + + it "should remove the item from the run list" do + @setup.run + @knife.run + expect(@role.run_list[0]).to be_nil + end + + it "should save the node" do + expect(@role).to receive(:save).and_return(true) + @knife.run + end + + it "should print the run list" do + expect(@knife).to receive(:output).and_return(true) + @knife.config[:print_after] = true + @setup.run + @knife.run + end + + describe "should clear an environmental run list of roles and recipes" do + it "should remove the items from the run list" do + @setup.name_args = [ "will", "recipe[orange::chicken]", "role[monkey]", "recipe[duck::type]", "role[person]", "role[bird]", "role[town]" ] + @setup.run + @knife.name_args = [ 'will' ] + @knife.run + expect(@role.run_list[0]).to be_nil + end + end + end +end + + + diff --git a/spec/unit/knife/role_run_list_remove_spec.rb b/spec/unit/knife/role_run_list_remove_spec.rb new file mode 100644 index 0000000000..0f4adf253b --- /dev/null +++ b/spec/unit/knife/role_run_list_remove_spec.rb @@ -0,0 +1,98 @@ +# +# Author:: Adam Jacob (<adam@opscode.com>) +# Author:: Will Albenzi (<walbenzi@gmail.com>) +# Copyright:: Copyright (c) 2008 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require 'spec_helper' + +describe Chef::Knife::RoleRunListRemove do + before(:each) do + Chef::Config[:role_name] = "will" + @setup = Chef::Knife::RoleRunListAdd.new + @setup.name_args = [ "will", "role[monkey]", "role[person]" ] + + @knife = Chef::Knife::RoleRunListRemove.new + @knife.config = { + :print_after => nil + } + @knife.name_args = [ "will", "role[monkey]" ] + allow(@knife).to receive(:output).and_return(true) + + @role = Chef::Role.new() + @role.name("will") + allow(@role).to receive(:save).and_return(true) + + allow(@knife.ui).to receive(:confirm).and_return(true) + allow(Chef::Role).to receive(:load).and_return(@role) + + end + + + + describe "run" do + + +# it "should display all the things" do +# @knife.run +# @role.to_json.should == 'show all the things' +# end + + it "should load the node" do + expect(Chef::Role).to receive(:load).with("will").and_return(@role) + @knife.run + end + + it "should remove the item from the run list" do + @setup.run + @knife.run + expect(@role.run_list[0]).to eq('role[person]') + expect(@role.run_list[1]).to be_nil + end + + it "should save the node" do + expect(@role).to receive(:save).and_return(true) + @knife.run + end + + it "should print the run list" do + expect(@knife).to receive(:output).and_return(true) + @knife.config[:print_after] = true + @setup.run + @knife.run + end + + describe "run with a list of roles and recipes" do + it "should remove the items from the run list" do + @setup.name_args = [ "will", "recipe[orange::chicken]", "role[monkey]", "recipe[duck::type]", "role[person]", "role[bird]", "role[town]" ] + @setup.run + @knife.name_args = [ 'will', 'role[monkey]' ] + @knife.run + @knife.name_args = [ 'will', 'recipe[duck::type]' ] + @knife.run + expect(@role.run_list).not_to include('role[monkey]') + expect(@role.run_list).not_to include('recipe[duck::type]') + expect(@role.run_list[0]).to eq('recipe[orange::chicken]') + expect(@role.run_list[1]).to eq('role[person]') + expect(@role.run_list[2]).to eq('role[bird]') + expect(@role.run_list[3]).to eq('role[town]') + end + end + end +end + + + diff --git a/spec/unit/knife/role_run_list_replace_spec.rb b/spec/unit/knife/role_run_list_replace_spec.rb new file mode 100644 index 0000000000..2ff38f573c --- /dev/null +++ b/spec/unit/knife/role_run_list_replace_spec.rb @@ -0,0 +1,101 @@ +# +# Author:: Adam Jacob (<adam@opscode.com>) +# Author:: Will Albenzi (<walbenzi@gmail.com>) +# Copyright:: Copyright (c) 2008 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require 'spec_helper' + +describe Chef::Knife::RoleRunListReplace do + before(:each) do + Chef::Config[:role_name] = "will" + @setup = Chef::Knife::RoleRunListAdd.new + @setup.name_args = [ "will", "role[monkey]", "role[dude]", "role[fixer]" ] + + @knife = Chef::Knife::RoleRunListReplace.new + @knife.config = { + :print_after => nil + } + @knife.name_args = [ "will", "role[dude]", "role[person]" ] + allow(@knife).to receive(:output).and_return(true) + + @role = Chef::Role.new() + @role.name("will") + allow(@role).to receive(:save).and_return(true) + + allow(@knife.ui).to receive(:confirm).and_return(true) + allow(Chef::Role).to receive(:load).and_return(@role) + + end + + + + describe "run" do + + +# it "should display all the things" do +# @knife.run +# @role.to_json.should == 'show all the things' +# end + + it "should load the node" do + expect(Chef::Role).to receive(:load).with("will").and_return(@role) + @knife.run + end + + it "should remove the item from the run list" do + @setup.run + @knife.run + expect(@role.run_list[0]).to eq('role[monkey]') + expect(@role.run_list[1]).not_to eq('role[dude]') + expect(@role.run_list[1]).to eq('role[person]') + expect(@role.run_list[2]).to eq('role[fixer]') + expect(@role.run_list[3]).to be_nil + end + + it "should save the node" do + expect(@role).to receive(:save).and_return(true) + @knife.run + end + + it "should print the run list" do + expect(@knife).to receive(:output).and_return(true) + @knife.config[:print_after] = true + @setup.run + @knife.run + end + + describe "run with a list of roles and recipes" do + it "should replace the items from the run list" do + @setup.name_args = [ "will", "recipe[orange::chicken]", "role[monkey]", "recipe[duck::type]", "role[person]", "role[bird]", "role[town]" ] + @setup.run + @knife.name_args = [ 'will', 'role[monkey]', 'role[gibbon]' ] + @knife.run + @knife.name_args = [ 'will', 'recipe[duck::type]', 'recipe[duck::mallard]' ] + @knife.run + expect(@role.run_list).not_to include('role[monkey]') + expect(@role.run_list).not_to include('recipe[duck::type]') + expect(@role.run_list[0]).to eq('recipe[orange::chicken]') + expect(@role.run_list[1]).to eq('role[gibbon]') + expect(@role.run_list[2]).to eq('recipe[duck::mallard]') + expect(@role.run_list[3]).to eq('role[person]') + expect(@role.run_list[4]).to eq('role[bird]') + expect(@role.run_list[5]).to eq('role[town]') + expect(@role.run_list[6]).to be_nil + end + end + end +end diff --git a/spec/unit/knife/role_run_list_set_spec.rb b/spec/unit/knife/role_run_list_set_spec.rb new file mode 100644 index 0000000000..1350741f10 --- /dev/null +++ b/spec/unit/knife/role_run_list_set_spec.rb @@ -0,0 +1,92 @@ +# +# Author:: Adam Jacob (<adam@opscode.com>) +# Author:: Will Albenzi (<walbenzi@gmail.com>) +# Copyright:: Copyright (c) 2008 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require 'spec_helper' + +describe Chef::Knife::RoleRunListSet do + before(:each) do + Chef::Config[:role_name] = "will" + @setup = Chef::Knife::RoleRunListAdd.new + @setup.name_args = [ "will", "role[monkey]", "role[person]", "role[bucket]" ] + + @knife = Chef::Knife::RoleRunListSet.new + @knife.config = { + :print_after => nil + } + @knife.name_args = [ "will", "role[owen]", "role[mauntel]" ] + allow(@knife).to receive(:output).and_return(true) + + @role = Chef::Role.new() + @role.name("will") + allow(@role).to receive(:save).and_return(true) + + allow(@knife.ui).to receive(:confirm).and_return(true) + allow(Chef::Role).to receive(:load).and_return(@role) + + end + + + + describe "run" do + + +# it "should display all the things" do +# @knife.run +# @role.to_json.should == 'show all the things' +# end + + it "should load the node" do + expect(Chef::Role).to receive(:load).with("will").and_return(@role) + @knife.run + end + + it "should replace all the items in the runlist with what is specified" do + @setup.run + @knife.run + expect(@role.run_list[0]).to eq("role[owen]") + expect(@role.run_list[1]).to eq("role[mauntel]") + expect(@role.run_list[2]).to be_nil + end + + it "should save the node" do + expect(@role).to receive(:save).and_return(true) + @knife.run + end + + it "should print the run list" do + expect(@knife).to receive(:output).and_return(true) + @knife.config[:print_after] = true + @setup.run + @knife.run + end + + describe "should clear an environmental run list of roles and recipes" do + it "should remove the items from the run list" do + @setup.name_args = [ "will", "recipe[orange::chicken]", "role[monkey]", "recipe[duck::type]", "role[person]", "role[bird]", "role[town]" ] + @setup.run + @knife.name_args = [ "will", "role[coke]", "role[pepsi]" ] + @knife.run + expect(@role.run_list[0]).to eq("role[coke]") + expect(@role.run_list[1]).to eq("role[pepsi]") + expect(@role.run_list[2]).to be_nil + expect(@role.run_list[3]).to be_nil + end + end + end +end diff --git a/spec/unit/lwrp_spec.rb b/spec/unit/lwrp_spec.rb index 35963dec64..ec39174da6 100644 --- a/spec/unit/lwrp_spec.rb +++ b/spec/unit/lwrp_spec.rb @@ -36,6 +36,30 @@ describe "LWRP" do allow($stderr).to receive(:write) end + it "should not skip loading a resource when there's a top level symbol of the same name" do + Object.const_set('LwrpFoo', Class.new) + file = File.expand_path( "lwrp/resources/foo.rb", CHEF_SPEC_DATA) + expect(Chef::Log).not_to receive(:info).with(/Skipping/) + expect(Chef::Log).not_to receive(:debug).with(/anymore/) + Chef::Resource::LWRPBase.build_from_file("lwrp", file, nil) + Object.send(:remove_const, 'LwrpFoo') + Chef::Resource.send(:remove_const, 'LwrpFoo') + end + + it "should not skip loading a provider when there's a top level symbol of the same name" do + Object.const_set('LwrpBuckPasser', Class.new) + file = File.expand_path( "lwrp/providers/buck_passer.rb", CHEF_SPEC_DATA) + expect(Chef::Log).not_to receive(:info).with(/Skipping/) + expect(Chef::Log).not_to receive(:debug).with(/anymore/) + Chef::Provider::LWRPBase.build_from_file("lwrp", file, nil) + Object.send(:remove_const, 'LwrpBuckPasser') + Chef::Provider.send(:remove_const, 'LwrpBuckPasser') + end + + # @todo: we need a before block to manually remove_const all of the LWRPs that we + # load in these tests. we're threading state through these tests in LWRPs that + # have already been loaded in prior tests, which probably renders some of them bogus + it "should log if attempting to load resource of same name" do Dir[File.expand_path( "lwrp/resources/*", CHEF_SPEC_DATA)].each do |file| Chef::Resource::LWRPBase.build_from_file("lwrp", file, nil) @@ -317,8 +341,8 @@ describe "LWRP" do Chef::Runner.new(@run_context).converge expect(@run_context.resource_collection[0]).to eql(injector) - expect(@run_context.resource_collection[1].name).to eql(:prepared_thumbs) - expect(@run_context.resource_collection[2].name).to eql(:twiddled_thumbs) + expect(@run_context.resource_collection[1].name).to eql('prepared_thumbs') + expect(@run_context.resource_collection[2].name).to eql('twiddled_thumbs') expect(@run_context.resource_collection[3]).to eql(dummy) end @@ -341,12 +365,12 @@ describe "LWRP" do Chef::Runner.new(@run_context).converge expect(@run_context.resource_collection[0]).to eql(injector) - expect(@run_context.resource_collection[1].name).to eql(:prepared_thumbs) - expect(@run_context.resource_collection[2].name).to eql(:twiddled_thumbs) + expect(@run_context.resource_collection[1].name).to eql('prepared_thumbs') + expect(@run_context.resource_collection[2].name).to eql('twiddled_thumbs') expect(@run_context.resource_collection[3]).to eql(dummy) expect(@run_context.resource_collection[4]).to eql(injector2) - expect(@run_context.resource_collection[5].name).to eql(:prepared_eyes) - expect(@run_context.resource_collection[6].name).to eql(:dried_paint_watched) + expect(@run_context.resource_collection[5].name).to eql('prepared_eyes') + expect(@run_context.resource_collection[6].name).to eql('dried_paint_watched') end it "should properly handle a new_resource reference" do diff --git a/spec/unit/org_spec.rb b/spec/unit/org_spec.rb new file mode 100644 index 0000000000..cd6cc94d91 --- /dev/null +++ b/spec/unit/org_spec.rb @@ -0,0 +1,196 @@ +# +# Author:: Steven Danna (steve@opscode.com) +# Copyright:: Copyright (c) 2014 Chef Software, Inc +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require 'spec_helper' + +require 'chef/org' +require 'tempfile' + +describe Chef::Org do + let(:org) { Chef::Org.new("an_org") } + + describe "initialize" do + it "is a Chef::Org" do + expect(org).to be_a_kind_of(Chef::Org) + end + end + + describe "name" do + it "lets you set the name to a string" do + org.name "sg1" + expect(org.name).to eq("sg1") + end + + # It is not feasible to check all invalid characters. Here are a few + # that we probably care about. + it "raises on invalid characters" do + # capital letters + expect { org.name "Bar" }.to raise_error(ArgumentError) + # slashes + expect { org.name "foo/bar" }.to raise_error(ArgumentError) + # ? + expect { org.name "foo?" }.to raise_error(ArgumentError) + # & + expect { org.name "foo&" }.to raise_error(ArgumentError) + # spaces + expect { org.name "foo " }.to raise_error(ArgumentError) + end + + it "raises an ArgumentError if you feed it anything but a string" do + expect { org.name Hash.new }.to raise_error(ArgumentError) + end + end + + describe "full_name" do + it "lets you set the full name" do + org.full_name "foo" + expect(org.full_name).to eq("foo") + end + + it "raises an ArgumentError if you feed it anything but a string" do + expect { org.name Hash.new }.to raise_error(ArgumentError) + end + end + + describe "private_key" do + it "returns the private key" do + org.private_key("super private") + expect(org.private_key).to eq("super private") + end + + it "raises an ArgumentError if you feed it something lame" do + expect { org.private_key Hash.new }.to raise_error(ArgumentError) + end + end + + describe "when serializing to JSON" do + let(:json) do + org.name("black") + org.full_name("black crowes") + org.to_json + end + + it "serializes as a JSON object" do + expect(json).to match(/^\{.+\}$/) + end + + it "includes the name value" do + expect(json).to include(%q{"name":"black"}) + end + + it "includes the full name value" do + expect(json).to include(%q{"full_name":"black crowes"}) + end + + it "includes the private key when present" do + org.private_key("monkeypants") + expect(org.to_json).to include(%q{"private_key":"monkeypants"}) + end + + it "does not include the private key if not present" do + expect(json).to_not include("private_key") + end + end + + describe "when deserializing from JSON" do + let(:org) do + o = { "name" => "turtle", + "full_name" => "turtle_club", + "private_key" => "pandas" } + Chef::Org.from_json(o.to_json) + end + + it "deserializes to a Chef::Org object" do + expect(org).to be_a_kind_of(Chef::Org) + end + + it "preserves the name" do + expect(org.name).to eq("turtle") + end + + it "preserves the full_name" do + expect(org.full_name).to eq("turtle_club") + end + + it "includes the private key if present" do + expect(org.private_key).to eq("pandas") + end + end + + describe "API Interactions" do + let(:rest) do + Chef::Config[:chef_server_root] = "http://www.example.com" + r = double('rest') + allow(Chef::REST).to receive(:new).and_return(r) + r + end + + let(:org) do + o = Chef::Org.new("foobar") + o.full_name "foo bar bat" + o + end + + describe "list" do + let(:response) { {"foobar" => "http://www.example.com/organizations/foobar"} } + let(:inflated_response) { {"foobar" => org } } + + it "lists all orgs" do + expect(rest).to receive(:get_rest).with("organizations").and_return(response) + expect(Chef::Org.list).to eq(response) + end + + it "inflate all orgs" do + allow(Chef::Org).to receive(:load).with("foobar").and_return(org) + expect(rest).to receive(:get_rest).with("organizations").and_return(response) + expect(Chef::Org.list(true)).to eq(inflated_response) + end + end + + describe "create" do + it "creates a new org via the API" do + expect(rest).to receive(:post_rest).with("organizations", {:name => "foobar", :full_name => "foo bar bat"}).and_return({}) + org.create + end + end + + describe "read" do + it "loads a named org from the API" do + expect(rest).to receive(:get_rest).with("organizations/foobar").and_return({"name" => "foobar", "full_name" => "foo bar bat", "private_key" => "private"}) + org = Chef::Org.load("foobar") + expect(org.name).to eq("foobar") + expect(org.full_name).to eq("foo bar bat") + expect(org.private_key).to eq("private") + end + end + + describe "update" do + it "updates an existing org on via the API" do + expect(rest).to receive(:put_rest).with("organizations/foobar", {:name => "foobar", :full_name => "foo bar bat"}).and_return({}) + org.update + end + end + + describe "destroy" do + it "deletes the specified org via the API" do + expect(rest).to receive(:delete_rest).with("organizations/foobar") + org.destroy + end + end + end +end diff --git a/spec/unit/policy_builder/policyfile_spec.rb b/spec/unit/policy_builder/policyfile_spec.rb index 5e2844201d..8b6e928a46 100644 --- a/spec/unit/policy_builder/policyfile_spec.rb +++ b/spec/unit/policy_builder/policyfile_spec.rb @@ -144,7 +144,7 @@ describe Chef::PolicyBuilder::Policyfile do end - describe "when using compatibility mode" do + describe "loading policy data" do let(:http_api) { double("Chef::REST") } @@ -171,49 +171,113 @@ describe Chef::PolicyBuilder::Policyfile do allow(policy_builder).to receive(:http_api).and_return(http_api) end - context "when the deployment group cannot be loaded" do - let(:error404) { Net::HTTPServerException.new("404 message", :body) } + describe "when using compatibility mode (policy_document_native_api == false)" do - before do - expect(Chef::Node).to receive(:find_or_create).with(node_name).and_return(node) - expect(http_api).to receive(:get). - with("data/policyfiles/example-policy-stage"). - and_raise(error404) - end + context "when the deployment group cannot be loaded" do + let(:error404) { Net::HTTPServerException.new("404 message", :body) } + + before do + expect(Chef::Node).to receive(:find_or_create).with(node_name).and_return(node) + expect(http_api).to receive(:get). + with("data/policyfiles/example-policy-stage"). + and_raise(error404) + end + + it "raises an error" do + expect { policy_builder.load_node }.to raise_error(err_namespace::ConfigurationError) + end + + it "sends error message to the event system" do + expect(events).to receive(:node_load_failed).with(node_name, an_instance_of(err_namespace::ConfigurationError), Chef::Config) + expect { policy_builder.load_node }.to raise_error(err_namespace::ConfigurationError) + end - it "raises an error" do - expect { policy_builder.load_node }.to raise_error(err_namespace::ConfigurationError) end - it "sends error message to the event system" do - expect(events).to receive(:node_load_failed).with(node_name, an_instance_of(err_namespace::ConfigurationError), Chef::Config) - expect { policy_builder.load_node }.to raise_error(err_namespace::ConfigurationError) + context "when the deployment_group is not configured" do + before do + Chef::Config[:deployment_group] = nil + expect(Chef::Node).to receive(:find_or_create).with(node_name).and_return(node) + end + + it "errors while loading the node" do + expect { policy_builder.load_node }.to raise_error(err_namespace::ConfigurationError) + end + + + it "passes error information to the event system" do + # TODO: also make sure something acceptable happens with the error formatters + err_class = err_namespace::ConfigurationError + expect(events).to receive(:node_load_failed).with(node_name, an_instance_of(err_class), Chef::Config) + expect { policy_builder.load_node }.to raise_error(err_class) + end end + context "when deployment_group is correctly configured" do + + let(:policy_relative_url) { "data/policyfiles/example-policy-stage" } + + before do + expect(http_api).to receive(:get).with(policy_relative_url).and_return(parsed_policyfile_json) + end + + it "fetches the policy file from a data bag item" do + expect(policy_builder.policy).to eq(parsed_policyfile_json) + end + + it "extracts the run_list from the policyfile" do + expect(policy_builder.run_list).to eq(policyfile_run_list) + end + + end end - describe "when the deployment_group is not configured" do + context "and policy_document_native_api is configured" do + before do - Chef::Config[:deployment_group] = nil - expect(Chef::Node).to receive(:find_or_create).with(node_name).and_return(node) + Chef::Config[:policy_document_native_api] = true + Chef::Config[:policy_group] = "policy-stage" + Chef::Config[:policy_name] = "example" end - it "errors while loading the node" do - expect { policy_builder.load_node }.to raise_error(err_namespace::ConfigurationError) + context "and policy_name or policy_group are not configured" do + + it "raises a Configuration error for policy_group" do + Chef::Config[:policy_group] = nil + expect { policy_builder.policy }.to raise_error(err_namespace::ConfigurationError) + end + + it "raises a Configuration error for policy_name" do + Chef::Config[:policy_name] = nil + expect { policy_builder.policy }.to raise_error(err_namespace::ConfigurationError) + end + end + context "and policy_name and policy_group are configured" do + + let(:policy_relative_url) { "policies/policy-stage/example" } + + before do + expect(http_api).to receive(:get).with(policy_relative_url).and_return(parsed_policyfile_json) + end + + it "fetches the policy file from a data bag item" do + expect(policy_builder.policy).to eq(parsed_policyfile_json) + end - it "passes error information to the event system" do - # TODO: also make sure something acceptable happens with the error formatters - err_class = err_namespace::ConfigurationError - expect(events).to receive(:node_load_failed).with(node_name, an_instance_of(err_class), Chef::Config) - expect { policy_builder.load_node }.to raise_error(err_class) + it "extracts the run_list from the policyfile" do + expect(policy_builder.run_list).to eq(policyfile_run_list) + end end + end - context "and a deployment_group is configured" do + + describe "building policy from the policyfile" do + before do - expect(http_api).to receive(:get).with("data/policyfiles/example-policy-stage").and_return(parsed_policyfile_json) + allow(policy_builder).to receive(:policy).and_return(parsed_policyfile_json) end it "fetches the policy file from a data bag item" do @@ -334,67 +398,91 @@ describe Chef::PolicyBuilder::Policyfile do let(:cookbook_synchronizer) { double("Chef::CookbookSynchronizer") } - context "and a cookbook is missing" do + shared_examples_for "fetching cookbooks" do + context "and a cookbook is missing" do - let(:error404) { Net::HTTPServerException.new("404 message", :body) } + let(:error404) { Net::HTTPServerException.new("404 message", :body) } - before do - expect(Chef::Node).to receive(:find_or_create).with(node_name).and_return(node) + before do + expect(Chef::Node).to receive(:find_or_create).with(node_name).and_return(node) - # Remove references to example2 cookbook because we're iterating - # over a Hash data structure and on ruby 1.8.7 iteration order will - # not be stable. - parsed_policyfile_json["cookbook_locks"].delete("example2") - parsed_policyfile_json["run_list"].delete("recipe[example2::server]") + policy_builder.load_node + policy_builder.build_node - policy_builder.load_node - policy_builder.build_node + expect(http_api).to receive(:get).with(cookbook1_url). + and_raise(error404) + end - expect(http_api).to receive(:get).with("cookbooks/example1/#{example1_xyz_version}"). - and_raise(error404) - end + it "raises an error indicating which cookbook is missing" do + expect { policy_builder.cookbooks_to_sync }.to raise_error(Chef::Exceptions::CookbookNotFound) + end - it "raises an error indicating which cookbook is missing" do - expect { policy_builder.cookbooks_to_sync }.to raise_error(Chef::Exceptions::CookbookNotFound) end - end + context "and the cookbooks can be fetched" do + before do + expect(Chef::Node).to receive(:find_or_create).with(node_name).and_return(node) - context "and the cookbooks can be fetched" do - before do - expect(Chef::Node).to receive(:find_or_create).with(node_name).and_return(node) + policy_builder.load_node + policy_builder.build_node + + expect(http_api).to receive(:get).with(cookbook1_url). + and_return(example1_cookbook_object) + expect(http_api).to receive(:get).with(cookbook2_url). + and_return(example2_cookbook_object) - policy_builder.load_node - policy_builder.build_node + allow(Chef::CookbookSynchronizer).to receive(:new). + with(expected_cookbook_hash, events). + and_return(cookbook_synchronizer) + end - expect(http_api).to receive(:get).with("cookbooks/example1/#{example1_xyz_version}"). - and_return(example1_cookbook_object) - expect(http_api).to receive(:get).with("cookbooks/example2/#{example2_xyz_version}"). - and_return(example2_cookbook_object) + it "builds a Hash of the form 'cookbook_name' => Chef::CookbookVersion" do + expect(policy_builder.cookbooks_to_sync).to eq(expected_cookbook_hash) + end + + it "syncs the desired cookbooks via CookbookSynchronizer" do + expect(cookbook_synchronizer).to receive(:sync_cookbooks) + policy_builder.sync_cookbooks + end + + it "builds a run context" do + expect(cookbook_synchronizer).to receive(:sync_cookbooks) + expect_any_instance_of(Chef::RunContext).to receive(:load).with(policy_builder.run_list_expansion_ish) + run_context = policy_builder.setup_run_context + expect(run_context.node).to eq(node) + expect(run_context.cookbook_collection.keys).to match_array(["example1", "example2"]) + end - allow(Chef::CookbookSynchronizer).to receive(:new). - with(expected_cookbook_hash, events). - and_return(cookbook_synchronizer) end + end # shared_examples_for "fetching cookbooks" + + context "when using compatibility mode (policy_document_native_api == false)" do + include_examples "fetching cookbooks" do + + let(:cookbook1_url) { "cookbooks/example1/#{example1_xyz_version}" } + let(:cookbook2_url) { "cookbooks/example2/#{example2_xyz_version}" } - it "builds a Hash of the form 'cookbook_name' => Chef::CookbookVersion" do - expect(policy_builder.cookbooks_to_sync).to eq(expected_cookbook_hash) end - it "syncs the desired cookbooks via CookbookSynchronizer" do - expect(cookbook_synchronizer).to receive(:sync_cookbooks) - policy_builder.sync_cookbooks + end + + context "when using native API mode (policy_document_native_api == true)" do + + before do + Chef::Config[:policy_document_native_api] = true + Chef::Config[:policy_group] = "policy-stage" + Chef::Config[:policy_name] = "example" end - it "builds a run context" do - expect(cookbook_synchronizer).to receive(:sync_cookbooks) - expect_any_instance_of(Chef::RunContext).to receive(:load).with(policy_builder.run_list_expansion_ish) - run_context = policy_builder.setup_run_context - expect(run_context.node).to eq(node) - expect(run_context.cookbook_collection.keys).to match_array(["example1", "example2"]) + include_examples "fetching cookbooks" do + + let(:cookbook1_url) { "cookbook_artifacts/example1/#{example1_xyz_version}" } + let(:cookbook2_url) { "cookbook_artifacts/example2/#{example2_xyz_version}" } + end end + end end diff --git a/spec/unit/provider/env_spec.rb b/spec/unit/provider/env_spec.rb index 19233dfba9..230603dcb3 100644 --- a/spec/unit/provider/env_spec.rb +++ b/spec/unit/provider/env_spec.rb @@ -252,7 +252,7 @@ describe Chef::Provider::Env do end context "when new_resource's value contains the delimiter" do - it "should return false if all the current values are contained" do + it "should return false if all the current values are contained in specified order" do @new_resource.value("C:/biz;C:/baz") @new_resource.delim(";") @current_resource.value("C:/biz;C:/foo/bin;C:/baz") @@ -265,6 +265,13 @@ describe Chef::Provider::Env do @current_resource.value("C:/biz;C:/foo/bin;C:/baz") expect(@provider.requires_modify_or_create?).to be_truthy end + + it "should return true if values are contained in different order" do + @new_resource.value("C:/biz;C:/baz") + @new_resource.delim(";") + @current_resource.value("C:/baz;C:/foo/bin;C:/biz") + expect(@provider.requires_modify_or_create?).to be_truthy + end end end @@ -286,12 +293,18 @@ describe Chef::Provider::Env do expect(passed_value).to eq(new_value) end - it "should only add values not already contained when a delimiter is provided" do + it "should only add values not already contained" do @new_resource.value("C:/foo;C:/bar;C:/baz") - @new_resource.delim(";") - @current_resource.value("C:/foo/bar;C:/bar;C:/baz") + @current_resource.value("C:/bar;C:/baz;C:/foo/bar") + @provider.modify_env + expect(@new_resource.value).to eq("C:/foo;C:/bar;C:/baz;C:/foo/bar") + end + + it "should reorder values to keep order which asked" do + @new_resource.value("C:/foo;C:/bar;C:/baz") + @current_resource.value("C:/foo/bar;C:/baz;C:/bar") @provider.modify_env - expect(@new_resource.value).to eq("C:/foo;C:/foo/bar;C:/bar;C:/baz") + expect(@new_resource.value).to eq("C:/foo;C:/bar;C:/baz;C:/foo/bar") end end end diff --git a/spec/unit/provider/package/aix_spec.rb b/spec/unit/provider/package/aix_spec.rb index 6908b1288d..a39ab096c7 100644 --- a/spec/unit/provider/package/aix_spec.rb +++ b/spec/unit/provider/package/aix_spec.rb @@ -54,8 +54,8 @@ describe Chef::Provider::Package::Aix do it "should raise an exception if a source is supplied but not found" do allow(@provider).to receive(:popen4).and_return(@status) allow(::File).to receive(:exists?).and_return(false) - @provider.define_resource_requirements @provider.load_current_resource + @provider.define_resource_requirements expect { @provider.process_resource_requirements }.to raise_error(Chef::Exceptions::Package) end diff --git a/spec/unit/provider/package/apt_spec.rb b/spec/unit/provider/package/apt_spec.rb index e53fdc3f27..acf0707bbf 100644 --- a/spec/unit/provider/package/apt_spec.rb +++ b/spec/unit/provider/package/apt_spec.rb @@ -198,6 +198,11 @@ mpg123 1.12.1-0ubuntu1 it "raises an exception if a source is specified (CHEF-5113)" do @new_resource.source "pluto" + expect(@provider).to receive(:shell_out!).with( + "apt-cache policy #{@new_resource.package_name}", + :timeout => @timeout + ).and_return(@shell_out) + @provider.load_current_resource @provider.define_resource_requirements expect(@provider).to receive(:shell_out!).with("apt-cache policy irssi", {:timeout=>900}).and_return(@shell_out) expect { @provider.run_action(:install) }.to raise_error(Chef::Exceptions::Package) @@ -307,8 +312,7 @@ mpg123 1.12.1-0ubuntu1 end it "should get the full path to the preseed response file" do - expect(@provider).to receive(:get_preseed_file).with("irssi", "0.8.12-7").and_return("/tmp/irssi-0.8.12-7.seed") - file = @provider.get_preseed_file("irssi", "0.8.12-7") + file = "/tmp/irssi-0.8.12-7.seed" expect(@provider).to receive(:shell_out!).with( "debconf-set-selections /tmp/irssi-0.8.12-7.seed", diff --git a/spec/unit/provider/package/dpkg_spec.rb b/spec/unit/provider/package/dpkg_spec.rb index fdd9e50c8e..154809f88c 100644 --- a/spec/unit/provider/package/dpkg_spec.rb +++ b/spec/unit/provider/package/dpkg_spec.rb @@ -88,8 +88,8 @@ describe Chef::Provider::Package::Dpkg do it "should raise an exception if the source is not set but we are installing" do @new_resource = Chef::Resource::Package.new("wget") @provider.new_resource = @new_resource - @provider.define_resource_requirements @provider.load_current_resource + @provider.define_resource_requirements expect { @provider.run_action(:install)}.to raise_error(Chef::Exceptions::Package) end diff --git a/spec/unit/provider/package/ips_spec.rb b/spec/unit/provider/package/ips_spec.rb index 4e0afc46e9..342ac4c040 100644 --- a/spec/unit/provider/package/ips_spec.rb +++ b/spec/unit/provider/package/ips_spec.rb @@ -190,9 +190,8 @@ REMOTE expect(@provider).to receive(:shell_out).with("pkg info #{@new_resource.package_name}").and_return(local) expect(@provider).to receive(:shell_out!).with("pkg info -r #{@new_resource.package_name}").and_return(remote) - @provider.load_current_resource expect(@provider).to receive(:install_package).exactly(0).times - @provider.action_install + @provider.run_action(:install) end context "when accept_license is true" do diff --git a/spec/unit/provider/package/rpm_spec.rb b/spec/unit/provider/package/rpm_spec.rb index 2aceee59a5..cd72044998 100644 --- a/spec/unit/provider/package/rpm_spec.rb +++ b/spec/unit/provider/package/rpm_spec.rb @@ -19,138 +19,186 @@ require 'spec_helper' describe Chef::Provider::Package::Rpm do - before(:each) do - @node = Chef::Node.new - @events = Chef::EventDispatch::Dispatcher.new - @run_context = Chef::RunContext.new(@node, {}, @events) - - @new_resource = Chef::Resource::Package.new("ImageMagick-c++") - @new_resource.source "/tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm" - - @provider = Chef::Provider::Package::Rpm.new(@new_resource, @run_context) + let(:provider) { Chef::Provider::Package::Rpm.new(new_resource, run_context) } + let(:node) { Chef::Node.new } + let(:events) { Chef::EventDispatch::Dispatcher.new } + let(:run_context) { Chef::RunContext.new(node, {}, events) } + let(:new_resource) do + Chef::Resource::Package.new("ImageMagick-c++").tap do |resource| + resource.source "/tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm" + end + end + let(:exitstatus) { 0 } + let(:stdout) { String.new('') } + let(:status) { double('Process::Status', exitstatus: exitstatus, stdout: stdout) } - @status = double("Status", :exitstatus => 0) + before(:each) do allow(::File).to receive(:exists?).and_return(true) + allow(provider).to receive(:shell_out!).and_return(status) end describe "when determining the current state of the package" do - it "should create a current resource with the name of new_resource" do - allow(@provider).to receive(:popen4).and_return(@status) - @provider.load_current_resource - expect(@provider.current_resource.name).to eq("ImageMagick-c++") + provider.load_current_resource + expect(provider.current_resource.name).to eq("ImageMagick-c++") end it "should set the current reource package name to the new resource package name" do - allow(@provider).to receive(:popen4).and_return(@status) - @provider.load_current_resource - expect(@provider.current_resource.package_name).to eq('ImageMagick-c++') + provider.load_current_resource + expect(provider.current_resource.package_name).to eq('ImageMagick-c++') end it "should raise an exception if a source is supplied but not found" do allow(::File).to receive(:exists?).and_return(false) - expect { @provider.run_action(:any) }.to raise_error(Chef::Exceptions::Package) + expect { provider.run_action(:any) }.to raise_error(Chef::Exceptions::Package) end - it "should get the source package version from rpm if provided" do - @stdout = StringIO.new("ImageMagick-c++ 6.5.4.7-7.el6_5") - expect(@provider).to receive(:popen4).with("rpm -qp --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm").and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) - expect(@provider).to receive(:popen4).with("rpm -q --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' ImageMagick-c++").and_return(@status) - @provider.load_current_resource - expect(@provider.current_resource.package_name).to eq("ImageMagick-c++") - expect(@provider.new_resource.version).to eq("6.5.4.7-7.el6_5") - end + context "installation exists" do + let(:stdout) { "ImageMagick-c++ 6.5.4.7-7.el6_5" } + + it "should get the source package version from rpm if provided" do + expect(provider).to receive(:shell_out!).with("rpm -qp --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm").and_return(status) + expect(provider).to receive(:shell_out!).with("rpm -q --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' ImageMagick-c++").and_return(status) + provider.load_current_resource + expect(provider.current_resource.package_name).to eq("ImageMagick-c++") + expect(provider.new_resource.version).to eq("6.5.4.7-7.el6_5") + end - it "should return the current version installed if found by rpm" do - @stdout = StringIO.new("ImageMagick-c++ 6.5.4.7-7.el6_5") - expect(@provider).to receive(:popen4).with("rpm -qp --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm").and_return(@status) - expect(@provider).to receive(:popen4).with("rpm -q --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' ImageMagick-c++").and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) - @provider.load_current_resource - expect(@provider.current_resource.version).to eq("6.5.4.7-7.el6_5") + it "should return the current version installed if found by rpm" do + expect(provider).to receive(:shell_out!).with("rpm -qp --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm").and_return(status) + expect(provider).to receive(:shell_out!).with("rpm -q --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' ImageMagick-c++").and_return(status) + provider.load_current_resource + expect(provider.current_resource.version).to eq("6.5.4.7-7.el6_5") + end end - it "should raise an exception if the source is not set but we are installing" do - new_resource = Chef::Resource::Package.new("ImageMagick-c++") - provider = Chef::Provider::Package::Rpm.new(new_resource, @run_context) - expect { provider.run_action(:any) }.to raise_error(Chef::Exceptions::Package) + context "source is uri formed" do + before(:each) do + allow(::File).to receive(:exists?).and_return(false) + end + + %w(http HTTP https HTTPS ftp FTP).each do |scheme| + it "should accept uri formed source (#{scheme})" do + new_resource.source "#{scheme}://example.com/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm" + expect(provider.load_current_resource).not_to be_nil + end + end + + %w(file FILE).each do |scheme| + it "should accept uri formed source (#{scheme})" do + new_resource.source "#{scheme}:///ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm" + expect(provider.load_current_resource).not_to be_nil + end + end + + it "should raise an exception if an uri formed source is non-supported scheme" do + new_resource.source "foobar://example.com/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm" + expect(provider.load_current_resource).to be_nil + expect { provider.run_action(:any) }.to raise_error(Chef::Exceptions::Package) + end end - it "should raise an exception if rpm fails to run" do - status = double("Status", :exitstatus => -1) - allow(@provider).to receive(:popen4).and_return(status) - expect { @provider.run_action(:any) }.to raise_error(Chef::Exceptions::Package) + context "source is not defiend" do + let(:new_resource) { Chef::Resource::Package.new("ImageMagick-c++") } + + it "should raise an exception if the source is not set but we are installing" do + expect { provider.run_action(:any) }.to raise_error(Chef::Exceptions::Package) + end end - it "should not detect the package name as version when not installed" do - @status = double("Status", :exitstatus => -1) - @stdout = StringIO.new("package openssh-askpass is not installed") - @new_resource = Chef::Resource::Package.new("openssh-askpass") - @new_resource.source 'openssh-askpass' - @provider = Chef::Provider::Package::Rpm.new(@new_resource, @run_context) - expect(@provider).to receive(:popen4).with("rpm -qp --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' openssh-askpass").and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) - expect(@provider).to receive(:popen4).with("rpm -q --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' openssh-askpass").and_return(@status) - @provider.load_current_resource - expect(@provider.current_resource.version).to be_nil + context "installation does not exist" do + let(:stdout) { String.new("package openssh-askpass is not installed") } + let(:exitstatus) { -1 } + let(:new_resource) do + Chef::Resource::Package.new("openssh-askpass").tap do |resource| + resource.source "openssh-askpass" + end + end + + it "should raise an exception if rpm fails to run" do + allow(provider).to receive(:shell_out!).and_return(status) + expect { provider.run_action(:any) }.to raise_error(Chef::Exceptions::Package) + end + + it "should not detect the package name as version when not installed" do + expect(provider).to receive(:shell_out!).with("rpm -qp --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' openssh-askpass").and_return(status) + expect(provider).to receive(:shell_out!).with("rpm -q --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' openssh-askpass").and_return(status) + provider.load_current_resource + expect(provider.current_resource.version).to be_nil + end end end describe "after the current resource is loaded" do - before do - @current_resource = Chef::Resource::Package.new("ImageMagick-c++") - @provider.current_resource = @current_resource + let(:current_resource) { Chef::Resource::Package.new("ImageMagick-c++") } + let(:provider) do + Chef::Provider::Package::Rpm.new(new_resource, run_context).tap do |provider| + provider.current_resource = current_resource + end end describe "when installing or upgrading" do it "should run rpm -i with the package source to install" do - expect(@provider).to receive(:shell_out!).with("rpm -i /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm") - @provider.install_package("ImageMagick-c++", "6.5.4.7-7.el6_5") + expect(provider).to receive(:shell_out!).with("rpm -i /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm") + provider.install_package("ImageMagick-c++", "6.5.4.7-7.el6_5") end it "should run rpm -U with the package source to upgrade" do - @current_resource.version("21.4-19.el5") - expect(@provider).to receive(:shell_out!).with("rpm -U /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm") - @provider.upgrade_package("ImageMagick-c++", "6.5.4.7-7.el6_5") + current_resource.version("21.4-19.el5") + expect(provider).to receive(:shell_out!).with("rpm -U /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm") + provider.upgrade_package("ImageMagick-c++", "6.5.4.7-7.el6_5") end it "should install package if missing and set to upgrade" do - @current_resource.version("ImageMagick-c++") - expect(@provider).to receive(:shell_out!).with("rpm -U /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm") - @provider.upgrade_package("ImageMagick-c++", "6.5.4.7-7.el6_5") + current_resource.version("ImageMagick-c++") + expect(provider).to receive(:shell_out!).with("rpm -U /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm") + provider.upgrade_package("ImageMagick-c++", "6.5.4.7-7.el6_5") end - it "should install from a path when the package is a path and the source is nil" do - @new_resource = Chef::Resource::Package.new("/tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm") - @provider = Chef::Provider::Package::Rpm.new(@new_resource, @run_context) - expect(@new_resource.source).to eq("/tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm") - @current_resource = Chef::Resource::Package.new("ImageMagick-c++") - @provider.current_resource = @current_resource - expect(@provider).to receive(:shell_out!).with("rpm -i /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm") - @provider.install_package("/tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm", "6.5.4.7-7.el6_5") + context "allowing downgrade" do + let(:new_resource) { Chef::Resource::RpmPackage.new("/tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm") } + let(:current_resource) { Chef::Resource::RpmPackage.new("ImageMagick-c++") } + + it "should run rpm -U --oldpackage with the package source to downgrade" do + new_resource.allow_downgrade(true) + current_resource.version("21.4-19.el5") + expect(provider).to receive(:shell_out!).with("rpm -U --oldpackage /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm") + provider.upgrade_package("ImageMagick-c++", "6.5.4.7-7.el6_5") + end end - it "should uprgrade from a path when the package is a path and the source is nil" do - @new_resource = Chef::Resource::Package.new("/tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm") - @provider = Chef::Provider::Package::Rpm.new(@new_resource, @run_context) - expect(@new_resource.source).to eq("/tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm") - @current_resource = Chef::Resource::Package.new("ImageMagick-c++") - @current_resource.version("21.4-19.el5") - @provider.current_resource = @current_resource - expect(@provider).to receive(:shell_out!).with("rpm -U /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm") - @provider.upgrade_package("/tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm", "6.5.4.7-7.el6_5") + context "installing when the name is a path" do + let(:new_resource) { Chef::Resource::Package.new("/tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm") } + let(:current_resource) { Chef::Resource::Package.new("ImageMagick-c++") } + + it "should install from a path when the package is a path and the source is nil" do + expect(new_resource.source).to eq("/tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm") + provider.current_resource = current_resource + expect(provider).to receive(:shell_out!).with("rpm -i /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm") + provider.install_package("/tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm", "6.5.4.7-7.el6_5") + end + + it "should uprgrade from a path when the package is a path and the source is nil" do + expect(new_resource.source).to eq("/tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm") + current_resource.version("21.4-19.el5") + provider.current_resource = current_resource + expect(provider).to receive(:shell_out!).with("rpm -U /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm") + provider.upgrade_package("/tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm", "6.5.4.7-7.el6_5") + end end it "installs with custom options specified in the resource" do - @provider.candidate_version = '11' - @new_resource.options("--dbpath /var/lib/rpm") - expect(@provider).to receive(:shell_out!).with("rpm --dbpath /var/lib/rpm -i /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm") - @provider.install_package(@new_resource.name, @provider.candidate_version) + provider.candidate_version = '11' + new_resource.options("--dbpath /var/lib/rpm") + expect(provider).to receive(:shell_out!).with("rpm --dbpath /var/lib/rpm -i /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm") + provider.install_package(new_resource.name, provider.candidate_version) end end describe "when removing the package" do it "should run rpm -e to remove the package" do - expect(@provider).to receive(:shell_out!).with("rpm -e ImageMagick-c++-6.5.4.7-7.el6_5") - @provider.remove_package("ImageMagick-c++", "6.5.4.7-7.el6_5") + expect(provider).to receive(:shell_out!).with("rpm -e ImageMagick-c++-6.5.4.7-7.el6_5") + provider.remove_package("ImageMagick-c++", "6.5.4.7-7.el6_5") end end end diff --git a/spec/unit/provider/package/rubygems_spec.rb b/spec/unit/provider/package/rubygems_spec.rb index b4960b2af3..b17c216ddd 100644 --- a/spec/unit/provider/package/rubygems_spec.rb +++ b/spec/unit/provider/package/rubygems_spec.rb @@ -371,6 +371,8 @@ describe Chef::Provider::Package::Rubygems do # We choose detect omnibus via RbConfig::CONFIG['bindir'] in Chef::Provider::Package::Rubygems.new allow(RbConfig::CONFIG).to receive(:[]).with('bindir').and_return("/usr/bin/ruby") + # Rubygems uses this interally + allow(RbConfig::CONFIG).to receive(:[]).with('arch').and_call_original @provider = Chef::Provider::Package::Rubygems.new(@new_resource, @run_context) end @@ -379,7 +381,7 @@ describe Chef::Provider::Package::Rubygems do it "target_version_already_installed? should return false so that we can search for candidates" do @provider.load_current_resource - expect(@provider.target_version_already_installed?).to be_falsey + expect(@provider.target_version_already_installed?(@provider.current_resource.version, @new_resource.version)).to be_falsey end end @@ -469,6 +471,8 @@ describe Chef::Provider::Package::Rubygems do it "determines the candidate version by querying the remote gem servers" do @new_resource.source('http://mygems.example.com') + @provider.load_current_resource + @provider.current_resource.version('0.0.1') version = Gem::Version.new(@spec_version) expect(@provider.gem_env).to receive(:candidate_version_from_remote). with(Gem::Dependency.new('rspec-core', @spec_version), "http://mygems.example.com"). @@ -478,8 +482,9 @@ describe Chef::Provider::Package::Rubygems do it "parses the gem's specification if the requested source is a file" do @new_resource.package_name('chef-integration-test') - @new_resource.version('>= 0') @new_resource.source(CHEF_SPEC_DATA + '/gems/chef-integration-test-0.1.0.gem') + @new_resource.version('>= 0') + @provider.load_current_resource expect(@provider.candidate_version).to eq('0.1.0') end @@ -496,20 +501,23 @@ describe Chef::Provider::Package::Rubygems do describe "in the current gem environment" do it "installs the gem via the gems api when no explicit options are used" do expect(@provider.gem_env).to receive(:install).with(@gem_dep, :sources => nil) - expect(@provider.action_install).to be_truthy + @provider.run_action(:install) + expect(@new_resource).to be_updated_by_last_action end it "installs the gem via the gems api when a remote source is provided" do @new_resource.source('http://gems.example.org') sources = ['http://gems.example.org'] expect(@provider.gem_env).to receive(:install).with(@gem_dep, :sources => sources) - expect(@provider.action_install).to be_truthy + @provider.run_action(:install) + expect(@new_resource).to be_updated_by_last_action end it "installs the gem from file via the gems api when no explicit options are used" do @new_resource.source(CHEF_SPEC_DATA + '/gems/chef-integration-test-0.1.0.gem') expect(@provider.gem_env).to receive(:install).with(CHEF_SPEC_DATA + '/gems/chef-integration-test-0.1.0.gem') - expect(@provider.action_install).to be_truthy + @provider.run_action(:install) + expect(@new_resource).to be_updated_by_last_action end it "installs the gem from file via the gems api when the package is a path and the source is nil" do @@ -518,7 +526,8 @@ describe Chef::Provider::Package::Rubygems do @provider.current_resource = @current_resource expect(@new_resource.source).to eq(CHEF_SPEC_DATA + '/gems/chef-integration-test-0.1.0.gem') expect(@provider.gem_env).to receive(:install).with(CHEF_SPEC_DATA + '/gems/chef-integration-test-0.1.0.gem') - expect(@provider.action_install).to be_truthy + @provider.run_action(:install) + expect(@new_resource).to be_updated_by_last_action end # this catches 'gem_package "foo"' when "./foo" is a file in the cwd, and instead of installing './foo' it fetches the remote gem @@ -526,28 +535,35 @@ describe Chef::Provider::Package::Rubygems do allow(::File).to receive(:exists?).and_return(true) @new_resource.package_name('rspec-core') expect(@provider.gem_env).to receive(:install).with(@gem_dep, :sources => nil) - expect(@provider.action_install).to be_truthy + @provider.run_action(:install) + expect(@new_resource).to be_updated_by_last_action end it "installs the gem by shelling out when options are provided as a String" do @new_resource.options('-i /alt/install/location') expected ="gem install rspec-core -q --no-rdoc --no-ri -v \"#{@spec_version}\" -i /alt/install/location" expect(@provider).to receive(:shell_out!).with(expected, :env => nil) - expect(@provider.action_install).to be_truthy + @provider.run_action(:install) + expect(@new_resource).to be_updated_by_last_action end - it "installs the gem by shelling out when options are provided but no version is given" do - @new_resource.options('-i /alt/install/location') - @new_resource.version('') - expected ="gem install \"rspec-core\" -q --no-rdoc --no-ri -i /alt/install/location" - expect(@provider).to receive(:shell_out!).with(expected, :env => nil) - expect(@provider.action_install).to be_truthy + context "when no version is given" do + let(:target_version) { nil } + + it "installs the gem by shelling out when options are provided but no version is given" do + @new_resource.options('-i /alt/install/location') + expected ="gem install rspec-core -q --no-rdoc --no-ri -v \"#{@provider.candidate_version}\" -i /alt/install/location" + expect(@provider).to receive(:shell_out!).with(expected, :env => nil) + @provider.run_action(:install) + expect(@new_resource).to be_updated_by_last_action + end end it "installs the gem via the gems api when options are given as a Hash" do @new_resource.options(:install_dir => '/alt/install/location') expect(@provider.gem_env).to receive(:install).with(@gem_dep, :sources => nil, :install_dir => '/alt/install/location') - expect(@provider.action_install).to be_truthy + @provider.run_action(:install) + expect(@new_resource).to be_updated_by_last_action end describe "at a specific version" do @@ -557,24 +573,25 @@ describe Chef::Provider::Package::Rubygems do it "installs the gem via the gems api" do expect(@provider.gem_env).to receive(:install).with(@gem_dep, :sources => nil) - expect(@provider.action_install).to be_truthy + @provider.run_action(:install) + expect(@new_resource).to be_updated_by_last_action end end describe "at version specified with comparison operator" do it "skips install if current version satisifies requested version" do - allow(@current_resource).to receive(:version).and_return("2.3.3") - allow(@new_resource).to receive(:version).and_return(">=2.3.0") + @current_resource.version("2.3.3") + @new_resource.version(">=2.3.0") expect(@provider.gem_env).not_to receive(:install) - @provider.action_install + @provider.run_action(:install) end it "allows user to specify gem version with fuzzy operator" do - allow(@current_resource).to receive(:version).and_return("2.3.3") - allow(@new_resource).to receive(:version).and_return("~>2.3.0") + @current_resource.version("2.3.3") + @new_resource.version("~>2.3.0") expect(@provider.gem_env).not_to receive(:install) - @provider.action_install + @provider.run_action(:install) end end end @@ -583,7 +600,8 @@ describe Chef::Provider::Package::Rubygems do it "installs the gem by shelling out to gem install" do @new_resource.gem_binary('/usr/weird/bin/gem') expect(@provider).to receive(:shell_out!).with("/usr/weird/bin/gem install rspec-core -q --no-rdoc --no-ri -v \"#{@spec_version}\"", :env=>nil) - expect(@provider.action_install).to be_truthy + @provider.run_action(:install) + expect(@new_resource).to be_updated_by_last_action end it "installs the gem from file by shelling out to gem install" do @@ -591,7 +609,8 @@ describe Chef::Provider::Package::Rubygems do @new_resource.source(CHEF_SPEC_DATA + '/gems/chef-integration-test-0.1.0.gem') @new_resource.version('>= 0') expect(@provider).to receive(:shell_out!).with("/usr/weird/bin/gem install #{CHEF_SPEC_DATA}/gems/chef-integration-test-0.1.0.gem -q --no-rdoc --no-ri -v \">= 0\"", :env=>nil) - expect(@provider.action_install).to be_truthy + @provider.run_action(:install) + expect(@new_resource).to be_updated_by_last_action end it "installs the gem from file by shelling out to gem install when the package is a path and the source is nil" do @@ -602,7 +621,8 @@ describe Chef::Provider::Package::Rubygems do @new_resource.version('>= 0') expect(@new_resource.source).to eq(CHEF_SPEC_DATA + '/gems/chef-integration-test-0.1.0.gem') expect(@provider).to receive(:shell_out!).with("/usr/weird/bin/gem install #{CHEF_SPEC_DATA}/gems/chef-integration-test-0.1.0.gem -q --no-rdoc --no-ri -v \">= 0\"", :env=>nil) - expect(@provider.action_install).to be_truthy + @provider.run_action(:install) + expect(@new_resource).to be_updated_by_last_action end end diff --git a/spec/unit/provider/package/solaris_spec.rb b/spec/unit/provider/package/solaris_spec.rb index 8438202576..332fa9db1a 100644 --- a/spec/unit/provider/package/solaris_spec.rb +++ b/spec/unit/provider/package/solaris_spec.rb @@ -64,8 +64,8 @@ PKGINFO it "should raise an exception if a source is supplied but not found" do allow(@provider).to receive(:popen4).and_return(@status) allow(::File).to receive(:exists?).and_return(false) - @provider.define_resource_requirements @provider.load_current_resource + @provider.define_resource_requirements expect { @provider.process_resource_requirements }.to raise_error(Chef::Exceptions::Package) end diff --git a/spec/unit/provider/package/yum_spec.rb b/spec/unit/provider/package/yum_spec.rb index 0d2a44f3ae..e5e32bc9c0 100644 --- a/spec/unit/provider/package/yum_spec.rb +++ b/spec/unit/provider/package/yum_spec.rb @@ -337,9 +337,9 @@ describe Chef::Provider::Package::Yum do @provider.load_current_resource allow(Chef::Provider::Package::Yum::RPMUtils).to receive(:rpmvercmp).and_return(-1) expect(@provider).to receive(:yum_command).with( - "yum -d0 -e0 -y install emacs-1.0" + "yum -d0 -e0 -y install cups-1.2.4-11.19.el5" ) - @provider.install_package("emacs", "1.0") + @provider.install_package("cups", "1.2.4-11.19.el5") end it "should run yum localinstall if given a path to an rpm" do @@ -366,14 +366,14 @@ describe Chef::Provider::Package::Yum do allow(@new_resource).to receive(:arch).and_return("i386") allow(Chef::Provider::Package::Yum::RPMUtils).to receive(:rpmvercmp).and_return(-1) expect(@provider).to receive(:yum_command).with( - "yum -d0 -e0 -y install emacs-21.4-20.el5.i386" + "yum -d0 -e0 -y install cups-1.2.4-11.19.el5.i386" ) - @provider.install_package("emacs", "21.4-20.el5") + @provider.install_package("cups", "1.2.4-11.19.el5") end it "installs the package with the options given in the resource" do @provider.load_current_resource - @provider.candidate_version = '11' + allow(@provider).to receive(:candidate_version).and_return('11') allow(@new_resource).to receive(:options).and_return("--disablerepo epmd") allow(Chef::Provider::Package::Yum::RPMUtils).to receive(:rpmvercmp).and_return(-1) expect(@provider).to receive(:yum_command).with( @@ -467,10 +467,10 @@ describe Chef::Provider::Package::Yum do @provider.load_current_resource allow(Chef::Provider::Package::Yum::RPMUtils).to receive(:rpmvercmp).and_return(-1) expect(@provider).to receive(:yum_command).with( - "yum -d0 -e0 -y install emacs-1.0" + "yum -d0 -e0 -y install cups-1.2.4-11.15.el5" ) expect(@yum_cache).to receive(:reload).once - @provider.install_package("emacs", "1.0") + @provider.install_package("cups", "1.2.4-11.15.el5") end it "should run yum install then not flush the cache if :after is false" do @@ -478,17 +478,17 @@ describe Chef::Provider::Package::Yum do @provider.load_current_resource allow(Chef::Provider::Package::Yum::RPMUtils).to receive(:rpmvercmp).and_return(-1) expect(@provider).to receive(:yum_command).with( - "yum -d0 -e0 -y install emacs-1.0" + "yum -d0 -e0 -y install cups-1.2.4-11.15.el5" ) expect(@yum_cache).not_to receive(:reload) - @provider.install_package("emacs", "1.0") + @provider.install_package("cups", "1.2.4-11.15.el5") end end describe "when upgrading a package" do it "should run yum install if the package is installed and a version is given" do @provider.load_current_resource - @provider.candidate_version = '11' + allow(@provider).to receive(:candidate_version).and_return('11') allow(Chef::Provider::Package::Yum::RPMUtils).to receive(:rpmvercmp).and_return(-1) expect(@provider).to receive(:yum_command).with( "yum -d0 -e0 -y install cups-11" @@ -499,7 +499,7 @@ describe Chef::Provider::Package::Yum do it "should run yum install if the package is not installed" do @provider.load_current_resource @current_resource = Chef::Resource::Package.new('cups') - @provider.candidate_version = '11' + allow(@provider).to receive(:candidate_version).and_return('11') allow(Chef::Provider::Package::Yum::RPMUtils).to receive(:rpmvercmp).and_return(-1) expect(@provider).to receive(:yum_command).with( "yum -d0 -e0 -y install cups-11" @@ -528,42 +528,41 @@ describe Chef::Provider::Package::Yum do # Test our little workaround, some crossover into Chef::Provider::Package territory it "should call action_upgrade in the parent if the current resource version is nil" do allow(@yum_cache).to receive(:installed_version).and_return(nil) - @provider.load_current_resource @current_resource = Chef::Resource::Package.new('cups') - @provider.candidate_version = '11' + allow(@provider).to receive(:candidate_version).and_return('11') expect(@provider).to receive(:upgrade_package).with( "cups", "11" ) - @provider.action_upgrade + @provider.run_action(:upgrade) end it "should call action_upgrade in the parent if the candidate version is nil" do @provider.load_current_resource @current_resource = Chef::Resource::Package.new('cups') - @provider.candidate_version = nil + allow(@provider).to receive(:candidate_version).and_return(nil) expect(@provider).not_to receive(:upgrade_package) - @provider.action_upgrade + @provider.run_action(:upgrade) end it "should call action_upgrade in the parent if the candidate is newer" do @provider.load_current_resource @current_resource = Chef::Resource::Package.new('cups') - @provider.candidate_version = '11' + allow(@provider).to receive(:candidate_version).and_return('11') expect(@provider).to receive(:upgrade_package).with( "cups", "11" ) - @provider.action_upgrade + @provider.run_action(:upgrade) end it "should not call action_upgrade in the parent if the candidate is older" do allow(@yum_cache).to receive(:installed_version).and_return("12") @provider.load_current_resource @current_resource = Chef::Resource::Package.new('cups') - @provider.candidate_version = '11' + allow(@provider).to receive(:candidate_version).and_return('11') expect(@provider).not_to receive(:upgrade_package) - @provider.action_upgrade + @provider.run_action(:upgrade) end end @@ -1861,3 +1860,103 @@ EOF end end + +describe "Chef::Provider::Package::Yum - Multi" do + before(:each) do + @node = Chef::Node.new + @events = Chef::EventDispatch::Dispatcher.new + @run_context = Chef::RunContext.new(@node, {}, @events) + @new_resource = Chef::Resource::Package.new(['cups', 'vim']) + @status = double("Status", :exitstatus => 0) + @yum_cache = double( + 'Chef::Provider::Yum::YumCache', + :reload_installed => true, + :reset => true, + :installed_version => 'XXXX', + :candidate_version => 'YYYY', + :package_available? => true, + :version_available? => true, + :allow_multi_install => [ 'kernel' ], + :package_repository => 'base', + :disable_extra_repo_control => true + ) + allow(Chef::Provider::Package::Yum::YumCache).to receive(:instance).and_return(@yum_cache) + @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context) + @pid = double("PID") + end + + describe "when loading the current system state" do + it "should create a current resource with the name of the new_resource" do + @provider.load_current_resource + expect(@provider.current_resource.name).to eq('cups, vim') + end + + it "should set the current resources package name to the new resources package name" do + @provider.load_current_resource + expect(@provider.current_resource.package_name).to eq(['cups', 'vim']) + end + + it "should set the installed version to nil on the current resource if no installed package" do + allow(@yum_cache).to receive(:installed_version).and_return(nil) + @provider.load_current_resource + expect(@provider.current_resource.version).to eq([nil, nil]) + end + + it "should set the installed version if yum has one" do + allow(@yum_cache).to receive(:installed_version).with('cups', nil).and_return('1.2.4-11.18.el5') + allow(@yum_cache).to receive(:installed_version).with('vim', nil).and_return('1.0') + allow(@yum_cache).to receive(:candidate_version).with('cups', nil).and_return('1.2.4-11.18.el5_2.3') + allow(@yum_cache).to receive(:candidate_version).with('vim', nil).and_return('1.5') + @provider.load_current_resource + expect(@provider.current_resource.version).to eq(['1.2.4-11.18.el5', '1.0']) + end + + it "should set the candidate version if yum info has one" do + allow(@yum_cache).to receive(:installed_version).with('cups', nil).and_return('1.2.4-11.18.el5') + allow(@yum_cache).to receive(:installed_version).with('vim', nil).and_return('1.0') + allow(@yum_cache).to receive(:candidate_version).with('cups', nil).and_return('1.2.4-11.18.el5_2.3') + allow(@yum_cache).to receive(:candidate_version).with('vim', nil).and_return('1.5') + @provider.load_current_resource + expect(@provider.candidate_version).to eql(['1.2.4-11.18.el5_2.3', '1.5']) + end + + it "should return the current resouce" do + expect(@provider.load_current_resource).to eql(@provider.current_resource) + end + end + + describe "when installing a package" do + it "should run yum install with the package name and version" do + @provider.load_current_resource + allow(Chef::Provider::Package::Yum::RPMUtils).to receive(:rpmvercmp).and_return(-1) + allow(@yum_cache).to receive(:installed_version).with('cups', nil).and_return('1.2.4-11.18.el5') + allow(@yum_cache).to receive(:installed_version).with('vim', nil).and_return('0.9') + expect(@provider).to receive(:yum_command).with( + "yum -d0 -e0 -y install cups-1.2.4-11.19.el5 vim-1.0" + ) + @provider.install_package(["cups", "vim"], ["1.2.4-11.19.el5", '1.0']) + end + + it "should run yum install with the package name, version and arch" do + @provider.load_current_resource + allow(@new_resource).to receive(:arch).and_return("i386") + allow(Chef::Provider::Package::Yum::RPMUtils).to receive(:rpmvercmp).and_return(-1) + expect(@provider).to receive(:yum_command).with( + "yum -d0 -e0 -y install cups-1.2.4-11.19.el5.i386 vim-1.0.i386" + ) + @provider.install_package(["cups", "vim"], ["1.2.4-11.19.el5", "1.0"]) + end + + it "installs the package with the options given in the resource" do + @provider.load_current_resource + allow(Chef::Provider::Package::Yum::RPMUtils).to receive(:rpmvercmp).and_return(-1) + allow(@yum_cache).to receive(:installed_version).with('cups', nil).and_return('1.2.4-11.18.el5') + allow(@yum_cache).to receive(:installed_version).with('vim', nil).and_return('0.9') + expect(@provider).to receive(:yum_command).with( + "yum -d0 -e0 -y --disablerepo epmd install cups-1.2.4-11.19.el5 vim-1.0" + ) + allow(@new_resource).to receive(:options).and_return("--disablerepo epmd") + @provider.install_package(["cups", "vim"], ["1.2.4-11.19.el5", '1.0']) + end + end +end diff --git a/spec/unit/provider/package_spec.rb b/spec/unit/provider/package_spec.rb index 2aeaf717e6..1633d18f9d 100644 --- a/spec/unit/provider/package_spec.rb +++ b/spec/unit/provider/package_spec.rb @@ -152,7 +152,7 @@ describe Chef::Provider::Package do it "should print the word 'uninstalled' if there was no original version" do allow(@current_resource).to receive(:version).and_return(nil) - expect(Chef::Log).to receive(:info).with("package[emacs] upgraded from uninstalled to 1.0") + expect(Chef::Log).to receive(:info).with("package[emacs] upgraded emacs to 1.0") @provider.run_action(:upgrade) expect(@new_resource).to be_updated_by_last_action end @@ -425,3 +425,277 @@ describe Chef::Provider::Package do end end + +describe "Chef::Provider::Package - Multi" do + before do + @node = Chef::Node.new + @events = Chef::EventDispatch::Dispatcher.new + @run_context = Chef::RunContext.new(@node, {}, @events) + @new_resource = Chef::Resource::Package.new(['emacs', 'vi']) + @current_resource = Chef::Resource::Package.new(['emacs', 'vi']) + @provider = Chef::Provider::Package.new(@new_resource, @run_context) + @provider.current_resource = @current_resource + @provider.candidate_version = ['1.0', '6.2'] + end + + describe "when installing multiple packages" do + before(:each) do + @provider.current_resource = @current_resource + allow(@provider).to receive(:install_package).and_return(true) + end + + it "installs the candidate versions when none are installed" do + expect(@provider).to receive(:install_package).with( + ["emacs", "vi"], + ["1.0", "6.2"] + ).and_return(true) + @provider.run_action(:install) + expect(@new_resource).to be_updated + end + + it "installs the candidate versions when some are installed" do + expect(@provider).to receive(:install_package).with( + [ 'vi' ], + [ '6.2' ] + ).and_return(true) + @current_resource.version(['1.0', nil]) + @provider.run_action(:install) + expect(@new_resource).to be_updated + end + + it "installs the specified version when some are out of date" do + @current_resource.version(['1.0', '6.2']) + @new_resource.version(['1.0', '6.1']) + @provider.run_action(:install) + expect(@new_resource).to be_updated + end + + it "does not install any version if all are installed at the right version" do + @current_resource.version(['1.0', '6.2']) + @new_resource.version(['1.0', '6.2']) + @provider.run_action(:install) + expect(@new_resource).not_to be_updated_by_last_action + end + + it "does not install any version if all are installed, and no version was specified" do + @current_resource.version(['1.0', '6.2']) + @provider.run_action(:install) + expect(@new_resource).not_to be_updated_by_last_action + end + + it "raises an exception if both are not installed and no caondidates are available" do + @current_resource.version([nil, nil]) + @provider.candidate_version = [nil, nil] + expect { @provider.run_action(:install) }.to raise_error(Chef::Exceptions::Package) + end + + it "raises an exception if one is not installed and no candidates are available" do + @current_resource.version(['1.0', nil]) + @provider.candidate_version = ['1.0', nil] + expect { @provider.run_action(:install) }.to raise_error(Chef::Exceptions::Package) + end + + it "does not raise an exception if the packages are installed or have a candidate" do + @current_resource.version(['1.0', nil]) + @provider.candidate_version = [nil, '6.2'] + expect { @provider.run_action(:install) }.not_to raise_error + end + + it "raises an exception if an explicit version is asked for, an old version is installed, but no candidate" do + @new_resource.version ['1.0', '6.2'] + @current_resource.version(['1.0', '6.1']) + @provider.candidate_version = ['1.0', nil] + expect { @provider.run_action(:install) }.to raise_error(Chef::Exceptions::Package) + end + + it "does not raise an exception if an explicit version is asked for, and is installed, but no candidate" do + @new_resource.version ['1.0', '6.2'] + @current_resource.version(['1.0', '6.2']) + @provider.candidate_version = ['1.0', nil] + expect { @provider.run_action(:install) }.not_to raise_error + end + + it "raise an exception if an explicit version is asked for, and is not installed, and no candidate" do + @new_resource.version ['1.0', '6.2'] + @current_resource.version(['1.0', nil]) + @provider.candidate_version = ['1.0', nil] + expect { @provider.run_action(:install) }.to raise_error(Chef::Exceptions::Package) + end + + it "does not raise an exception if an explicit version is asked for, and is not installed, and there is a candidate" do + @new_resource.version ['1.0', '6.2'] + @current_resource.version(['1.0', nil]) + @provider.candidate_version = ['1.0', '6.2'] + expect { @provider.run_action(:install) }.not_to raise_error + end + end + + describe "when upgrading multiple packages" do + before(:each) do + @provider.current_resource = @current_resource + allow(@provider).to receive(:upgrade_package).and_return(true) + end + + it "should upgrade the package if the current versions are not the candidate version" do + @current_resource.version ['0.9', '6.1'] + expect(@provider).to receive(:upgrade_package).with( + @new_resource.package_name, + @provider.candidate_version + ).and_return(true) + @provider.run_action(:upgrade) + expect(@new_resource).to be_updated_by_last_action + end + + it "should upgrade the package if some of current versions are not the candidate versions" do + @current_resource.version ['1.0', '6.1'] + expect(@provider).to receive(:upgrade_package).with( + ["vi"], + ["6.2"] + ).and_return(true) + @provider.run_action(:upgrade) + expect(@new_resource).to be_updated_by_last_action + end + + it "should not install the package if the current versions are the candidate version" do + @current_resource.version ['1.0', '6.2'] + expect(@provider).not_to receive(:upgrade_package) + @provider.run_action(:upgrade) + expect(@new_resource).not_to be_updated_by_last_action + end + + it "should raise an exception if both are not installed and no caondidates are available" do + @current_resource.version([nil, nil]) + @provider.candidate_version = [nil, nil] + expect { @provider.run_action(:upgrade) }.to raise_error(Chef::Exceptions::Package) + end + + it "should raise an exception if one is not installed and no candidates are available" do + @current_resource.version(['1.0', nil]) + @provider.candidate_version = ['1.0', nil] + expect { @provider.run_action(:upgrade) }.to raise_error(Chef::Exceptions::Package) + end + + it "should not raise an exception if the packages are installed or have a candidate" do + @current_resource.version(['1.0', nil]) + @provider.candidate_version = [nil, '6.2'] + expect { @provider.run_action(:upgrade) }.not_to raise_error + end + + it "should not raise an exception if the packages are installed or have a candidate" do + @current_resource.version(['1.0', nil]) + @provider.candidate_version = [nil, '6.2'] + expect { @provider.run_action(:upgrade) }.not_to raise_error + end + end + + describe "When removing multiple packages " do + before(:each) do + allow(@provider).to receive(:remove_package).and_return(true) + @current_resource.version ['1.0', '6.2'] + end + + it "should remove the packages if all are installed" do + expect(@provider).to be_removing_package + expect(@provider).to receive(:remove_package).with(['emacs', 'vi'], nil) + @provider.run_action(:remove) + expect(@new_resource).to be_updated + expect(@new_resource).to be_updated_by_last_action + end + + it "should remove the packages if some are installed" do + @current_resource.version ['1.0', nil] + expect(@provider).to be_removing_package + expect(@provider).to receive(:remove_package).with(['emacs', 'vi'], nil) + @provider.run_action(:remove) + expect(@new_resource).to be_updated + expect(@new_resource).to be_updated_by_last_action + end + + it "should remove the packages at a specific version if they are installed at that version" do + @new_resource.version ['1.0', '6.2'] + expect(@provider).to be_removing_package + expect(@provider).to receive(:remove_package).with(['emacs', 'vi'], ['1.0', '6.2']) + @provider.run_action(:remove) + expect(@new_resource).to be_updated_by_last_action + end + + it "should remove the packages at a specific version any are is installed at that version" do + @new_resource.version ['0.5', '6.2'] + expect(@provider).to be_removing_package + expect(@provider).to receive(:remove_package).with(['emacs', 'vi'], ['0.5', '6.2']) + @provider.run_action(:remove) + expect(@new_resource).to be_updated_by_last_action + end + + it "should not remove the packages at a specific version if they are not installed at that version" do + @new_resource.version ['0.5', '6.0'] + expect(@provider).not_to be_removing_package + expect(@provider).not_to receive(:remove_package) + @provider.run_action(:remove) + expect(@new_resource).not_to be_updated_by_last_action + end + + it "should not remove the packages if they are not installed" do + expect(@provider).not_to receive(:remove_package) + allow(@current_resource).to receive(:version).and_return(nil) + @provider.run_action(:remove) + expect(@new_resource).not_to be_updated_by_last_action + end + + end + + describe "When purging multiple packages " do + before(:each) do + allow(@provider).to receive(:purge_package).and_return(true) + @current_resource.version ['1.0', '6.2'] + end + + it "should purge the packages if all are installed" do + expect(@provider).to be_removing_package + expect(@provider).to receive(:purge_package).with(['emacs', 'vi'], nil) + @provider.run_action(:purge) + expect(@new_resource).to be_updated + expect(@new_resource).to be_updated_by_last_action + end + + it "should purge the packages if some are installed" do + @current_resource.version ['1.0', nil] + expect(@provider).to be_removing_package + expect(@provider).to receive(:purge_package).with(['emacs', 'vi'], nil) + @provider.run_action(:purge) + expect(@new_resource).to be_updated + expect(@new_resource).to be_updated_by_last_action + end + + it "should purge the packages at a specific version if they are installed at that version" do + @new_resource.version ['1.0', '6.2'] + expect(@provider).to be_removing_package + expect(@provider).to receive(:purge_package).with(['emacs', 'vi'], ['1.0', '6.2']) + @provider.run_action(:purge) + expect(@new_resource).to be_updated_by_last_action + end + + it "should purge the packages at a specific version any are is installed at that version" do + @new_resource.version ['0.5', '6.2'] + expect(@provider).to be_removing_package + expect(@provider).to receive(:purge_package).with(['emacs', 'vi'], ['0.5', '6.2']) + @provider.run_action(:purge) + expect(@new_resource).to be_updated_by_last_action + end + + it "should not purge the packages at a specific version if they are not installed at that version" do + @new_resource.version ['0.5', '6.0'] + expect(@provider).not_to be_removing_package + expect(@provider).not_to receive(:purge_package) + @provider.run_action(:purge) + expect(@new_resource).not_to be_updated_by_last_action + end + + it "should not purge the packages if they are not installed" do + expect(@provider).not_to receive(:purge_package) + allow(@current_resource).to receive(:version).and_return(nil) + @provider.run_action(:purge) + expect(@new_resource).not_to be_updated_by_last_action + end + end +end diff --git a/spec/unit/provider/package_spec.rbe b/spec/unit/provider/package_spec.rbe new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/spec/unit/provider/package_spec.rbe diff --git a/spec/unit/provider/service/freebsd_service_spec.rb b/spec/unit/provider/service/freebsd_service_spec.rb index 91d2d8e063..5a55425d87 100644 --- a/spec/unit/provider/service/freebsd_service_spec.rb +++ b/spec/unit/provider/service/freebsd_service_spec.rb @@ -580,6 +580,13 @@ EOF expect(provider).not_to receive(:write_rc_conf) provider.enable_service end + + it "should remove commented out versions of it being enabled" do + allow(current_resource).to receive(:enabled).and_return(false) + expect(provider).to receive(:read_rc_conf).and_return([ "foo", "bar", "\# #{new_resource.service_name}_enable=\"YES\"", "\# #{new_resource.service_name}_enable=\"NO\""]) + expect(provider).to receive(:write_rc_conf).with(["foo", "bar", "#{new_resource.service_name}_enable=\"YES\""]) + provider.enable_service() + end end describe Chef::Provider::Service::Freebsd, "disable_service" do @@ -607,5 +614,12 @@ EOF expect(provider).not_to receive(:write_rc_conf) provider.disable_service() end + + it "should remove commented out versions of it being disabled or enabled" do + allow(current_resource).to receive(:enabled).and_return(true) + expect(provider).to receive(:read_rc_conf).and_return([ "foo", "bar", "\# #{new_resource.service_name}_enable=\"YES\"", "\# #{new_resource.service_name}_enable=\"NO\""]) + expect(provider).to receive(:write_rc_conf).with(["foo", "bar", "#{new_resource.service_name}_enable=\"NO\""]) + provider.disable_service() + end end end diff --git a/spec/unit/provider/service/openbsd_service_spec.rb b/spec/unit/provider/service/openbsd_service_spec.rb new file mode 100644 index 0000000000..1b5206470e --- /dev/null +++ b/spec/unit/provider/service/openbsd_service_spec.rb @@ -0,0 +1,543 @@ +# +# Author:: Bryan McLellan (btm@loftninjas.org) +# Author:: Scott Bonds (scott@ggr.com) +# Copyright:: Copyright (c) 2009 Bryan McLellan +# Copyright:: Copyright (c) 2014 Scott Bonds +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require 'spec_helper' + +class Chef::Provider::Service::Openbsd + public :builtin_service_enable_variable_name + public :determine_enabled_status! + public :determine_current_status! + public :is_enabled? + attr_accessor :rc_conf, :rc_conf_local +end + +describe Chef::Provider::Service::Openbsd do + let(:node) do + node = Chef::Node.new + node.automatic_attrs[:command] = {:ps => "ps -ax"} + node + end + + let(:new_resource) do + new_resource = Chef::Resource::Service.new("sndiod") + new_resource.pattern("sndiod") + new_resource.supports({:status => false}) + new_resource + end + + let(:current_resource) do + current_resource = Chef::Resource::Service.new("sndiod") + current_resource + end + + let(:provider) do + events = Chef::EventDispatch::Dispatcher.new + run_context = Chef::RunContext.new(node, {}, events) + allow(::File).to receive(:read).with('/etc/rc.conf').and_return('') + allow(::File).to receive(:read).with('/etc/rc.conf.local').and_return('') + provider = Chef::Provider::Service::Openbsd.new(new_resource,run_context) + provider.action = :start + provider + end + + before do + allow(Chef::Resource::Service).to receive(:new).and_return(current_resource) + end + + def stub_etc_rcd_script + allow(::File).to receive(:exist?).and_return(false) + expect(::File).to receive(:exist?).with("/etc/rc.d/#{new_resource.service_name}").and_return(true) + end + + def run_load_current_resource + stub_etc_rcd_script + provider.load_current_resource + end + + describe Chef::Provider::Service::Openbsd, "initialize" do + it "should find /etc/rc.d init scripts" do + stub_etc_rcd_script + expect(provider.init_command).to eql "/etc/rc.d/sndiod" + end + + it "should set init_command to nil if it can't find anything" do + expect(::File).to receive(:exist?).with('/etc/rc.d/sndiod').and_return(false) + expect(provider.init_command).to be nil + end + end + + describe Chef::Provider::Service::Openbsd, "determine_current_status!" do + before do + stub_etc_rcd_script + provider.current_resource = current_resource + current_resource.service_name(new_resource.service_name) + end + + context "when a status command has been specified" do + let(:status) { double(:stdout => "", :exitstatus => 0) } + + before do + new_resource.status_command("/bin/chefhasmonkeypants status") + end + + it "should run the services status command if one has been specified" do + expect(provider).to receive(:shell_out).with("/bin/chefhasmonkeypants status").and_return(status) + provider.determine_current_status! + end + end + + context "when the service supports status" do + let(:status) { double(:stdout => "", :exitstatus => 0) } + + before do + new_resource.supports({:status => true}) + end + + it "should run '/etc/rc.d/service_name status'" do + expect(provider).to receive(:shell_out).with("/etc/rc.d/#{new_resource.service_name} check").and_return(status) + provider.determine_current_status! + end + + it "should set running to true if the status command returns 0" do + expect(provider).to receive(:shell_out).with("/etc/rc.d/#{new_resource.service_name} check").and_return(status) + provider.determine_current_status! + expect(current_resource.running).to be true + end + + it "should set running to false if the status command returns anything except 0" do + expect(provider).to receive(:shell_out).with("/etc/rc.d/#{new_resource.service_name} check").and_raise(Mixlib::ShellOut::ShellCommandFailed) + provider.determine_current_status! + expect(current_resource.running).to be false + end + end + end + + describe Chef::Provider::Service::Openbsd, "determine_enabled_status!" do + before do + stub_etc_rcd_script + provider.current_resource = current_resource + current_resource.service_name(new_resource.service_name) + + allow(provider).to receive(:service_enable_variable_name).and_return("#{new_resource.service_name}_enable") + end + + context "when the service is builtin" do + before do + expect(::File).to receive(:open).with("/etc/rc.d/#{new_resource.service_name}") + provider.rc_conf = "#{provider.builtin_service_enable_variable_name}=NO" + provider.rc_conf_local = lines.join("\n") + end + + %w{YES Yes yes yEs YeS}.each do |setting| + context "when the enable variable is set to #{setting}" do + let(:lines) { [ %Q{#{provider.builtin_service_enable_variable_name}="#{setting}"} ] } + it "sets enabled to true" do + provider.determine_enabled_status! + expect(current_resource.enabled).to be true + end + end + end + + %w{No NO no nO None NONE none nOnE}.each do |setting| + context "when the enable variable is set to #{setting}" do + let(:lines) { [ %Q{#{provider.builtin_service_enable_variable_name}="#{setting}"} ] } + it "sets enabled to false" do + provider.determine_enabled_status! + expect(current_resource.enabled).to be false + end + end + end + + context "when the enable variable is garbage" do + let(:lines) { [ %Q{#{provider.builtin_service_enable_variable_name}_enable="alskdjflasdkjflakdfj"} ] } + it "sets enabled to false" do + provider.determine_enabled_status! + expect(current_resource.enabled).to be false + end + end + + context "when the enable variable partial matches (left) some other service and we are disabled" do + let(:lines) { [ + %Q{thing_#{provider.builtin_service_enable_variable_name}="YES"}, + %Q{#{provider.builtin_service_enable_variable_name}="NO"}, + ] } + it "sets enabled based on the exact match (false)" do + provider.determine_enabled_status! + expect(current_resource.enabled).to be false + end + end + + context "when the enable variable partial matches (right) some other service and we are disabled" do + let(:lines) { [ + %Q{#{provider.builtin_service_enable_variable_name}_thing="YES"}, + %Q{#{provider.builtin_service_enable_variable_name}}, + ] } + it "sets enabled based on the exact match (false)" do + provider.determine_enabled_status! + expect(current_resource.enabled).to be false + end + end + + context "when the enable variable partial matches (left) some other disabled service and we are enabled" do + let(:lines) { [ + %Q{thing_#{provider.builtin_service_enable_variable_name}="NO"}, + %Q{#{provider.builtin_service_enable_variable_name}="YES"}, + ] } + it "sets enabled based on the exact match (true)" do + provider.determine_enabled_status! + expect(current_resource.enabled).to be true + end + end + + context "when the enable variable partial matches (right) some other disabled service and we are enabled" do + let(:lines) { [ + %Q{#{provider.builtin_service_enable_variable_name}_thing="NO"}, + %Q{#{provider.builtin_service_enable_variable_name}="YES"}, + ] } + it "sets enabled based on the exact match (true)" do + provider.determine_enabled_status! + expect(current_resource.enabled).to be true + end + end + + context "when the enable variable only partial matches (left) some other enabled service" do + let(:lines) { [ %Q{thing_#{provider.builtin_service_enable_variable_name}_enable="YES"} ] } + it "sets enabled to false" do + provider.determine_enabled_status! + expect(current_resource.enabled).to be false + end + end + + context "when the enable variable only partial matches (right) some other enabled service" do + let(:lines) { [ %Q{#{provider.builtin_service_enable_variable_name}_thing_enable="YES"} ] } + it "sets enabled to false" do + provider.determine_enabled_status! + expect(current_resource.enabled).to be false + end + end + + context "when nothing matches" do + let(:lines) { [] } + it "sets enabled to true" do + provider.determine_enabled_status! + expect(current_resource.enabled).to be false + end + end + end + end + + describe Chef::Provider::Service::Openbsd, "load_current_resource" do + before(:each) do + stub_etc_rcd_script + expect(provider).to receive(:determine_current_status!) + current_resource.running(false) + allow(provider).to receive(:service_enable_variable_name).and_return "#{new_resource.service_name}_enable" + expect(::File).to receive(:open).with("/etc/rc.d/#{new_resource.service_name}") + end + + it "should create a current resource with the name of the new resource" do + expect(Chef::Resource::Service).to receive(:new).and_return(current_resource) + provider.load_current_resource + end + + it "should set the current resources service name to the new resources service name" do + provider.load_current_resource + expect(current_resource.service_name).to eq(new_resource.service_name) + end + + it "should return the current resource" do + expect(provider.load_current_resource).to eql(current_resource) + end + + end + + context "when testing actions" do + before(:each) do + stub_etc_rcd_script + expect(provider).to receive(:determine_current_status!) + current_resource.running(false) + expect(provider).to receive(:determine_enabled_status!) + current_resource.enabled(false) + provider.load_current_resource + end + + describe Chef::Provider::Service::Openbsd, "start_service" do + it "should call the start command if one is specified" do + new_resource.start_command("/etc/rc.d/chef startyousillysally") + expect(provider).to receive(:shell_out_with_systems_locale!).with("/etc/rc.d/chef startyousillysally") + provider.start_service() + end + + it "should call '/usr/local/etc/rc.d/service_name start' if no start command is specified" do + expect(provider).to receive(:shell_out_with_systems_locale!).with("/etc/rc.d/#{new_resource.service_name} start") + provider.start_service() + end + end + + describe Chef::Provider::Service::Openbsd, "stop_service" do + it "should call the stop command if one is specified" do + new_resource.stop_command("/etc/init.d/chef itoldyoutostop") + expect(provider).to receive(:shell_out_with_systems_locale!).with("/etc/init.d/chef itoldyoutostop") + provider.stop_service() + end + + it "should call '/usr/local/etc/rc.d/service_name stop' if no stop command is specified" do + expect(provider).to receive(:shell_out_with_systems_locale!).with("/etc/rc.d/#{new_resource.service_name} stop") + provider.stop_service() + end + end + + describe Chef::Provider::Service::Openbsd, "restart_service" do + it "should call 'restart' on the service_name if the resource supports it" do + new_resource.supports({:restart => true}) + expect(provider).to receive(:shell_out_with_systems_locale!).with("/etc/rc.d/#{new_resource.service_name} restart") + provider.restart_service() + end + + it "should call the restart_command if one has been specified" do + new_resource.restart_command("/etc/init.d/chef restartinafire") + expect(provider).to receive(:shell_out_with_systems_locale!).with("/etc/init.d/chef restartinafire") + provider.restart_service() + end + + it "otherwise it should call stop and start" do + expect(provider).to receive(:stop_service) + expect(provider).to receive(:start_service) + provider.restart_service() + end + end + end + + describe Chef::Provider::Service::Openbsd, "define_resource_requirements" do + before do + provider.current_resource = current_resource + end + + context "when the init script is not found" do + before do + provider.init_command = nil + allow(provider).to receive(:builtin_service_enable_variable_name).and_return("#{new_resource.service_name}_enable") + end + + [ "start", "reload", "restart", "enable" ].each do |action| + it "should raise an exception when the action is #{action}" do + provider.define_resource_requirements + provider.action = action + expect { provider.process_resource_requirements }.to raise_error(Chef::Exceptions::Service) + end + end + + [ "stop", "disable" ].each do |action| + it "should not raise an error when the action is #{action}" do + provider.define_resource_requirements + provider.action = action + expect { provider.process_resource_requirements }.not_to raise_error + end + end + end + + context "when the init script is found, but the service_enable_variable_name is nil" do + before do + allow(provider).to receive(:builtin_service_enable_variable_name).and_return(nil) + end + + [ "start", "reload", "restart", "enable" ].each do |action| + it "should raise an exception when the action is #{action}" do + provider.action = action + provider.define_resource_requirements + expect { provider.process_resource_requirements }.to raise_error(Chef::Exceptions::Service) + end + end + + [ "stop", "disable" ].each do |action| + it "should not raise an error when the action is #{action}" do + provider.action = action + provider.define_resource_requirements + expect { provider.process_resource_requirements }.not_to raise_error + end + end + end + end + + describe Chef::Provider::Service::Openbsd, "enable_service" do + before do + provider.current_resource = current_resource + allow(FileUtils).to receive(:touch).with('/etc/rc.conf.local') + end + context "is builtin and disabled by default" do + before do + provider.rc_conf = "#{provider.builtin_service_enable_variable_name}=NO" + end + context "is enabled" do + before do + provider.rc_conf_local = "#{provider.builtin_service_enable_variable_name}=\"\"" + end + it "should not change rc.conf.local since it is already enabled" do + expect(::File).not_to receive(:write) + provider.enable_service + end + end + context "is disabled" do + before do + provider.rc_conf_local = '' + end + it "should enable the service by adding a line to rc.conf.local" do + expect(::File).to receive(:write).with('/etc/rc.conf.local', include("#{provider.builtin_service_enable_variable_name}=\"\"")) + expect(provider.is_enabled?).to be false + provider.enable_service + expect(provider.is_enabled?).to be true + end + end + end + context "is builtin and enabled by default" do + before do + provider.rc_conf = "#{provider.builtin_service_enable_variable_name}=\"\"" + end + context "is enabled" do + before do + provider.rc_conf_local = '' + end + it "should not change rc.conf.local since it is already enabled" do + expect(::File).not_to receive(:write) + provider.enable_service + end + end + context "is disabled" do + before do + provider.rc_conf_local = "#{provider.builtin_service_enable_variable_name}=NO" + end + it "should enable the service by removing a line from rc.conf.local" do + expect(::File).to receive(:write).with('/etc/rc.conf.local', /^(?!#{provider.builtin_service_enable_variable_name})$/) + expect(provider.is_enabled?).to be false + provider.enable_service + expect(provider.is_enabled?).to be true + end + end + end + context "is not builtin" do + before do + provider.rc_conf = '' + end + context "is enabled" do + before do + provider.rc_conf_local = "pkg_scripts=\"#{new_resource.service_name}\"\n" + end + it "should not change rc.conf.local since it is already enabled" do + expect(::File).not_to receive(:write) + provider.enable_service + end + end + context "is disabled" do + before do + provider.rc_conf_local = '' + end + it "should enable the service by adding it to the pkg_scripts list" do + expect(::File).to receive(:write).with('/etc/rc.conf.local', "\npkg_scripts=\"#{new_resource.service_name}\"\n") + expect(provider.is_enabled?).to be false + provider.enable_service + expect(provider.is_enabled?).to be true + end + end + end + end + + describe Chef::Provider::Service::Openbsd, "disable_service" do + before do + provider.current_resource = current_resource + allow(FileUtils).to receive(:touch).with('/etc/rc.conf.local') + end + context "is builtin and disabled by default" do + before do + provider.rc_conf = "#{provider.builtin_service_enable_variable_name}=NO" + end + context "is enabled" do + before do + provider.rc_conf_local = "#{provider.builtin_service_enable_variable_name}=\"\"" + end + it "should disable the service by removing its line from rc.conf.local" do + expect(::File).to receive(:write).with('/etc/rc.conf.local', /^(?!#{provider.builtin_service_enable_variable_name})$/) + expect(provider.is_enabled?).to be true + provider.disable_service + expect(provider.is_enabled?).to be false + end + end + context "is disabled" do + before do + provider.rc_conf_local = '' + end + it "should not change rc.conf.local since it is already disabled" do + expect(::File).not_to receive(:write) + provider.disable_service + end + end + end + context "is builtin and enabled by default" do + before do + provider.rc_conf = "#{provider.builtin_service_enable_variable_name}=\"\"" + end + context "is enabled" do + before do + provider.rc_conf_local = '' + end + it "should disable the service by adding a line to rc.conf.local" do + expect(::File).to receive(:write).with('/etc/rc.conf.local', include("#{provider.builtin_service_enable_variable_name}=\"NO\"")) + expect(provider.is_enabled?).to be true + provider.disable_service + expect(provider.is_enabled?).to be false + end + end + context "is disabled" do + before do + provider.rc_conf_local = "#{provider.builtin_service_enable_variable_name}=NO" + end + it "should not change rc.conf.local since it is already disabled" do + expect(::File).not_to receive(:write) + provider.disable_service + end + end + end + context "is not builtin" do + before do + provider.rc_conf = '' + end + context "is enabled" do + before do + provider.rc_conf_local = "pkg_scripts=\"#{new_resource.service_name}\"\n" + end + it "should disable the service by removing it from the pkg_scripts list" do + expect(::File).to receive(:write).with('/etc/rc.conf.local', /^(?!#{new_resource.service_name})$/) + expect(provider.is_enabled?).to be true + provider.disable_service + expect(provider.is_enabled?).to be false + end + end + context "is disabled" do + before do + provider.rc_conf_local = '' + end + it "should not change rc.conf.local since it is already disabled" do + expect(::File).not_to receive(:write) + provider.disable_service + end + end + end + end + +end diff --git a/spec/unit/provider/user_spec.rb b/spec/unit/provider/user_spec.rb index 44434794e7..381168647b 100644 --- a/spec/unit/provider/user_spec.rb +++ b/spec/unit/provider/user_spec.rb @@ -91,7 +91,7 @@ describe Chef::Provider::User do expect(@current_resource.username).to eq(@new_resource.username) end - it "should change the encoding of gecos to the encoding of the new resource", :ruby_gte_19_only do + it "should change the encoding of gecos to the encoding of the new resource" do @pw_user.gecos.force_encoding('ASCII-8BIT') @provider.load_current_resource expect(@provider.current_resource.comment.encoding).to eq(@new_resource.comment.encoding) diff --git a/spec/unit/recipe_spec.rb b/spec/unit/recipe_spec.rb index 5ade7c86e2..8d0b1bcfd2 100644 --- a/spec/unit/recipe_spec.rb +++ b/spec/unit/recipe_spec.rb @@ -591,7 +591,7 @@ describe Chef::Recipe do describe "included DSL" do it "should include features from Chef::DSL::Audit" do expect(recipe.singleton_class.included_modules).to include(Chef::DSL::Audit) - expect(recipe.respond_to?(:controls)).to be true + expect(recipe.respond_to?(:control_group)).to be true end end end diff --git a/spec/unit/resource/chef_gem_spec.rb b/spec/unit/resource/chef_gem_spec.rb index 657713d54f..7352a8f5fe 100644 --- a/spec/unit/resource/chef_gem_spec.rb +++ b/spec/unit/resource/chef_gem_spec.rb @@ -63,7 +63,12 @@ describe Chef::Resource::ChefGem, "gem_binary" do Chef::Recipe.new("hjk", "test", run_context) end - let(:resource) { Chef::Resource::ChefGem.new("foo", run_context) } + let(:chef_gem_compile_time) { nil } + + let(:resource) do + Chef::Config[:chef_gem_compile_time] = chef_gem_compile_time + Chef::Resource::ChefGem.new("foo", run_context) + end before do expect(Chef::Resource::ChefGem).to receive(:new).and_return(resource) @@ -71,20 +76,20 @@ describe Chef::Resource::ChefGem, "gem_binary" do it "runs the install at compile-time by default", :chef_lt_13_only do expect(resource).to receive(:run_action).with(:install) - expect(Chef::Log).to receive(:warn).at_least(:once) + expect(Chef::Log).to receive(:deprecation).at_least(:once) recipe.chef_gem "foo" end # the default behavior will change in Chef-13 it "does not runs the install at compile-time by default", :chef_gte_13_only do expect(resource).not_to receive(:run_action).with(:install) - expect(Chef::Log).not_to receive(:warn) + expect(Chef::Log).not_to receive(:deprecation) recipe.chef_gem "foo" end it "compile_time true installs at compile-time" do expect(resource).to receive(:run_action).with(:install) - expect(Chef::Log).not_to receive(:warn) + expect(Chef::Log).not_to receive(:deprecation) recipe.chef_gem "foo" do compile_time true end @@ -92,10 +97,65 @@ describe Chef::Resource::ChefGem, "gem_binary" do it "compile_time false does not install at compile-time" do expect(resource).not_to receive(:run_action).with(:install) - expect(Chef::Log).not_to receive(:warn) + expect(Chef::Log).not_to receive(:deprecation) recipe.chef_gem "foo" do compile_time false end end + + describe "when Chef::Config[:chef_gem_compile_time] is explicitly true" do + let(:chef_gem_compile_time) { true } + + before do + expect(Chef::Log).not_to receive(:deprecation) + end + + it "by default installs at compile-time" do + expect(resource).to receive(:run_action).with(:install) + recipe.chef_gem "foo" + end + + it "compile_time true installs at compile-time" do + expect(resource).to receive(:run_action).with(:install) + recipe.chef_gem "foo" do + compile_time true + end + end + + it "compile_time false does not install at compile-time" do + expect(resource).not_to receive(:run_action).with(:install) + recipe.chef_gem "foo" do + compile_time false + end + end + end + + describe "when Chef::Config[:chef_gem_compile_time] is explicitly false" do + + let(:chef_gem_compile_time) { false } + + before do + expect(Chef::Log).not_to receive(:deprecation) + end + + it "by default does not install at compile-time" do + expect(resource).not_to receive(:run_action).with(:install) + recipe.chef_gem "foo" + end + + it "compile_time true installs at compile-time" do + expect(resource).to receive(:run_action).with(:install) + recipe.chef_gem "foo" do + compile_time true + end + end + + it "compile_time false does not install at compile-time" do + expect(resource).not_to receive(:run_action).with(:install) + recipe.chef_gem "foo" do + compile_time false + end + end + end end end diff --git a/spec/unit/resource/conditional_spec.rb b/spec/unit/resource/conditional_spec.rb index 779c69425a..49240edfdf 100644 --- a/spec/unit/resource/conditional_spec.rb +++ b/spec/unit/resource/conditional_spec.rb @@ -47,7 +47,7 @@ describe Chef::Resource::Conditional do end describe "when created as an `only_if`" do - describe "after running a successful command" do + describe "after running a successful command given as a string" do before do @conditional = Chef::Resource::Conditional.only_if(@parent_resource, "true") end @@ -57,7 +57,7 @@ describe Chef::Resource::Conditional do end end - describe "after running a negative/false command" do + describe "after running a negative/false command given as a string" do before do @status.send("success?=", false) @conditional = Chef::Resource::Conditional.only_if(@parent_resource, "false") @@ -68,6 +68,27 @@ describe Chef::Resource::Conditional do end end + describe "after running a successful command given as an array" do + before do + @conditional = Chef::Resource::Conditional.only_if(@parent_resource, ["true"]) + end + + it "indicates that resource convergence should continue" do + expect(@conditional.continue?).to be true + end + end + + describe "after running a negative/false command given as an array" do + before do + @status.send("success?=", false) + @conditional = Chef::Resource::Conditional.only_if(@parent_resource, ["false"]) + end + + it "indicates that resource convergence should not continue" do + expect(@conditional.continue?).to be false + end + end + describe 'after running a command which timed out' do before do @conditional = Chef::Resource::Conditional.only_if(@parent_resource, "false") @@ -106,7 +127,7 @@ describe Chef::Resource::Conditional do end describe "when created as a `not_if`" do - describe "after running a successful/true command" do + describe "after running a successful/true command given as a string" do before do @conditional = Chef::Resource::Conditional.not_if(@parent_resource, "true") end @@ -116,7 +137,7 @@ describe Chef::Resource::Conditional do end end - describe "after running a failed/false command" do + describe "after running a failed/false command given as a string" do before do @status.send("success?=", false) @conditional = Chef::Resource::Conditional.not_if(@parent_resource, "false") @@ -127,6 +148,27 @@ describe Chef::Resource::Conditional do end end + describe "after running a successful/true command given as an array" do + before do + @conditional = Chef::Resource::Conditional.not_if(@parent_resource, ["true"]) + end + + it "indicates that resource convergence should not continue" do + expect(@conditional.continue?).to be false + end + end + + describe "after running a failed/false command given as an array" do + before do + @status.send("success?=", false) + @conditional = Chef::Resource::Conditional.not_if(@parent_resource, ["false"]) + end + + it "indicates that resource convergence should continue" do + expect(@conditional.continue?).to be true + end + end + describe 'after running a command which timed out' do before do @conditional = Chef::Resource::Conditional.not_if(@parent_resource, "false") diff --git a/spec/unit/resource/execute_spec.rb b/spec/unit/resource/execute_spec.rb index 70b9d87d4c..09160ddbd0 100644 --- a/spec/unit/resource/execute_spec.rb +++ b/spec/unit/resource/execute_spec.rb @@ -28,4 +28,8 @@ describe Chef::Resource::Execute do expect(execute_resource.guard_interpreter).to be(:execute) end + it "defaults to not being a guard interpreter" do + expect(execute_resource.is_guard_interpreter).to eq(false) + end + end diff --git a/spec/unit/resource/rpm_package_spec.rb b/spec/unit/resource/rpm_package_spec.rb index d209c6a5a2..d3b505fff5 100644 --- a/spec/unit/resource/rpm_package_spec.rb +++ b/spec/unit/resource/rpm_package_spec.rb @@ -32,3 +32,15 @@ describe Chef::Resource::RpmPackage, "initialize" do end end + +describe Chef::Resource::RpmPackage, "allow_downgrade" do + before(:each) do + @resource = Chef::Resource::RpmPackage.new("foo") + end + + it "should allow you to specify whether allow_downgrade is true or false" do + expect { @resource.allow_downgrade true }.not_to raise_error + expect { @resource.allow_downgrade false }.not_to raise_error + expect { @resource.allow_downgrade "monkey" }.to raise_error(ArgumentError) + end +end diff --git a/spec/unit/resource_spec.rb b/spec/unit/resource_spec.rb index 56c7401c92..8214021f65 100644 --- a/spec/unit/resource_spec.rb +++ b/spec/unit/resource_spec.rb @@ -194,12 +194,12 @@ describe Chef::Resource do expect(@resource.name).to eql("monkey") end - it "should not be valid without a name" do - expect { @resource.name false }.to raise_error(ArgumentError) + it "coerces arrays to names" do + expect(@resource.name ['a', 'b']).to eql('a, b') end - it "should always have a string for name" do - expect { @resource.name Hash.new }.to raise_error(ArgumentError) + it "should coerce objects to a string" do + expect(@resource.name Object.new).to be_a(String) end end @@ -258,6 +258,12 @@ describe Chef::Resource do expected_notification = Chef::Resource::Notification.new({:service => "apache"}, :restart, @resource) expect(@resource.delayed_notifications).to include(expected_notification) end + + it "notifies a resource with an array for its name via its prettified string name" do + @run_context.resource_collection << Chef::Resource::ZenMaster.new(["coffee", "tea"]) + @resource.notifies :reload, @run_context.resource_collection.find(:zen_master => "coffee, tea") + expect(@resource.delayed_notifications.detect{|e| e.resource.name == "coffee, tea" && e.action == :reload}).not_to be_nil + end end describe "subscribes" do diff --git a/spec/unit/util/diff_spec.rb b/spec/unit/util/diff_spec.rb index ea226f1c04..b0a57a32c0 100644 --- a/spec/unit/util/diff_spec.rb +++ b/spec/unit/util/diff_spec.rb @@ -105,7 +105,7 @@ shared_examples_for "a diff util" do end end - describe "when the default external encoding is UTF-8", :ruby_gte_19_only do + describe "when the default external encoding is UTF-8" do before do @saved_default_external = Encoding.default_external @@ -170,7 +170,7 @@ shared_examples_for "a diff util" do end - describe "when the default external encoding is Latin-1", :ruby_gte_19_only do + describe "when the default external encoding is Latin-1" do before do @saved_default_external = Encoding.default_external @@ -234,7 +234,7 @@ shared_examples_for "a diff util" do end end - describe "when the default external encoding is Shift_JIS", :ruby_gte_19_only do + describe "when the default external encoding is Shift_JIS" do before do @saved_default_external = Encoding.default_external @@ -411,7 +411,7 @@ shared_examples_for "a diff util" do end end - describe "when the default external encoding is UTF-8", :ruby_gte_19_only do + describe "when the default external encoding is UTF-8" do before do @saved_default_external = Encoding.default_external @@ -456,7 +456,7 @@ shared_examples_for "a diff util" do end - describe "when the default external encoding is Latin-1", :ruby_gte_19_only do + describe "when the default external encoding is Latin-1" do before do @saved_default_external = Encoding.default_external @@ -500,7 +500,7 @@ shared_examples_for "a diff util" do end end - describe "when the default external encoding is Shift-JIS", :ruby_gte_19_only do + describe "when the default external encoding is Shift-JIS" do before do @saved_default_external = Encoding.default_external diff --git a/spec/unit/util/dsc/local_configuration_manager_spec.rb b/spec/unit/util/dsc/local_configuration_manager_spec.rb index 1281862e67..1cff9e445b 100644 --- a/spec/unit/util/dsc/local_configuration_manager_spec.rb +++ b/spec/unit/util/dsc/local_configuration_manager_spec.rb @@ -65,7 +65,7 @@ EOH let(:lcm_cmdlet_success) { true } it 'should successfully return resource information for normally formatted output when cmdlet the cmdlet succeeds' do - test_configuration_result = lcm.test_configuration('config') + test_configuration_result = lcm.test_configuration('config', {}) expect(test_configuration_result.class).to be(Array) expect(test_configuration_result.length).to be > 0 expect(Chef::Log).not_to receive(:warn) @@ -85,7 +85,7 @@ EOH expect(Chef::Log).to receive(:warn).at_least(:once) expect(lcm).to receive(:whatif_not_supported?).and_call_original test_configuration_result = nil - expect {test_configuration_result = lcm.test_configuration('config')}.not_to raise_error + expect {test_configuration_result = lcm.test_configuration('config', {})}.not_to raise_error expect(test_configuration_result.class).to be(Array) end end @@ -99,13 +99,13 @@ EOH expect(Chef::Log).to receive(:warn).at_least(:once) expect(lcm).to receive(:dsc_module_import_failure?).and_call_original test_configuration_result = nil - expect {test_configuration_result = lcm.test_configuration('config')}.not_to raise_error + expect {test_configuration_result = lcm.test_configuration('config', {})}.not_to raise_error end it 'should return a (possibly empty) array of ResourceInfo instances' do expect(Chef::Log).to receive(:warn).at_least(:once) test_configuration_result = nil - expect {test_configuration_result = lcm.test_configuration('config')}.not_to raise_error + expect {test_configuration_result = lcm.test_configuration('config', {})}.not_to raise_error expect(test_configuration_result.class).to be(Array) end end @@ -118,7 +118,7 @@ EOH it 'should log a warning' do expect(Chef::Log).to receive(:warn).at_least(:once) expect(lcm).to receive(:dsc_module_import_failure?).and_call_original - expect {lcm.test_configuration('config')}.not_to raise_error + expect {lcm.test_configuration('config', {})}.not_to raise_error end end end diff --git a/spec/unit/util/path_helper_spec.rb b/spec/unit/util/path_helper_spec.rb index 4df4b9b1ff..5756c29b90 100644 --- a/spec/unit/util/path_helper_spec.rb +++ b/spec/unit/util/path_helper_spec.rb @@ -189,16 +189,8 @@ describe Chef::Util::PathHelper do end context "not on windows", :unix_only do - context "ruby is at least 1.9", :ruby_gte_19_only do - it "returns a canonical path" do - expect(PathHelper.canonical_path("/etc//apache.d/sites-enabled/../sites-available/default")).to eq("/etc/apache.d/sites-available/default") - end - end - - context "ruby is less than 1.9", :ruby_18_only do - it "returns a canonical path" do - expect { PathHelper.canonical_path("/etc//apache.d/sites-enabled/../sites-available/default") }.to raise_error(NotImplementedError) - end + it "returns a canonical path" do + expect(PathHelper.canonical_path("/etc//apache.d/sites-enabled/../sites-available/default")).to eq("/etc/apache.d/sites-available/default") end end end |