diff options
Diffstat (limited to 'spec')
22 files changed, 517 insertions, 59 deletions
diff --git a/spec/functional/rebooter_spec.rb b/spec/functional/rebooter_spec.rb index a28491cc0b..36961593b0 100644 --- a/spec/functional/rebooter_spec.rb +++ b/spec/functional/rebooter_spec.rb @@ -35,8 +35,9 @@ describe Chef::Platform::Rebooter do resource end + let(:node) { Chef::Node.new } + let(:run_context) do - node = Chef::Node.new events = Chef::EventDispatch::Dispatcher.new Chef::RunContext.new(node, {}, events) end @@ -44,7 +45,8 @@ describe Chef::Platform::Rebooter do let(:expected) do { :windows => "#{ENV['SYSTEMROOT']}/System32/shutdown.exe /r /t 300 /c \"rebooter spec test\"", - :linux => 'shutdown -r +5 "rebooter spec test"', + :linux => 'shutdown -r +5 "rebooter spec test" &', + :solaris => 'shutdown -i6 -g5 -y "rebooter spec test" &', } end @@ -69,8 +71,9 @@ describe Chef::Platform::Rebooter do end shared_context "test a reboot method" do - def test_rebooter_method(method_sym, is_windows, expected_reboot_str) + def test_rebooter_method(method_sym, is_windows, is_solaris, expected_reboot_str) allow(ChefConfig).to receive(:windows?).and_return(is_windows) + node.automatic["os"] = node.automatic["platform"] = node.automatic["platform_family"] = "solaris2" if is_solaris expect(rebooter).to receive(:shell_out!).once.with(expected_reboot_str) expect(rebooter).to receive(:raise).with(Chef::Exceptions::Reboot) expect(rebooter).to receive(method_sym).once.and_call_original @@ -81,24 +84,32 @@ describe Chef::Platform::Rebooter do describe "when using #reboot_if_needed!" do include_context "test a reboot method" - it "should produce the correct string on Windows", :windows_only do - test_rebooter_method(:reboot_if_needed!, true, expected[:windows]) + it "should produce the correct string on Windows" do + test_rebooter_method(:reboot_if_needed!, true, false, expected[:windows]) + end + + it "should produce a SysV-like shutdown on solaris" do + test_rebooter_method(:reboot_if_needed!, false, true, expected[:solaris]) end - it "should produce the correct (Linux-specific) string on non-Windows" do - test_rebooter_method(:reboot_if_needed!, false, expected[:linux]) + it "should produce a BSD-like shutdown by default" do + test_rebooter_method(:reboot_if_needed!, false, false, expected[:linux]) end end describe "when using #reboot!" do include_context "test a reboot method" - it "should produce the correct string on Windows", :windows_only do - test_rebooter_method(:reboot!, true, expected[:windows]) + it "should produce the correct string on Windows" do + test_rebooter_method(:reboot!, true, false, expected[:windows]) + end + + it "should produce a SysV-like shutdown on solaris" do + test_rebooter_method(:reboot!, false, true, expected[:solaris]) end - it "should produce the correct (Linux-specific) string on non-Windows" do - test_rebooter_method(:reboot!, false, expected[:linux]) + it "should produce a BSD-like shutdown by default" do + test_rebooter_method(:reboot!, false, false, expected[:linux]) end end end diff --git a/spec/functional/resource/user/useradd_spec.rb b/spec/functional/resource/user/useradd_spec.rb index e783356c9f..175809b5c0 100644 --- a/spec/functional/resource/user/useradd_spec.rb +++ b/spec/functional/resource/user/useradd_spec.rb @@ -646,10 +646,10 @@ describe Chef::Provider::User::Useradd, metadata do expect(@error.message).to include("Cannot unlock the password") end elsif %w{rhel}.include?(OHAI_SYSTEM["platform_family"]) && - OHAI_SYSTEM["platform_version"].to_f == 6.8 - # usermod -U returns following message for rhel68 on s390x platforms - # usermod: unlocking the user's password would result in a passwordless account. - #You should set a password with usermod -p to unlock this user's password. + (Chef::VersionConstraint.new("~> 6.8").include?(OHAI_SYSTEM["platform_version"].to_f) || Chef::VersionConstraint.new("~> 7.3").include?(OHAI_SYSTEM["platform_version"].to_f)) + # RHEL 6.8 and 7.3 ship with a fixed `usermod` command + # Reference: https://access.redhat.com/errata/RHBA-2016:0864 + # Reference: https://access.redhat.com/errata/RHBA-2016:2322 it "errors out trying to unlock the user" do expect(@error).to be_a(Mixlib::ShellOut::ShellCommandFailed) expect(@error.message).to include("You should set a password") diff --git a/spec/functional/resource/windows_task_spec.rb b/spec/functional/resource/windows_task_spec.rb index c2496c702f..6c4b4c4fdc 100644 --- a/spec/functional/resource/windows_task_spec.rb +++ b/spec/functional/resource/windows_task_spec.rb @@ -163,6 +163,31 @@ describe Chef::Resource::WindowsTask, :windows_only do end end + context "frequency :none" do + subject do + new_resource = Chef::Resource::WindowsTask.new(task_name, run_context) + new_resource.command task_name + new_resource.run_level :highest + new_resource.frequency :none + new_resource.random_delay "" + new_resource + end + + it "creates the scheduled task to run on demand only" do + subject.run_action(:create) + task_details = windows_task_provider.send(:load_task_hash, task_name) + + expect(task_details[:TaskName]).to eq("\\chef-client") + expect(task_details[:TaskToRun]).to eq("chef-client") + expect(task_details[:ScheduleType]).to eq("On demand only") + expect(task_details[:StartTime]).to eq("N/A") + expect(task_details[:StartDate]).to eq("N/A") + expect(task_details[:NextRunTime]).to eq("N/A") + expect(task_details[:none]).to eq(true) + expect(task_details[:run_level]).to eq("HighestAvailable") + end + end + context "frequency :weekly" do subject do new_resource = Chef::Resource::WindowsTask.new(task_name, run_context) diff --git a/spec/functional/win32/security_spec.rb b/spec/functional/win32/security_spec.rb index 40ae99bfa4..f3faf24c52 100644 --- a/spec/functional/win32/security_spec.rb +++ b/spec/functional/win32/security_spec.rb @@ -17,6 +17,8 @@ # require "spec_helper" +require "mixlib/shellout" +require "chef/mixin/user_context" if Chef::Platform.windows? require "chef/win32/security" end @@ -26,13 +28,37 @@ describe "Chef::Win32::Security", :windows_only do expect(Chef::ReservedNames::Win32::Security.has_admin_privileges?).to eq(true) end - # We've done some investigation adding a negative test and it turned - # out to be a lot of work since mixlib-shellout doesn't have user - # support for windows. - # - # TODO - Add negative tests once mixlib-shellout has user support - it "has_admin_privileges? returns false when running as non-admin" do - skip "requires user support in mixlib-shellout" + describe "running as non admin user" do + include Chef::Mixin::UserContext + let(:user) { "security_user" } + let(:password) { "Security@123" } + + let(:domain) do + whoami = Mixlib::ShellOut.new("whoami") + whoami.run_command + whoami.error! + whoami.stdout.split("\\")[0] + end + before do + allow_any_instance_of(Chef::Mixin::UserContext).to receive(:node).and_return({ "platform_family" => "windows" }) + allow(Chef::Platform).to receive(:windows_server_2003?).and_return(false) + allow(Chef::ReservedNames::Win32::Security).to receive(:OpenProcessToken).and_return(true) + add_user = Mixlib::ShellOut.new("net user #{user} #{password} /ADD") + add_user.run_command + add_user.error! + end + + after do + delete_user = Mixlib::ShellOut.new("net user #{user} /delete") + delete_user.run_command + delete_user.error! + end + it "has_admin_privileges? returns false" do + has_admin_privileges = with_user_context(user, password, domain) do + Chef::ReservedNames::Win32::Security.has_admin_privileges? + end + expect(has_admin_privileges).to eq(false) + end end describe "get_file_security" do diff --git a/spec/support/shared/functional/execute_resource.rb b/spec/support/shared/functional/execute_resource.rb index 4f7cea1cd1..1a14bb38c3 100644 --- a/spec/support/shared/functional/execute_resource.rb +++ b/spec/support/shared/functional/execute_resource.rb @@ -63,7 +63,7 @@ shared_context "a command that can be executed as an alternate user" do after do File.delete(script_output_path) if File.exists?(script_output_path) - Dir.rmdir(script_output_dir) if Dir.exists?(script_output_dir) + Dir.rmdir(script_output_dir) if Dir.exist?(script_output_dir) end end diff --git a/spec/unit/chef_fs/data_handler/data_bag_item_data_handler.rb b/spec/unit/chef_fs/data_handler/data_bag_item_data_handler.rb new file mode 100644 index 0000000000..fea7a2d54d --- /dev/null +++ b/spec/unit/chef_fs/data_handler/data_bag_item_data_handler.rb @@ -0,0 +1,79 @@ +# +# Author:: Sandra Tiffin (<sandi.tiffin@gmail.com>) +# Copyright:: Copyright 2014-2016, 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 "lib/chef/chef_fs/data_handler/data_bag_item_data_handler.rb" + +class TestDataBag < Mash + attr_accessor :name + + def initialize(bag_name) + @name = bag_name + end +end + +class TestDataBagItem < Mash + attr_accessor :name, :parent + + def path_for_printing + "/some/path" + end + + def initialize(bag_name, item_name) + @name = "#{item_name}.json" + @parent = TestDataBag.new(bag_name) + end +end + +describe Chef::ChefFS::DataHandler::DataBagItemDataHandler do + let(:handler) { described_class.new } + + describe "#verify_integrity" do + context "json id does not match data bag item name" do + let(:entry) { TestDataBagItem.new("luggage", "bag") } + let(:object) do + { "raw_data" => { "id" => "duffel" } } + end + it "rejects the data bag item name" do + expect { |b| handler.verify_integrity(object, entry, &b) }.to yield_with_args + end + end + + context "using a reserved word for the data bag name" do + %w{node role environment client}.each do |reserved_word| + let(:entry) { TestDataBagItem.new(reserved_word, "bag") } + let(:object) do + { "raw_data" => { "id" => "bag" } } + end + it "rejects the data bag name '#{reserved_word}'" do + expect { |b| handler.verify_integrity(object, entry, &b) }.to yield_with_args + end + end + end + + context "valid data" do + let(:entry) { TestDataBagItem.new("luggage", "bag") } + let(:object) do + { "raw_data" => { "id" => "bag" } } + end + it "validates the data bag item" do + expect(handler.verify_integrity(object, entry)).to be_nil + end + end + end +end diff --git a/spec/unit/client_spec.rb b/spec/unit/client_spec.rb index d348c24385..2aff7b2a71 100644 --- a/spec/unit/client_spec.rb +++ b/spec/unit/client_spec.rb @@ -38,12 +38,23 @@ describe Chef::Client do end it "runs ohai with only the minimum required plugins" do - expected_filter = %w{fqdn machinename hostname platform platform_version os os_version} + expected_filter = %w{fqdn machinename hostname platform platform_version ohai_time os os_version} expect(ohai_system).to receive(:all_plugins).with(expected_filter) client.run_ohai end end + context "when Ohai tells us to fail" do + it "fails" do + ohai_system = Ohai::System.new + module Ohai::Exceptions + class CriticalPluginFailure < Error; end + end + expect(ohai_system).to receive(:all_plugins) { raise Ohai::Exceptions::CriticalPluginFailure } + expect { client.run_ohai }.to raise_error(SystemExit) + end + end + describe "authentication protocol selection" do context "when FIPS is disabled" do before do diff --git a/spec/unit/knife/data_bag_create_spec.rb b/spec/unit/knife/data_bag_create_spec.rb index b7d185a58c..1f99fe74fe 100644 --- a/spec/unit/knife/data_bag_create_spec.rb +++ b/spec/unit/knife/data_bag_create_spec.rb @@ -72,6 +72,14 @@ describe Chef::Knife::DataBagCreate do expect { knife.run }.to exit_with_code(1) end + it "won't create a data bag with a reserved name for search" do + %w{node role client environment}.each do |name| + knife.name_args = [name] + expect(Chef::DataBag).to receive(:validate_name!).with(knife.name_args[0]).and_raise(Chef::Exceptions::InvalidDataBagName) + expect { knife.run }.to exit_with_code(1) + end + end + context "when given one argument" do before do knife.name_args = [bag_name] diff --git a/spec/unit/mixin/user_context_spec.rb b/spec/unit/mixin/user_context_spec.rb index f2119b6dbc..3dadf6a2c3 100644 --- a/spec/unit/mixin/user_context_spec.rb +++ b/spec/unit/mixin/user_context_spec.rb @@ -41,7 +41,6 @@ describe "a class that mixes in user_context" do before do allow(::Chef::Platform).to receive(:windows?).and_return(true) allow(::Chef::Util::Windows::LogonSession).to receive(:new).and_return(logon_session) - allow(instance_with_user_context).to receive(:node).and_return({ "platform_family" => "windows" }) end let(:logon_session) { instance_double("::Chef::Util::Windows::LogonSession", :set_user_context => nil, :open => nil, :close => nil) } @@ -99,7 +98,7 @@ describe "a class that mixes in user_context" do context "when not running on Windows" do before do - allow(instance_with_user_context).to receive(:node).and_return({ "platform_family" => "ubuntu" }) + allow(::Chef::Platform).to receive(:windows?).and_return(false) end it "raises a ::Chef::Exceptions::UnsupportedPlatform exception" do diff --git a/spec/unit/provider/package/apt_spec.rb b/spec/unit/provider/package/apt_spec.rb index 46ae7fcadc..ff14edcffd 100644 --- a/spec/unit/provider/package/apt_spec.rb +++ b/spec/unit/provider/package/apt_spec.rb @@ -475,6 +475,40 @@ mpg123 1.12.1-0ubuntu1 end end + describe "#action_install" do + it "should run dpkg to compare versions if an existing version is installed" do + allow(@provider).to receive(:get_current_versions).and_return("1.4.0") + allow(@new_resource).to receive(:allow_downgrade).and_return(false) + expect(@provider).to receive(:shell_out_compact_timeout).with( + "dpkg", "--compare-versions", "1.4.0", "gt", "0.8.12-7" + ).and_return(double(error?: false)) + @provider.run_action(:upgrade) + end + + it "should install the package if the installed version is older" do + allow(@provider).to receive(:get_current_versions).and_return("0.4.0") + allow(@new_resource).to receive(:allow_downgrade).and_return(false) + expect(@provider).to receive(:version_compare).and_return(-1) + expect(@provider).to receive(:shell_out!).with( + "apt-get", "-q", "-y", "install", "irssi=0.8.12-7", + :env => { "DEBIAN_FRONTEND" => "noninteractive" }, + :timeout => @timeout + ) + @provider.run_action(:upgrade) + end + + it "should not compare versions if an existing version is not installed" do + allow(@provider).to receive(:get_current_versions).and_return(nil) + allow(@new_resource).to receive(:allow_downgrade).and_return(false) + expect(@provider).not_to receive(:version_compare) + expect(@provider).to receive(:shell_out!).with( + "apt-get", "-q", "-y", "install", "irssi=0.8.12-7", + :env => { "DEBIAN_FRONTEND" => "noninteractive" }, + :timeout => @timeout + ) + @provider.run_action(:upgrade) + end + end end end end diff --git a/spec/unit/provider/package/chocolatey_spec.rb b/spec/unit/provider/package/chocolatey_spec.rb index 68b121960c..afc068041d 100644 --- a/spec/unit/provider/package/chocolatey_spec.rb +++ b/spec/unit/provider/package/chocolatey_spec.rb @@ -59,7 +59,9 @@ Git|2.6.2 munin-node|1.6.1.20130823 EOF remote_list_obj = double(stdout: remote_list_stdout) - allow(provider).to receive(:shell_out!).with("#{choco_exe} list -r #{package_names.join ' '}#{args}", { :returns => [0], timeout: timeout }).and_return(remote_list_obj) + package_names.each do |pkg| + allow(provider).to receive(:shell_out!).with("#{choco_exe} list -r #{pkg}#{args}", { :returns => [0], timeout: timeout }).and_return(remote_list_obj) + end end describe "#initialize" do diff --git a/spec/unit/provider/package/rubygems_spec.rb b/spec/unit/provider/package/rubygems_spec.rb index 856f8d460c..ac2b511ca9 100644 --- a/spec/unit/provider/package/rubygems_spec.rb +++ b/spec/unit/provider/package/rubygems_spec.rb @@ -383,6 +383,11 @@ describe Chef::Provider::Package::Rubygems do provider.load_current_resource expect(provider.target_version_already_installed?(provider.current_resource.version, new_resource.version)).to be_falsey end + + it "version_equals? should return false so that we can search for candidates" do + provider.load_current_resource + expect(provider.version_equals?(provider.current_resource.version, new_resource.version)).to be_falsey + end end describe "when new_resource version is an rspec version" do diff --git a/spec/unit/provider/package/zypper_spec.rb b/spec/unit/provider/package/zypper_spec.rb index b20a548c73..598fedc9fa 100644 --- a/spec/unit/provider/package/zypper_spec.rb +++ b/spec/unit/provider/package/zypper_spec.rb @@ -140,6 +140,14 @@ describe Chef::Provider::Package::Zypper do provider.install_package(["emacs"], ["1.0"]) end + it "setting the property should allow downgrade" do + new_resource.allow_downgrade true + shell_out_expectation!( + "zypper", "--non-interactive", "install", "--auto-agree-with-licenses", "--oldpackage", "emacs=1.0" + ) + provider.install_package(["emacs"], ["1.0"]) + end + it "should add user provided options to the command" do new_resource.options "--user-provided" shell_out_expectation!( diff --git a/spec/unit/provider/remote_file/network_file_spec.rb b/spec/unit/provider/remote_file/network_file_spec.rb index 621d2769a4..ecb326fc64 100644 --- a/spec/unit/provider/remote_file/network_file_spec.rb +++ b/spec/unit/provider/remote_file/network_file_spec.rb @@ -33,7 +33,7 @@ describe Chef::Provider::RemoteFile::NetworkFile do let(:source_file) { double("::File", :read => nil) } before do - allow(fetcher).to receive(:node).and_return({ "platform_family" => "windows" }) + allow(Chef::Platform).to receive(:windows?).and_return(true) end it "stages the local file to a temporary file" do diff --git a/spec/unit/provider/route_spec.rb b/spec/unit/provider/route_spec.rb index 5e655bda0c..ea6ddffb81 100644 --- a/spec/unit/provider/route_spec.rb +++ b/spec/unit/provider/route_spec.rb @@ -236,9 +236,11 @@ describe Chef::Provider::Route do @node.automatic_attrs[:platform] = platform route_file = StringIO.new + allow(File).to receive(:exist?).with("/etc/sysconfig/network").and_return(false) expect(File).to receive(:new).with("/etc/sysconfig/network", "w").and_return(route_file) @run_context.resource_collection << @default_resource @default_provider.generate_config + expect(route_file.string).to match(/GATEWAY=10\.0\.0\.9/) end end diff --git a/spec/unit/provider/windows_task_spec.rb b/spec/unit/provider/windows_task_spec.rb index b18d842bfa..55a1e77e4e 100644 --- a/spec/unit/provider/windows_task_spec.rb +++ b/spec/unit/provider/windows_task_spec.rb @@ -143,6 +143,17 @@ describe Chef::Provider::WindowsTask do provider.run_action(:create) expect(new_resource).to be_updated_by_last_action end + + it "updates the task XML if frequency is set as `:none`" do + new_resource.frequency :none + new_resource.random_delay "" + allow(provider).to receive(:task_need_update?).and_return(true) + allow(provider).to receive(:basic_validation).and_return(true) + allow(provider).to receive(:run_schtasks).and_return("CREATE", { "F" => "", "SC" => :once, "ST" => "00:00", "SD" => "12/12/2012", "TR" => nil, "RU" => "SYSTEM" }) + expect(provider).to receive(:update_task_xml) + provider.run_action(:create) + expect(new_resource).to be_updated_by_last_action + end end end @@ -507,6 +518,18 @@ describe Chef::Provider::WindowsTask do expect(provider).to receive(:run_schtasks).twice output = provider.send(:update_task_xml, ["random_delay"]) end + + it "updates the task XML if frequency is set as `:none`" do + new_resource.frequency :none + new_resource.random_delay "" + shell_out_obj = double("xml", :exitstatus => 0, :stdout => task_xml) + allow(provider).to receive(:powershell_out).and_return(shell_out_obj) + expect(::File).to receive(:delete) + expect(::File).to receive(:join) + expect(::File).to receive(:open) + expect(provider).to receive(:run_schtasks).twice + output = provider.send(:update_task_xml, ["random_delay"]) + end end describe "#load_task_hash" do @@ -541,5 +564,10 @@ describe Chef::Provider::WindowsTask do new_resource.frequency :once expect(provider.send(:frequency_modifier_allowed)).to be(false) end + + it "returns false for frequency :none" do + new_resource.frequency :none + expect(provider.send(:frequency_modifier_allowed)).to be(false) + end end end diff --git a/spec/unit/provider/zypper_repository_spec.rb b/spec/unit/provider/zypper_repository_spec.rb new file mode 100644 index 0000000000..a366a33e86 --- /dev/null +++ b/spec/unit/provider/zypper_repository_spec.rb @@ -0,0 +1,124 @@ +# +# Author:: Tim Smith (<tsmith@chef.io>) +# Copyright:: 2017, 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" + +# Output of the command: +# => rpm -qa gpg-pubkey* +RPM_KEYS = <<-EOF +gpg-pubkey-307e3d54-4be01a65 +gpg-pubkey-3dbdc284-53674dd4 +EOF + +# Output of the command: +# => gpg --with-fingerprint [FILE] +GPG_FINGER = <<-EOF +pub 2048R/3DBDC284 2011-08-19 [expires: 2024-06-14] + Key fingerprint = 573B FD6B 3D8F BC64 1079 A6AB ABF5 BD82 7BD9 BF62 +uid nginx signing key <signing-key@nginx.com> +EOF + +describe Chef::Provider::ZypperRepository do + let(:new_resource) { Chef::Resource::ZypperRepository.new("Nginx Repository") } + let(:provider) do + node = Chef::Node.new + events = Chef::EventDispatch::Dispatcher.new + run_context = Chef::RunContext.new(node, {}, events) + Chef::Provider::ZypperRepository.new(new_resource, run_context) + end + + let(:rpm_key_finger) do + double("shell_out_with_systems_locale", stdout: RPM_KEYS, exitstatus: 0, error?: false) + end + + let(:gpg_finger) do + double("shell_out_with_systems_locale", stdout: GPG_FINGER, exitstatus: 0, error?: false) + end + + it "responds to load_current_resource" do + expect(provider).to respond_to(:load_current_resource) + end + + describe "#action_create" do + it "skips key import if gpgautoimportkeys is false" do + new_resource.gpgautoimportkeys(false) + expect(provider).to receive(:declare_resource) + expect(Chef::Log).to receive(:debug) + provider.run_action(:create) + end + end + + describe "#escaped_repo_name" do + it "returns an escaped repo name" do + expect(provider.escaped_repo_name).to eq('Nginx\\ Repository') + end + end + + describe "#cookbook_name" do + it "returns 'test' when the cookbook property is set" do + new_resource.cookbook("test") + expect(provider.cookbook_name).to eq("test") + end + end + + describe "#key_type" do + it "returns :remote_file with an http URL" do + expect(provider.key_type("https://www.chef.io/key")).to eq(:remote_file) + end + + it "returns :cookbook_file with a chef managed file" do + expect(provider).to receive(:has_cookbook_file?).and_return(true) + expect(provider.key_type("/foo/nginx.key")).to eq(:cookbook_file) + end + + it "throws exception if an unknown file specified" do + expect(provider).to receive(:has_cookbook_file?).and_return(false) + expect { provider.key_type("/foo/nginx.key") }.to raise_error(Chef::Exceptions::FileNotFound) + end + end + + describe "#key_installed?" do + before do + expect(provider).to receive(:shell_out).with("rpm -qa gpg-pubkey*").and_return(rpm_key_finger) + end + + it "returns true if the key is installed" do + expect(provider).to receive(:key_fingerprint).and_return("3dbdc284") + expect(provider.key_installed?("/foo/nginx.key")).to be_truthy + end + + it "returns false if the key is not installed" do + expect(provider).to receive(:key_fingerprint).and_return("BOGUS") + expect(provider.key_installed?("/foo/nginx.key")).to be_falsey + end + end + + describe "#key_fingerprint" do + it "returns the key's fingerprint" do + expect(provider).to receive(:shell_out!).with("gpg --with-fingerprint /foo/nginx.key").and_return(gpg_finger) + expect(provider.key_fingerprint("/foo/nginx.key")).to eq("3dbdc284") + end + end + + describe "#install_gpg_key" do + it "skips installing the key if a nil value for key is passed" do + expect(Chef::Log).to receive(:debug) + provider.install_gpg_key(nil) + end + end +end diff --git a/spec/unit/provider_resolver_spec.rb b/spec/unit/provider_resolver_spec.rb index 1902fb5375..d1aaa6a8ea 100644 --- a/spec/unit/provider_resolver_spec.rb +++ b/spec/unit/provider_resolver_spec.rb @@ -708,18 +708,21 @@ describe Chef::ProviderResolver do "rhel" => { # service: [ Chef::Resource::SystemdService, Chef::Provider::Service::Systemd ], - package: [ Chef::Resource::YumPackage, Chef::Provider::Package::Yum ], + package: [ Chef::Resource::DnfPackage, Chef::Provider::Package::Dnf ], ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig::Redhat ], %w{amazon xcp xenserver ibm_powerkvm cloudlinux parallels} => { "3.1.4" => { + package: [ Chef::Resource::YumPackage, Chef::Provider::Package::Yum ], # service: [ Chef::Resource::RedhatService, Chef::Provider::Service::Redhat ], }, }, %w{redhat centos scientific oracle} => { "7.0" => { + package: [ Chef::Resource::YumPackage, Chef::Provider::Package::Yum ], }, "6.0" => { + package: [ Chef::Resource::YumPackage, Chef::Provider::Package::Yum ], # service: [ Chef::Resource::RedhatService, Chef::Provider::Service::Redhat ], }, }, diff --git a/spec/unit/resource/windows_task_spec.rb b/spec/unit/resource/windows_task_spec.rb index 2b3ee16024..cf4651cf52 100644 --- a/spec/unit/resource/windows_task_spec.rb +++ b/spec/unit/resource/windows_task_spec.rb @@ -102,8 +102,14 @@ describe Chef::Resource::WindowsTask do end context "#validate_start_time" do - it "raises error if start_time is nil" do - expect { resource.send(:validate_start_time, nil) }.to raise_error(Chef::Exceptions::ArgumentError, "`start_time` needs to be provided with `frequency :once`") + it "raises error if start_time is nil when frequency `:once`" do + resource.frequency :once + expect { resource.send(:validate_start_time, nil, :once) }.to raise_error(Chef::Exceptions::ArgumentError, "`start_time` needs to be provided with `frequency :once`") + end + + it "raises error if start_time is given when frequency `:none`" do + resource.frequency :none + expect { resource.send(:validate_start_time, "12.00", :none) }.to raise_error(Chef::Exceptions::ArgumentError, "`start_time` property is not supported with `frequency :none`") end end diff --git a/spec/unit/resource/zypper_repository_spec.rb b/spec/unit/resource/zypper_repository_spec.rb index 16951d071c..de08b183a5 100644 --- a/spec/unit/resource/zypper_repository_spec.rb +++ b/spec/unit/resource/zypper_repository_spec.rb @@ -46,20 +46,22 @@ describe Chef::Resource::ZypperRepository do expect { resource.action :delete }.to raise_error(ArgumentError) end - it "should resolve to a Noop class when zypper is not found" do - expect(Chef::Provider::ZypperRepository).to receive(:which).with("zypper").and_return(false) + it "resolves to a Noop class when on non-linux OS" do + node.automatic[:os] = "windows" + node.automatic[:platform_family] = "windows" expect(resource.provider_for_action(:add)).to be_a(Chef::Provider::Noop) end - it "should resolve to a ZypperRepository class when zypper is found" do - expect(Chef::Provider::ZypperRepository).to receive(:which).with("zypper").and_return(true) - expect(resource.provider_for_action(:add)).to be_a(Chef::Provider::ZypperRepository) + it "resolves to a Noop class when on non-suse linux" do + node.automatic[:os] = "linux" + node.automatic[:platform_family] = "debian" + expect(resource.provider_for_action(:add)).to be_a(Chef::Provider::Noop) end - end - context "on windows", :windows_only do - it "should resolve to a NoOp provider" do - expect(resource.provider_for_action(:add)).to be_a(Chef::Provider::Noop) + it "resolves to a ZypperRepository class when on a suse platform_family" do + node.automatic[:os] = "linux" + node.automatic[:platform_family] = "suse" + expect(resource.provider_for_action(:add)).to be_a(Chef::Provider::ZypperRepository) end end end diff --git a/spec/unit/util/dsc/lcm_output_parser_spec.rb b/spec/unit/util/dsc/lcm_output_parser_spec.rb index d59497de6f..65eaafe19c 100644 --- a/spec/unit/util/dsc/lcm_output_parser_spec.rb +++ b/spec/unit/util/dsc/lcm_output_parser_spec.rb @@ -19,20 +19,33 @@ require "chef/util/dsc/lcm_output_parser" describe Chef::Util::DSC::LocalConfigurationManager::Parser do - context "empty input parameter" do + context "empty input parameter for WhatIfParser" do it "raises an exception when there are no valid lines" do str = <<-EOF EOF - expect { Chef::Util::DSC::LocalConfigurationManager::Parser.parse(str) }.to raise_error(Chef::Exceptions::LCMParser) + expect { Chef::Util::DSC::LocalConfigurationManager::Parser.parse(str, false) }.to raise_error(Chef::Exceptions::LCMParser) end it "raises an exception for a nil input" do - expect { Chef::Util::DSC::LocalConfigurationManager::Parser.parse(nil) }.to raise_error(Chef::Exceptions::LCMParser) + expect { Chef::Util::DSC::LocalConfigurationManager::Parser.parse(nil, false) }.to raise_error(Chef::Exceptions::LCMParser) end end - context "correctly formatted output from lcm" do + context "empty input parameter for TestDSCParser" do + it "raises an exception when there are no valid lines" do + str = <<-EOF + + EOF + expect { Chef::Util::DSC::LocalConfigurationManager::Parser.parse(str, true) }.to raise_error(Chef::Exceptions::LCMParser) + end + + it "raises an exception for a nil input" do + expect { Chef::Util::DSC::LocalConfigurationManager::Parser.parse(nil, true) }.to raise_error(Chef::Exceptions::LCMParser) + end + end + + context "correctly formatted output from lcm for WhatIfParser" do it "returns a single resource when only 1 logged with the correct name" do str = <<EOF logtype: [machinename]: LCM: [ Start Set ] @@ -40,7 +53,7 @@ logtype: [machinename]: LCM: [ Start Resource ] [name] logtype: [machinename]: LCM: [ End Resource ] [name] logtype: [machinename]: LCM: [ End Set ] EOF - resources = Chef::Util::DSC::LocalConfigurationManager::Parser.parse(str) + resources = Chef::Util::DSC::LocalConfigurationManager::Parser.parse(str, false) expect(resources.length).to eq(1) expect(resources[0].name).to eq("[name]") end @@ -54,7 +67,7 @@ logtype: [machinename]: LCM: [ End Set ] [name] logtype: [machinename]: LCM: [ End Resource ] [name] logtype: [machinename]: LCM: [ End Set ] EOF - resources = Chef::Util::DSC::LocalConfigurationManager::Parser.parse(str) + resources = Chef::Util::DSC::LocalConfigurationManager::Parser.parse(str, false) expect(resources[0].changes_state?).to be_truthy end @@ -68,11 +81,11 @@ logtype: [machinename]: LCM: [ End Set ] [name] logtype: [machinename]: LCM: [ End Resource ] [name] logtype: [machinename]: LCM: [ End Set ] EOF - resources = Chef::Util::DSC::LocalConfigurationManager::Parser.parse(str) + resources = Chef::Util::DSC::LocalConfigurationManager::Parser.parse(str, false) expect(resources[0].change_log).to match_array(["[name]", "[message]", "[name]"]) end - it "should return false for changes_state?" do + it "returns false for changes_state?" do str = <<EOF logtype: [machinename]: LCM: [ Start Set ] logtype: [machinename]: LCM: [ Start Resource ] [name] @@ -80,11 +93,11 @@ logtype: [machinename]: LCM: [ Skip Set ] [name] logtype: [machinename]: LCM: [ End Resource ] [name] logtype: [machinename]: LCM: [ End Set ] EOF - resources = Chef::Util::DSC::LocalConfigurationManager::Parser.parse(str) + resources = Chef::Util::DSC::LocalConfigurationManager::Parser.parse(str, false) expect(resources[0].changes_state?).to be_falsey end - it "should return an empty array for change_log if changes_state? is false" do + it "returns an empty array for change_log if changes_state? is false" do str = <<EOF logtype: [machinename]: LCM: [ Start Set ] logtype: [machinename]: LCM: [ Start Resource ] [name] @@ -92,13 +105,64 @@ logtype: [machinename]: LCM: [ Skip Set ] [name] logtype: [machinename]: LCM: [ End Resource ] [name] logtype: [machinename]: LCM: [ End Set ] EOF - resources = Chef::Util::DSC::LocalConfigurationManager::Parser.parse(str) + resources = Chef::Util::DSC::LocalConfigurationManager::Parser.parse(str, false) expect(resources[0].change_log).to be_empty end end - context "Incorrectly formatted output from LCM" do - it "should allow missing a [End Resource] when its the last one and still find all the resource" do + context "correctly formatted output from lcm for TestDSCParser" do + it "returns a single resource when only 1 logged with the correct name" do + str = <<EOF +InDesiredState : False +ResourcesInDesiredState : +ResourcesNotInDesiredState: [name] +ReturnValue : 0 +PSComputerName : . +EOF + resources = Chef::Util::DSC::LocalConfigurationManager::Parser.parse(str, true) + expect(resources.length).to eq(1) + expect(resources[0].name).to eq("[name]") + end + + it "identifies when a resource changes the state of the system" do + str = <<EOF +InDesiredState : False +ResourcesInDesiredState : +ResourcesNotInDesiredState: [name] +ReturnValue : 0 +PSComputerName : . +EOF + resources = Chef::Util::DSC::LocalConfigurationManager::Parser.parse(str, true) + expect(resources[0].changes_state?).to be_truthy + end + + it "returns false for changes_state?" do + str = <<EOF +InDesiredState : True +ResourcesInDesiredState : [name] +ResourcesNotInDesiredState: +ReturnValue : 0 +PSComputerName : . +EOF + resources = Chef::Util::DSC::LocalConfigurationManager::Parser.parse(str, true) + expect(resources[0].changes_state?).to be_falsey + end + + it "returns an empty array for change_log if changes_state? is false" do + str = <<EOF +InDesiredState : True +ResourcesInDesiredState : [name] +ResourcesNotInDesiredState: +ReturnValue : 0 +PSComputerName : . +EOF + resources = Chef::Util::DSC::LocalConfigurationManager::Parser.parse(str, true) + expect(resources[0].change_log).to be_empty + end + end + + context "Incorrectly formatted output from LCM for WhatIfParser" do + it "allows missing [End Resource] when its the last one and still find all the resource" do str = <<-EOF logtype: [machinename]: LCM: [ Start Set ] logtype: [machinename]: LCM: [ Start Resource ] [name] @@ -114,12 +178,12 @@ logtype: [machinename]: LCM: [ End Set ] logtype: [machinename]: LCM: [ End Set ] EOF - resources = Chef::Util::DSC::LocalConfigurationManager::Parser.parse(str) + resources = Chef::Util::DSC::LocalConfigurationManager::Parser.parse(str, false) expect(resources[0].changes_state?).to be_falsey expect(resources[1].changes_state?).to be_truthy end - it "should allow missing a [End Resource] when its the first one and still find all the resource" do + it "allow missing [End Resource] when its the first one and still find all the resource" do str = <<-EOF logtype: [machinename]: LCM: [ Start Set ] logtype: [machinename]: LCM: [ Start Resource ] [name] @@ -135,12 +199,12 @@ logtype: [machinename]: LCM: [ End Resource ] logtype: [machinename]: LCM: [ End Set ] EOF - resources = Chef::Util::DSC::LocalConfigurationManager::Parser.parse(str) + resources = Chef::Util::DSC::LocalConfigurationManager::Parser.parse(str, false) expect(resources[0].changes_state?).to be_falsey expect(resources[1].changes_state?).to be_truthy end - it "should allow missing set and end resource and assume an unconverged resource in this case" do + it "allows missing set and end resource and assume an unconverged resource in this case" do str = <<-EOF logtype: [machinename]: LCM: [ Start Set ] logtype: [machinename]: LCM: [ Start Resource ] [name] @@ -154,11 +218,31 @@ logtype: [machinename]: LCM: [ End Set ] logtype: [machinename]: LCM: [ End Resource ] logtype: [machinename]: LCM: [ End Set ] EOF - resources = Chef::Util::DSC::LocalConfigurationManager::Parser.parse(str) + resources = Chef::Util::DSC::LocalConfigurationManager::Parser.parse(str, false) expect(resources[0].changes_state?).to be_truthy expect(resources[0].name).to eql("[name]") expect(resources[1].changes_state?).to be_truthy expect(resources[1].name).to eql("[name2]") end end + + context "Incorrectly formatted output from LCM for TestDSCParser" do + it "allows missing [End Resource] when its the last one and still find all the resource" do + str = <<EOF +InDesiredState : True +ResourcesInDesiredState : +ResourcesNotInDesiredState: [name] +ReturnValue : 0 +PSComputerName : . +InDesiredState : True +ResourcesInDesiredState : +ResourcesNotInDesiredState: [name2] +ReturnValue : 0 +PSComputerName : . +EOF + + resources = Chef::Util::DSC::LocalConfigurationManager::Parser.parse(str, true) + expect(resources[0].changes_state?).to be_falsey + end + end end diff --git a/spec/unit/util/dsc/local_configuration_manager_spec.rb b/spec/unit/util/dsc/local_configuration_manager_spec.rb index c87b446286..4c33fc8616 100644 --- a/spec/unit/util/dsc/local_configuration_manager_spec.rb +++ b/spec/unit/util/dsc/local_configuration_manager_spec.rb @@ -57,6 +57,7 @@ EOH context "when interacting with the LCM using a PowerShell cmdlet" do before(:each) do allow(lcm).to receive(:run_configuration_cmdlet).and_return(lcm_status) + allow(lcm).to receive(:ps_version_gte_5?).and_return(false) end context "that returns successfully" do let(:lcm_standard_output) { normal_lcm_output } @@ -103,7 +104,7 @@ EOH let(:common_command_prefix) { "$ProgressPreference = 'SilentlyContinue';" } let(:ps4_base_command) { "#{common_command_prefix} Start-DscConfiguration -path tmp -wait -erroraction 'stop' -force" } let(:lcm_command_ps4) { ps4_base_command + " -whatif; if (! $?) { exit 1 }" } - let(:lcm_command_ps5) { "#{common_command_prefix} Test-DscConfiguration -path tmp" } + let(:lcm_command_ps5) { "#{common_command_prefix} Test-DscConfiguration -path tmp | format-list" } let(:lcm_standard_output) { normal_lcm_output } let(:lcm_standard_error) { nil } let(:lcm_cmdlet_success) { true } |