summaryrefslogtreecommitdiff
path: root/spec/functional/resource
diff options
context:
space:
mode:
Diffstat (limited to 'spec/functional/resource')
-rw-r--r--spec/functional/resource/apt_package_spec.rb (renamed from spec/functional/resource/package_spec.rb)10
-rw-r--r--spec/functional/resource/bash_spec.rb60
-rw-r--r--spec/functional/resource/batch_spec.rb6
-rw-r--r--spec/functional/resource/bff_spec.rb6
-rw-r--r--spec/functional/resource/chocolatey_package_spec.rb14
-rw-r--r--spec/functional/resource/cron_spec.rb13
-rw-r--r--spec/functional/resource/deploy_revision_spec.rb881
-rw-r--r--spec/functional/resource/dnf_package_spec.rb686
-rw-r--r--spec/functional/resource/dpkg_package_spec.rb4
-rw-r--r--spec/functional/resource/dsc_resource_spec.rb10
-rw-r--r--spec/functional/resource/dsc_script_spec.rb57
-rwxr-xr-xspec/functional/resource/env_spec.rb192
-rw-r--r--spec/functional/resource/execute_spec.rb29
-rw-r--r--spec/functional/resource/group_spec.rb71
-rw-r--r--spec/functional/resource/ifconfig_spec.rb9
-rw-r--r--spec/functional/resource/link_spec.rb132
-rw-r--r--spec/functional/resource/mount_spec.rb10
-rw-r--r--spec/functional/resource/msu_package_spec.rb84
-rw-r--r--spec/functional/resource/ohai_spec.rb12
-rw-r--r--spec/functional/resource/powershell_script_spec.rb2
-rw-r--r--spec/functional/resource/reboot_spec.rb4
-rw-r--r--spec/functional/resource/registry_spec.rb138
-rw-r--r--spec/functional/resource/remote_file_spec.rb200
-rw-r--r--spec/functional/resource/rpm_spec.rb17
-rw-r--r--spec/functional/resource/template_spec.rb39
-rw-r--r--spec/functional/resource/user/dscl_spec.rb12
-rw-r--r--spec/functional/resource/user/useradd_spec.rb75
-rw-r--r--spec/functional/resource/user/windows_spec.rb4
-rw-r--r--spec/functional/resource/windows_env_spec.rb285
-rw-r--r--spec/functional/resource/windows_path_spec.rb64
-rw-r--r--spec/functional/resource/windows_service_spec.rb30
-rw-r--r--spec/functional/resource/windows_task_spec.rb1454
-rw-r--r--spec/functional/resource/yum_package_spec.rb957
33 files changed, 4240 insertions, 1327 deletions
diff --git a/spec/functional/resource/package_spec.rb b/spec/functional/resource/apt_package_spec.rb
index 6dc55f7f01..c032bafc92 100644
--- a/spec/functional/resource/package_spec.rb
+++ b/spec/functional/resource/apt_package_spec.rb
@@ -1,7 +1,7 @@
# encoding: UTF-8
#
# Author:: Daniel DeLeo (<dan@chef.io>)
-# Copyright:: Copyright 2013-2016, Chef Software, Inc.
+# Copyright:: Copyright 2013-2018, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -23,7 +23,7 @@ require "webrick"
module AptServer
def enable_testing_apt_source
File.open("/etc/apt/sources.list.d/chef-integration-test.list", "w+") do |f|
- f.puts "deb http://localhost:9000/ sid main"
+ f.puts "deb [trusted=yes] http://localhost:9000/ sid main"
end
# Magic to update apt cache for only our repo
shell_out!("apt-get update " +
@@ -92,7 +92,7 @@ metadata = { :unix_only => true,
:arch => "x86_64" # test packages are 64bit
}
-describe Chef::Resource::Package, metadata do
+describe Chef::Resource::AptPackage, metadata do
include Chef::Mixin::ShellOut
context "with a remote package source" do
@@ -143,7 +143,7 @@ describe Chef::Resource::Package, metadata do
end
def base_resource
- r = Chef::Resource::Package.new("chef-integration-test", run_context)
+ r = Chef::Resource::AptPackage.new("chef-integration-test", run_context)
# The apt repository in the spec data is not gpg signed, so we need to
# force apt to accept the package:
r.options("--force-yes")
@@ -260,7 +260,7 @@ describe Chef::Resource::Package, metadata do
end
before do
- node.set[:preseed_value] = "FROM TEMPLATE"
+ node.normal[:preseed_value] = "FROM TEMPLATE"
end
it "preseeds the package, then installs it" do
diff --git a/spec/functional/resource/bash_spec.rb b/spec/functional/resource/bash_spec.rb
index 87211ec264..4a5fee64bc 100644
--- a/spec/functional/resource/bash_spec.rb
+++ b/spec/functional/resource/bash_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Serdar Sutay (<serdar@chef.io>)
-# Copyright:: Copyright 2014-2016, Chef Software Inc.
+# Copyright:: Copyright 2014-2017, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -21,61 +21,27 @@ require "functional/resource/base"
describe Chef::Resource::Bash, :unix_only do
let(:code) { "echo hello" }
- let(:resource) {
+ let(:resource) do
resource = Chef::Resource::Bash.new("foo_resource", run_context)
- resource.code(code)
+ resource.code(code) unless code.nil?
resource
- }
+ end
describe "when setting the command attribute" do
let (:command) { "wizard racket" }
- # in Chef-12 the `command` attribute is largely useless, but does set the identity attribute
- # so that notifications need to target the value of the command. it will not run the `command`
- # and if it is given without a code block then it does nothing and always succeeds.
- describe "in Chef-12", chef: "< 13" do
- it "gets the commmand attribute from the name" do
- expect(resource.command).to eql("foo_resource")
- end
-
- it "sets the resource identity to the command name" do
- resource.command command
- expect(resource.identity).to eql(command)
- end
-
- it "warns when the code is not present and a useless `command` is present" do
- expect(Chef::Log).to receive(:warn).with(/coding error/)
- expect(Chef::Log).to receive(:warn).with(/deprecated/)
- resource.code nil
- resource.command command
- expect { resource.run_action(:run) }.not_to raise_error
- end
-
- describe "when the code is not present" do
- let(:code) { nil }
- it "warns" do
- expect(Chef::Log).to receive(:warn)
- expect { resource.run_action(:run) }.not_to raise_error
- end
- end
+ it "should raise an exception when trying to set the command" do
+ expect { resource.command command }.to raise_error(Chef::Exceptions::Script)
end
- # in Chef-13 the `command` attribute needs to be for internal use only
- describe "in Chef-13", chef: ">= 13" do
- it "should raise an exception when trying to set the command" do
- expect { resource.command command }.to raise_error # FIXME: add a real error in Chef-13
- end
-
- it "should initialize the command to nil" do
- expect(resource.command).to be_nil
- end
+ it "should initialize the command to nil" do
+ expect(resource.command).to be_nil
+ end
- describe "when the code is not present" do
- let(:code) { nil }
- it "raises an exception" do
- expect { resource.run_action(:run) }.to raise_error # FIXME: add a real error in Chef-13
- expect { resource.run_action(:run) }.not_to raise_error
- end
+ describe "when the code is not present" do
+ let(:code) { nil }
+ it "raises an exception" do
+ expect { resource.run_action(:run) }.to raise_error(Chef::Exceptions::ValidationFailed)
end
end
end
diff --git a/spec/functional/resource/batch_spec.rb b/spec/functional/resource/batch_spec.rb
index e4fc6420c7..2b176ed06c 100644
--- a/spec/functional/resource/batch_spec.rb
+++ b/spec/functional/resource/batch_spec.rb
@@ -23,7 +23,11 @@ describe Chef::Resource::WindowsScript::Batch, :windows_only do
let(:output_command) { " > " }
- let (:architecture_command) { "@echo %PROCESSOR_ARCHITECTURE%" }
+ let(:architecture_command) { "@echo %PROCESSOR_ARCHITECTURE%" }
+
+ let(:resource) do
+ Chef::Resource::WindowsScript::Batch.new("Batch resource functional test", @run_context)
+ end
it_behaves_like "a Windows script running on Windows"
diff --git a/spec/functional/resource/bff_spec.rb b/spec/functional/resource/bff_spec.rb
index e7f7540e5a..0b45e097af 100644
--- a/spec/functional/resource/bff_spec.rb
+++ b/spec/functional/resource/bff_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Prabhu Das (<prabhu.das@clogeny.com>)
-# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# Copyright:: Copyright 2013-2017, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -62,7 +62,7 @@ describe Chef::Resource::BffPackage, :requires_root, :external => ohai[:platform
context "package install action with options" do
it "should install a package" do
- new_resource.options("-e/tmp/installp.log")
+ new_resource.options("-e#{Dir.tmpdir}/installp.log")
new_resource.run_action(:install)
bff_pkg_should_be_installed(new_resource)
end
@@ -108,7 +108,7 @@ describe Chef::Resource::BffPackage, :requires_root, :external => ohai[:platform
end
it "should remove an installed package" do
- new_resource.options("-e/tmp/installp.log")
+ new_resource.options("-e#{Dir.tmpdir}/installp.log")
new_resource.run_action(:remove)
bff_pkg_should_be_removed(new_resource)
end
diff --git a/spec/functional/resource/chocolatey_package_spec.rb b/spec/functional/resource/chocolatey_package_spec.rb
index fb51fd2d64..e8dae581b9 100644
--- a/spec/functional/resource/chocolatey_package_spec.rb
+++ b/spec/functional/resource/chocolatey_package_spec.rb
@@ -18,16 +18,9 @@
require "spec_helper"
require "chef/mixin/powershell_out"
-describe Chef::Resource::ChocolateyPackage, :windows_only do
+describe Chef::Resource::ChocolateyPackage, :windows_only, :choco_installed do
include Chef::Mixin::PowershellOut
- before(:all) do
- powershell_out!("iex ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1'))")
- unless ENV["PATH"] =~ /chocolatey\\bin/
- ENV["PATH"] = "C:\\ProgramData\\chocolatey\\bin;#{ENV["PATH"]}"
- end
- end
-
let(:package_name) { "test-A" }
let(:package_list) { proc { powershell_out!("choco list -lo -r #{Array(package_name).join(' ')}").stdout.chomp } }
let(:package_source) { File.join(CHEF_SPEC_ASSETS, "chocolatey_feed") }
@@ -82,11 +75,6 @@ describe Chef::Resource::ChocolateyPackage, :windows_only do
subject.package_name "blah"
expect { subject.run_action(:install) }.to raise_error Chef::Exceptions::Package
end
-
- it "raises if package version is not found" do
- subject.version "3.0"
- expect { subject.run_action(:install) }.to raise_error Chef::Exceptions::Package
- end
end
context "upgrading a package" do
diff --git a/spec/functional/resource/cron_spec.rb b/spec/functional/resource/cron_spec.rb
index 3380eccb0d..1bff8bf874 100644
--- a/spec/functional/resource/cron_spec.rb
+++ b/spec/functional/resource/cron_spec.rb
@@ -1,7 +1,7 @@
# encoding: UTF-8
#
# Author:: Kaustubh Deorukhkar (<kaustubh@clogeny.com>)
-# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# Copyright:: Copyright 2013-2017, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -120,7 +120,7 @@ describe Chef::Resource::Cron, :requires_root, :unix_only do
return if %w{aix solaris}.include?(ohai[:platform])
# Test if the attribute exists on newly created cron
cron_should_exists(cron_name, "")
- expect(shell_out("crontab -l -u #{new_resource.user} | grep \"#{attribute.upcase}=#{value}\"").exitstatus).to eq(0)
+ expect(shell_out("crontab -l -u #{new_resource.user} | grep '#{attribute.upcase}=\"#{value}\"'").exitstatus).to eq(0)
end
after do
@@ -146,6 +146,13 @@ describe Chef::Resource::Cron, :requires_root, :unix_only do
new_resource.home "/home/opscode"
create_and_validate_with_attribute(new_resource, "home", "/home/opscode")
end
+
+ %i{ home mailto path shell }.each do |attr|
+ it "supports an empty string for #{attr} attribute" do
+ new_resource.send(attr, "")
+ create_and_validate_with_attribute(new_resource, attr.to_s, "")
+ end
+ end
end
describe "negative tests for create action" do
@@ -154,7 +161,7 @@ describe Chef::Resource::Cron, :requires_root, :unix_only do
end
def cron_create_should_raise_exception
- expect { new_resource.run_action(:create) }.to raise_error(Chef::Exceptions::Cron, /Error updating state of #{new_resource.name}, exit: 1/)
+ expect { new_resource.run_action(:create) }.to raise_error(Chef::Exceptions::Cron)
cron_should_not_exists(new_resource.name)
end
diff --git a/spec/functional/resource/deploy_revision_spec.rb b/spec/functional/resource/deploy_revision_spec.rb
deleted file mode 100644
index 72eaea3c12..0000000000
--- a/spec/functional/resource/deploy_revision_spec.rb
+++ /dev/null
@@ -1,881 +0,0 @@
-#
-# Author:: Daniel DeLeo (<dan@chef.io>)
-# Copyright:: Copyright 2012-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 "tmpdir"
-
-# Deploy relies heavily on symlinks, so it doesn't work on windows.
-describe Chef::Resource::DeployRevision, :unix_only => true, :requires_git => true do
-
- let(:file_cache_path) { Dir.mktmpdir }
- let(:deploy_directory) { Dir.mktmpdir }
-
- # By making restart or other operations write to this file, we can externally
- # track the order in which those operations happened.
- let(:observe_order_file) { Tempfile.new("deploy-resource-observe-operations") }
-
- before do
- Chef::Log.level = :info
- @old_file_cache_path = Chef::Config[:file_cache_path]
- Chef::Config[:file_cache_path] = file_cache_path
- end
-
- after do
- Chef::Config[:file_cache_path] = @old_file_cache_path
- FileUtils.remove_entry_secure deploy_directory if File.exist?(deploy_directory)
- FileUtils.remove_entry_secure file_cache_path
- observe_order_file.close
- FileUtils.remove_entry_secure observe_order_file.path
- end
-
- before(:all) do
- @ohai = Ohai::System.new
- @ohai.all_plugins(%w{platform os})
- end
-
- let(:node) do
- Chef::Node.new.tap do |n|
- n.name "rspec-test"
- n.consume_external_attrs(@ohai.data, {})
- end
- end
-
- let(:event_dispatch) { Chef::EventDispatch::Dispatcher.new }
- let(:run_context) { Chef::RunContext.new(node, {}, event_dispatch) }
-
- # These tests use git's bundle feature, which is a way to export an entire
- # git repo (or subset of commits) as a single file.
- #
- # Generally you can treat a git bundle as a regular git remote.
- #
- # See also: http://git-scm.com/2010/03/10/bundles.html
- let(:git_bundle_repo) { File.expand_path("git_bundles/sinatra-test-app.gitbundle", CHEF_SPEC_DATA) }
-
- let(:git_bundle_with_in_repo_callbacks) { File.expand_path("git_bundles/sinatra-test-app-with-callback-files.gitbundle", CHEF_SPEC_DATA) }
-
- let(:git_bundle_with_in_repo_symlinks) { File.expand_path("git_bundles/sinatra-test-app-with-symlinks.gitbundle", CHEF_SPEC_DATA) }
-
- # This is the fourth version
- let(:latest_rev) { "3eb5ca6c353c83d9179dd3b29347539829b401f3" }
-
- # This is the third version
- let(:previous_rev) { "6d19a6dbecc8e37f5b2277345885c0c783eb8fb1" }
-
- # This is the second version
- let(:second_rev) { "0827e1b0e5043608ac0a824da5c558e252154ad0" }
-
- # This is the sixth version, it is on the "with-deploy-scripts" branch
- let(:rev_with_in_repo_callbacks) { "2404d015882659754bdb93ad6e4b4d3d02691a82" }
-
- # This is the fifth version in the "with-symlinks" branch
- let(:rev_with_in_repo_symlinks) { "5a4748c52aaea8250b4346a9b8ede95ee3755e28" }
-
- # Read values from the +observe_order_file+ and split each line. This way you
- # can see in which order things really happened.
- def actual_operations_order
- IO.read(observe_order_file.path).split("\n").map(&:strip)
- end
-
- # 1. touch `restart.txt` in cwd so we know that the command is run with the
- # right cwd.
- # 2. Append +tag+ to the `observe_order_file` so we can check the order in
- # which operations happen later in the test.
- def shell_restart_command(tag)
- "touch restart.txt && echo '#{tag}' >> #{observe_order_file.path}"
- end
-
- let(:basic_deploy_resource) do
- Chef::Resource::DeployRevision.new(deploy_directory, run_context).tap do |r|
- r.name "deploy-revision-unit-test"
- r.repo git_bundle_repo
- r.symlink_before_migrate({})
- r.symlinks({})
- end
- end
-
- let(:deploy_to_latest_rev) do
- basic_deploy_resource.dup.tap do |r|
- r.revision(latest_rev)
- r.restart_command shell_restart_command(:deploy_to_latest_rev)
- end
- end
-
- let(:deploy_to_previous_rev) do
- basic_deploy_resource.dup.tap do |r|
- r.revision(previous_rev)
- r.restart_command shell_restart_command(:deploy_to_previous_rev)
- end
- end
-
- let(:deploy_to_latest_rev_again) do
- basic_deploy_resource.dup.tap do |r|
- r.revision(latest_rev)
- r.restart_command shell_restart_command(:deploy_to_latest_rev_again)
- end
- end
-
- let(:deploy_to_previous_rev_again) do
- basic_deploy_resource.dup.tap do |r|
- r.revision(previous_rev)
- r.restart_command shell_restart_command(:deploy_to_previous_rev_again)
- end
- end
-
- let(:deploy_to_second_rev) do
- basic_deploy_resource.dup.tap do |r|
- r.revision(second_rev)
- r.restart_command shell_restart_command(:deploy_to_second_rev)
- end
- end
-
- let(:deploy_to_second_rev_again) do
- basic_deploy_resource.dup.tap do |r|
- r.revision(second_rev)
- r.restart_command shell_restart_command(:deploy_to_second_rev_again)
- end
- end
-
- let(:deploy_to_second_rev_again_again) do
- basic_deploy_resource.dup.tap do |r|
- r.revision(second_rev)
- r.restart_command shell_restart_command(:deploy_to_second_rev_again_again)
- end
- end
-
- # Computes the full path for +path+ relative to the deploy directory
- def rel_path(path)
- File.expand_path(path, deploy_directory)
- end
-
- def actual_current_rev
- Dir.chdir(rel_path("current")) do
- `git rev-parse HEAD`.strip
- end
- end
-
- def self.the_app_is_deployed_at_revision(target_rev_spec)
- it "deploys the app to the target revision (#{target_rev_spec})" do
- target_rev = send(target_rev_spec)
-
- expect(File).to exist(rel_path("current"))
-
- expect(actual_current_rev).to eq(target_rev)
-
- # Is the app code actually there?
- expect(File).to exist(rel_path("current/app/app.rb"))
- end
- end
-
- context "when deploying a simple app" do
- describe "for the first time, with the required directory layout precreated" do
- before do
- FileUtils.mkdir_p(rel_path("releases"))
- FileUtils.mkdir_p(rel_path("shared"))
- deploy_to_latest_rev.run_action(:deploy)
- end
-
- the_app_is_deployed_at_revision(:latest_rev)
-
- it "restarts the application" do
- expect(File).to exist(rel_path("current/restart.txt"))
- expect(actual_operations_order).to eq(%w{deploy_to_latest_rev})
- end
-
- it "is marked as updated" do
- expect(deploy_to_latest_rev).to be_updated_by_last_action
- end
- end
-
- describe "back to a previously deployed revision, with the directory structure precreated" do
- before do
- FileUtils.mkdir_p(rel_path("releases"))
- FileUtils.mkdir_p(rel_path("shared"))
-
- deploy_to_latest_rev.run_action(:deploy)
- deploy_to_previous_rev.run_action(:deploy)
- deploy_to_latest_rev_again.run_action(:deploy)
- end
-
- the_app_is_deployed_at_revision(:latest_rev)
-
- it "restarts the application after rolling back" do
- expect(actual_operations_order).to eq(%w{deploy_to_latest_rev deploy_to_previous_rev deploy_to_latest_rev_again})
- end
-
- it "is marked updated" do
- expect(deploy_to_latest_rev_again).to be_updated_by_last_action
- end
-
- it "deploys the right code" do
- expect(IO.read(rel_path("current/app/app.rb"))).to include("this is the fourth version of the app")
- end
- end
-
- describe "for the first time, with no existing directory layout" do
- before do
- deploy_to_latest_rev.run_action(:deploy)
- end
-
- it "creates the required directory tree" do
- expect(File).to be_directory(rel_path("releases"))
- expect(File).to be_directory(rel_path("shared"))
- expect(File).to be_directory(rel_path("releases/#{latest_rev}"))
-
- expect(File).to be_directory(rel_path("current/tmp"))
- expect(File).to be_directory(rel_path("current/config"))
- expect(File).to be_directory(rel_path("current/public"))
-
- expect(File).to be_symlink(rel_path("current"))
- expect(File.readlink(rel_path("current"))).to eq(rel_path("releases/#{latest_rev}"))
- end
-
- the_app_is_deployed_at_revision(:latest_rev)
-
- it "restarts the application" do
- expect(File).to exist(rel_path("current/restart.txt"))
- expect(actual_operations_order).to eq(%w{deploy_to_latest_rev})
- end
-
- it "is marked as updated" do
- expect(deploy_to_latest_rev).to be_updated_by_last_action
- end
- end
-
- describe "again to the current revision" do
- before do
- deploy_to_latest_rev.run_action(:deploy)
- deploy_to_latest_rev.run_action(:deploy)
- end
-
- the_app_is_deployed_at_revision(:latest_rev)
-
- it "does not restart the app" do
- expect(actual_operations_order).to eq(%w{deploy_to_latest_rev})
- end
-
- it "is not marked updated" do
- expect(deploy_to_latest_rev).not_to be_updated_by_last_action
- end
-
- end
-
- describe "again with force_deploy" do
- before do
- deploy_to_latest_rev.run_action(:force_deploy)
- deploy_to_latest_rev_again.run_action(:force_deploy)
- end
-
- the_app_is_deployed_at_revision(:latest_rev)
-
- it "restarts the app" do
- expect(actual_operations_order).to eq(%w{deploy_to_latest_rev deploy_to_latest_rev_again})
- end
-
- it "is marked updated" do
- expect(deploy_to_latest_rev).to be_updated_by_last_action
- end
-
- end
-
- describe "again to a new revision" do
- before do
- deploy_to_previous_rev.run_action(:deploy)
- deploy_to_latest_rev.run_action(:deploy)
- end
-
- the_app_is_deployed_at_revision(:latest_rev)
-
- it "restarts the application after the new deploy" do
- expect(actual_operations_order).to eq(%w{deploy_to_previous_rev deploy_to_latest_rev})
- end
-
- it "is marked updated" do
- expect(deploy_to_previous_rev).to be_updated_by_last_action
- end
-
- it "leaves the old copy of the app around for rollback" do
- expect(File).to exist(File.join(deploy_directory, "releases", previous_rev))
- end
-
- end
-
- describe "back to a previously deployed revision (implicit rollback)" do
- before do
- deploy_to_latest_rev.run_action(:deploy)
- deploy_to_previous_rev.run_action(:deploy)
- deploy_to_latest_rev_again.run_action(:deploy)
- end
-
- the_app_is_deployed_at_revision(:latest_rev)
-
- it "restarts the application after rolling back" do
- expect(actual_operations_order).to eq(%w{deploy_to_latest_rev deploy_to_previous_rev deploy_to_latest_rev_again})
- end
-
- it "is marked updated" do
- expect(deploy_to_latest_rev_again).to be_updated_by_last_action
- end
-
- it "deploys the right code" do
- expect(IO.read(rel_path("current/app/app.rb"))).to include("this is the fourth version of the app")
- end
- end
-
- describe "back to a previously deployed revision where resource rev == latest revision (explicit rollback)" do
- before do
- deploy_to_previous_rev.run_action(:deploy)
- @previous_rev_all_releases = deploy_to_previous_rev.provider_for_action(:deploy).all_releases
- deploy_to_latest_rev.run_action(:deploy)
- @latest_rev_all_releases = deploy_to_latest_rev.provider_for_action(:deploy).all_releases
- deploy_to_latest_rev_again.run_action(:rollback)
- @previous_rev_again_all_releases = deploy_to_latest_rev_again.provider_for_action(:deploy).all_releases
- end
-
- the_app_is_deployed_at_revision(:previous_rev)
-
- it "restarts the application after rolling back" do
- expect(actual_operations_order).to eq(%w{deploy_to_previous_rev deploy_to_latest_rev deploy_to_latest_rev_again})
- end
-
- it "is marked updated" do
- expect(deploy_to_latest_rev_again).to be_updated_by_last_action
- end
-
- it "deploys the right code" do
- expect(IO.read(rel_path("current/app/app.rb"))).to include("this is the third version of the app")
- end
-
- it "all_releases after first deploy should have one entry" do
- expect(@previous_rev_all_releases.length).to eq(1)
- end
-
- it "all_releases after second deploy should have two entries" do
- expect(@latest_rev_all_releases.length).to eq(2)
- end
-
- it "all_releases after rollback should have one entry" do
- expect(@previous_rev_again_all_releases.length).to eq(1)
- end
-
- it "all_releases after rollback should be the same as after the first deploy" do
- expect(@previous_rev_again_all_releases).to eq(@previous_rev_all_releases)
- end
-
- end
-
- describe "back to a previously deployed revision where resource rev == previous revision (explicit rollback)" do
- before do
- deploy_to_previous_rev.run_action(:deploy)
- @previous_rev_all_releases = deploy_to_previous_rev.provider_for_action(:deploy).all_releases
- deploy_to_latest_rev.run_action(:deploy)
- @latest_rev_all_releases = deploy_to_latest_rev.provider_for_action(:deploy).all_releases
- deploy_to_previous_rev_again.run_action(:rollback)
- # FIXME: only difference with previous test is using latest_rev_again insetad of previous_rev_again
- @previous_rev_again_all_releases = deploy_to_latest_rev_again.provider_for_action(:deploy).all_releases
- end
-
- the_app_is_deployed_at_revision(:previous_rev)
-
- it "restarts the application after rolling back" do
- expect(actual_operations_order).to eq(%w{deploy_to_previous_rev deploy_to_latest_rev deploy_to_previous_rev_again})
- end
-
- it "is marked updated" do
- expect(deploy_to_previous_rev_again).to be_updated_by_last_action
- end
-
- it "deploys the right code" do
- expect(IO.read(rel_path("current/app/app.rb"))).to include("this is the third version of the app")
- end
-
- it "all_releases after first deploy should have one entry" do
- expect(@previous_rev_all_releases.length).to eq(1)
- end
-
- it "all_releases after second deploy should have two entries" do
- expect(@latest_rev_all_releases.length).to eq(2)
- end
-
- it "all_releases after rollback should have one entry" do
- expect(@previous_rev_again_all_releases.length).to eq(1)
- end
-
- it "all_releases after rollback should be the same as after the first deploy" do
- expect(@previous_rev_again_all_releases).to eq(@previous_rev_all_releases)
- end
- end
-
- describe "back to a previously deployed revision where resource rev == latest revision (explicit rollback)" do
- before do
- deploy_to_second_rev.run_action(:deploy)
- @first_deploy_all_releases = deploy_to_second_rev.provider_for_action(:deploy).all_releases
- deploy_to_previous_rev.run_action(:deploy)
- @second_deploy_all_releases = deploy_to_previous_rev.provider_for_action(:deploy).all_releases
- deploy_to_previous_rev_again.run_action(:rollback)
- @third_deploy_all_releases = deploy_to_previous_rev_again.provider_for_action(:deploy).all_releases
- deploy_to_latest_rev.run_action(:deploy)
- @fourth_deploy_all_releases = deploy_to_latest_rev.provider_for_action(:deploy).all_releases
- deploy_to_latest_rev_again.run_action(:rollback)
- @fifth_deploy_all_releases = deploy_to_latest_rev_again.provider_for_action(:deploy).all_releases
- end
-
- the_app_is_deployed_at_revision(:second_rev)
-
- it "restarts the application after rolling back" do
- expect(actual_operations_order).to eq(%w{deploy_to_second_rev deploy_to_previous_rev deploy_to_previous_rev_again deploy_to_latest_rev deploy_to_latest_rev_again})
- end
-
- it "is marked updated" do
- expect(deploy_to_latest_rev_again).to be_updated_by_last_action
- end
-
- it "deploys the right code" do
- expect(IO.read(rel_path("current/app/app.rb"))).to include("this is the second version of the app")
- end
-
- it "all_releases after rollback should have one entry" do
- expect(@fifth_deploy_all_releases.length).to eq(1)
- end
-
- it "all_releases after rollback should be the same as after the first deploy" do
- expect(@fifth_deploy_all_releases).to eq(@first_deploy_all_releases)
- end
- end
-
- describe "back to a previously deployed revision where resource rev == latest revision (explicit rollback)" do
- before do
- deploy_to_second_rev.run_action(:deploy)
- @first_deploy_all_releases = deploy_to_second_rev.provider_for_action(:deploy).all_releases
- deploy_to_previous_rev.run_action(:deploy)
- @second_deploy_all_releases = deploy_to_previous_rev.provider_for_action(:deploy).all_releases
- deploy_to_second_rev_again.run_action(:rollback)
- @third_deploy_all_releases = deploy_to_second_rev_again.provider_for_action(:deploy).all_releases
- deploy_to_latest_rev.run_action(:deploy)
- @fourth_deploy_all_releases = deploy_to_latest_rev.provider_for_action(:deploy).all_releases
- deploy_to_second_rev_again_again.run_action(:rollback)
- @fifth_deploy_all_releases = deploy_to_second_rev_again_again.provider_for_action(:deploy).all_releases
- end
-
- the_app_is_deployed_at_revision(:second_rev)
-
- it "restarts the application after rolling back" do
- expect(actual_operations_order).to eq(%w{deploy_to_second_rev deploy_to_previous_rev deploy_to_second_rev_again deploy_to_latest_rev deploy_to_second_rev_again_again})
- end
-
- it "is marked updated" do
- expect(deploy_to_second_rev_again_again).to be_updated_by_last_action
- end
-
- it "deploys the right code" do
- expect(IO.read(rel_path("current/app/app.rb"))).to include("this is the second version of the app")
- end
-
- it "all_releases after rollback should have one entry" do
- expect(@fifth_deploy_all_releases.length).to eq(1)
- end
-
- it "all_releases after rollback should be the same as after the first deploy" do
- expect(@fifth_deploy_all_releases).to eq(@first_deploy_all_releases)
- end
-
- end
-
- # CHEF-3435
- describe "to a deploy_to path that does not yet exist" do
-
- let(:top_level_tmpdir) { Dir.mktmpdir }
-
- # override top level deploy_directory let block with one that is two
- # directories deeper
- let(:deploy_directory) { File.expand_path("nested/deeper", top_level_tmpdir) }
-
- after do
- FileUtils.remove_entry_secure top_level_tmpdir
- end
-
- before do
- expect(File).not_to exist(deploy_directory)
- deploy_to_latest_rev.run_action(:deploy)
- end
-
- it "creates the required directory tree" do
- expect(File).to be_directory(rel_path("releases"))
- expect(File).to be_directory(rel_path("shared"))
- expect(File).to be_directory(rel_path("releases/#{latest_rev}"))
-
- expect(File).to be_directory(rel_path("current/tmp"))
- expect(File).to be_directory(rel_path("current/config"))
- expect(File).to be_directory(rel_path("current/public"))
-
- expect(File).to be_symlink(rel_path("current"))
- expect(File.readlink(rel_path("current"))).to eq(rel_path("releases/#{latest_rev}"))
- end
-
- the_app_is_deployed_at_revision(:latest_rev)
-
- end
- end
-
- context "when deploying an app with inline recipe callbacks" do
-
- # Use closures to capture and mutate this variable. This allows us to track
- # ordering of operations.
- callback_order = []
-
- let(:deploy_to_latest_with_inline_recipes) do
- deploy_to_latest_rev.dup.tap do |r|
- r.symlink_before_migrate "config/config.ru" => "config.ru"
- r.before_migrate do
- callback_order << :before_migrate
-
- file "#{release_path}/before_migrate.txt" do
- # The content here isn't relevant, but it gets printed when running
- # the tests. Could be handy for debugging.
- content callback_order.inspect
- end
- end
- r.before_symlink do
- callback_order << :before_symlink
-
- current_release_path = release_path
- ruby_block "ensure before symlink" do
- block do
- if ::File.exist?(::File.join(current_release_path, "/tmp"))
- raise "Ordering issue with provider, expected symlinks to not have been created"
- end
- end
- end
-
- file "#{release_path}/before_symlink.txt" do
- content callback_order.inspect
- end
- end
- r.before_restart do
- callback_order << :before_restart
-
- current_release_path = release_path
- ruby_block "ensure after symlink" do
- block do
- unless ::File.exist?(::File.join(current_release_path, "/tmp"))
- raise "Ordering issue with provider, expected symlinks to have been created"
- end
- end
- end
-
- file "#{release_path}/tmp/before_restart.txt" do
- content callback_order.inspect
- end
- end
- r.after_restart do
- callback_order << :after_restart
- file "#{release_path}/tmp/after_restart.txt" do
- content callback_order.inspect
- end
- end
- end
- end
-
- before do
- callback_order.clear # callback_order variable is global for this context group
- deploy_to_latest_with_inline_recipes.run_action(:deploy)
- end
-
- the_app_is_deployed_at_revision(:latest_rev)
-
- it "is marked updated" do
- expect(deploy_to_latest_with_inline_recipes).to be_updated_by_last_action
- end
-
- it "calls the callbacks in order" do
- expect(callback_order).to eq([:before_migrate, :before_symlink, :before_restart, :after_restart])
- end
-
- it "runs chef resources in the callbacks" do
- expect(File).to exist(rel_path("current/before_migrate.txt"))
- expect(File).to exist(rel_path("current/before_symlink.txt"))
- expect(File).to exist(rel_path("current/tmp/before_restart.txt"))
- expect(File).to exist(rel_path("current/tmp/after_restart.txt"))
- end
- end
-
- context "when deploying an app with in-repo callback scripts" do
- let(:deploy_with_in_repo_callbacks) do
- basic_deploy_resource.dup.tap do |r|
- r.repo git_bundle_with_in_repo_callbacks
- r.revision rev_with_in_repo_callbacks
- end
- end
-
- before do
- deploy_with_in_repo_callbacks.run_action(:deploy)
- end
-
- the_app_is_deployed_at_revision(:rev_with_in_repo_callbacks)
-
- it "runs chef resources in the callbacks" do
- expect(File).to exist(rel_path("current/before_migrate.txt"))
- expect(File).to exist(rel_path("current/before_symlink.txt"))
- expect(File).to exist(rel_path("current/tmp/before_restart.txt"))
- expect(File).to exist(rel_path("current/tmp/after_restart.txt"))
- end
-
- end
-
- context "when deploying an app with migrations" do
- let(:deploy_with_migration) do
- basic_deploy_resource.dup.tap do |r|
-
- # Need this so we can call methods from this test inside the inline
- # recipe callbacks
- spec_context = self
-
- r.revision latest_rev
-
- # enable migrations
- r.migrate true
- # abuse `shell_restart_command` so we can observe order of when the
- # miration command gets run
- r.migration_command shell_restart_command("migration")
- r.before_migrate do
-
- # inline recipe callbacks don't cwd, so you have to get the release
- # directory as a local and "capture" it in the closure.
- current_release = release_path
- execute spec_context.shell_restart_command("before_migrate") do
- cwd current_release
- end
- end
- r.before_symlink do
- current_release = release_path
- execute spec_context.shell_restart_command("before_symlink") do
- cwd current_release
- end
- end
-
- r.before_restart do
- current_release = release_path
- execute spec_context.shell_restart_command("before_restart") do
- cwd current_release
- end
- end
-
- r.after_restart do
- current_release = release_path
- execute spec_context.shell_restart_command("after_restart") do
- cwd current_release
- end
- end
-
- end
- end
-
- before do
- deploy_with_migration.run_action(:deploy)
- end
-
- it "runs migrations in between the before_migrate and before_symlink steps" do
- expect(actual_operations_order).to eq(%w{before_migrate migration before_symlink before_restart after_restart})
- end
- end
-
- context "when deploying an app with in-repo symlinks" do
- let(:deploy_with_in_repo_symlinks) do
- basic_deploy_resource.dup.tap do |r|
- r.repo git_bundle_with_in_repo_symlinks
- r.revision rev_with_in_repo_symlinks
- end
- end
-
- it "should not raise an exception calling File.utime on symlinks" do
- expect { deploy_with_in_repo_symlinks.run_action(:deploy) }.not_to raise_error
- end
- end
-
- context "when a previously deployed application has been nuked" do
-
- shared_examples_for "a redeployed application" do
-
- it "should redeploy the application" do
- expect(File).to be_directory(rel_path("releases"))
- expect(File).to be_directory(rel_path("shared"))
- expect(File).to be_directory(rel_path("releases/#{latest_rev}"))
-
- expect(File).to be_directory(rel_path("current/tmp"))
- expect(File).to be_directory(rel_path("current/config"))
- expect(File).to be_directory(rel_path("current/public"))
-
- expect(File).to be_symlink(rel_path("current"))
- expect(File.readlink(rel_path("current"))).to eq(rel_path("releases/#{latest_rev}"))
- end
- end
-
- # background: If a deployment is hosed and the user decides to rm -rf the
- # deployment dir, deploy resource should detect that and nullify its cache.
-
- context "by removing the entire deploy directory" do
-
- before do
- deploy_to_latest_rev.dup.run_action(:deploy)
- FileUtils.rm_rf(deploy_directory)
- deploy_to_latest_rev.dup.run_action(:deploy)
- end
-
- include_examples "a redeployed application"
-
- end
-
- context "by removing the current/ directory" do
-
- before do
- deploy_to_latest_rev.dup.run_action(:deploy)
- FileUtils.rm(rel_path("current"))
- deploy_to_latest_rev.dup.run_action(:deploy)
- end
-
- include_examples "a redeployed application"
-
- end
- end
-
- context "when a deployment fails" do
-
- shared_examples_for "a recovered deployment" do
-
- it "should redeploy the application" do
- expect(File).to be_directory(rel_path("releases"))
- expect(File).to be_directory(rel_path("shared"))
- expect(File).to be_directory(rel_path("releases/#{latest_rev}"))
-
- expect(File).to be_directory(rel_path("current/tmp"))
- expect(File).to be_directory(rel_path("current/config"))
- expect(File).to be_directory(rel_path("current/public"))
-
- expect(File).to be_symlink(rel_path("current"))
- expect(File.readlink(rel_path("current"))).to eq(rel_path("releases/#{latest_rev}"))
-
- # if callbacks ran, we know the app was deployed and not merely rolled
- # back to a (busted) prior deployment.
- expect(callback_order).to eq([:before_migrate,
- :before_symlink,
- :before_restart,
- :after_restart ])
- end
- end
-
- let!(:callback_order) { [] }
-
- let(:deploy_to_latest_with_callback_tracking) do
- resource = deploy_to_latest_rev.dup
- tracker = callback_order
- resource.before_migrate { tracker << :before_migrate }
- resource.before_symlink { tracker << :before_symlink }
- resource.before_restart { tracker << :before_restart }
- resource.after_restart { tracker << :after_restart }
- resource
- end
-
- [:before_migrate, :before_symlink, :before_restart, :after_restart].each do |callback|
-
- context "in the `#{callback}' callback" do
- before do
- expect { deploy_that_fails.run_action(:deploy) }.to raise_error(Exception, %r{I am a failed deploy})
- deploy_to_latest_with_callback_tracking.run_action(:deploy)
- end
-
- let(:deploy_that_fails) do
- resource = deploy_to_latest_rev.dup
- errant_callback = lambda { |x| raise Exception, "I am a failed deploy" }
- resource.send(callback, &errant_callback)
- resource
- end
-
- include_examples "a recovered deployment"
-
- end
-
- end
-
- context "in the service restart step" do
-
- let(:deploy_that_fails) do
- resource = deploy_to_latest_rev.dup
- resource.restart_command("RUBYOPT=\"\" ruby -e 'exit 1'")
- resource
- end
-
- before do
- expect { deploy_that_fails.run_action(:deploy) }.to raise_error(Mixlib::ShellOut::ShellCommandFailed)
- deploy_to_latest_with_callback_tracking.run_action(:deploy)
- end
-
- include_examples "a recovered deployment"
- end
-
- context "when cloning the app code" do
-
- class BadTimeScmProvider
- def initialize(new_resource, run_context)
- end
-
- def load_current_resource
- end
-
- def revision_slug
- "5"
- end
-
- def run_action(action)
- raise RuntimeError, "network error"
- end
- end
-
- let(:deploy_that_fails) do
- resource = deploy_to_latest_rev.dup
- resource.scm_provider(BadTimeScmProvider)
- resource
- end
-
- before do
- expect { deploy_that_fails.run_action(:deploy) }.to raise_error(RuntimeError, /network error/)
- deploy_to_latest_with_callback_tracking.run_action(:deploy)
- end
-
- include_examples "a recovered deployment"
- end
-
- context "and then is deployed to a different revision" do
-
- let(:deploy_that_fails) do
- resource = deploy_to_previous_rev.dup
- resource.after_restart { |x| raise Exception, "I am a failed deploy" }
- resource
- end
-
- before do
- expect { deploy_that_fails.run_action(:deploy) }.to raise_error(Exception, %r{I am a failed deploy})
- deploy_to_latest_rev.run_action(:deploy)
- end
-
- it "removes the unsuccessful deploy after a later successful deploy" do
- expect(::File).not_to exist(File.join(deploy_directory, "releases", previous_rev))
- end
-
- end
-
- end
-end
diff --git a/spec/functional/resource/dnf_package_spec.rb b/spec/functional/resource/dnf_package_spec.rb
new file mode 100644
index 0000000000..01611ef996
--- /dev/null
+++ b/spec/functional/resource/dnf_package_spec.rb
@@ -0,0 +1,686 @@
+#
+# Copyright:: Copyright 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 "functional/resource/base"
+require "chef/mixin/shell_out"
+
+# run this test only for following platforms.
+exclude_test = !(%w{rhel fedora}.include?(ohai[:platform_family]) && File.exist?("/usr/bin/dnf"))
+describe Chef::Resource::RpmPackage, :requires_root, :external => exclude_test do
+ include Chef::Mixin::ShellOut
+
+ def flush_cache
+ # needed on at least fc23/fc24 sometimes to deal with the dnf cache getting out of sync with the rpm db
+ FileUtils.rm_f "/var/cache/dnf/@System.solv"
+ Chef::Resource::DnfPackage.new("shouldnt-matter", run_context).run_action(:flush_cache)
+ end
+
+ def preinstall(*rpms)
+ rpms.each do |rpm|
+ shell_out!("rpm -ivh #{CHEF_SPEC_ASSETS}/yumrepo/#{rpm}")
+ end
+ flush_cache
+ end
+
+ before(:each) do
+ File.open("/etc/yum.repos.d/chef-dnf-localtesting.repo", "w+") do |f|
+ f.write <<-EOF
+[chef-dnf-localtesting]
+name=Chef DNF spec testing repo
+baseurl=file://#{CHEF_SPEC_ASSETS}/yumrepo
+enable=1
+gpgcheck=0
+ EOF
+ end
+ shell_out!("rpm -qa | grep chef_rpm | xargs -r rpm -e")
+ end
+
+ after(:all) do
+ shell_out!("rpm -qa | grep chef_rpm | xargs -r rpm -e")
+ FileUtils.rm_f "/etc/yum.repos.d/chef-dnf-localtesting.repo"
+ end
+
+ let(:package_name) { "chef_rpm" }
+ let(:dnf_package) { Chef::Resource::DnfPackage.new(package_name, run_context) }
+
+ describe ":install" do
+ context "vanilla use case" do
+ let(:package_name) { "chef_rpm" }
+
+ it "installs if the package is not installed" do
+ flush_cache
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.x86_64")
+ end
+
+ it "does not install if the package is installed" do
+ preinstall("chef_rpm-1.10-1.x86_64.rpm")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.x86_64")
+ end
+
+ it "does not install twice" do
+ flush_cache
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.x86_64")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.x86_64")
+ end
+
+ it "does not install if the prior version package is installed" do
+ preinstall("chef_rpm-1.2-1.x86_64.rpm")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.x86_64")
+ end
+
+ it "does not install if the i686 package is installed" do
+ skip "FIXME: do nothing, or install the x86_64 version?"
+ preinstall("chef_rpm-1.10-1.i686.rpm")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.i686")
+ end
+
+ it "does not install if the prior version i686 package is installed" do
+ skip "FIXME: do nothing, or install the x86_64 version?"
+ preinstall("chef_rpm-1.2-1.i686.rpm")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.i686")
+ end
+ end
+
+ context "with versions or globs in the name" do
+ it "works with a version" do
+ flush_cache
+ dnf_package.package_name("chef_rpm-1.10")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.x86_64")
+ end
+
+ it "works with an older version" do
+ flush_cache
+ dnf_package.package_name("chef_rpm-1.2")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.x86_64")
+ end
+
+ it "works with an evr" do
+ flush_cache
+ dnf_package.package_name("chef_rpm-0:1.2-1")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.x86_64")
+ end
+
+ it "works with a version glob" do
+ flush_cache
+ dnf_package.package_name("chef_rpm-1*")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.x86_64")
+ end
+
+ it "works with a name glob + version glob" do
+ flush_cache
+ dnf_package.package_name("chef_rp*-1*")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.x86_64")
+ end
+ end
+
+ # version only matches the actual dnf version, does not work with epoch or release or combined evr
+ context "with version property" do
+ it "matches the full version" do
+ flush_cache
+ dnf_package.package_name("chef_rpm")
+ dnf_package.version("1.10")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.x86_64")
+ end
+
+ it "matches with a glob" do
+ flush_cache
+ dnf_package.package_name("chef_rpm")
+ dnf_package.version("1*")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.x86_64")
+ end
+
+ it "matches the vr" do
+ flush_cache
+ dnf_package.package_name("chef_rpm")
+ dnf_package.version("1.10-1")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.x86_64")
+ end
+
+ it "matches the evr" do
+ flush_cache
+ dnf_package.package_name("chef_rpm")
+ dnf_package.version("0:1.10-1")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.x86_64")
+ end
+
+ it "matches with a vr glob" do
+ pending "doesn't work on command line either"
+ flush_cache
+ dnf_package.package_name("chef_rpm")
+ dnf_package.version("1.10-1*")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.x86_64")
+ end
+
+ it "matches with an evr glob" do
+ pending "doesn't work on command line either"
+ flush_cache
+ dnf_package.package_name("chef_rpm")
+ dnf_package.version("0:1.10-1*")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.x86_64")
+ end
+ end
+
+ context "downgrades" do
+ it "just work with DNF" do
+ preinstall("chef_rpm-1.10-1.x86_64.rpm")
+ dnf_package.version("1.2")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.x86_64")
+ end
+
+ it "throws a deprecation warning with allow_downgrade" do
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
+ expect(Chef).to receive(:deprecated).with(:dnf_package_allow_downgrade, /^the allow_downgrade property on the dnf_package provider is not used/)
+ preinstall("chef_rpm-1.10-1.x86_64.rpm")
+ dnf_package.version("1.2")
+ dnf_package.run_action(:install)
+ dnf_package.allow_downgrade true
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.x86_64")
+ end
+ end
+
+ context "with arches" do
+ it "installs with 64-bit arch in the name" do
+ flush_cache
+ dnf_package.package_name("chef_rpm.x86_64")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.x86_64")
+ end
+
+ it "installs with 32-bit arch in the name" do
+ flush_cache
+ dnf_package.package_name("chef_rpm.i686")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.i686")
+ end
+
+ it "installs with 64-bit arch in the property" do
+ flush_cache
+ dnf_package.package_name("chef_rpm")
+ dnf_package.arch("x86_64")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.x86_64")
+ end
+
+ it "installs with 32-bit arch in the property" do
+ flush_cache
+ dnf_package.package_name("chef_rpm")
+ dnf_package.arch("i686")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.i686")
+ end
+ end
+
+ context "with constraints" do
+ it "with nothing installed, it installs the latest version" do
+ flush_cache
+ dnf_package.package_name("chef_rpm >= 1.2")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.x86_64")
+ end
+
+ it "when it is met, it does nothing" do
+ preinstall("chef_rpm-1.2-1.x86_64.rpm")
+ dnf_package.package_name("chef_rpm >= 1.2")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.x86_64")
+ end
+
+ it "when it is met, it does nothing" do
+ preinstall("chef_rpm-1.10-1.x86_64.rpm")
+ dnf_package.package_name("chef_rpm >= 1.2")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.x86_64")
+ end
+
+ it "with nothing intalled, it installs the latest version" do
+ flush_cache
+ dnf_package.package_name("chef_rpm > 1.2")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.x86_64")
+ end
+
+ it "when it is not met by an installed rpm, it upgrades" do
+ preinstall("chef_rpm-1.2-1.x86_64.rpm")
+ dnf_package.package_name("chef_rpm > 1.2")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.x86_64")
+ end
+
+ it "when it is met by an installed rpm, it does nothing" do
+ preinstall("chef_rpm-1.10-1.x86_64.rpm")
+ dnf_package.package_name("chef_rpm > 1.2")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.x86_64")
+ end
+
+ it "when there is no solution to the contraint" do
+ flush_cache
+ dnf_package.package_name("chef_rpm > 2.0")
+ expect { dnf_package.run_action(:install) }.to raise_error(Chef::Exceptions::Package, /No candidate version available/)
+ end
+
+ it "when there is no solution to the contraint but an rpm is preinstalled" do
+ preinstall("chef_rpm-1.10-1.x86_64.rpm")
+ dnf_package.package_name("chef_rpm > 2.0")
+ expect { dnf_package.run_action(:install) }.to raise_error(Chef::Exceptions::Package, /No candidate version available/)
+ end
+ end
+
+ context "with source arguments" do
+ it "raises an exception when the package does not exist" do
+ flush_cache
+ dnf_package.package_name("#{CHEF_SPEC_ASSETS}/yumrepo/this-file-better-not-exist.rpm")
+ expect { dnf_package.run_action(:install) }.to raise_error(Chef::Exceptions::Package, /No candidate version available/)
+ end
+
+ it "does not raise a hard exception in why-run mode when the package does not exist" do
+ Chef::Config[:why_run] = true
+ flush_cache
+ dnf_package.package_name("#{CHEF_SPEC_ASSETS}/yumrepo/this-file-better-not-exist.rpm")
+ dnf_package.run_action(:install)
+ expect { dnf_package.run_action(:install) }.not_to raise_error
+ end
+
+ it "installs the package when using the source argument" do
+ flush_cache
+ dnf_package.name "something"
+ dnf_package.package_name "somethingelse"
+ dnf_package.source("#{CHEF_SPEC_ASSETS}/yumrepo/chef_rpm-1.2-1.x86_64.rpm")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.x86_64")
+ end
+
+ it "installs the package when the name is a path to a file" do
+ flush_cache
+ dnf_package.package_name("#{CHEF_SPEC_ASSETS}/yumrepo/chef_rpm-1.2-1.x86_64.rpm")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.x86_64")
+ end
+
+ it "does not downgrade the package with :install" do
+ preinstall("chef_rpm-1.10-1.x86_64.rpm")
+ dnf_package.package_name("#{CHEF_SPEC_ASSETS}/yumrepo/chef_rpm-1.2-1.x86_64.rpm")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.x86_64")
+ end
+
+ it "does not upgrade the package with :install" do
+ preinstall("chef_rpm-1.2-1.x86_64.rpm")
+ dnf_package.package_name("#{CHEF_SPEC_ASSETS}/yumrepo/chef_rpm-1.10-1.x86_64.rpm")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.x86_64")
+ end
+
+ it "is idempotent when the package is already installed" do
+ preinstall("chef_rpm-1.2-1.x86_64.rpm")
+ dnf_package.package_name("#{CHEF_SPEC_ASSETS}/yumrepo/chef_rpm-1.2-1.x86_64.rpm")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.x86_64")
+ end
+ end
+
+ context "with no available version" do
+ it "works when a package is installed" do
+ FileUtils.rm_f "/etc/yum.repos.d/chef-dnf-localtesting.repo"
+ preinstall("chef_rpm-1.2-1.x86_64.rpm")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.x86_64")
+ end
+
+ it "works with a local source" do
+ FileUtils.rm_f "/etc/yum.repos.d/chef-dnf-localtesting.repo"
+ flush_cache
+ dnf_package.package_name("#{CHEF_SPEC_ASSETS}/yumrepo/chef_rpm-1.2-1.x86_64.rpm")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.x86_64")
+ end
+ end
+
+ context "multipackage with arches" do
+ it "installs two rpms" do
+ flush_cache
+ dnf_package.package_name([ "chef_rpm.x86_64", "chef_rpm.i686" ] )
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to match(/chef_rpm-1.10-1.x86_64/)
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to match(/chef_rpm-1.10-1.i686/)
+ end
+
+ it "does nothing if both are installed" do
+ preinstall("chef_rpm-1.10-1.x86_64.rpm", "chef_rpm-1.10-1.i686.rpm")
+ flush_cache
+ dnf_package.package_name([ "chef_rpm.x86_64", "chef_rpm.i686" ] )
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be false
+ end
+
+ it "installs the second rpm if the first is installed" do
+ preinstall("chef_rpm-1.10-1.x86_64.rpm")
+ dnf_package.package_name([ "chef_rpm.x86_64", "chef_rpm.i686" ] )
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to match(/chef_rpm-1.10-1.x86_64/)
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to match(/chef_rpm-1.10-1.i686/)
+ end
+
+ it "installs the first rpm if the second is installed" do
+ preinstall("chef_rpm-1.10-1.i686.rpm")
+ dnf_package.package_name([ "chef_rpm.x86_64", "chef_rpm.i686" ] )
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to match(/chef_rpm-1.10-1.x86_64/)
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to match(/chef_rpm-1.10-1.i686/)
+ end
+
+ # unlikely to work consistently correct, okay to deprecate the arch-array in favor of the arch in the name
+ it "installs two rpms with multi-arch" do
+ flush_cache
+ dnf_package.package_name(%w{chef_rpm chef_rpm} )
+ dnf_package.arch(%w{x86_64 i686})
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to match(/chef_rpm-1.10-1.x86_64/)
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to match(/chef_rpm-1.10-1.i686/)
+ end
+
+ # unlikely to work consistently correct, okay to deprecate the arch-array in favor of the arch in the name
+ it "installs the second rpm if the first is installed (muti-arch)" do
+ preinstall("chef_rpm-1.10-1.x86_64.rpm")
+ dnf_package.package_name(%w{chef_rpm chef_rpm} )
+ dnf_package.arch(%w{x86_64 i686})
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to match(/chef_rpm-1.10-1.x86_64/)
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to match(/chef_rpm-1.10-1.i686/)
+ end
+
+ # unlikely to work consistently correct, okay to deprecate the arch-array in favor of the arch in the name
+ it "installs the first rpm if the second is installed (muti-arch)" do
+ preinstall("chef_rpm-1.10-1.x86_64.rpm")
+ dnf_package.package_name(%w{chef_rpm chef_rpm} )
+ dnf_package.arch(%w{x86_64 i686})
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to match(/chef_rpm-1.10-1.x86_64/)
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to match(/chef_rpm-1.10-1.i686/)
+ end
+
+ # unlikely to work consistently correct, okay to deprecate the arch-array in favor of the arch in the name
+ it "does nothing if both are installed (muti-arch)" do
+ preinstall("chef_rpm-1.10-1.x86_64.rpm", "chef_rpm-1.10-1.i686.rpm")
+ dnf_package.package_name(%w{chef_rpm chef_rpm} )
+ dnf_package.arch(%w{x86_64 i686})
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be false
+ end
+ end
+ end
+
+ describe ":upgrade" do
+ context "downgrades" do
+ it "just work with DNF" do
+ preinstall("chef_rpm-1.10-1.x86_64.rpm")
+ dnf_package.version("1.2")
+ dnf_package.run_action(:install)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.x86_64")
+ end
+
+ it "throws a deprecation warning with allow_downgrade" do
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
+ expect(Chef).to receive(:deprecated).with(:dnf_package_allow_downgrade, /^the allow_downgrade property on the dnf_package provider is not used/)
+ preinstall("chef_rpm-1.10-1.x86_64.rpm")
+ dnf_package.version("1.2")
+ dnf_package.run_action(:install)
+ dnf_package.allow_downgrade true
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.x86_64")
+ end
+ end
+
+ context "with source arguments" do
+ it "installs the package when using the source argument" do
+ flush_cache
+ dnf_package.name "something"
+ dnf_package.package_name "somethingelse"
+ dnf_package.source("#{CHEF_SPEC_ASSETS}/yumrepo/chef_rpm-1.2-1.x86_64.rpm")
+ dnf_package.run_action(:upgrade)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.x86_64")
+ end
+
+ it "installs the package when the name is a path to a file" do
+ flush_cache
+ dnf_package.package_name("#{CHEF_SPEC_ASSETS}/yumrepo/chef_rpm-1.2-1.x86_64.rpm")
+ dnf_package.run_action(:upgrade)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.x86_64")
+ end
+
+ it "downgrades the package" do
+ preinstall("chef_rpm-1.10-1.x86_64.rpm")
+ dnf_package.package_name("#{CHEF_SPEC_ASSETS}/yumrepo/chef_rpm-1.2-1.x86_64.rpm")
+ dnf_package.run_action(:upgrade)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.x86_64")
+ end
+
+ it "upgrades the package" do
+ preinstall("chef_rpm-1.2-1.x86_64.rpm")
+ dnf_package.package_name("#{CHEF_SPEC_ASSETS}/yumrepo/chef_rpm-1.10-1.x86_64.rpm")
+ dnf_package.run_action(:upgrade)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.x86_64")
+ end
+
+ it "is idempotent when the package is already installed" do
+ preinstall("chef_rpm-1.2-1.x86_64.rpm")
+ dnf_package.package_name("#{CHEF_SPEC_ASSETS}/yumrepo/chef_rpm-1.2-1.x86_64.rpm")
+ dnf_package.run_action(:upgrade)
+ expect(dnf_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.x86_64")
+ end
+ end
+
+ context "with no available version" do
+ it "works when a package is installed" do
+ FileUtils.rm_f "/etc/yum.repos.d/chef-dnf-localtesting.repo"
+ preinstall("chef_rpm-1.2-1.x86_64.rpm")
+ dnf_package.package_name("#{CHEF_SPEC_ASSETS}/yumrepo/chef_rpm-1.2-1.x86_64.rpm")
+ dnf_package.run_action(:upgrade)
+ expect(dnf_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.x86_64")
+ end
+
+ it "works with a local source" do
+ FileUtils.rm_f "/etc/yum.repos.d/chef-dnf-localtesting.repo"
+ flush_cache
+ dnf_package.package_name("#{CHEF_SPEC_ASSETS}/yumrepo/chef_rpm-1.2-1.x86_64.rpm")
+ dnf_package.run_action(:upgrade)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.x86_64")
+ end
+ end
+ end
+
+ describe ":remove" do
+ context "vanilla use case" do
+ let(:package_name) { "chef_rpm" }
+ it "does nothing if the package is not installed" do
+ flush_cache
+ dnf_package.run_action(:remove)
+ expect(dnf_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("package chef_rpm is not installed")
+ end
+
+ it "removes the package if the package is installed" do
+ preinstall("chef_rpm-1.10-1.x86_64.rpm")
+ dnf_package.run_action(:remove)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("package chef_rpm is not installed")
+ end
+
+ it "does not remove the package twice" do
+ preinstall("chef_rpm-1.10-1.x86_64.rpm")
+ dnf_package.run_action(:remove)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("package chef_rpm is not installed")
+ dnf_package.run_action(:remove)
+ expect(dnf_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("package chef_rpm is not installed")
+ end
+
+ it "removes the package if the prior version package is installed" do
+ preinstall("chef_rpm-1.2-1.x86_64.rpm")
+ dnf_package.run_action(:remove)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("package chef_rpm is not installed")
+ end
+
+ it "removes the package if the i686 package is installed" do
+ skip "FIXME: should this be fixed or is the current behavior correct?"
+ preinstall("chef_rpm-1.10-1.i686.rpm")
+ dnf_package.run_action(:remove)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("package chef_rpm is not installed")
+ end
+
+ it "removes the package if the prior version i686 package is installed" do
+ skip "FIXME: should this be fixed or is the current behavior correct?"
+ preinstall("chef_rpm-1.2-1.i686.rpm")
+ dnf_package.run_action(:remove)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("package chef_rpm is not installed")
+ end
+ end
+
+ context "with 64-bit arch" do
+ let(:package_name) { "chef_rpm.x86_64" }
+ it "does nothing if the package is not installed" do
+ flush_cache
+ dnf_package.run_action(:remove)
+ expect(dnf_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("package chef_rpm is not installed")
+ end
+
+ it "removes the package if the package is installed" do
+ preinstall("chef_rpm-1.10-1.x86_64.rpm")
+ dnf_package.run_action(:remove)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("package chef_rpm is not installed")
+ end
+
+ it "removes the package if the prior version package is installed" do
+ preinstall("chef_rpm-1.2-1.x86_64.rpm")
+ dnf_package.run_action(:remove)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("package chef_rpm is not installed")
+ end
+
+ it "does nothing if the i686 package is installed" do
+ preinstall("chef_rpm-1.10-1.i686.rpm")
+ dnf_package.run_action(:remove)
+ expect(dnf_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.i686")
+ end
+
+ it "does nothing if the prior version i686 package is installed" do
+ preinstall("chef_rpm-1.2-1.i686.rpm")
+ dnf_package.run_action(:remove)
+ expect(dnf_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.2-1.i686")
+ end
+ end
+
+ context "with 32-bit arch" do
+ let(:package_name) { "chef_rpm.i686" }
+ it "removes only the 32-bit arch if both are installed" do
+ preinstall("chef_rpm-1.10-1.x86_64.rpm", "chef_rpm-1.10-1.i686.rpm")
+ dnf_package.run_action(:remove)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("chef_rpm-1.10-1.x86_64")
+ end
+ end
+
+ context "with no available version" do
+ it "works when a package is installed" do
+ FileUtils.rm_f "/etc/yum.repos.d/chef-dnf-localtesting.repo"
+ preinstall("chef_rpm-1.2-1.x86_64.rpm")
+ dnf_package.run_action(:remove)
+ expect(dnf_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q chef_rpm").stdout.chomp).to eql("package chef_rpm is not installed")
+ end
+ end
+ end
+end
diff --git a/spec/functional/resource/dpkg_package_spec.rb b/spec/functional/resource/dpkg_package_spec.rb
index d65256231b..1988fd0c7d 100644
--- a/spec/functional/resource/dpkg_package_spec.rb
+++ b/spec/functional/resource/dpkg_package_spec.rb
@@ -27,11 +27,11 @@ describe Chef::Resource::DpkgPackage, :requires_root, :debian_family_only, arch:
let(:test1_1) { File.join(apt_data, "chef-integration-test_1.1-1_amd64.deb") }
let(:test2_0) { File.join(apt_data, "chef-integration-test2_1.0-1_amd64.deb") }
- let(:run_context) {
+ let(:run_context) do
node = TEST_NODE.dup
events = Chef::EventDispatch::Dispatcher.new
Chef::RunContext.new(node, {}, events)
- }
+ end
let(:dpkg_package) { Chef::Resource::DpkgPackage.new(test1_0, run_context) }
diff --git a/spec/functional/resource/dsc_resource_spec.rb b/spec/functional/resource/dsc_resource_spec.rb
index 8e4940d475..bb3cf2157d 100644
--- a/spec/functional/resource/dsc_resource_spec.rb
+++ b/spec/functional/resource/dsc_resource_spec.rb
@@ -21,17 +21,17 @@ require "spec_helper"
describe Chef::Resource::DscResource, :windows_powershell_dsc_only do
let(:event_dispatch) { Chef::EventDispatch::Dispatcher.new }
- let(:node) {
+ let(:node) do
Chef::Node.new.tap do |n|
n.consume_external_attrs(OHAI_SYSTEM.data, {})
end
- }
+ end
let(:run_context) { Chef::RunContext.new(node, {}, event_dispatch) }
- let(:new_resource) {
+ let(:new_resource) do
Chef::Resource::DscResource.new("dsc_resource_test", run_context)
- }
+ end
context "when Powershell does not support Invoke-DscResource"
context "when Powershell supports Invoke-DscResource" do
@@ -77,7 +77,7 @@ describe Chef::Resource::DscResource, :windows_powershell_dsc_only do
new_resource.run_action(:run)
expect(new_resource).to be_updated
reresource =
- Chef::Resource::DscResource.new("dsc_resource_retest", run_context)
+ Chef::Resource::DscResource.new("dsc_resource_retest", run_context)
reresource.resource :File
reresource.property :Contents, test_text
reresource.property :DestinationPath, tmp_file_name
diff --git a/spec/functional/resource/dsc_script_spec.rb b/spec/functional/resource/dsc_script_spec.rb
index 42c23a695f..ce92c468f0 100644
--- a/spec/functional/resource/dsc_script_spec.rb
+++ b/spec/functional/resource/dsc_script_spec.rb
@@ -65,28 +65,27 @@ describe Chef::Resource::DscScript, :windows_powershell_dsc_only do
end
def delete_user(target_user)
- begin
- shell_out!("net user #{target_user} /delete")
- rescue Mixlib::ShellOut::ShellCommandFailed
- end
+ shell_out!("net user #{target_user} /delete")
+ rescue Mixlib::ShellOut::ShellCommandFailed
end
let(:dsc_env_variable) { "chefenvtest" }
let(:dsc_env_value1) { "value1" }
let(:env_value2) { "value2" }
- let(:dsc_test_run_context) {
+ let(:dsc_test_run_context) do
node = Chef::Node.new
+ node.automatic["os"] = "windows"
node.automatic["platform"] = "windows"
node.automatic["platform_version"] = "6.1"
node.automatic["kernel"][:machine] = :x86_64 # Only 64-bit architecture is supported
node.automatic[:languages][:powershell][:version] = "4.0"
empty_events = Chef::EventDispatch::Dispatcher.new
Chef::RunContext.new(node, {}, empty_events)
- }
+ end
let(:dsc_test_resource_name) { "DSCTest" }
- let(:dsc_test_resource_base) {
+ let(:dsc_test_resource_base) do
Chef::Resource::DscScript.new(dsc_test_resource_name, dsc_test_run_context)
- }
+ end
let(:test_registry_key) { 'HKEY_LOCAL_MACHINE\Software\Chef\Spec\Functional\Resource\dsc_script_spec' }
let(:test_registry_value) { "Registration" }
let(:test_registry_data1) { "LL927" }
@@ -94,7 +93,8 @@ describe Chef::Resource::DscScript, :windows_powershell_dsc_only do
let(:reg_key_name_param_name) { "testregkeyname" }
let(:reg_key_value_param_name) { "testregvaluename" }
let(:registry_embedded_parameters) { "$#{reg_key_name_param_name} = '#{test_registry_key}';$#{reg_key_value_param_name} = '#{test_registry_value}'" }
- let(:dsc_reg_code) { <<-EOH
+ let(:dsc_reg_code) do
+ <<-EOH
#{registry_embedded_parameters}
Registry "ChefRegKey"
{
@@ -104,14 +104,15 @@ describe Chef::Resource::DscScript, :windows_powershell_dsc_only do
Ensure = 'Present'
}
EOH
- }
+ end
let(:dsc_code) { dsc_reg_code }
- let(:dsc_reg_script) { <<-EOH
+ let(:dsc_reg_script) do
+ <<-EOH
param($testregkeyname, $testregvaluename)
#{dsc_reg_code}
EOH
- }
+ end
let(:dsc_user_prefix) { "dsc" }
let(:dsc_user_suffix) { "chefx" }
@@ -128,7 +129,8 @@ EOH
let(:dsc_user_param_code) { "\"$(#{dsc_user_prefix_param_code})_usr_$(#{dsc_user_suffix_param_code})\"" }
let(:config_flags) { nil }
- let(:config_params) { <<-EOH
+ let(:config_params) do
+ <<-EOH
[CmdletBinding()]
param
@@ -137,14 +139,15 @@ EOH
$#{dsc_user_suffix_param_name}
)
EOH
- }
+ end
let(:config_param_section) { "" }
let(:dsc_user_code) { "'#{dsc_user}'" }
let(:dsc_user_prefix_code) { dsc_user_prefix }
let(:dsc_user_suffix_code) { dsc_user_suffix }
let(:dsc_script_environment_attribute) { nil }
- let(:dsc_user_resources_code) { <<-EOH
+ let(:dsc_user_resources_code) do
+ <<-EOH
#{config_param_section}
node localhost
{
@@ -164,9 +167,9 @@ User dsctestusercreate
}
}
EOH
- }
+ end
- let(:dsc_user_config_data) {
+ let(:dsc_user_config_data) do
<<-EOH
@{
AllNodes = @(
@@ -178,13 +181,14 @@ EOH
}
EOH
- }
+ end
let(:dsc_environment_env_var_name) { "dsc_test_cwd" }
let(:dsc_environment_no_fail_not_etc_directory) { "#{ENV['systemroot']}\\system32" }
let(:dsc_environment_fail_etc_directory) { "#{ENV['systemroot']}\\system32\\drivers\\etc" }
let(:exception_message_signature) { "LL927-LL928" }
- let(:dsc_environment_config) {<<-EOH
+ let(:dsc_environment_config) do
+ <<-EOH
if (($pwd.path -eq '#{dsc_environment_fail_etc_directory}') -and (test-path('#{dsc_environment_fail_etc_directory}')))
{
throw 'Signature #{exception_message_signature}: Purposefully failing because cwd == #{dsc_environment_fail_etc_directory}'
@@ -196,21 +200,21 @@ environment "whatsmydir"
Ensure = 'Present'
}
EOH
- }
+ end
- let(:dsc_config_name) {
+ let(:dsc_config_name) do
dsc_test_resource_base.name
- }
- let(:dsc_resource_from_code) {
+ end
+ let(:dsc_resource_from_code) do
dsc_test_resource_base.code(dsc_code)
dsc_test_resource_base
- }
+ end
let(:config_name_value) { dsc_test_resource_base.name }
- let(:dsc_resource_from_path) {
+ let(:dsc_resource_from_path) do
dsc_test_resource_base.command(create_config_script_from_code(dsc_code, config_name_value))
dsc_test_resource_base
- }
+ end
before(:each) do
test_key_resource = Chef::Resource::RegistryKey.new(test_registry_key, dsc_test_run_context)
@@ -469,6 +473,7 @@ EOF
end
it "allows the use of ps_credential" do
+ skip("Skipped until we can adjust the test cert to meet the WMF 5 cert requirements.")
expect(user_exists?(dsc_user)).to eq(false)
powershell_script_resource.run_action(:run)
expect(File).to exist(configuration_data_path)
diff --git a/spec/functional/resource/env_spec.rb b/spec/functional/resource/env_spec.rb
deleted file mode 100755
index 83328a6738..0000000000
--- a/spec/functional/resource/env_spec.rb
+++ /dev/null
@@ -1,192 +0,0 @@
-#
-# Author:: Adam Edwards (<adamed@chef.io>)
-# 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"
-
-describe Chef::Resource::Env, :windows_only do
- context "when running on Windows" do
- let(:chef_env_test_lower_case) { "chefenvtest" }
- let(:chef_env_test_mixed_case) { "chefENVtest" }
- let(:env_dne_key) { "env_dne_key" }
- let(:env_value1) { "value1" }
- let(:env_value2) { "value2" }
-
- let(:env_value_expandable) { "%SystemRoot%" }
- let(:test_run_context) {
- node = Chef::Node.new
- node.default["os"] = "windows"
- node.default["platform"] = "windows"
- node.default["platform_version"] = "6.1"
- empty_events = Chef::EventDispatch::Dispatcher.new
- Chef::RunContext.new(node, {}, empty_events)
- }
- let(:test_resource) {
- Chef::Resource::Env.new("unknown", test_run_context)
- }
-
- before(:each) do
- resource_lower = Chef::Resource::Env.new(chef_env_test_lower_case, test_run_context)
- resource_lower.run_action(:delete)
- resource_mixed = Chef::Resource::Env.new(chef_env_test_mixed_case, test_run_context)
- resource_mixed.run_action(:delete)
- end
-
- context "when the create action is invoked" do
- it "should create an environment variable for action create" do
- expect(ENV[chef_env_test_lower_case]).to eq(nil)
- test_resource.key_name(chef_env_test_lower_case)
- test_resource.value(env_value1)
- test_resource.run_action(:create)
- expect(ENV[chef_env_test_lower_case]).to eq(env_value1)
- end
-
- it "should modify an existing variable's value to a new value" do
- test_resource.key_name(chef_env_test_lower_case)
- test_resource.value(env_value1)
- test_resource.run_action(:create)
- expect(ENV[chef_env_test_lower_case]).to eq(env_value1)
- test_resource.value(env_value2)
- test_resource.run_action(:create)
- expect(ENV[chef_env_test_lower_case]).to eq(env_value2)
- end
-
- it "should modify an existing variable's value to a new value if the variable name case differs from the existing variable" do
- test_resource.key_name(chef_env_test_lower_case)
- test_resource.value(env_value1)
- test_resource.run_action(:create)
- expect(ENV[chef_env_test_lower_case]).to eq(env_value1)
- test_resource.key_name(chef_env_test_mixed_case)
- test_resource.value(env_value2)
- test_resource.run_action(:create)
- expect(ENV[chef_env_test_lower_case]).to eq(env_value2)
- end
-
- it "should not expand environment variables if the variable is not PATH" do
- expect(ENV[chef_env_test_lower_case]).to eq(nil)
- test_resource.key_name(chef_env_test_lower_case)
- test_resource.value(env_value_expandable)
- test_resource.run_action(:create)
- expect(ENV[chef_env_test_lower_case]).to eq(env_value_expandable)
- end
- end
-
- context "when the modify action is invoked" do
- it "should raise an exception for modify if the variable doesn't exist" do
- expect(ENV[chef_env_test_lower_case]).to eq(nil)
- test_resource.key_name(chef_env_test_lower_case)
- test_resource.value(env_value1)
- expect { test_resource.run_action(:modify) }.to raise_error(Chef::Exceptions::Env)
- end
-
- it "should modify an existing variable's value to a new value" do
- test_resource.key_name(chef_env_test_lower_case)
- test_resource.value(env_value1)
- test_resource.run_action(:create)
- expect(ENV[chef_env_test_lower_case]).to eq(env_value1)
- test_resource.value(env_value2)
- test_resource.run_action(:modify)
- expect(ENV[chef_env_test_lower_case]).to eq(env_value2)
- end
-
- # This examlpe covers Chef Issue #1754
- it "should modify an existing variable's value to a new value if the variable name case differs from the existing variable" do
- test_resource.key_name(chef_env_test_lower_case)
- test_resource.value(env_value1)
- test_resource.run_action(:create)
- expect(ENV[chef_env_test_lower_case]).to eq(env_value1)
- test_resource.key_name(chef_env_test_mixed_case)
- test_resource.value(env_value2)
- test_resource.run_action(:modify)
- expect(ENV[chef_env_test_lower_case]).to eq(env_value2)
- end
-
- it "should not expand environment variables if the variable is not PATH" do
- test_resource.key_name(chef_env_test_lower_case)
- test_resource.value(env_value1)
- test_resource.run_action(:create)
- expect(ENV[chef_env_test_lower_case]).to eq(env_value1)
- test_resource.value(env_value_expandable)
- test_resource.run_action(:modify)
- expect(ENV[chef_env_test_lower_case]).to eq(env_value_expandable)
- end
-
- context "when using PATH" do
- let(:random_name) { Time.now.to_i }
- let(:env_val) { "#{env_value_expandable}_#{random_name}" }
- let!(:path_before) { test_resource.provider_for_action(test_resource.action).env_value("PATH") || "" }
- let!(:env_path_before) { ENV["PATH"] }
-
- it "should expand PATH" do
- expect(path_before).not_to include(env_val)
- test_resource.key_name("PATH")
- test_resource.value("#{path_before};#{env_val}")
- test_resource.run_action(:create)
- expect(ENV["PATH"]).not_to include(env_val)
- expect(ENV["PATH"]).to include("#{random_name}")
- end
-
- after(:each) do
- # cleanup so we don't flood the path
- test_resource.key_name("PATH")
- test_resource.value(path_before)
- test_resource.run_action(:create)
- ENV["PATH"] = env_path_before
- end
- end
-
- end
-
- context "when the delete action is invoked" do
- it "should delete an environment variable" do
- test_resource.key_name(chef_env_test_lower_case)
- test_resource.value(env_value1)
- test_resource.run_action(:create)
- expect(ENV[chef_env_test_lower_case]).to eq(env_value1)
- test_resource.run_action(:delete)
- expect(ENV[chef_env_test_lower_case]).to eq(nil)
- end
-
- it "should not raise an exception when a non-existent environment variable is deleted" do
- expect(ENV[chef_env_test_lower_case]).to eq(nil)
- test_resource.key_name(chef_env_test_lower_case)
- test_resource.value(env_value1)
- expect { test_resource.run_action(:delete) }.not_to raise_error
- expect(ENV[chef_env_test_lower_case]).to eq(nil)
- end
-
- it "should delete an existing variable's value to a new value if the specified variable name case differs from the existing variable" do
- test_resource.key_name(chef_env_test_lower_case)
- test_resource.value(env_value1)
- test_resource.run_action(:create)
- expect(ENV[chef_env_test_lower_case]).to eq(env_value1)
- test_resource.key_name(chef_env_test_mixed_case)
- test_resource.run_action(:delete)
- expect(ENV[chef_env_test_lower_case]).to eq(nil)
- expect(ENV[chef_env_test_mixed_case]).to eq(nil)
- end
-
- it "should delete a value from the current process even if it is not in the registry" do
- expect(ENV[env_dne_key]).to eq(nil)
- ENV[env_dne_key] = env_value1
- test_resource.key_name(env_dne_key)
- test_resource.run_action(:delete)
- expect(ENV[env_dne_key]).to eq(nil)
- end
- end
- end
-end
diff --git a/spec/functional/resource/execute_spec.rb b/spec/functional/resource/execute_spec.rb
index c5978da519..c0956c5594 100644
--- a/spec/functional/resource/execute_spec.rb
+++ b/spec/functional/resource/execute_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Serdar Sutay (<serdar@chef.io>)
-# Copyright:: Copyright 2014-2016, Chef Software Inc.
+# Copyright:: Copyright 2014-2017, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -21,11 +21,11 @@ require "functional/resource/base"
require "timeout"
describe Chef::Resource::Execute do
- let(:resource) {
+ let(:resource) do
resource = Chef::Resource::Execute.new("foo_resource", run_context)
resource.command("echo hello")
resource
- }
+ end
describe "when guard is ruby block" do
it "guard can still run" do
@@ -41,17 +41,17 @@ describe Chef::Resource::Execute do
end
let(:guard) { "ruby -e 'exit 0'" }
- let!(:guard_resource) {
+ let!(:guard_resource) do
interpreter = Chef::GuardInterpreter::ResourceGuardInterpreter.new(resource, guard, nil)
interpreter.send(:get_interpreter_resource, resource)
- }
+ end
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
+ expect_any_instance_of(Chef::Provider::Execute).to receive(:shell_out_with_systems_locale!).once
resource.only_if guard
resource.run_action(:run)
@@ -137,6 +137,18 @@ describe Chef::Resource::Execute do
end
end
+ describe "when a guard is specified" do
+ describe "when using the default guard interpreter" do
+ let(:guard_interpreter_resource) { nil }
+ it_behaves_like "a resource with a guard specifying an alternate user identity"
+ end
+
+ describe "when using the execute resource as the guard interpreter" do
+ let(:guard_interpreter_resource) { :execute }
+ it_behaves_like "a resource with a guard specifying an alternate user identity"
+ end
+ end
+
# Ensure that CommandTimeout is raised, and is caused by resource.timeout really expiring.
# https://github.com/chef/chef/issues/2985
#
@@ -151,4 +163,9 @@ describe Chef::Resource::Execute do
expect { resource.run_action(:run) }.to raise_error(Mixlib::ShellOut::CommandTimeout)
end
end
+
+ describe "when running with an alternate user identity" do
+ let(:resource_command_property) { :command }
+ it_behaves_like "an execute resource that supports alternate user identity"
+ end
end
diff --git a/spec/functional/resource/group_spec.rb b/spec/functional/resource/group_spec.rb
index a5de63b7c6..ea9aa5c2b7 100644
--- a/spec/functional/resource/group_spec.rb
+++ b/spec/functional/resource/group_spec.rb
@@ -81,25 +81,39 @@ describe Chef::Resource::Group, :requires_root_or_running_windows, :not_supporte
if user && domain != "."
computer_name = ENV["computername"]
- !domain.casecmp(computer_name.downcase).zero?
+ !domain.casecmp(computer_name.downcase) == 0
end
end
+ def node
+ node = Chef::Node.new
+ node.consume_external_attrs(ohai.data, {})
+ node
+ end
+
def user(username)
- usr = Chef::Resource::User.new("#{username}", run_context)
+ usr = Chef::Resource.resource_for_node(:user, node).new(username, run_context)
if ohai[:platform_family] == "windows"
usr.password("ComplexPass11!")
end
usr
end
- def create_user(username)
- user(username).run_action(:create) if ! windows_domain_user?(username)
+ def create_user(username, uid = nil)
+ if ! windows_domain_user?(username)
+ user_to_create = user(username)
+ user_to_create.uid(uid) if uid
+ user_to_create.run_action(:create)
+ end
# TODO: User should exist
end
def remove_user(username)
- user(username).run_action(:remove) if ! windows_domain_user?(username)
+ if ! windows_domain_user?(username)
+ u = user(username)
+ u.manage_home false # jekins hosts throw mail spool file not owned by user if we use manage_home true
+ u.run_action(:remove)
+ end
# TODO: User shouldn't exist
end
@@ -159,8 +173,11 @@ describe Chef::Resource::Group, :requires_root_or_running_windows, :not_supporte
describe "when the users exist" do
before do
+ high_uid = 30000
(spec_members).each do |member|
- create_user(member)
+ remove_user(member)
+ create_user(member, high_uid)
+ high_uid += 1
end
end
@@ -282,12 +299,13 @@ describe Chef::Resource::Group, :requires_root_or_running_windows, :not_supporte
let(:group_name) { "group#{SecureRandom.random_number(9999)}" }
let(:included_members) { nil }
let(:excluded_members) { nil }
- let(:group_resource) {
+ let(:group_resource) do
group = Chef::Resource::Group.new(group_name, run_context)
group.members(included_members)
group.excluded_members(excluded_members)
+ group.gid(30000) unless ohai[:platform_family] == "mac_os_x"
group
- }
+ end
it "append should be false by default" do
expect(group_resource.append).to eq(false)
@@ -305,10 +323,11 @@ describe Chef::Resource::Group, :requires_root_or_running_windows, :not_supporte
end
describe "when group name is length 256", :windows_only do
- let!(:group_name) { "theoldmanwalkingdownthestreetalwayshadagood\
+ let!(:group_name) do
+ "theoldmanwalkingdownthestreetalwayshadagood\
smileonhisfacetheoldmanwalkingdownthestreetalwayshadagoodsmileonhisface\
theoldmanwalkingdownthestreetalwayshadagoodsmileonhisfacetheoldmanwalking\
-downthestreetalwayshadagoodsmileonhisfacetheoldmanwalkingdownthestree" }
+downthestreetalwayshadagoodsmileonhisfacetheoldmanwalkingdownthestree" end
it "should create a group" do
group_resource.run_action(:create)
@@ -316,18 +335,6 @@ downthestreetalwayshadagoodsmileonhisfacetheoldmanwalkingdownthestree" }
end
end
- describe "when group name length is more than 256", :windows_only do
- let!(:group_name) { "theoldmanwalkingdownthestreetalwayshadagood\
-smileonhisfacetheoldmanwalkingdownthestreetalwayshadagoodsmileonhisface\
-theoldmanwalkingdownthestreetalwayshadagoodsmileonhisfacetheoldmanwalking\
-downthestreetalwayshadagoodsmileonhisfacetheoldmanwalkingdownthestreeQQQQQQ" }
-
- it "should not create a group" do
- expect { group_resource.run_action(:create) }.to raise_error(ArgumentError)
- group_should_not_exist(group_name)
- end
- end
-
# not_supported_on_solaris because of the use of excluded_members
describe "should raise an error when same member is included in the members and excluded_members", :not_supported_on_solaris do
it "should raise an error" do
@@ -339,6 +346,25 @@ downthestreetalwayshadagoodsmileonhisfacetheoldmanwalkingdownthestreeQQQQQQ" }
end
end
+ # Note:This testcase is written separately from the `group create action` defined above because
+ # for group name > 256, Windows 2016 returns "The parameter is incorrect"
+ context "group create action: when group name length is more than 256", :windows_only do
+ let!(:group_name) do
+ "theoldmanwalkingdownthestreetalwayshadagood\
+smileonhisfacetheoldmanwalkingdownthestreetalwayshadagoodsmileonhisface\
+theoldmanwalkingdownthestreetalwayshadagoodsmileonhisfacetheoldmanwalking\
+downthestreetalwayshadagoodsmileonhisfacetheoldmanwalkingdownthestreeQQQQQQ" end
+
+ it "should not create a group" do
+ expect { group_resource.run_action(:create) }.to raise_error(ArgumentError)
+ if windows_gte_10?
+ expect { Chef::Util::Windows::NetGroup.new(group_name).local_get_members }.to raise_error(ArgumentError, /The parameter is incorrect./)
+ else
+ group_should_not_exist(group_name)
+ end
+ end
+ end
+
describe "group remove action" do
describe "when there is a group" do
before do
@@ -405,6 +431,7 @@ downthestreetalwayshadagoodsmileonhisfacetheoldmanwalkingdownthestreeQQQQQQ" }
end
it "does not raise an error on manage" do
+ allow(Etc).to receive(:getpwnam).and_return(double("User"))
expect { group_resource.run_action(:manage) }.not_to raise_error
end
end
diff --git a/spec/functional/resource/ifconfig_spec.rb b/spec/functional/resource/ifconfig_spec.rb
index a30dcff641..f32ed069b5 100644
--- a/spec/functional/resource/ifconfig_spec.rb
+++ b/spec/functional/resource/ifconfig_spec.rb
@@ -16,11 +16,12 @@
# limitations under the License.
#
+require "spec_helper"
require "functional/resource/base"
require "chef/mixin/shell_out"
# run this test only for following platforms.
-include_flag = !(%w{ubuntu centos aix}.include?(ohai[:platform]))
+include_flag = !(%w{amazon debian aix}.include?(ohai[:platform_family]) || (ohai[:platform_family] == "rhel" && ohai[:platform_version].to_i < 7))
describe Chef::Resource::Ifconfig, :requires_root, :skip_travis, :external => include_flag do
# This test does not work in travis because there is no eth0
@@ -51,11 +52,17 @@ describe Chef::Resource::Ifconfig, :requires_root, :skip_travis, :external => in
end
end
+ def fetch_first_interface_name
+ shell_out("ip link list |grep UP|grep -vi loop|head -1|cut -d':' -f 2").stdout.strip
+ end
+
# **Caution: any updates to core interfaces can be risky.
def en0_interface_for_test
case ohai[:platform]
when "aix"
"en0"
+ when "ubuntu"
+ fetch_first_interface_name
else
"eth0"
end
diff --git a/spec/functional/resource/link_spec.rb b/spec/functional/resource/link_spec.rb
index 6dd6ad8422..2b8b509730 100644
--- a/spec/functional/resource/link_spec.rb
+++ b/spec/functional/resource/link_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: John Keiser (<jkeiser@chef.io>)
-# Copyright:: Copyright 2011-2016, Chef Software Inc.
+# Copyright:: Copyright 2011-2017, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,12 +20,14 @@ require "spec_helper"
if windows?
require "chef/win32/file" #probably need this in spec_helper
+ require "chef/win32/security"
end
describe Chef::Resource::Link do
let(:file_base) { "file_spec" }
let(:expect_updated?) { true }
+ let(:logger) { double("Mixlib::Log::Child").as_null_object }
# We create the files in a different directory than tmp to exercise
# different file deployment strategies more completely.
@@ -62,6 +64,18 @@ describe Chef::Resource::Link do
end
end
+ def node
+ node = Chef::Node.new
+ node.consume_external_attrs(ohai.data, {})
+ node
+ end
+
+ def user(user)
+ usr = Chef::Resource.resource_for_node(:user, node).new(user, run_context)
+ usr.password("ComplexPass11!") if windows?
+ usr
+ end
+
def cleanup_link(path)
if windows? && File.directory?(path)
# If the link target is a directory rm_rf doesn't work all the
@@ -108,12 +122,49 @@ describe Chef::Resource::Link do
end
end
+ let(:test_user) { windows? ? nil : ENV["USER"] }
+
+ def expected_owner
+ if windows?
+ get_sid(test_user)
+ else
+ test_user
+ end
+ end
+
+ def get_sid(value)
+ if value.kind_of?(String)
+ Chef::ReservedNames::Win32::Security::SID.from_account(value)
+ elsif value.kind_of?(Chef::ReservedNames::Win32::Security::SID)
+ value
+ else
+ raise "Must specify username or SID: #{value}"
+ end
+ end
+
+ def chown(file, user)
+ if windows?
+ Chef::ReservedNames::Win32::Security::SecurableObject.new(file).owner = get_sid(user)
+ else
+ File.lchown(Etc.getpwnam(user).uid, Etc.getpwnam(user).gid, file)
+ end
+ end
+
+ def owner(file)
+ if windows?
+ Chef::ReservedNames::Win32::Security::SecurableObject.new(file).security_descriptor.owner
+ else
+ Etc.getpwuid(File.lstat(file).uid).name
+ end
+ end
+
def create_resource
node = Chef::Node.new
events = Chef::EventDispatch::Dispatcher.new
cookbook_repo = File.expand_path(File.join(CHEF_SPEC_DATA, "cookbooks"))
cookbook_collection = Chef::CookbookCollection.new(Chef::CookbookLoader.new(cookbook_repo))
run_context = Chef::RunContext.new(node, cookbook_collection, events)
+ allow(run_context).to receive(:logger).and_return(logger)
resource = Chef::Resource::Link.new(target_file, run_context)
resource.to(to)
resource
@@ -123,7 +174,7 @@ describe Chef::Resource::Link do
create_resource
end
- describe "when supported on platform", :not_supported_on_win2k3 do
+ describe "when supported on platform" do
shared_examples_for "delete errors out" do
it "delete errors out" do
expect { resource.run_action(:delete) }.to raise_error(Chef::Exceptions::Link)
@@ -135,7 +186,7 @@ describe Chef::Resource::Link do
describe "the :delete action" do
before(:each) do
@info = []
- allow(Chef::Log).to receive(:info) { |msg| @info << msg }
+ allow(logger).to receive(:info) { |msg| @info << msg }
resource.run_action(:delete)
end
@@ -156,7 +207,7 @@ describe Chef::Resource::Link do
describe "the :delete action" do
before(:each) do
@info = []
- allow(Chef::Log).to receive(:info) { |msg| @info << msg }
+ allow(logger).to receive(:info) { |msg| @info << msg }
resource.run_action(:delete)
end
@@ -177,13 +228,14 @@ describe Chef::Resource::Link do
describe "the :create action" do
before(:each) do
@info = []
- allow(Chef::Log).to receive(:info) { |msg| @info << msg }
+ allow(logger).to receive(:info) { |msg| @info << msg }
resource.run_action(:create)
end
it "links to the target file" do
expect(symlink?(target_file)).to be_truthy
expect(readlink(target_file)).to eq(canonicalize(to))
+ expect(owner(target_file)).to eq(expected_owner) unless test_user.nil?
end
it "marks the resource updated" do
expect(resource).to be_updated
@@ -198,13 +250,14 @@ describe Chef::Resource::Link do
describe "the :create action" do
before(:each) do
@info = []
- allow(Chef::Log).to receive(:info) { |msg| @info << msg }
+ allow(logger).to receive(:info) { |msg| @info << msg }
resource.run_action(:create)
end
it "leaves the file linked" do
expect(symlink?(target_file)).to be_truthy
expect(readlink(target_file)).to eq(canonicalize(to))
+ expect(owner(target_file)).to eq(expected_owner) unless test_user.nil?
end
it "does not mark the resource updated" do
expect(resource).not_to be_updated
@@ -219,7 +272,7 @@ describe Chef::Resource::Link do
describe "the :create action" do
before(:each) do
@info = []
- allow(Chef::Log).to receive(:info) { |msg| @info << msg }
+ allow(logger).to receive(:info) { |msg| @info << msg }
resource.run_action(:create)
end
it "preserves the hard link" do
@@ -244,7 +297,7 @@ describe Chef::Resource::Link do
describe "the :create action" do
before(:each) do
@info = []
- allow(Chef::Log).to receive(:info) { |msg| @info << msg }
+ allow(logger).to receive(:info) { |msg| @info << msg }
resource.run_action(:create)
end
it "links to the target file" do
@@ -291,13 +344,23 @@ describe Chef::Resource::Link do
expect(File.exists?(to)).to be_truthy
end
end
- context "pointing somewhere else" do
+ context "pointing somewhere else", :requires_root_or_running_windows do
+ let(:test_user) { "test-link-user" }
+ before do
+ user(test_user).run_action(:create)
+ end
+ after do
+ user(test_user).run_action(:remove)
+ end
before(:each) do
+ resource.owner(test_user)
@other_target = File.join(test_file_dir, make_tmpname("other_spec"))
File.open(@other_target, "w") { |file| file.write("eek") }
symlink(@other_target, target_file)
+ chown(target_file, test_user)
expect(symlink?(target_file)).to be_truthy
expect(readlink(target_file)).to eq(canonicalize(@other_target))
+ expect(owner(target_file)).to eq(expected_owner)
end
after(:each) do
File.delete(@other_target)
@@ -388,6 +451,14 @@ describe Chef::Resource::Link do
symlink(other_dir, target_file)
end
include_context "create symbolic link succeeds"
+ include_context "delete succeeds"
+ end
+ context "and the link already exists and points at the target" do
+ before do
+ symlink(to, target_file)
+ end
+ include_context "create symbolic link is noop"
+ include_context "delete succeeds"
end
end
context "when the link destination is a symbolic link" do
@@ -406,6 +477,19 @@ describe Chef::Resource::Link do
include_context "create symbolic link succeeds"
include_context "delete is noop"
end
+ context "and the destination itself has another symbolic link" do
+ context "to a link that exist" do
+ before do
+ symlink(to, target_file)
+ end
+ include_context "create symbolic link is noop"
+ include_context "delete succeeds"
+ end
+ context "to a link that does not exist" do
+ include_context "create symbolic link succeeds"
+ include_context "delete is noop"
+ end
+ end
end
context "to a file that does not exist" do
before(:each) do
@@ -418,6 +502,19 @@ describe Chef::Resource::Link do
include_context "create symbolic link succeeds"
include_context "delete is noop"
end
+ context "and the destination itself has another symbolic link" do
+ context "to a link that exist" do
+ before do
+ symlink(to, target_file)
+ end
+ include_context "create symbolic link is noop"
+ include_context "delete succeeds"
+ end
+ context "to a link that does not exist" do
+ include_context "create symbolic link succeeds"
+ include_context "delete is noop"
+ end
+ end
end
end
context "when the link destination does not exist" do
@@ -559,7 +656,7 @@ describe Chef::Resource::Link do
end
context "and the link does not yet exist" do
it "links to the target file" do
- skip("OS X/FreeBSD/AIX symlink? and readlink working on hard links to symlinks") if os_x? || freebsd? || aix?
+ skip("OS X/FreeBSD/AIX/Solaris symlink? and readlink working on hard links to symlinks") if os_x? || freebsd? || aix? || solaris?
resource.run_action(:create)
expect(File.exists?(target_file)).to be_truthy
# OS X gets angry about this sort of link. Bug in OS X, IMO.
@@ -578,14 +675,9 @@ describe Chef::Resource::Link do
end
context "and the link does not yet exist" do
it "links to the target file" do
- skip("OS X/FreeBSD/AIX fails to create hardlinks to broken symlinks") if os_x? || freebsd? || aix?
+ skip("OS X/FreeBSD/AIX/Solaris fails to create hardlinks to broken symlinks") if os_x? || freebsd? || aix? || solaris?
resource.run_action(:create)
- # Windows and Unix have different definitions of exists? here, and that's OK.
- if windows?
- expect(File.exists?(target_file)).to be_truthy
- else
- expect(File.exists?(target_file)).to be_falsey
- end
+ expect(File.exists?(target_file) || File.symlink?(target_file)).to be_truthy
expect(symlink?(target_file)).to be_truthy
expect(readlink(target_file)).to eq(canonicalize(@other_target))
end
@@ -604,10 +696,4 @@ describe Chef::Resource::Link do
end
end
end
-
- describe "when not supported on platform", :win2k3_only do
- it "raises error" do
- expect { resource }.to raise_error(Chef::Exceptions::Win32APIFunctionNotImplemented)
- end
- end
end
diff --git a/spec/functional/resource/mount_spec.rb b/spec/functional/resource/mount_spec.rb
index c756b0d3d4..c98d6cec25 100644
--- a/spec/functional/resource/mount_spec.rb
+++ b/spec/functional/resource/mount_spec.rb
@@ -22,7 +22,7 @@ require "chef/mixin/shell_out"
require "tmpdir"
# run this test only for following platforms.
-include_flag = !(%w{ubuntu centos aix solaris2}.include?(ohai[:platform]))
+include_flag = !(%w{debian rhel amazon aix solaris2}.include?(ohai[:platform_family]))
describe Chef::Resource::Mount, :requires_root, :skip_travis, :external => include_flag do
# Disabled in travis because it refuses to let us mount a ramdisk. /dev/ramX does not
@@ -35,15 +35,19 @@ describe Chef::Resource::Mount, :requires_root, :skip_travis, :external => inclu
def setup_device_for_mount
# use ramdisk for creating a test device for mount.
# This can cleaner if we have chef resource/provider for ramdisk.
- case ohai[:platform]
+ case ohai[:platform_family]
when "aix"
# On AIX, we can't create a ramdisk inside a WPAR, so we use
# a "namefs" mount against / to test
# https://www-304.ibm.com/support/knowledgecenter/ssw_aix_71/com.ibm.aix.performance/namefs_file_sys.htm
device = "/"
fstype = "namefs"
- when "ubuntu", "centos"
+ when "debian", "rhel", "amazon"
device = "/dev/ram1"
+ unless File.exist?(device)
+ shell_out("mknod -m 660 #{device} b 1 0")
+ shell_out("chown root:disk #{device}")
+ end
shell_out("ls -1 /dev/ram*").stdout.each_line do |d|
if shell_out("mount | grep #{d}").exitstatus == "1"
# this device is not mounted, so use it.
diff --git a/spec/functional/resource/msu_package_spec.rb b/spec/functional/resource/msu_package_spec.rb
new file mode 100644
index 0000000000..23342be6ae
--- /dev/null
+++ b/spec/functional/resource/msu_package_spec.rb
@@ -0,0 +1,84 @@
+#
+# Author:: Nimisha Sharad (<nimisha.sharad@msystechnologies.com>)
+# Copyright:: Copyright (c) 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 "chef/provider/package/cab"
+
+describe Chef::Resource::MsuPackage, :win2012r2_only do
+
+ let(:package_name) { "Package_for_KB2959977" }
+ let(:package_source) { "https://download.microsoft.com/download/3/B/3/3B320C07-B7B1-41E5-81F4-79EBC02DF7D3/Windows8.1-KB2959977-x64.msu" }
+
+ let(:new_resource) { Chef::Resource::CabPackage.new("windows_test_pkg") }
+ let(:cab_provider) do
+ node = Chef::Node.new
+ events = Chef::EventDispatch::Dispatcher.new
+ run_context = Chef::RunContext.new(node, {}, events)
+ Chef::Provider::Package::Cab.new(new_resource, run_context)
+ end
+
+ subject do
+ new_resource = Chef::Resource::MsuPackage.new("test msu package", run_context)
+ new_resource.package_name package_name
+ new_resource.source package_source
+ new_resource
+ end
+
+ context "installing package" do
+ after { remove_package }
+
+ it "installs the package successfully" do
+ subject.run_action(:install)
+ found_packages = cab_provider.installed_packages.select { |p| p["package_identity"] =~ /^#{package_name}~/ }
+ expect(found_packages.length).to be == 1
+ end
+ end
+
+ context "removing a package" do
+ it "removes an installed package" do
+ subject.run_action(:install)
+ remove_package
+ found_packages = cab_provider.installed_packages.select { |p| p["package_identity"] =~ /^#{package_name}~/ }
+ expect(found_packages.length).to be == 0
+ end
+ end
+
+ context "when an invalid msu package is given" do
+ def package_name
+ "Package_for_KB2859903"
+ end
+
+ def package_source
+ "https://download.microsoft.com/download/5/2/B/52BE95BF-22D8-4415-B644-0FDF398F6D96/IE10-Windows6.1-KB2859903-x86.msu"
+ end
+
+ it "raises error while installing" do
+ expect { subject.run_action(:install) }.to raise_error(Chef::Exceptions::Package)
+ end
+
+ it "raises error while removing" do
+ expect { subject.run_action(:remove) }.to raise_error(Chef::Exceptions::Package)
+ end
+ end
+
+ def remove_package
+ pkg_to_remove = Chef::Resource::MsuPackage.new(package_name, run_context)
+ pkg_to_remove.source = package_source
+ pkg_to_remove.run_action(:remove)
+ end
+end
diff --git a/spec/functional/resource/ohai_spec.rb b/spec/functional/resource/ohai_spec.rb
index 9ce989d8df..06bccfc398 100644
--- a/spec/functional/resource/ohai_spec.rb
+++ b/spec/functional/resource/ohai_spec.rb
@@ -19,18 +19,18 @@
require "spec_helper"
describe Chef::Resource::Ohai do
- let(:ohai) {
+ let(:ohai) do
OHAI_SYSTEM
- }
+ end
let(:node) { Chef::Node.new }
- let(:run_context) {
+ let(:run_context) do
node.default[:platform] = ohai[:platform]
node.default[:platform_version] = ohai[:platform_version]
events = Chef::EventDispatch::Dispatcher.new
Chef::RunContext.new(node, {}, events)
- }
+ end
shared_examples_for "reloaded :uptime" do
it "should reload :uptime" do
@@ -51,11 +51,11 @@ describe Chef::Resource::Ohai do
end
describe "when reloading only uptime" do
- let(:ohai_resource) {
+ let(:ohai_resource) do
r = Chef::Resource::Ohai.new("reload all", run_context)
r.plugin("uptime")
r
- }
+ end
it_behaves_like "reloaded :uptime"
end
diff --git a/spec/functional/resource/powershell_script_spec.rb b/spec/functional/resource/powershell_script_spec.rb
index af345b0ea4..bbd304fd06 100644
--- a/spec/functional/resource/powershell_script_spec.rb
+++ b/spec/functional/resource/powershell_script_spec.rb
@@ -36,8 +36,6 @@ describe Chef::Resource::WindowsScript::PowershellScript, :windows_only do
let(:cmdlet_exit_code_success_content) { "get-item ." }
let(:windows_process_exit_code_success_content) { "#{ENV['SystemRoot']}\\system32\\attrib.exe $env:systemroot" }
let(:windows_process_exit_code_not_found_content) { "findstr /notavalidswitch" }
- # Note that process exit codes on 32-bit Win2k3 cannot
- # exceed maximum value of signed integer
let(:arbitrary_nonzero_process_exit_code) { 4193 }
let(:arbitrary_nonzero_process_exit_code_content) { "exit #{arbitrary_nonzero_process_exit_code}" }
let(:invalid_powershell_interpreter_flag) { "/thisflagisinvalid" }
diff --git a/spec/functional/resource/reboot_spec.rb b/spec/functional/resource/reboot_spec.rb
index 3cf7f58e55..c264b122a7 100644
--- a/spec/functional/resource/reboot_spec.rb
+++ b/spec/functional/resource/reboot_spec.rb
@@ -80,9 +80,9 @@ describe Chef::Resource::Reboot do
it "should have modified the run context correctly" do
# this doesn't actually test the flow of Chef::Client#do_run, unfortunately.
- expect {
+ expect do
resource.run_action(:reboot_now)
- }.to throw_symbol(:end_client_run_early)
+ end.to throw_symbol(:end_client_run_early)
test_reboot_action(resource)
end
diff --git a/spec/functional/resource/registry_spec.rb b/spec/functional/resource/registry_spec.rb
index e64b6697c5..7318086034 100644
--- a/spec/functional/resource/registry_spec.rb
+++ b/spec/functional/resource/registry_spec.rb
@@ -1,7 +1,7 @@
#
# Author:: Prajakta Purohit (<prajakta@chef.io>)
# Author:: Lamont Granquist (<lamont@chef.io>)
-# Copyright:: Copyright 2011-2016, Chef Software Inc.
+# Copyright:: Copyright 2011-2018, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -112,9 +112,9 @@ describe Chef::Resource::RegistryKey, :windows_only, :broken => true do
@node.name("windowsbox")
@rest_client = double("Chef::ServerAPI (mock)")
- allow(@rest_client).to receive(:create_url).and_return("reports/nodes/windowsbox/runs/#{@run_id}");
- allow(@rest_client).to receive(:raw_http_request).and_return({ "result" => "ok" });
- allow(@rest_client).to receive(:post_rest).and_return({ "uri" => "https://example.com/reports/nodes/windowsbox/runs/#{@run_id}" });
+ allow(@rest_client).to receive(:create_url).and_return("reports/nodes/windowsbox/runs/#{@run_id}")
+ allow(@rest_client).to receive(:raw_http_request).and_return({ "result" => "ok" })
+ allow(@rest_client).to receive(:post_rest).and_return({ "uri" => "https://example.com/reports/nodes/windowsbox/runs/#{@run_id}" })
@resource_reporter = Chef::ResourceReporter.new(@rest_client)
@events.register(@resource_reporter)
@@ -124,7 +124,7 @@ describe Chef::Resource::RegistryKey, :windows_only, :broken => true do
@new_resource.cookbook_name = "monkey"
@cookbook_version = double("Cookbook::Version", :version => "1.2.3")
- allow(@new_resource).to receive(:cookbook_version).and_return(@cookbook_version)
+ @new_resource.cookbook_version(@cookbook_version)
end
after (:all) do
@@ -153,6 +153,16 @@ describe Chef::Resource::RegistryKey, :windows_only, :broken => true do
expect(@registry.data_exists?(reg_child, { :name => "Color", :type => :string, :data => "Orange" })).to eq(true)
end
+ it "does not create the key if it already exists with same value and type but datatype of data differs" do
+ @new_resource.key(reg_child)
+ @new_resource.values([{ :name => "number", :type => :dword, :data => "12345" }])
+ @new_resource.run_action(:create)
+
+ expect(@new_resource).not_to be_updated_by_last_action
+ expect(@registry.key_exists?(reg_child)).to eq(true)
+ expect(@registry.data_exists?(reg_child, { :name => "number", :type => :dword, :data => 12344 })).to eq(true)
+ end
+
it "creates a value if it does not exist" do
@new_resource.key(reg_child)
@new_resource.values([{ :name => "Mango", :type => :string, :data => "Yellow" }])
@@ -187,13 +197,37 @@ describe Chef::Resource::RegistryKey, :windows_only, :broken => true do
expect(@registry.value_exists?(reg_child + '\OpscodeTest', { :name => "Chef", :type => :multi_string, :data => %w{OpscodeOrange Rules} })).to eq(true)
end
- it "gives error if action create and parent does not exist and recursive is set to false" do
+ it "raises an error if action create and parent does not exist and recursive is set to false" do
@new_resource.key(reg_child + '\Missing1\Missing2')
@new_resource.values([{ :name => "OC", :type => :string, :data => "MissingData" }])
@new_resource.recursive(false)
expect { @new_resource.run_action(:create) }.to raise_error(Chef::Exceptions::Win32RegNoRecursive)
end
+ it "raises an error if action create and type key missing in values hash" do
+ @new_resource.key(reg_child)
+ @new_resource.values([{ :name => "OC", :data => "my_data" }])
+ expect { @new_resource.run_action(:create) }.to raise_error(Chef::Exceptions::RegKeyValuesTypeMissing)
+ end
+
+ it "raises an error if action create and data key missing in values hash" do
+ @new_resource.key(reg_child)
+ @new_resource.values([{ :name => "OC", :type => :string }])
+ expect { @new_resource.run_action(:create) }.to raise_error(Chef::Exceptions::RegKeyValuesDataMissing)
+ end
+
+ it "raises an error if action create and only name key present in values hash" do
+ @new_resource.key(reg_child)
+ @new_resource.values([{ :name => "OC" }])
+ expect { @new_resource.run_action(:create) }.to raise_error(Chef::Exceptions::RegKeyValuesTypeMissing)
+ end
+
+ it "does not raise an error if action create and all keys are present in values hash" do
+ @new_resource.key(reg_child)
+ @new_resource.values([{ :name => "OC", :type => :string, :data => "my_data" }])
+ expect { @new_resource.run_action(:create) }.to_not raise_error
+ end
+
it "creates missing keys if action create and parent does not exist and recursive is set to true" do
@new_resource.key(reg_child + '\Missing1\Missing2')
@new_resource.values([{ :name => "OC", :type => :string, :data => "MissingData" }])
@@ -210,7 +244,7 @@ describe Chef::Resource::RegistryKey, :windows_only, :broken => true do
@new_resource.recursive(true)
@new_resource.run_action(:create)
- @new_resource.values.each do |value|
+ @new_resource.each_value do |value|
expect(@registry.value_exists?(reg_child, value)).to eq(true)
end
end
@@ -260,7 +294,7 @@ describe Chef::Resource::RegistryKey, :windows_only, :broken => true do
Chef::Config[:why_run] = true
end
- it "does not throw an exception if the keys do not exist but recursive is set to false" do
+ it "does not raise an exception if the keys do not exist but recursive is set to false" do
@new_resource.key(reg_child + '\Slitheen\Raxicoricofallapatorius')
@new_resource.values([{ :name => "BriskWalk", :type => :string, :data => "is good for health" }])
@new_resource.recursive(false)
@@ -268,6 +302,7 @@ describe Chef::Resource::RegistryKey, :windows_only, :broken => true do
expect(@registry.key_exists?(reg_child + '\Slitheen')).to eq(false)
expect(@registry.key_exists?(reg_child + '\Slitheen\Raxicoricofallapatorius')).to eq(false)
end
+
it "does not create key if the action is create" do
@new_resource.key(reg_child + '\Slitheen')
@new_resource.values([{ :name => "BriskWalk", :type => :string, :data => "is good for health" }])
@@ -275,6 +310,34 @@ describe Chef::Resource::RegistryKey, :windows_only, :broken => true do
@new_resource.run_action(:create)
expect(@registry.key_exists?(reg_child + '\Slitheen')).to eq(false)
end
+
+ it "does not raise an exception if the action create and type key missing in values hash" do
+ @new_resource.key(reg_child + '\Slitheen')
+ @new_resource.values([{ :name => "BriskWalk", :data => "my_data" }])
+ @new_resource.run_action(:create) # should not raise_error
+ expect(@registry.key_exists?(reg_child + '\Slitheen')).to eq(false)
+ end
+
+ it "does not raise an exception if the action create and data key missing in values hash" do
+ @new_resource.key(reg_child + '\Slitheen')
+ @new_resource.values([{ :name => "BriskWalk", :type => :string }])
+ @new_resource.run_action(:create) # should not raise_error
+ expect(@registry.key_exists?(reg_child + '\Slitheen')).to eq(false)
+ end
+
+ it "does not raise an exception if the action create and only name key present in values hash" do
+ @new_resource.key(reg_child + '\Slitheen')
+ @new_resource.values([{ :name => "BriskWalk" }])
+ @new_resource.run_action(:create) # should not raise_error
+ expect(@registry.key_exists?(reg_child + '\Slitheen')).to eq(false)
+ end
+
+ it "does not raise an exception if the action create and all keys are present in values hash" do
+ @new_resource.key(reg_child + '\Slitheen')
+ @new_resource.values([{ :name => "BriskWalk", :type => :string, :data => "my_data" }])
+ @new_resource.run_action(:create) # should not raise_error
+ expect(@registry.key_exists?(reg_child + '\Slitheen')).to eq(false)
+ end
end
end
@@ -320,13 +383,37 @@ describe Chef::Resource::RegistryKey, :windows_only, :broken => true do
expect(@registry.value_exists?(reg_child + '\Pyrovile', { :name => "Chef", :type => :multi_string, :data => %w{OpscodeOrange Rules} })).to eq(true)
end
- it "gives error if action create and parent does not exist and recursive is set to false" do
+ it "raises an error if action create and parent does not exist and recursive is set to false" do
@new_resource.key(reg_child + '\Sontaran\Sontar')
@new_resource.values([{ :name => "OC", :type => :string, :data => "MissingData" }])
@new_resource.recursive(false)
expect { @new_resource.run_action(:create_if_missing) }.to raise_error(Chef::Exceptions::Win32RegNoRecursive)
end
+ it "raises an error if action create_if_missing and type key missing in values hash" do
+ @new_resource.key(reg_child)
+ @new_resource.values([{ :name => "OC", :data => "my_data" }])
+ expect { @new_resource.run_action(:create_if_missing) }.to raise_error(Chef::Exceptions::RegKeyValuesTypeMissing)
+ end
+
+ it "raises an error if action create_if_missing and data key missing in values hash" do
+ @new_resource.key(reg_child)
+ @new_resource.values([{ :name => "OC", :type => :string }])
+ expect { @new_resource.run_action(:create_if_missing) }.to raise_error(Chef::Exceptions::RegKeyValuesDataMissing)
+ end
+
+ it "raises an error if action create_if_missing and only name key present in values hash" do
+ @new_resource.key(reg_child)
+ @new_resource.values([{ :name => "OC" }])
+ expect { @new_resource.run_action(:create_if_missing) }.to raise_error(Chef::Exceptions::RegKeyValuesTypeMissing)
+ end
+
+ it "does not raise an error if action create_if_missing and all keys are present in values hash" do
+ @new_resource.key(reg_child)
+ @new_resource.values([{ :name => "OC", :type => :string, :data => "my_data" }])
+ expect { @new_resource.run_action(:create_if_missing) }.to_not raise_error
+ end
+
it "creates missing keys if action create and parent does not exist and recursive is set to true" do
@new_resource.key(reg_child + '\Sontaran\Sontar')
@new_resource.values([{ :name => "OC", :type => :string, :data => "MissingData" }])
@@ -343,7 +430,7 @@ describe Chef::Resource::RegistryKey, :windows_only, :broken => true do
@new_resource.recursive(true)
@new_resource.run_action(:create_if_missing)
- @new_resource.values.each do |value|
+ @new_resource.each_value do |value|
expect(@registry.value_exists?(reg_child + '\Adipose', value)).to eq(true)
end
end
@@ -371,7 +458,7 @@ describe Chef::Resource::RegistryKey, :windows_only, :broken => true do
Chef::Config[:why_run] = true
end
- it "does not throw an exception if the keys do not exist but recursive is set to false" do
+ it "does not raise an exception if the keys do not exist but recursive is set to false" do
@new_resource.key(reg_child + '\Zygons\Zygor')
@new_resource.values([{ :name => "BriskWalk", :type => :string, :data => "is good for health" }])
@new_resource.recursive(false)
@@ -379,6 +466,7 @@ describe Chef::Resource::RegistryKey, :windows_only, :broken => true do
expect(@registry.key_exists?(reg_child + '\Zygons')).to eq(false)
expect(@registry.key_exists?(reg_child + '\Zygons\Zygor')).to eq(false)
end
+
it "does nothing if the action is create_if_missing" do
@new_resource.key(reg_child + '\Zygons')
@new_resource.values([{ :name => "BriskWalk", :type => :string, :data => "is good for health" }])
@@ -386,6 +474,34 @@ describe Chef::Resource::RegistryKey, :windows_only, :broken => true do
@new_resource.run_action(:create_if_missing)
expect(@registry.key_exists?(reg_child + '\Zygons')).to eq(false)
end
+
+ it "does not raise an exception if the action create_if_missing and type key missing in values hash" do
+ @new_resource.key(reg_child + '\Zygons')
+ @new_resource.values([{ :name => "BriskWalk", :data => "my_data" }])
+ @new_resource.run_action(:create_if_missing) # should not raise_error
+ expect(@registry.key_exists?(reg_child + '\Zygons')).to eq(false)
+ end
+
+ it "does not raise an exception if the action create_if_missing and data key missing in values hash" do
+ @new_resource.key(reg_child + '\Zygons')
+ @new_resource.values([{ :name => "BriskWalk", :type => :string }])
+ @new_resource.run_action(:create_if_missing) # should not raise_error
+ expect(@registry.key_exists?(reg_child + '\Zygons')).to eq(false)
+ end
+
+ it "does not raise an exception if the action create_if_missing and only name key present in values hash" do
+ @new_resource.key(reg_child + '\Zygons')
+ @new_resource.values([{ :name => "BriskWalk" }])
+ @new_resource.run_action(:create_if_missing) # should not raise_error
+ expect(@registry.key_exists?(reg_child + '\Zygons')).to eq(false)
+ end
+
+ it "does not raise an exception if the action create_if_missing and all keys are present in values hash" do
+ @new_resource.key(reg_child + '\Zygons')
+ @new_resource.values([{ :name => "BriskWalk", :type => :string, :data => "my_data" }])
+ @new_resource.run_action(:create_if_missing) # should not raise_error
+ expect(@registry.key_exists?(reg_child + '\Zygons')).to eq(false)
+ end
end
end
diff --git a/spec/functional/resource/remote_file_spec.rb b/spec/functional/resource/remote_file_spec.rb
index b394bd0240..8e484b2968 100644
--- a/spec/functional/resource/remote_file_spec.rb
+++ b/spec/functional/resource/remote_file_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Seth Chisamore (<schisamo@chef.io>)
-# Copyright:: Copyright 2011-2016, Chef Software Inc.
+# Copyright:: Copyright 2011-2018, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -28,6 +28,9 @@ describe Chef::Resource::RemoteFile do
before(:each) do
@old_file_cache = Chef::Config[:file_cache_path]
Chef::Config[:file_cache_path] = file_cache_path
+ Chef::Config[:rest_timeout] = 2
+ Chef::Config[:http_retry_delay] = 0
+ Chef::Config[:http_retry_count] = 0
end
after(:each) do
@@ -56,7 +59,7 @@ describe Chef::Resource::RemoteFile do
context "when fetching files over HTTP" do
before(:all) do
- start_tiny_server
+ start_tiny_server(RequestTimeout: 1)
end
after(:all) do
@@ -103,10 +106,11 @@ describe Chef::Resource::RemoteFile do
key_text = File.read(File.expand_path("ssl/chef-rspec.key", CHEF_SPEC_DATA))
key = OpenSSL::PKey::RSA.new(key_text)
- server_opts = { :SSLEnable => true,
- :SSLVerifyClient => OpenSSL::SSL::VERIFY_NONE,
- :SSLCertificate => cert,
- :SSLPrivateKey => key }
+ server_opts = { SSLEnable: true,
+ SSLVerifyClient: OpenSSL::SSL::VERIFY_NONE,
+ SSLCertificate: cert,
+ SSLPrivateKey: key,
+ RequestTimeout: 1 }
start_tiny_server(server_opts)
end
@@ -123,9 +127,180 @@ describe Chef::Resource::RemoteFile do
end
+ context "when running on Windows", :windows_only do
+ describe "when fetching files over SMB" do
+ include Chef::Mixin::ShellOut
+ let(:smb_share_root_directory) { directory = File.join(Dir.tmpdir, make_tmpname("windows_script_test")); Dir.mkdir(directory); directory }
+ let(:smb_file_local_file_name) { "smb_file.txt" }
+ let(:smb_file_local_path) { File.join( smb_share_root_directory, smb_file_local_file_name ) }
+ let(:smb_share_name) { "chef_smb_test" }
+ let(:smb_remote_path) { File.join("//#{ENV['COMPUTERNAME']}", smb_share_name, smb_file_local_file_name).gsub(/\//, "\\") }
+ let(:smb_file_content) { "hellofun" }
+ let(:local_destination_path) { File.join(Dir.tmpdir, make_tmpname("chef_remote_file")) }
+ let(:windows_current_user) { ENV["USERNAME"] }
+ let(:windows_current_user_domain) { ENV["USERDOMAIN"] || ENV["COMPUTERNAME"] }
+ let(:windows_current_user_qualified) { "#{windows_current_user_domain}\\#{windows_current_user}" }
+
+ let(:remote_domain) { nil }
+ let(:remote_user) { nil }
+ let(:remote_password) { nil }
+
+ let(:resource) do
+ node = Chef::Node.new
+ events = Chef::EventDispatch::Dispatcher.new
+ run_context = Chef::RunContext.new(node, {}, events)
+ resource = Chef::Resource::RemoteFile.new(path, run_context)
+ end
+
+ before do
+ shell_out("net.exe share #{smb_share_name} /delete")
+ File.write(smb_file_local_path, smb_file_content )
+ shell_out!("net.exe share #{smb_share_name}=\"#{smb_share_root_directory.gsub(/\//, '\\')}\" /grant:\"authenticated users\",read")
+ end
+
+ after do
+ shell_out("net.exe share #{smb_share_name} /delete")
+ File.delete(smb_file_local_path) if File.exist?(smb_file_local_path)
+ File.delete(local_destination_path) if File.exist?(local_destination_path)
+ Dir.rmdir(smb_share_root_directory)
+ end
+
+ context "when configuring the Windows identity used to access the remote file" do
+ before do
+ resource.path(local_destination_path)
+ resource.source(smb_remote_path)
+ resource.remote_domain(remote_domain)
+ resource.remote_user(remote_user)
+ resource.remote_password(remote_password)
+ resource.node.default["platform_family"] = "windows"
+ allow_any_instance_of(Chef::Provider::RemoteFile::NetworkFile).to receive(:node).and_return({ "platform_family" => "windows" })
+ end
+
+ shared_examples_for "a remote_file resource accessing a remote file to which the specified user has access" do
+ it "has the same content as the original file" do
+ expect { resource.run_action(:create) }.not_to raise_error
+ expect(::File.read(local_destination_path).chomp).to eq smb_file_content
+ end
+ end
+
+ shared_examples_for "a remote_file resource accessing a remote file to which the specified user does not have access" do
+ it "causes an error to be raised" do
+ expect { resource.run_action(:create) }.to raise_error(Errno::EACCES)
+ end
+ end
+
+ shared_examples_for "a remote_file resource accessing a remote file with invalid user" do
+ it "causes an error to be raised" do
+ allow(Chef::Util::Windows::LogonSession).to receive(:validate_session_open!).and_return(true)
+ expect { resource.run_action(:create) }.to raise_error(Chef::Exceptions::Win32APIError)
+ end
+ end
+
+ context "when the file is accessible to non-admin users only as the current identity" do
+ before do
+ shell_out!("icacls #{smb_file_local_path} /grant:r \"authenticated users:(W)\" /grant \"#{windows_current_user_qualified}:(R)\" /inheritance:r")
+ end
+
+ context "when the resource is accessed using the current user's identity" do
+ let(:remote_user) { nil }
+ let(:remote_domain) { nil }
+ let(:remote_password) { nil }
+
+ it_behaves_like "a remote_file resource accessing a remote file to which the specified user has access"
+
+ describe "uses the ::Chef::Provider::RemoteFile::NetworkFile::TRANSFER_CHUNK_SIZE constant to chunk the file" do
+ let(:invalid_chunk_size) { -1 }
+ before do
+ stub_const("::Chef::Provider::RemoteFile::NetworkFile::TRANSFER_CHUNK_SIZE", invalid_chunk_size)
+ end
+
+ it "raises an ArgumentError when the chunk size is negative" do
+ expect(::Chef::Provider::RemoteFile::NetworkFile::TRANSFER_CHUNK_SIZE).to eq(invalid_chunk_size)
+ expect { resource.run_action(:create) }.to raise_error(ArgumentError)
+ end
+ end
+
+ context "when the file must be transferred in more than one chunk" do
+ before do
+ stub_const("::Chef::Provider::RemoteFile::NetworkFile::TRANSFER_CHUNK_SIZE", 3)
+ end
+ it_behaves_like "a remote_file resource accessing a remote file to which the specified user has access"
+ end
+ end
+
+ context "when the resource is accessed using an alternate user's identity with no access to the file" do
+ let (:windows_nonadmin_user) { "chefremfile1" }
+ let (:windows_nonadmin_user_password) { "j82ajfxK3;2Xe1" }
+ include_context "a non-admin Windows user"
+
+ before do
+ shell_out!("icacls #{smb_file_local_path} /grant:r \"authenticated users:(W)\" /deny \"#{windows_current_user_qualified}:(R)\" /inheritance:r")
+ end
+
+ let(:remote_user) { windows_nonadmin_user }
+ let(:remote_domain) { windows_nonadmin_user_domain }
+ let(:remote_password) { windows_nonadmin_user_password }
+
+ it_behaves_like "a remote_file resource accessing a remote file to which the specified user does not have access"
+ end
+ end
+
+ context "when the the file is only accessible as a specific alternate identity" do
+ let (:windows_nonadmin_user) { "chefremfile2" }
+ let (:windows_nonadmin_user_password) { "j82ajfxK3;2Xe2" }
+ include_context "a non-admin Windows user"
+
+ before do
+ shell_out!("icacls #{smb_file_local_path} /grant:r \"authenticated users:(W)\" /grant \"#{windows_current_user_qualified}:(R)\" /inheritance:r")
+ end
+
+ context "when the resource is accessed using the specific non-qualified alternate user identity with access" do
+ let(:remote_user) { windows_nonadmin_user }
+ let(:remote_domain) { "." }
+ let(:remote_password) { windows_nonadmin_user_password }
+
+ it_behaves_like "a remote_file resource accessing a remote file to which the specified user has access"
+ end
+
+ context "when the resource is accessed using the specific alternate user identity with access and the domain is specified" do
+ let(:remote_user) { windows_nonadmin_user }
+ let(:remote_domain) { windows_nonadmin_user_domain }
+ let(:remote_password) { windows_nonadmin_user_password }
+
+ it_behaves_like "a remote_file resource accessing a remote file to which the specified user has access"
+ end
+
+ context "when the resource is accessed using the current user's identity" do
+ before do
+ shell_out!("icacls #{smb_file_local_path} /grant:r \"authenticated users:(W)\" /grant \"#{windows_nonadmin_user_qualified}:(R)\" /deny #{windows_current_user_qualified}:(R) /inheritance:r")
+ end
+
+ it_behaves_like "a remote_file resource accessing a remote file to which the specified user does not have access"
+ end
+
+ context "when the resource is accessed using an alternate user's identity with no access to the file" do
+ let (:windows_nonadmin_user) { "chefremfile3" }
+ let (:windows_nonadmin_user_password) { "j82ajfxK3;2Xe3" }
+ include_context "a non-admin Windows user"
+
+ let(:remote_user) { windows_nonadmin_user_qualified }
+ let(:remote_domain) { nil }
+ let(:remote_password) { windows_nonadmin_user_password }
+
+ before do
+ allow_any_instance_of(Chef::Util::Windows::LogonSession).to receive(:validate_session_open!).and_return(true)
+ end
+
+ it_behaves_like "a remote_file resource accessing a remote file with invalid user"
+ end
+ end
+ end
+ end
+ end
+
context "when dealing with content length checking" do
before(:all) do
- start_tiny_server
+ start_tiny_server(RequestTimeout: 1)
end
after(:all) do
@@ -232,7 +407,16 @@ describe Chef::Resource::RemoteFile do
end
it "should not create the file" do
- expect { resource.run_action(:create) }.to raise_error
+ # This can legitimately raise either Errno::EADDRNOTAVAIL or Errno::ECONNREFUSED
+ # in different Ruby versions.
+ old_value = RSpec::Expectations.configuration.on_potential_false_positives
+ RSpec::Expectations.configuration.on_potential_false_positives = :nothing
+ begin
+ expect { resource.run_action(:create) }.to raise_error
+ ensure
+ RSpec::Expectations.configuration.on_potential_false_positives = old_value
+ end
+
expect(File).not_to exist(path)
end
end
diff --git a/spec/functional/resource/rpm_spec.rb b/spec/functional/resource/rpm_spec.rb
index ce9332e4ed..17d0bf9e3c 100644
--- a/spec/functional/resource/rpm_spec.rb
+++ b/spec/functional/resource/rpm_spec.rb
@@ -21,7 +21,7 @@ require "functional/resource/base"
require "chef/mixin/shell_out"
# run this test only for following platforms.
-exclude_test = !%w{aix centos redhat suse}.include?(ohai[:platform])
+exclude_test = !%w{aix rhel fedora suse}.include?(ohai[:platform_family])
describe Chef::Resource::RpmPackage, :requires_root, :external => exclude_test do
include Chef::Mixin::ShellOut
@@ -32,37 +32,34 @@ describe Chef::Resource::RpmPackage, :requires_root, :external => exclude_test d
end
def rpm_pkg_should_be_installed(resource)
- case ohai[:platform]
# Due to dependency issues , different rpm pkgs are used in different platforms.
# dummy rpm package works in aix, without any dependency issues.
- when "aix"
+ if ohai[:platform] == "aix"
expect(shell_out("rpm -qa | grep dummy").exitstatus).to eq(0)
# mytest rpm package works in centos, redhat and in suse without any dependency issues.
- when "centos", "redhat", "suse"
+ else
expect(shell_out("rpm -qa | grep mytest").exitstatus).to eq(0)
::File.exists?("/opt/mytest/mytest.sh") # The mytest rpm package contains the mytest.sh file
end
end
def rpm_pkg_should_not_be_installed(resource)
- case ohai[:platform]
- when "aix"
+ if ohai[:platform] == "aix"
expect(shell_out("rpm -qa | grep dummy").exitstatus).to eq(1)
- when "centos", "redhat", "suse"
+ else
expect(shell_out("rpm -qa | grep mytest").exitstatus).to eq(1)
!::File.exists?("/opt/mytest/mytest.sh")
end
end
before(:all) do
- case ohai[:platform]
# Due to dependency issues , different rpm pkgs are used in different platforms.
- when "aix"
+ if ohai[:platform] == "aix"
@pkg_name = "dummy"
@pkg_version = "1-0"
@pkg_path = "#{Dir.tmpdir}/dummy-1-0.aix6.1.noarch.rpm"
FileUtils.cp(File.join(CHEF_SPEC_ASSETS, "dummy-1-0.aix6.1.noarch.rpm") , @pkg_path)
- when "centos", "redhat", "suse"
+ else
@pkg_name = "mytest"
@pkg_version = "1.0-1"
@pkg_path = "#{Dir.tmpdir}/mytest-1.0-1.noarch.rpm"
diff --git a/spec/functional/resource/template_spec.rb b/spec/functional/resource/template_spec.rb
index f270043f2c..b9a39255f4 100644
--- a/spec/functional/resource/template_spec.rb
+++ b/spec/functional/resource/template_spec.rb
@@ -32,6 +32,7 @@ describe Chef::Resource::Template do
let(:node) do
node = Chef::Node.new
node.normal[:slappiness] = "a warm gun"
+ node.normal[:nested][:secret] = "value"
node
end
@@ -110,7 +111,7 @@ describe Chef::Resource::Template do
context "using single helper syntax referencing @node" do
before do
- node.set[:helper_test_attr] = "value from helper method"
+ node.normal[:helper_test_attr] = "value from helper method"
resource.helper(:helper_method) { "#{@node[:helper_test_attr]}" }
end
@@ -131,7 +132,7 @@ describe Chef::Resource::Template do
context "using an inline block referencing @node" do
before do
- node.set[:helper_test_attr] = "value from helper method"
+ node.normal[:helper_test_attr] = "value from helper method"
resource.helpers do
def helper_method
@@ -168,7 +169,7 @@ describe Chef::Resource::Template do
end
before do
- node.set[:helper_test_attr] = "value from helper method"
+ node.normal[:helper_test_attr] = "value from helper method"
resource.helpers(ExampleModuleReferencingATNode)
end
@@ -209,4 +210,36 @@ describe Chef::Resource::Template do
end
end
+ describe "when template variables contain lazy{} calls" do
+ it "resolves the DelayedEvaluator" do
+ resource.source("openldap_variable_stuff.conf.erb")
+ resource.variables(:secret => Chef::DelayedEvaluator.new { "nutella" })
+ resource.run_action(:create)
+ expect(IO.read(path)).to eq("super secret is nutella")
+ end
+
+ it "does not mutate the resource variables" do
+ resource.source("openldap_variable_stuff.conf.erb")
+ resource.variables(:secret => Chef::DelayedEvaluator.new { "nutella" })
+ resource.run_action(:create)
+ expect(resource.variables[:secret]).to be_a Chef::DelayedEvaluator
+ end
+
+ it "resolves the DelayedEvaluator when deeply nested" do
+ resource.source("openldap_nested_variable_stuff.erb")
+ resource.variables(:secret => [{ "key" => Chef::DelayedEvaluator.new { "nutella" } }])
+ resource.run_action(:create)
+ expect(IO.read(path)).to eq("super secret is nutella")
+ end
+ end
+
+ describe "when passing a node attribute mash as a template variable" do
+ it "uses the node attributes like a hash" do
+ resource.source("openldap_variable_stuff.conf.erb")
+ resource.variables(node[:nested])
+ resource.run_action(:create)
+ expect(IO.read(path)).to eq("super secret is value")
+ end
+ end
+
end
diff --git a/spec/functional/resource/user/dscl_spec.rb b/spec/functional/resource/user/dscl_spec.rb
index 5d904a980b..ed96e31bac 100644
--- a/spec/functional/resource/user/dscl_spec.rb
+++ b/spec/functional/resource/user/dscl_spec.rb
@@ -28,11 +28,9 @@ describe "Chef::Resource::User with Chef::Provider::User::Dscl provider", metada
include Chef::Mixin::ShellOut
def clean_user
- begin
- shell_out!("/usr/bin/dscl . -delete '/Users/#{username}'")
- rescue Mixlib::ShellOut::ShellCommandFailed
+ shell_out!("/usr/bin/dscl . -delete '/Users/#{username}'")
+ rescue Mixlib::ShellOut::ShellCommandFailed
# Raised when the user is already cleaned
- end
end
def user_should_exist
@@ -76,7 +74,7 @@ describe "Chef::Resource::User with Chef::Provider::User::Dscl provider", metada
let(:iterations) { nil }
let(:user_resource) do
- r = Chef::Resource::User.new("TEST USER RESOURCE", run_context)
+ r = Chef::Resource::User::DsclUser.new("TEST USER RESOURCE", run_context)
r.username(username)
r.uid(uid)
r.gid(gid)
@@ -123,7 +121,7 @@ describe "Chef::Resource::User with Chef::Provider::User::Dscl provider", metada
end
describe "when password is being set via shadow hash" do
- let(:password) {
+ let(:password) do
if node[:platform_version].start_with?("10.7.")
# On Mac 10.7 we only need to set the password
"c9b3bd1a0cde797eef0eff16c580dab996ba3a21961cccc\
@@ -139,7 +137,7 @@ b1d4880833aa7a190afc13e2bf0936b8\
c5adbbac718b7eb99463a7b679571e0f\
1c9fef2ef08d0b9e9c2bcf644eed2ffc"
end
- }
+ end
let(:iterations) { 25000 }
let(:salt) { "9e2e7d5ee473b496fd24cf0bbfcaedfcb291ee21740e570d1e917e874f8788ca" }
diff --git a/spec/functional/resource/user/useradd_spec.rb b/spec/functional/resource/user/useradd_spec.rb
index 43c26ac006..175809b5c0 100644
--- a/spec/functional/resource/user/useradd_spec.rb
+++ b/spec/functional/resource/user/useradd_spec.rb
@@ -21,19 +21,26 @@ require "spec_helper"
require "functional/resource/base"
require "chef/mixin/shell_out"
-def user_provider_for_platform
- case ohai[:platform]
+def resource_for_platform(username, run_context)
+ Chef::Resource.resource_for_node(:user, node).new(username, run_context)
+end
+
+# ideally we could somehow pass an array of [ ...::Aix, ...::Linux ] to the
+# filter, but we have to pick the right one for the O/S.
+def user_provider_filter
+ case ohai[:os]
when "aix"
Chef::Provider::User::Aix
- else
- Chef::Provider::User::Useradd
+ when "linux"
+ Chef::Provider::User::Linux
end
end
-metadata = { :unix_only => true,
- :requires_root => true,
- :not_supported_on_mac_osx => true,
- :provider => { :user => user_provider_for_platform },
+metadata = {
+ :unix_only => true,
+ :requires_root => true,
+ :not_supported_on_mac_osx => true,
+ :provider => { :user => user_provider_filter },
}
describe Chef::Provider::User::Useradd, metadata do
@@ -81,12 +88,13 @@ describe Chef::Provider::User::Useradd, metadata do
end
def try_cleanup
- ["/home/cheftestfoo", "/home/cheftestbar"].each do |f|
+ ["/home/cheftestfoo", "/home/cheftestbar", "/home/cf-test"].each do |f|
FileUtils.rm_rf(f) if File.exists? f
end
["cf-test"].each do |u|
- r = Chef::Resource::User.new("DELETE USER", run_context)
+ r = resource_for_platform("DELETE USER", run_context)
+ r.manage_home true
r.username("cf-test")
r.run_action(:remove)
end
@@ -111,7 +119,7 @@ describe Chef::Provider::User::Useradd, metadata do
break if status.exitstatus != 8
sleep 1
- max_retries = max_retries - 1
+ max_retries -= 1
rescue UserNotFound
break
end
@@ -134,10 +142,7 @@ describe Chef::Provider::User::Useradd, metadata do
Chef::RunContext.new(node, {}, events)
end
- let(:username) do
- "cf-test"
- end
-
+ let(:username) { "cf-test" }
let(:uid) { nil }
let(:home) { nil }
let(:manage_home) { false }
@@ -146,7 +151,7 @@ describe Chef::Provider::User::Useradd, metadata do
let(:comment) { nil }
let(:user_resource) do
- r = Chef::Resource::User.new("TEST USER RESOURCE", run_context)
+ r = resource_for_platform("TEST USER RESOURCE", run_context)
r.username(username)
r.uid(uid)
r.home(home)
@@ -242,15 +247,8 @@ describe Chef::Provider::User::Useradd, metadata do
expect(pw_entry.home).to eq(home)
end
- if %w{rhel fedora wrlinux}.include?(OHAI_SYSTEM["platform_family"])
- # Inconsistent behavior. See: CHEF-2205
- it "creates the home dir when not explicitly asked to on RHEL (XXX)" do
- expect(File).to exist(home)
- end
- else
- it "does not create the home dir without `manage_home'" do
- expect(File).not_to exist(home)
- end
+ it "does not create the home dir without `manage_home'" do
+ expect(File).not_to exist(home)
end
context "and manage_home is enabled" do
@@ -260,6 +258,14 @@ describe Chef::Provider::User::Useradd, metadata do
expect(File).to exist(home)
end
end
+
+ context "and manage_home is the default" do
+ let(:manage_home) { nil }
+
+ it "does not create the home dir without `manage_home'" do
+ expect(File).not_to exist(home)
+ end
+ end
end
context "when a password is specified" do
@@ -310,8 +316,8 @@ describe Chef::Provider::User::Useradd, metadata do
let(:existing_comment) { nil }
let(:existing_user) do
- r = Chef::Resource::User.new("TEST USER RESOURCE", run_context)
- # username is identity attr, must match.
+ r = resource_for_platform("TEST USER RESOURCE", run_context)
+ # username is identity attr, must match.
r.username(username)
r.uid(existing_uid)
r.home(existing_home)
@@ -631,12 +637,23 @@ describe Chef::Provider::User::Useradd, metadata do
context "and has no password" do
# TODO: platform_family should be setup in spec_helper w/ tags
- if %w{suse opensuse}.include?(OHAI_SYSTEM["platform_family"])
- # suse gets this right:
+ if %w{opensuse}.include?(OHAI_SYSTEM["platform_family"]) ||
+ (%w{suse}.include?(OHAI_SYSTEM["platform_family"]) &&
+ OHAI_SYSTEM["platform_version"].to_f < 12.0)
+ # suse 11.x gets this right:
it "errors out trying to unlock the user" do
expect(@error).to be_a(Mixlib::ShellOut::ShellCommandFailed)
expect(@error.message).to include("Cannot unlock the password")
end
+ elsif %w{rhel}.include?(OHAI_SYSTEM["platform_family"]) &&
+ (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")
+ end
else
# borked on all other platforms:
diff --git a/spec/functional/resource/user/windows_spec.rb b/spec/functional/resource/user/windows_spec.rb
index f61a51c636..56ae962ee4 100644
--- a/spec/functional/resource/user/windows_spec.rb
+++ b/spec/functional/resource/user/windows_spec.rb
@@ -31,6 +31,7 @@ describe Chef::Provider::User::Windows, :windows_only do
end
let(:events) { Chef::EventDispatch::Dispatcher.new }
+ let(:logger) { double("Mixlib::Log::Child").as_null_object }
let(:run_context) { Chef::RunContext.new(node, {}, events) }
let(:new_resource) do
Chef::Resource::User.new(username, run_context).tap do |r|
@@ -45,6 +46,7 @@ describe Chef::Provider::User::Windows, :windows_only do
before do
delete_user(username)
+ allow(run_context).to receive(:logger).and_return(logger)
end
describe "action :create" do
@@ -69,7 +71,7 @@ describe Chef::Provider::User::Windows, :windows_only do
context "with a gid specified" do
it "warns unsupported" do
- expect(Chef::Log).to receive(:warn).with(/not implemented/)
+ expect(logger).to receive(:warn).with(/not implemented/)
new_resource.gid("agroup")
new_resource.run_action(:create)
end
diff --git a/spec/functional/resource/windows_env_spec.rb b/spec/functional/resource/windows_env_spec.rb
new file mode 100644
index 0000000000..a6c6b39970
--- /dev/null
+++ b/spec/functional/resource/windows_env_spec.rb
@@ -0,0 +1,285 @@
+#
+# Author:: Adam Edwards (<adamed@chef.io>)
+# 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"
+
+describe Chef::Resource::WindowsEnv, :windows_only do
+ context "when running on Windows" do
+ let(:chef_env_test_lower_case) { "chefenvtest" }
+ let(:chef_env_test_mixed_case) { "chefENVtest" }
+ let(:chef_env_with_delim) { "chef_env_with_delim" }
+ let(:chef_env_delim) { ";" }
+ let(:chef_env_test_delim) { "#{value1};#{value2}" }
+ let(:env_dne_key) { "env_dne_key" }
+ let(:env_value1) { "value1" }
+ let(:env_value2) { "value2" }
+ let(:delim_value) { "#{env_value1};#{env_value2}" }
+ let(:env_user) { ENV["USERNAME"].upcase }
+ let(:default_env_user) { "<SYSTEM>" }
+
+ let(:env_obj) do
+ wmi = WmiLite::Wmi.new
+ environment_variables = wmi.query("select * from Win32_Environment where name = '#{test_resource.key_name}'")
+ if environment_variables && environment_variables.length > 0
+ environment_variables.each do |env|
+ env_obj = env.wmi_ole_object
+ return env_obj if env_obj.username.split('\\').last.casecmp(test_resource.user) == 0
+ end
+ end
+ nil
+ end
+
+ let(:env_value_expandable) { "%SystemRoot%" }
+ let(:test_run_context) do
+ node = Chef::Node.new
+ node.default["os"] = "windows"
+ node.default["platform"] = "windows"
+ node.default["platform_version"] = "6.1"
+ empty_events = Chef::EventDispatch::Dispatcher.new
+ Chef::RunContext.new(node, {}, empty_events)
+ end
+ let(:test_resource) do
+ Chef::Resource::WindowsEnv.new("unknown", test_run_context)
+ end
+
+ before(:each) do
+ resource_lower = Chef::Resource::WindowsEnv.new(chef_env_test_lower_case, test_run_context)
+ resource_lower.run_action(:delete)
+ resource_lower = Chef::Resource::WindowsEnv.new(chef_env_test_lower_case, test_run_context)
+ resource_lower.user(env_user)
+ resource_lower.run_action(:delete)
+ resource_mixed = Chef::Resource::WindowsEnv.new(chef_env_test_mixed_case, test_run_context)
+ resource_mixed.run_action(:delete)
+ resource_mixed = Chef::Resource::WindowsEnv.new(chef_env_test_mixed_case, test_run_context)
+ resource_lower.user(env_user)
+ resource_mixed.run_action(:delete)
+ end
+
+ context "when the create action is invoked" do
+ it "should create an environment variable for action create" do
+ expect(ENV[chef_env_test_lower_case]).to eq(nil)
+ test_resource.key_name(chef_env_test_lower_case)
+ test_resource.value(env_value1)
+ test_resource.run_action(:create)
+ expect(ENV[chef_env_test_lower_case]).to eq(env_value1)
+ end
+
+ it "should create an environment variable with default user System for action create" do
+ expect(ENV[chef_env_test_lower_case]).to eq(nil)
+ test_resource.key_name(chef_env_test_lower_case)
+ test_resource.value(env_value1)
+ test_resource.run_action(:create)
+ expect(env_obj.username.upcase).to eq(default_env_user)
+ end
+
+ it "should create an environment variable with user for action create" do
+ expect(ENV[chef_env_test_lower_case]).to eq(nil)
+ test_resource.key_name(chef_env_test_lower_case)
+ test_resource.value(env_value1)
+ test_resource.user(env_user)
+ test_resource.run_action(:create)
+ expect(env_obj.username.split('\\').last.upcase).to eq(env_user)
+ end
+
+ context "when env variable exist with same name" do
+ before(:each) do
+ test_resource.key_name(chef_env_test_lower_case)
+ test_resource.value(env_value1)
+ test_resource.run_action(:create)
+ end
+ it "should modify an existing variable's value to a new value" do
+ expect(ENV[chef_env_test_lower_case]).to eq(env_value1)
+ test_resource.value(env_value2)
+ test_resource.run_action(:create)
+ expect(ENV[chef_env_test_lower_case]).to eq(env_value2)
+ end
+
+ it "should not modify an existing variable's value to a new value if the users are different" do
+ expect(ENV[chef_env_test_lower_case]).to eq(env_value1)
+ test_resource.value(env_value2)
+ test_resource.user(env_user)
+ test_resource.run_action(:create)
+ test_resource.key_name(chef_env_test_lower_case)
+ test_resource.user(default_env_user)
+ expect(env_obj.variablevalue).to eq(env_value1)
+ end
+
+ it "should modify an existing variable's value to a new value if the variable name case differs from the existing variable" do
+ expect(ENV[chef_env_test_lower_case]).to eq(env_value1)
+ test_resource.key_name(chef_env_test_mixed_case)
+ test_resource.value(env_value2)
+ test_resource.run_action(:create)
+ expect(ENV[chef_env_test_lower_case]).to eq(env_value2)
+ end
+ end
+
+ it "should not expand environment variables if the variable is not PATH" do
+ expect(ENV[chef_env_test_lower_case]).to eq(nil)
+ test_resource.key_name(chef_env_test_lower_case)
+ test_resource.value(env_value_expandable)
+ test_resource.run_action(:create)
+ expect(ENV[chef_env_test_lower_case]).to eq(env_value_expandable)
+ end
+ end
+
+ context "when the modify action is invoked" do
+ it "should raise an exception for modify if the variable doesn't exist" do
+ expect(ENV[chef_env_test_lower_case]).to eq(nil)
+ test_resource.key_name(chef_env_test_lower_case)
+ test_resource.value(env_value1)
+ expect { test_resource.run_action(:modify) }.to raise_error(Chef::Exceptions::WindowsEnv)
+ end
+
+ context "when env variable exist with same name" do
+ before(:each) do
+ test_resource.key_name(chef_env_test_lower_case)
+ test_resource.value(env_value1)
+ test_resource.run_action(:create)
+ end
+
+ it "should modify an existing variable's value to a new value" do
+ expect(ENV[chef_env_test_lower_case]).to eq(env_value1)
+ test_resource.value(env_value2)
+ test_resource.run_action(:modify)
+ expect(ENV[chef_env_test_lower_case]).to eq(env_value2)
+ end
+
+ # This examlpe covers Chef Issue #1754
+ it "should modify an existing variable's value to a new value if the variable name case differs from the existing variable" do
+ expect(ENV[chef_env_test_lower_case]).to eq(env_value1)
+ test_resource.key_name(chef_env_test_mixed_case)
+ test_resource.value(env_value2)
+ test_resource.run_action(:modify)
+ expect(ENV[chef_env_test_lower_case]).to eq(env_value2)
+ end
+
+ it "should not expand environment variables if the variable is not PATH" do
+ expect(ENV[chef_env_test_lower_case]).to eq(env_value1)
+ test_resource.value(env_value_expandable)
+ test_resource.run_action(:modify)
+ expect(ENV[chef_env_test_lower_case]).to eq(env_value_expandable)
+ end
+ end
+
+ context "when using PATH" do
+ let(:random_name) { Time.now.to_i }
+ let(:env_val) { "#{env_value_expandable}_#{random_name}" }
+ let!(:path_before) { test_resource.provider_for_action(test_resource.action).env_value("PATH") || "" }
+ let!(:env_path_before) { ENV["PATH"] }
+
+ it "should expand PATH" do
+ expect(path_before).not_to include(env_val)
+ test_resource.key_name("PATH")
+ test_resource.value("#{path_before};#{env_val}")
+ test_resource.run_action(:create)
+ expect(ENV["PATH"]).not_to include(env_val)
+ expect(ENV["PATH"]).to include("#{random_name}")
+ end
+
+ after(:each) do
+ # cleanup so we don't flood the path
+ test_resource.key_name("PATH")
+ test_resource.value(path_before)
+ test_resource.run_action(:create)
+ ENV["PATH"] = env_path_before
+ end
+ end
+
+ end
+
+ context "when the delete action is invoked" do
+ context "when env variable exist with same name" do
+ before(:each) do
+ test_resource.key_name(chef_env_test_lower_case)
+ test_resource.value(env_value1)
+ test_resource.run_action(:create)
+ end
+
+ it "should delete a System environment variable" do
+ expect(ENV[chef_env_test_lower_case]).to eq(env_value1)
+ test_resource.run_action(:delete)
+ expect(ENV[chef_env_test_lower_case]).to eq(nil)
+ end
+
+ it "should not delete an System environment variable if user are passed" do
+ expect(ENV[chef_env_test_lower_case]).to eq(env_value1)
+ test_resource.user(env_user)
+ test_resource.run_action(:delete)
+ test_resource.user(default_env_user)
+ expect(env_obj).not_to be_nil
+ end
+ end
+
+ context "when env variable exist with same name" do
+ before(:each) do
+ test_resource.key_name(chef_env_test_lower_case)
+ test_resource.value(env_value1)
+ test_resource.user(env_user)
+ test_resource.run_action(:create)
+ end
+
+ it "should delete a user environment variable" do
+ expect(ENV[chef_env_test_lower_case]).to eq(env_value1)
+ test_resource.run_action(:delete)
+ expect(env_obj).to eq(nil)
+ end
+
+ it "should not delete an user environment variable if user is not passed" do
+ expect(ENV[chef_env_test_lower_case]).to eq(env_value1)
+ test_resource.user(default_env_user)
+ test_resource.run_action(:delete)
+ test_resource.user(env_user)
+ expect(env_obj).not_to be_nil
+ end
+ end
+
+ context "when env variable exist with same name" do
+ before(:each) do
+ test_resource.key_name(chef_env_with_delim)
+ test_resource.delim(chef_env_delim)
+ test_resource.value(delim_value)
+ test_resource.run_action(:create)
+ end
+
+ it "should not delete variable when a delim present" do
+ expect(ENV[chef_env_with_delim]).to eq(delim_value)
+ test_resource.value(env_value1)
+ test_resource.run_action(:delete)
+ expect(ENV[chef_env_with_delim]).to eq(env_value2)
+ end
+ end
+
+ it "should not raise an exception when a non-existent environment variable is deleted" do
+ expect(ENV[chef_env_test_lower_case]).to eq(nil)
+ test_resource.key_name(chef_env_test_lower_case)
+ test_resource.value(env_value1)
+ expect { test_resource.run_action(:delete) }.not_to raise_error
+ expect(ENV[chef_env_test_lower_case]).to eq(nil)
+ end
+
+ it "should delete a value from the current process even if it is not in the registry" do
+ expect(ENV[env_dne_key]).to eq(nil)
+ ENV[env_dne_key] = env_value1
+ test_resource.key_name(env_dne_key)
+ test_resource.run_action(:delete)
+ expect(ENV[env_dne_key]).to eq(nil)
+ end
+
+ end
+ end
+end
diff --git a/spec/functional/resource/windows_path_spec.rb b/spec/functional/resource/windows_path_spec.rb
new file mode 100644
index 0000000000..912abe6b24
--- /dev/null
+++ b/spec/functional/resource/windows_path_spec.rb
@@ -0,0 +1,64 @@
+#
+# Author:: Nimisha Sharad (<nimisha.sharad@msystechnologies.com>)
+# Copyright:: Copyright (c) 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"
+
+describe Chef::Resource::WindowsPath, :windows_only do
+ let(:path) { "test_path" }
+
+ before(:all) do
+ @old_path = ENV["PATH"].dup
+ end
+
+ after(:all) do
+ ENV["PATH"] = @old_path
+ end
+
+ subject do
+ new_resource = Chef::Resource::WindowsPath.new(path, run_context)
+ new_resource
+ end
+
+ describe "adding path" do
+ after { remove_path }
+
+ it "appends the user given path in the Environment variable Path" do
+ subject.run_action(:add)
+ expect(ENV["PATH"]).to include(path)
+ end
+ end
+
+ describe "removing path" do
+ before { add_path }
+
+ it "removes the user given path from the Environment variable Path" do
+ subject.run_action(:remove)
+ expect(ENV["PATH"]).not_to include(path)
+ end
+ end
+
+ def remove_path
+ new_resource = Chef::Resource::WindowsPath.new(path, run_context)
+ new_resource.run_action(:remove)
+ end
+
+ def add_path
+ new_resource = Chef::Resource::WindowsPath.new(path, run_context)
+ new_resource.run_action(:add)
+ end
+end
diff --git a/spec/functional/resource/windows_service_spec.rb b/spec/functional/resource/windows_service_spec.rb
index b4af1e9e6a..531f9e9250 100644
--- a/spec/functional/resource/windows_service_spec.rb
+++ b/spec/functional/resource/windows_service_spec.rb
@@ -27,19 +27,19 @@ describe Chef::Resource::WindowsService, :windows_only, :system_windows_service_
let(:qualified_username) { "#{ENV['COMPUTERNAME']}\\#{username}" }
let(:password) { "1a2b3c4X!&narf" }
- let(:user_resource) {
- r = Chef::Resource::User.new(username, run_context)
+ let(:user_resource) do
+ r = Chef::Resource::User::WindowsUser.new(username, run_context)
r.username(username)
r.password(password)
r.comment("temp spec user")
r
- }
+ end
- let(:global_service_file_path) {
+ let(:global_service_file_path) do
"#{ENV['WINDIR']}\\temp\\#{File.basename(test_service[:service_file_path])}"
- }
+ end
- let(:service_params) {
+ let(:service_params) do
id = "#{$$}_#{rand(1000)}"
@@ -51,19 +51,19 @@ describe Chef::Resource::WindowsService, :windows_only, :system_windows_service_
service_description: "Test service for running the windows_service functional spec.",
service_file_path: global_service_file_path,
} )
- }
+ end
- let(:manager) {
+ let(:manager) do
Chef::Application::WindowsServiceManager.new(service_params)
- }
+ end
- let(:service_resource) {
+ let(:service_resource) do
r = Chef::Resource::WindowsService.new(service_params[:service_name], run_context)
[:run_as_user, :run_as_password].each { |prop| r.send(prop, service_params[prop]) }
r
- }
+ end
- before {
+ before do
user_resource.run_action(:create)
# the service executable has to be outside the current user's home
@@ -81,13 +81,13 @@ describe Chef::Resource::WindowsService, :windows_only, :system_windows_service_
file.run_action(:create)
manager.run(%w{--action install})
- }
+ end
- after {
+ after do
user_resource.run_action(:remove)
manager.run(%w{--action uninstall})
File.delete(global_service_file_path)
- }
+ end
describe "logon as a service" do
it "successfully runs a service as another user" do
diff --git a/spec/functional/resource/windows_task_spec.rb b/spec/functional/resource/windows_task_spec.rb
new file mode 100644
index 0000000000..621802bd44
--- /dev/null
+++ b/spec/functional/resource/windows_task_spec.rb
@@ -0,0 +1,1454 @@
+#
+# Author:: Nimisha Sharad (<nimisha.sharad@msystechnologies.com>)
+# Copyright:: Copyright (c) 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 "chef/provider/windows_task"
+
+describe Chef::Resource::WindowsTask, :windows_only do
+ let(:task_name) { "chef-client" }
+ let(:new_resource) { Chef::Resource::WindowsTask.new(task_name) }
+ let(:windows_task_provider) do
+ node = Chef::Node.new
+ events = Chef::EventDispatch::Dispatcher.new
+ run_context = Chef::RunContext.new(node, {}, events)
+ Chef::Provider::WindowsTask.new(new_resource, run_context)
+ end
+
+ describe "action :create" do
+ after { delete_task }
+ context "when frequency_modifier are not passed" do
+ subject do
+ new_resource = Chef::Resource::WindowsTask.new(task_name, run_context)
+ new_resource.command task_name
+ new_resource.execution_time_limit = 259200 / 60 # converting "PT72H" into minutes and passing here since win32-taskscheduler accespts this
+ # Make sure MM/DD/YYYY is accepted
+ new_resource.start_day "09/20/2017"
+ new_resource.frequency :hourly
+ new_resource
+ end
+
+ it "creates a scheduled task to run every 1 hr starting on 09/20/2017" do
+ call_for_create_action
+ #loading current resource again to check new task is creted and it matches task parameters
+ current_resource = call_for_load_current_resource
+ expect(current_resource.exists).to eq(true)
+ expect(current_resource.task.application_name).to eq("chef-client")
+ trigger_details = current_resource.task.trigger(0)
+ expect(trigger_details[:start_year]).to eq("2017")
+ expect(trigger_details[:start_month]).to eq("09")
+ expect(trigger_details[:start_day]).to eq("20")
+ expect(trigger_details[:minutes_interval]).to eq(60)
+ expect(trigger_details[:trigger_type]).to eq(1)
+ end
+
+ it "does not converge the resource if it is already converged" do
+ subject.run_action(:create)
+ subject.run_action(:create)
+ expect(subject).not_to be_updated_by_last_action
+ end
+ end
+
+ context "frequency :minute" 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 :minute
+ new_resource.frequency_modifier 15
+ new_resource.execution_time_limit = 259200 / 60 # converting "PT72H" into minutes and passing here since win32-taskscheduler accespts this
+ new_resource
+ end
+
+ it "creates a scheduled task that runs after every 15 minutes" do
+ call_for_create_action
+ #loading current resource again to check new task is creted and it matches task parameters
+ current_resource = call_for_load_current_resource
+ expect(current_resource.exists).to eq(true)
+ trigger_details = current_resource.task.trigger(0)
+ expect(current_resource.task.application_name).to eq("chef-client")
+ expect(trigger_details[:minutes_interval]).to eq(15)
+ expect(trigger_details[:trigger_type]).to eq(1)
+ expect(current_resource.task.principals[:run_level]).to eq(1)
+ end
+
+ it "does not converge the resource if it is already converged" do
+ subject.run_action(:create)
+ subject.run_action(:create)
+ expect(subject).not_to be_updated_by_last_action
+ end
+
+ it "updates a scheduled task when frequency_modifier updated to 20" do
+ subject.run_action(:create)
+ current_resource = call_for_load_current_resource
+ trigger_details = current_resource.task.trigger(0)
+ expect(trigger_details[:minutes_interval]).to eq(15)
+ subject.frequency_modifier 20
+ subject.run_action(:create)
+ expect(subject).to be_updated_by_last_action
+ # #loading current resource again to check new task is creted and it matches task parameters
+ current_resource = call_for_load_current_resource
+ expect(current_resource.exists).to eq(true)
+ trigger_details = current_resource.task.trigger(0)
+ expect(current_resource.task.application_name).to eq("chef-client")
+ expect(trigger_details[:minutes_interval]).to eq(20)
+ expect(trigger_details[:trigger_type]).to eq(1)
+ expect(current_resource.task.principals[:run_level]).to eq(1)
+ end
+ end
+
+ context "frequency :hourly" 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 :hourly
+ new_resource.frequency_modifier 3
+ new_resource.execution_time_limit = 259200 / 60 # converting "PT72H" into minutes and passing here since win32-taskscheduler accespts this
+ new_resource
+ end
+
+ it "creates a scheduled task that runs after every 3 hrs" do
+ call_for_create_action
+ #loading current resource again to check new task is creted and it matches task parameters
+ current_resource = call_for_load_current_resource
+ expect(current_resource.exists).to eq(true)
+ trigger_details = current_resource.task.trigger(0)
+ expect(current_resource.task.application_name).to eq("chef-client")
+ expect(trigger_details[:minutes_interval]).to eq(180)
+ expect(trigger_details[:trigger_type]).to eq(1)
+ end
+
+ it "does not converge the resource if it is already converged" do
+ subject.run_action(:create)
+ subject.run_action(:create)
+ expect(subject).not_to be_updated_by_last_action
+ end
+
+ it "updates a scheduled task to run every 5 hrs when frequency modifer updated to 5" do
+ subject.run_action(:create)
+ current_resource = call_for_load_current_resource
+ trigger_details = current_resource.task.trigger(0)
+ expect(trigger_details[:minutes_interval]).to eq(180)
+ # updating frequency modifer to 5 from 3
+ subject.frequency_modifier 5
+ subject.run_action(:create)
+ expect(subject).to be_updated_by_last_action
+ current_resource = call_for_load_current_resource
+ expect(current_resource.exists).to eq(true)
+ trigger_details = current_resource.task.trigger(0)
+ expect(current_resource.task.application_name).to eq("chef-client")
+ expect(trigger_details[:minutes_interval]).to eq(300)
+ expect(trigger_details[:trigger_type]).to eq(1)
+ end
+ end
+
+ context "frequency :daily" 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 :daily
+ new_resource.execution_time_limit = 259200 / 60 # converting "PT72H" into minutes and passing here since win32-taskscheduler accespts this
+ new_resource
+ end
+
+ it "creates a scheduled task to run daily" do
+ call_for_create_action
+ #loading current resource again to check new task is creted and it matches task parameters
+ current_resource = call_for_load_current_resource
+ expect(current_resource.exists).to eq(true)
+ trigger_details = current_resource.task.trigger(0)
+ expect(current_resource.task.application_name).to eq("chef-client")
+ expect(trigger_details[:trigger_type]).to eq(2)
+ expect(current_resource.task.principals[:run_level]).to eq(1)
+ expect(trigger_details[:type][:days_interval]).to eq(1)
+ end
+
+ it "does not converge the resource if it is already converged" do
+ subject.run_action(:create)
+ subject.run_action(:create)
+ expect(subject).not_to be_updated_by_last_action
+ end
+ end
+
+ describe "frequency :monthly" 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 :monthly
+ new_resource.execution_time_limit = 259200 / 60 # converting "PT72H" into minutes and passing here since win32-taskscheduler accespts this
+ new_resource
+ end
+
+ context "with start_day and start_time" do
+ before do
+ subject.start_day "02/12/2018"
+ subject.start_time "05:15"
+ end
+
+ it "if day property is not set creates a scheduled task to run monthly on first day of the month" do
+ call_for_create_action
+ #loading current resource again to check new task is creted and it matches task parameters
+ current_resource = call_for_load_current_resource
+ expect(current_resource.exists).to eq(true)
+ trigger_details = current_resource.task.trigger(0)
+ expect(current_resource.task.application_name).to eq("chef-client")
+ expect(trigger_details[:trigger_type]).to eq(4)
+ expect(current_resource.task.principals[:run_level]).to eq(1)
+ expect(trigger_details[:type][:days]).to eq(1)
+ expect(trigger_details[:type][:months]).to eq(4095)
+ end
+
+ it "does not converge the resource if it is already converged" do
+ subject.run_action(:create)
+ subject.run_action(:create)
+ expect(subject).not_to be_updated_by_last_action
+ end
+
+ it "creates a scheduled task to run monthly on first, second and third day of the month" do
+ subject.day "1, 2, 3"
+ call_for_create_action
+ #loading current resource again to check new task is created and it matches task parameters
+ current_resource = call_for_load_current_resource
+ expect(current_resource.exists).to eq(true)
+ trigger_details = current_resource.task.trigger(0)
+ expect(current_resource.task.application_name).to eq("chef-client")
+ expect(trigger_details[:trigger_type]).to eq(4)
+ expect(current_resource.task.principals[:run_level]).to eq(1)
+ expect(trigger_details[:type][:days]).to eq(7)
+ expect(trigger_details[:type][:months]).to eq(4095)
+ end
+
+ it "does not converge the resource if it is already converged" do
+ subject.day "1, 2, 3"
+ subject.run_action(:create)
+ subject.run_action(:create)
+ expect(subject).not_to be_updated_by_last_action
+ end
+
+ it "creates a scheduled task to run monthly on 1, 2, 3, 4, 8, 20, 21, 15, 28, 31 day of the month" do
+ subject.day "1, 2, 3, 4, 8, 20, 21, 15, 28, 31"
+ call_for_create_action
+ #loading current resource again to check new task is created and it matches task parameters
+ current_resource = call_for_load_current_resource
+ expect(current_resource.exists).to eq(true)
+ trigger_details = current_resource.task.trigger(0)
+ expect(current_resource.task.application_name).to eq("chef-client")
+ expect(trigger_details[:trigger_type]).to eq(4)
+ expect(current_resource.task.principals[:run_level]).to eq(1)
+ expect(trigger_details[:type][:days]).to eq(1209548943) #TODO:: windows_task_provider.send(:days_of_month)
+ expect(trigger_details[:type][:months]).to eq(4095) #windows_task_provider.send(:months_of_year)
+ end
+
+ it "does not converge the resource if it is already converged" do
+ subject.day "1, 2, 3, 4, 8, 20, 21, 15, 28, 31"
+ subject.run_action(:create)
+ subject.run_action(:create)
+ expect(subject).not_to be_updated_by_last_action
+ end
+
+ it "creates a scheduled task to run monthly on Jan, Feb, Apr, Dec on 1st 2nd 3rd 4th 8th and 20th day of these months" do
+ subject.day "1, 2, 3, 4, 8, 20, 21, 30"
+ subject.months "Jan, Feb, May, Sep, Dec"
+ call_for_create_action
+ #loading current resource again to check new task is created and it matches task parameters
+ current_resource = call_for_load_current_resource
+ expect(current_resource.exists).to eq(true)
+ trigger_details = current_resource.task.trigger(0)
+ expect(current_resource.task.application_name).to eq("chef-client")
+ expect(trigger_details[:trigger_type]).to eq(4)
+ expect(current_resource.task.principals[:run_level]).to eq(1)
+ expect(trigger_details[:type][:days]).to eq(538443919) #TODO:windows_task_provider.send(:days_of_month)
+ expect(trigger_details[:type][:months]).to eq(2323) #windows_task_provider.send(:months_of_year)
+ end
+
+ it "does not converge the resource if it is already converged" do
+ subject.day "1, 2, 3, 4, 8, 20, 21, 30"
+ subject.months "Jan, Feb, May, Sep, Dec"
+ subject.run_action(:create)
+ subject.run_action(:create)
+ expect(subject).not_to be_updated_by_last_action
+ end
+
+ it "creates a scheduled task to run monthly by giving day option with frequency_modifier" do
+ subject.frequency_modifier "First"
+ subject.day "Mon, Fri, Sun"
+ call_for_create_action
+ #loading current resource again to check new task is created and it matches task parameters
+ current_resource = call_for_load_current_resource
+ expect(current_resource.exists).to eq(true)
+ trigger_details = current_resource.task.trigger(0)
+ expect(current_resource.task.application_name).to eq("chef-client")
+ expect(trigger_details[:trigger_type]).to eq(5)
+ expect(current_resource.task.principals[:run_level]).to eq(1)
+ expect(trigger_details[:type][:days_of_week]).to eq(35)
+ expect(trigger_details[:type][:weeks_of_month]).to eq(1)
+ expect(trigger_details[:type][:months]).to eq(4095) #windows_task_provider.send(:months_of_year)
+ end
+
+ it "does not converge the resource if it is already converged" do
+ subject.frequency_modifier "First"
+ subject.day "Mon, Fri, Sun"
+ subject.run_action(:create)
+ subject.run_action(:create)
+ expect(subject).not_to be_updated_by_last_action
+ end
+ end
+
+ context "with frequency_modifier" 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 :monthly
+ new_resource.execution_time_limit = 259200 / 60 # converting "PT72H" into minutes and passing here since win32-taskscheduler accespts this
+ new_resource
+ end
+
+ it "raises argument error if frequency_modifier is 'first, second' and day is not provided." do
+ subject.frequency_modifier "first, second"
+ expect { subject.after_created }.to raise_error("Please select day on which you want to run the task e.g. 'Mon, Tue'. Multiple values must be seprated by comma.")
+ end
+
+ it "raises argument error if months is passed along with frequency_modifier" do
+ subject.frequency_modifier 3
+ subject.months "Jan, Mar"
+ expect { subject.after_created }.to raise_error("For frequency :monthly either use property months or frequency_modifier to set months.")
+ end
+
+ it "not raises any Argument error if frequency_modifier set as 'first, second, third' and day is provided" do
+ subject.frequency_modifier "first, second, third"
+ subject.day "Mon, Fri"
+ expect { subject.after_created }.not_to raise_error(ArgumentError)
+ end
+
+ it "not raises any Argument error if frequency_modifier 2 " do
+ subject.frequency_modifier 2
+ subject.day "Mon, Sun"
+ expect { subject.after_created }.not_to raise_error(ArgumentError)
+ end
+
+ it "raises argument error if frequency_modifier > 12" do
+ subject.frequency_modifier 13
+ expect { subject.after_created }.to raise_error("frequency_modifier value 13 is invalid. Valid values for :monthly frequency are 1 - 12, 'FIRST', 'SECOND', 'THIRD', 'FOURTH', 'LAST'.")
+ end
+
+ it "raises argument error if frequency_modifier < 1" do
+ subject.frequency_modifier 0
+ expect { subject.after_created }.to raise_error("frequency_modifier value 0 is invalid. Valid values for :monthly frequency are 1 - 12, 'FIRST', 'SECOND', 'THIRD', 'FOURTH', 'LAST'.")
+ end
+
+ it "creates scheduled task to run task monthly on Monday and Friday of first, second and thrid week of month" do
+ subject.frequency_modifier "first, second, third"
+ subject.day "Mon, Fri"
+ expect { subject.after_created }.not_to raise_error(ArgumentError)
+ call_for_create_action
+ current_resource = call_for_load_current_resource
+ expect(current_resource.exists).to eq(true)
+ trigger_details = current_resource.task.trigger(0)
+ expect(current_resource.task.application_name).to eq("chef-client")
+ expect(trigger_details[:trigger_type]).to eq(5)
+ expect(trigger_details[:type][:months]).to eq(4095)
+ expect(trigger_details[:type][:weeks_of_month]).to eq(7)
+ expect(trigger_details[:type][:days_of_week]).to eq(34)
+ end
+
+ it "does not converge the resource if it is already converged" do
+ subject.frequency_modifier "first, second, third"
+ subject.day "Mon, Fri"
+ subject.run_action(:create)
+ subject.run_action(:create)
+ expect(subject).not_to be_updated_by_last_action
+ end
+
+ it "creates scheduled task to run task monthly on every 6 months when frequency_modifier is 6 and to run on 1st and 2nd day of month" do
+ subject.frequency_modifier 6
+ subject.day "1, 2"
+ expect { subject.after_created }.not_to raise_error(ArgumentError)
+ call_for_create_action
+ current_resource = call_for_load_current_resource
+ expect(current_resource.exists).to eq(true)
+ trigger_details = current_resource.task.trigger(0)
+ expect(current_resource.task.application_name).to eq("chef-client")
+ expect(trigger_details[:trigger_type]).to eq(4)
+ expect(trigger_details[:type][:months]).to eq(2080)
+ expect(trigger_details[:type][:days]).to eq(3)
+ end
+
+ it "does not converge the resource if it is already converged" do
+ subject.frequency_modifier 6
+ subject.day "1, 2"
+ subject.run_action(:create)
+ subject.run_action(:create)
+ expect(subject).not_to be_updated_by_last_action
+ end
+ end
+
+ context "when day is set as last or lastday for frequency :monthly" 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 :monthly
+ new_resource.execution_time_limit = 259200 / 60 # converting "PT72H" into minutes and passing here since win32-taskscheduler accespts this
+ new_resource
+ end
+
+ it "creates scheduled task to run monthly to run last day of the month" do
+ subject.day "last"
+ expect { subject.after_created }.not_to raise_error(ArgumentError)
+ call_for_create_action
+ current_resource = call_for_load_current_resource
+ expect(current_resource.exists).to eq(true)
+ trigger_details = current_resource.task.trigger(0)
+ expect(current_resource.task.application_name).to eq("chef-client")
+ expect(trigger_details[:trigger_type]).to eq(4)
+ expect(trigger_details[:type][:months]).to eq(4095)
+ expect(trigger_details[:type][:days]).to eq(0)
+ expect(trigger_details[:run_on_last_day_of_month]).to eq(true)
+ end
+
+ it "does not converge the resource if it is already converged" do
+ subject.day "last"
+ subject.run_action(:create)
+ subject.run_action(:create)
+ expect(subject).not_to be_updated_by_last_action
+ end
+
+ it "day property set as 'lastday' creates scheduled task to run monthly to run last day of the month" do
+ subject.day "lastday"
+ expect { subject.after_created }.not_to raise_error(ArgumentError)
+ call_for_create_action
+ current_resource = call_for_load_current_resource
+ expect(current_resource.exists).to eq(true)
+ trigger_details = current_resource.task.trigger(0)
+ expect(current_resource.task.application_name).to eq("chef-client")
+ expect(trigger_details[:trigger_type]).to eq(4)
+ expect(trigger_details[:type][:months]).to eq(4095)
+ expect(trigger_details[:type][:days]).to eq(0)
+ expect(trigger_details[:run_on_last_day_of_month]).to eq(true)
+ end
+
+ it "does not converge the resource if it is already converged" do
+ subject.day "lastday"
+ subject.run_action(:create)
+ subject.run_action(:create)
+ expect(subject).not_to be_updated_by_last_action
+ end
+ end
+
+ context "when frequency_modifier is set as last for frequency :monthly" do
+ it "creates scheduled task to run monthly on last week of the month" do
+ subject.frequency_modifier "last"
+ subject.day "Mon, Fri"
+ expect { subject.after_created }.not_to raise_error(ArgumentError)
+ call_for_create_action
+ current_resource = call_for_load_current_resource
+ expect(current_resource.exists).to eq(true)
+ trigger_details = current_resource.task.trigger(0)
+ expect(current_resource.task.application_name).to eq("chef-client")
+ expect(trigger_details[:trigger_type]).to eq(5)
+ expect(trigger_details[:type][:months]).to eq(4095)
+ expect(trigger_details[:type][:days_of_week]).to eq(34)
+ expect(trigger_details[:run_on_last_week_of_month]).to eq(true)
+ end
+
+ it "does not converge the resource if it is already converged" do
+ subject.frequency_modifier "last"
+ subject.day "Mon, Fri"
+ subject.run_action(:create)
+ subject.run_action(:create)
+ expect(subject).not_to be_updated_by_last_action
+ end
+ end
+
+ context "when wild card (*) set as months" do
+ it "creates the scheduled task to run on 1st day of the all months" do
+ subject.months "*"
+ expect { subject.after_created }.not_to raise_error(ArgumentError)
+ call_for_create_action
+ current_resource = call_for_load_current_resource
+ expect(current_resource.exists).to eq(true)
+ trigger_details = current_resource.task.trigger(0)
+ expect(current_resource.task.application_name).to eq("chef-client")
+ expect(trigger_details[:trigger_type]).to eq(4)
+ expect(trigger_details[:type][:months]).to eq(4095)
+ expect(trigger_details[:type][:days]).to eq(1)
+ end
+
+ it "does not converge the resource if it is already converged" do
+ subject.months "*"
+ subject.run_action(:create)
+ subject.run_action(:create)
+ expect(subject).not_to be_updated_by_last_action
+ end
+ end
+
+ context "when wild card (*) set as day" do
+ it "raises argument error" do
+ subject.day "*"
+ expect { subject.after_created }.to raise_error("day wild card (*) is only valid with frequency :weekly")
+ end
+ end
+
+ context "Pass either start day or start time by passing day compulsory or only pass frequency_modifier" 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 :monthly
+ new_resource.execution_time_limit = 259200 / 60 # converting "PT72H" into minutes and passing here since win32-taskscheduler accespts this
+ new_resource
+ end
+
+ it "creates a scheduled task to run monthly on second day of the month" do
+ subject.day "2"
+ subject.start_day "03/07/2018"
+ call_for_create_action
+ #loading current resource again to check new task is creted and it matches task parameters
+ current_resource = call_for_load_current_resource
+ expect(current_resource.exists).to eq(true)
+ trigger_details = current_resource.task.trigger(0)
+ expect(current_resource.task.application_name).to eq("chef-client")
+ expect(trigger_details[:trigger_type]).to eq(4)
+ expect(current_resource.task.principals[:run_level]).to eq(1)
+ expect(trigger_details[:type][:days]).to eq(2)
+ expect(trigger_details[:type][:months]).to eq(4095)
+ end
+
+ it "does not converge the resource if it is already converged" do
+ subject.day "2"
+ subject.start_day "03/07/2018"
+ subject.run_action(:create)
+ subject.run_action(:create)
+ expect(subject).not_to be_updated_by_last_action
+ end
+
+ it "creates a scheduled task to run monthly on first, second and third day of the month" do
+ subject.day "1,2,3"
+ call_for_create_action
+ #loading current resource again to check new task is creted and it matches task parameters
+ current_resource = call_for_load_current_resource
+ expect(current_resource.exists).to eq(true)
+ trigger_details = current_resource.task.trigger(0)
+ expect(current_resource.task.application_name).to eq("chef-client")
+ expect(trigger_details[:trigger_type]).to eq(4)
+ expect(current_resource.task.principals[:run_level]).to eq(1)
+ expect(trigger_details[:type][:days]).to eq(7)
+ expect(trigger_details[:type][:months]).to eq(4095)
+ end
+
+ it "does not converge the resource if it is already converged" do
+ subject.day "1,2,3"
+ subject.run_action(:create)
+ subject.run_action(:create)
+ expect(subject).not_to be_updated_by_last_action
+ end
+
+ it "creates a scheduled task to run monthly on each wednesday of the month" do
+ subject.frequency_modifier "1"
+ call_for_create_action
+ #loading current resource again to check new task is creted and it matches task parameters
+ current_resource = call_for_load_current_resource
+ expect(current_resource.exists).to eq(true)
+ trigger_details = current_resource.task.trigger(0)
+ expect(current_resource.task.application_name).to eq("chef-client")
+ expect(trigger_details[:trigger_type]).to eq(4)
+ expect(current_resource.task.principals[:run_level]).to eq(1)
+ expect(trigger_details[:type][:days]).to eq(1)
+ expect(trigger_details[:type][:months]).to eq(4095) #windows_task_provider.send(:months_of_year)
+ end
+
+ it "does not converge the resource if it is already converged" do
+ subject.frequency_modifier "2"
+ subject.run_action(:create)
+ subject.run_action(:create)
+ expect(subject).not_to be_updated_by_last_action
+ end
+
+ it "creates a scheduled task to run monthly on each wednesday of the month" do
+ subject.frequency_modifier "2"
+ subject.months = nil
+ call_for_create_action
+ #loading current resource again to check new task is creted and it matches task parameters
+ current_resource = call_for_load_current_resource
+ expect(current_resource.exists).to eq(true)
+ trigger_details = current_resource.task.trigger(0)
+ #loading current resource
+ expect(current_resource.task.application_name).to eq("chef-client")
+ expect(trigger_details[:trigger_type]).to eq(4)
+ expect(current_resource.task.principals[:run_level]).to eq(1)
+ expect(trigger_details[:type][:days]).to eq(1)
+ expect(trigger_details[:type][:months]).to eq(2730) #windows_task_provider.send(:months_of_year)
+ end
+
+ it "does not converge the resource if it is already converged" do
+ subject.frequency_modifier "2"
+ subject.months = nil
+ subject.run_action(:create)
+ subject.run_action(:create)
+ expect(subject).not_to be_updated_by_last_action
+ end
+ end
+ end
+
+ ## ToDO: Add functional specs to handle frequency monthly with frequency modifier set as 1-12
+ context "frequency :once" 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 :once
+ new_resource.execution_time_limit = 259200 / 60 # converting "PT72H" into minutes and passing here since win32-taskscheduler accespts this
+ new_resource
+ end
+
+ context "when start_time is not provided" do
+ it "raises argument error" do
+ expect { subject.after_created }.to raise_error("`start_time` needs to be provided with `frequency :once`")
+ end
+ end
+
+ context "when start_time is provided" do
+ it "creates the scheduled task to run once at 5pm" do
+ subject.start_time "17:00"
+ call_for_create_action
+ #loading current resource again to check new task is creted and it matches task parameters
+ current_resource = call_for_load_current_resource
+ expect(current_resource.exists).to eq(true)
+ trigger_details = current_resource.task.trigger(0)
+ expect(current_resource.task.application_name).to eq("chef-client")
+ expect(trigger_details[:trigger_type]).to eq(1)
+ expect(current_resource.task.principals[:run_level]).to eq(1)
+ expect("#{trigger_details[:start_hour]}:#{trigger_details[:start_minute]}" ).to eq(subject.start_time)
+ end
+
+ it "does not converge the resource if it is already converged" do
+ subject.start_time "17:00"
+ subject.run_action(:create)
+ subject.run_action(:create)
+ expect(subject).not_to be_updated_by_last_action
+ end
+ end
+ end
+
+ context "frequency :weekly" 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 :weekly
+ new_resource.execution_time_limit = 259200 / 60 # converting "PT72H" into minutes and passing here since win32-taskscheduler accespts this
+ new_resource
+ end
+
+ it "creates the scheduled task to run weekly" do
+ call_for_create_action
+ #loading current resource again to check new task is creted and it matches task parameters
+ current_resource = call_for_load_current_resource
+ expect(current_resource.exists).to eq(true)
+ trigger_details = current_resource.task.trigger(0)
+ expect(current_resource.task.application_name).to eq("chef-client")
+ expect(current_resource.task.principals[:run_level]).to eq(1)
+ expect(trigger_details[:trigger_type]).to eq(3)
+ expect(trigger_details[:type][:weeks_interval]).to eq(1)
+ end
+
+ it "does not converge the resource if it is already converged" do
+ subject.run_action(:create)
+ subject.run_action(:create)
+ expect(subject).not_to be_updated_by_last_action
+ end
+
+ context "when wild card (*) is set as day" do
+ it "creates hte scheduled task for all days of week" do
+ subject.day "*"
+ call_for_create_action
+ #loading current resource again to check new task is creted and it matches task parameters
+ current_resource = call_for_load_current_resource
+ expect(current_resource.exists).to eq(true)
+ trigger_details = current_resource.task.trigger(0)
+ expect(current_resource.task.application_name).to eq("chef-client")
+ expect(current_resource.task.principals[:run_level]).to eq(1)
+ expect(trigger_details[:trigger_type]).to eq(3)
+ expect(trigger_details[:type][:weeks_interval]).to eq(1)
+ expect(trigger_details[:type][:days_of_week]).to eq(127)
+ end
+
+ it "does not converge the resource if it is already converged" do
+ subject.day "*"
+ subject.run_action(:create)
+ subject.run_action(:create)
+ expect(subject).not_to be_updated_by_last_action
+ end
+ end
+
+ context "when days are provided" do
+ it "creates the scheduled task to run on particular days" do
+ subject.day "Mon, Fri"
+ subject.frequency_modifier 2
+ call_for_create_action
+ #loading current resource again to check new task is creted and it matches task parameters
+ current_resource = call_for_load_current_resource
+ expect(current_resource.exists).to eq(true)
+ trigger_details = current_resource.task.trigger(0)
+ expect(current_resource.task.application_name).to eq("chef-client")
+ expect(current_resource.task.principals[:run_level]).to eq(1)
+ expect(trigger_details[:trigger_type]).to eq(3)
+ expect(trigger_details[:type][:weeks_interval]).to eq(2)
+ expect(trigger_details[:type][:days_of_week]).to eq(34)
+ end
+
+ it "updates the scheduled task to run on if frequency_modifier is updated" do
+ subject.day "sun"
+ subject.frequency_modifier 2
+ subject.run_action(:create)
+ current_resource = call_for_load_current_resource
+ trigger_details = current_resource.task.trigger(0)
+ expect(trigger_details[:type][:weeks_interval]).to eq(2)
+ expect(trigger_details[:type][:days_of_week]).to eq(1)
+ subject.day "Mon, Sun"
+ subject.frequency_modifier 3
+ # call for update
+ subject.run_action(:create)
+ expect(subject).to be_updated_by_last_action
+ current_resource = call_for_load_current_resource
+ expect(current_resource.exists).to eq(true)
+ trigger_details = current_resource.task.trigger(0)
+ expect(current_resource.task.application_name).to eq("chef-client")
+ expect(current_resource.task.principals[:run_level]).to eq(1)
+ expect(trigger_details[:trigger_type]).to eq(3)
+ expect(trigger_details[:type][:weeks_interval]).to eq(3)
+ expect(trigger_details[:type][:days_of_week]).to eq(3)
+ end
+
+ it "does not converge the resource if it is already converged" do
+ subject.day "Mon, Fri"
+ subject.frequency_modifier 3
+ subject.run_action(:create)
+ subject.run_action(:create)
+ expect(subject).not_to be_updated_by_last_action
+ end
+ end
+
+ context "when day property set as last" do
+ it "raises argument error" do
+ subject.day "last"
+ expect { subject.after_created }.to raise_error("day values 1-31 or last is only valid with frequency :monthly")
+ end
+ end
+
+ context "when invalid day is passed" do
+ it "raises error" do
+ subject.day "abc"
+ expect { subject.after_created }.to raise_error("day property invalid. Only valid values are: MON, TUE, WED, THU, FRI, SAT, SUN, *. Multiple values must be separated by a comma.")
+ end
+ end
+
+ context "when months are passed" do
+ it "raises error that months are supported only when frequency=:monthly" do
+ subject.months "Jan"
+ expect { subject.after_created }.to raise_error("months property is only valid for tasks that run monthly")
+ end
+ end
+
+ context "when start_day is not set" do
+ it "does not converge the resource if it is already converged" do
+ subject.run_action(:create)
+ subject.run_action(:create)
+ expect(subject).not_to be_updated_by_last_action
+ end
+
+ it "updates the day if start_day is not provided and user updates day property" do
+ skip "Unable to run this test case since start_day is current system date which can be different each time so can't verify the dynamic values"
+ subject.run_action(:create)
+ current_resource = call_for_load_current_resource
+ expect(current_resource.exists).to eq(true)
+ trigger_details = current_resource.task.trigger(0)
+ expect(trigger_details[:type][:days_of_week]).to eq(8)
+ subject.day "Sat"
+ subject.run_action(:create)
+ # #loading current resource again to check new task is creted and it matches task parameters
+ current_resource = call_for_load_current_resource
+ expect(current_resource.exists).to eq(true)
+ trigger_details = current_resource.task.trigger(0)
+ expect(current_resource.task.application_name).to eq("chef-client")
+ expect(current_resource.task.principals[:run_level]).to eq(1)
+ expect(trigger_details[:trigger_type]).to eq(3)
+ expect(trigger_details[:type][:weeks_interval]).to eq(1)
+ expect(trigger_details[:type][:days_of_week]).to eq(64)
+ end
+ end
+ end
+
+ context "frequency :onstart" 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 :onstart
+ new_resource.execution_time_limit = 259200 / 60 # converting "PT72H" into minutes and passing here since win32-taskscheduler accespts this
+ new_resource
+ end
+
+ it "creates the scheduled task to run at system start up" do
+ call_for_create_action
+ #loading current resource again to check new task is creted and it matches task parameters
+ current_resource = call_for_load_current_resource
+ expect(current_resource.exists).to eq(true)
+ trigger_details = current_resource.task.trigger(0)
+ expect(current_resource.task.application_name).to eq("chef-client")
+ expect(current_resource.task.principals[:run_level]).to eq(1)
+ expect(trigger_details[:trigger_type]).to eq(8)
+ end
+
+ it "does not converge the resource if it is already converged" do
+ subject.run_action(:create)
+ subject.run_action(:create)
+ expect(subject).not_to be_updated_by_last_action
+ end
+
+ context "when start_day and start_time is set" do
+ it "creates task to activate on '09/10/2018' at '15:00' when start_day = '09/10/2018' and start_time = '15:00' provided" do
+ subject.start_day "09/10/2018"
+ subject.start_time "15:00"
+ call_for_create_action
+ #loading current resource again to check new task is creted and it matches task parameters
+ current_resource = call_for_load_current_resource
+ expect(current_resource.exists).to eq(true)
+ trigger_details = current_resource.task.trigger(0)
+ expect(current_resource.task.application_name).to eq("chef-client")
+ expect(trigger_details[:trigger_type]).to eq(8)
+ expect(trigger_details[:start_year]).to eq("2018")
+ expect(trigger_details[:start_month]).to eq("09")
+ expect(trigger_details[:start_day]).to eq("10")
+ expect(trigger_details[:start_hour]).to eq("15")
+ expect(trigger_details[:start_minute]).to eq("00")
+ end
+ end
+ end
+
+ context "frequency :on_logon" 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 :on_logon
+ new_resource.execution_time_limit = 259200 / 60 # converting "PT72H" into minutes and passing here since win32-taskscheduler accespts this
+ new_resource
+ end
+
+ it "creates the scheduled task to on logon" do
+ call_for_create_action
+ #loading current resource again to check new task is creted and it matches task parameters
+ current_resource = call_for_load_current_resource
+ expect(current_resource.exists).to eq(true)
+ trigger_details = current_resource.task.trigger(0)
+ expect(current_resource.task.application_name).to eq("chef-client")
+ expect(current_resource.task.principals[:run_level]).to eq(1)
+ expect(trigger_details[:trigger_type]).to eq(9)
+ end
+
+ it "does not converge the resource if it is already converged" do
+ subject.run_action(:create)
+ subject.run_action(:create)
+ expect(subject).not_to be_updated_by_last_action
+ end
+
+ context "when start_day and start_time is set" do
+ it "creates task to activate on '09/10/2018' at '15:00' when start_day = '09/10/2018' and start_time = '15:00' provided" do
+ subject.start_day "09/10/2018"
+ subject.start_time "15:00"
+ call_for_create_action
+ #loading current resource again to check new task is creted and it matches task parameters
+ current_resource = call_for_load_current_resource
+ expect(current_resource.exists).to eq(true)
+ trigger_details = current_resource.task.trigger(0)
+ expect(current_resource.task.application_name).to eq("chef-client")
+ expect(trigger_details[:trigger_type]).to eq(9)
+ expect(trigger_details[:start_year]).to eq("2018")
+ expect(trigger_details[:start_month]).to eq("09")
+ expect(trigger_details[:start_day]).to eq("10")
+ expect(trigger_details[:start_hour]).to eq("15")
+ expect(trigger_details[:start_minute]).to eq("00")
+ end
+ end
+ end
+
+ context "frequency :on_idle" 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 :on_idle
+ new_resource.execution_time_limit = 259200 / 60 # converting "PT72H" into minutes and passing here since win32-taskscheduler accespts this
+ new_resource
+ end
+
+ context "when idle_time is not passed" do
+ it "raises error" do
+ expect { subject.after_created }.to raise_error("idle_time value should be set for :on_idle frequency.")
+ end
+ end
+
+ context "when idle_time is passed" do
+ it "creates the scheduled task to run when system is idle" do
+ subject.idle_time 20
+ call_for_create_action
+ #loading current resource again to check new task is creted and it matches task parameters
+ current_resource = call_for_load_current_resource
+ expect(current_resource.exists).to eq(true)
+ trigger_details = current_resource.task.trigger(0)
+ expect(current_resource.task.application_name).to eq("chef-client")
+ expect(current_resource.task.principals[:run_level]).to eq(1)
+ expect(trigger_details[:trigger_type]).to eq(6)
+ expect(current_resource.task.settings[:idle_settings][:idle_duration]).to eq("PT20M")
+ expect(current_resource.task.settings[:run_only_if_idle]).to eq(true)
+ end
+
+ it "does not converge the resource if it is already converged" do
+ subject.idle_time 20
+ subject.run_action(:create)
+ subject.run_action(:create)
+ expect(subject).not_to be_updated_by_last_action
+ end
+ end
+
+ context "when start_day and start_time is set" do
+ it "creates task to activate on '09/10/2018' at '15:00' when start_day = '09/10/2018' and start_time = '15:00' provided" do
+ subject.idle_time 20
+ subject.start_day "09/10/2018"
+ subject.start_time "15:00"
+ call_for_create_action
+ #loading current resource again to check new task is creted and it matches task parameters
+ current_resource = call_for_load_current_resource
+ expect(current_resource.exists).to eq(true)
+ trigger_details = current_resource.task.trigger(0)
+ expect(current_resource.task.application_name).to eq("chef-client")
+ expect(trigger_details[:trigger_type]).to eq(6)
+ expect(trigger_details[:start_year]).to eq("2018")
+ expect(trigger_details[:start_month]).to eq("09")
+ expect(trigger_details[:start_day]).to eq("10")
+ expect(trigger_details[:start_hour]).to eq("15")
+ expect(trigger_details[:start_minute]).to eq("00")
+ end
+ end
+ end
+
+ context "when random_delay is passed" 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.execution_time_limit = 259200 / 60 # converting "PT72H" into minutes and passing here since win32-taskscheduler accespts this
+ new_resource
+ end
+
+ it "sets the random_delay for frequency :minute" do
+ subject.frequency :minute
+ subject.random_delay "20"
+ call_for_create_action
+ #loading current resource again to check new task is creted and it matches task parameters
+ current_resource = call_for_load_current_resource
+ expect(current_resource.exists).to eq(true)
+ trigger_details = current_resource.task.trigger(0)
+ expect(current_resource.task.application_name).to eq("chef-client")
+ expect(current_resource.task.principals[:run_level]).to eq(1)
+ expect(trigger_details[:trigger_type]).to eq(1)
+ expect(trigger_details[:random_minutes_interval]).to eq(20)
+ end
+
+ it "does not converge the resource if it is already converged" do
+ subject.frequency :minute
+ subject.random_delay "20"
+ subject.run_action(:create)
+ subject.run_action(:create)
+ expect(subject).not_to be_updated_by_last_action
+ end
+
+ it "raises error if invalid random_delay is passed" do
+ subject.frequency :minute
+ subject.random_delay "abc"
+ expect { subject.after_created }.to raise_error("Invalid value passed for `random_delay`. Please pass seconds as an Integer (e.g. 60) or a String with numeric values only (e.g. '60').")
+ end
+
+ it "raises error if random_delay is passed with frequency on_idle" do
+ subject.frequency :on_idle
+ subject.random_delay "20"
+ expect { subject.after_created }.to raise_error("`random_delay` property is supported only for frequency :once, :minute, :hourly, :daily, :weekly and :monthly")
+ 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.execution_time_limit = 259200 / 60 # converting "PT72H" into minutes and passing here since win32-taskscheduler accespts this
+ new_resource
+ end
+
+ it "creates the scheduled task to run on demand only" do
+ call_for_create_action
+ #loading current resource again to check new task is creted and it matches task parameters
+ current_resource = call_for_load_current_resource
+ expect(current_resource.exists).to eq(true)
+
+ expect(current_resource.task.application_name).to eq("chef-client")
+ expect(current_resource.task.principals[:run_level]).to eq(1)
+ expect(current_resource.task.trigger_count).to eq(0)
+ end
+
+ it "does not converge the resource if it is already converged" do
+ subject.run_action(:create)
+ subject.run_action(:create)
+ expect(subject).not_to be_updated_by_last_action
+ end
+ end
+ end
+
+ describe "Examples of idempotent checks for each frequency" do
+ after { delete_task }
+ context "For frequency :once" 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 :once
+ new_resource.start_time "17:00"
+ new_resource.execution_time_limit = 259200 / 60 # converting "PT72H" into minutes and passing here since win32-taskscheduler accespts this
+ new_resource
+ end
+
+ it "create task by adding frequency_modifier as 1" do
+ subject.frequency_modifier 1
+ subject.run_action(:create)
+ subject.run_action(:create)
+ expect(subject).not_to be_updated_by_last_action
+ end
+
+ it "create task by adding frequency_modifier as 5" do
+ subject.frequency_modifier 5
+ subject.run_action(:create)
+ subject.run_action(:create)
+ expect(subject).not_to be_updated_by_last_action
+ end
+ end
+
+ context "For 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.execution_time_limit = 259200 / 60 # converting "PT72H" into minutes and passing here since win32-taskscheduler accespts this
+ new_resource.frequency :none
+ new_resource
+ end
+
+ it "create task by adding frequency_modifier as 1" do
+ subject.frequency_modifier 1
+ subject.run_action(:create)
+ subject.run_action(:create)
+ expect(subject).not_to be_updated_by_last_action
+ end
+
+ it "create task by adding frequency_modifier as 5" do
+ subject.frequency_modifier 5
+ subject.run_action(:create)
+ subject.run_action(:create)
+ expect(subject).not_to be_updated_by_last_action
+ end
+ end
+
+ context "For frequency :weekly" 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 :weekly
+ new_resource.execution_time_limit = 259200 / 60 # converting "PT72H" into minutes and passing here since win32-taskscheduler accespts this
+ new_resource
+ end
+
+ it "create task by adding start_day" do
+ subject.start_day "12/28/2018"
+ subject.run_action(:create)
+ subject.run_action(:create)
+ expect(subject).not_to be_updated_by_last_action
+ end
+
+ it "create task by adding frequency_modifier and random_delay" do
+ subject.frequency_modifier 3
+ subject.random_delay "60"
+ subject.run_action(:create)
+ subject.run_action(:create)
+ expect(subject).not_to be_updated_by_last_action
+ end
+ end
+
+ context "For frequency :monthly" 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 :once
+ new_resource.start_time "17:00"
+ new_resource.execution_time_limit = 259200 / 60 # converting "PT72H" into minutes and passing here since win32-taskscheduler accespts this
+ new_resource
+ end
+
+ it "create task by adding frequency_modifier as 1" do
+ subject.frequency_modifier 1
+ subject.run_action(:create)
+ subject.run_action(:create)
+ expect(subject).not_to be_updated_by_last_action
+ end
+
+ it "create task by adding frequency_modifier as 5" do
+ subject.frequency_modifier 5
+ subject.run_action(:create)
+ subject.run_action(:create)
+ expect(subject).not_to be_updated_by_last_action
+ end
+ end
+
+ context "For frequency :hourly" 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 :hourly
+ new_resource.frequency_modifier 5
+ new_resource.random_delay "2400"
+ new_resource.execution_time_limit = 259200 / 60 # converting "PT72H" into minutes and passing here since win32-taskscheduler accespts this
+ new_resource
+ end
+
+ it "create task by adding frequency_modifier and random_delay" do
+ subject.run_action(:create)
+ subject.run_action(:create)
+ expect(subject).not_to be_updated_by_last_action
+ end
+ end
+
+ context "For frequency :daily" 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 :daily
+ new_resource.frequency_modifier 2
+ new_resource.random_delay "2400"
+ new_resource.execution_time_limit = 259200 / 60 # converting "PT72H" into minutes and passing here since win32-taskscheduler accespts this
+ new_resource
+ end
+
+ it "create task by adding frequency_modifier and random_delay" do
+ subject.run_action(:create)
+ subject.run_action(:create)
+ expect(subject).not_to be_updated_by_last_action
+ end
+ end
+
+ context "For frequency :on_logon" do
+ subject do
+ new_resource = Chef::Resource::WindowsTask.new(task_name, run_context)
+ new_resource.command task_name
+ new_resource.frequency :on_logon
+ new_resource.execution_time_limit = 259200 / 60 # converting "PT72H" into minutes and passing here since win32-taskscheduler accespts this
+ new_resource
+ end
+
+ it "create task by adding frequency_modifier and random_delay" do
+ subject.run_action(:create)
+ subject.run_action(:create)
+ expect(subject).not_to be_updated_by_last_action
+ end
+
+ it "create task by adding frequency_modifier as 5" do
+ subject.frequency_modifier 5
+ subject.run_action(:create)
+ subject.run_action(:create)
+ expect(subject).not_to be_updated_by_last_action
+ end
+ end
+
+ context "For frequency :onstart" 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 :onstart
+ new_resource.frequency_modifier 20
+ new_resource.execution_time_limit = 259200 / 60 # converting "PT72H" into minutes and passing here since win32-taskscheduler accespts this
+ new_resource
+ end
+
+ it "create task by adding frequency_modifier as 20" do
+ subject.run_action(:create)
+ subject.run_action(:create)
+ expect(subject).not_to be_updated_by_last_action
+ end
+ end
+ end
+
+ describe "#after_created" 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.execution_time_limit = 259200 / 60 # converting "PT72H" into minutes and passing here since win32-taskscheduler accespts this
+ new_resource
+ end
+
+ context "when start_day is passed with frequency :onstart" do
+ it "not raises error" do
+ subject.frequency :onstart
+ subject.start_day "09/20/2017"
+ expect { subject.after_created }.not_to raise_error
+ end
+ end
+
+ context "when a non-system user is passed without password" do
+ it "raises error" do
+ subject.user "Administrator"
+ subject.frequency :onstart
+ expect { subject.after_created }.to raise_error(%q{Cannot specify a user other than the system users without specifying a password!. Valid passwordless users: 'NT AUTHORITY\SYSTEM', 'SYSTEM', 'NT AUTHORITY\LOCALSERVICE', 'NT AUTHORITY\NETWORKSERVICE', 'BUILTIN\USERS', 'USERS'})
+ end
+ end
+
+ context "when interactive_enabled is passed for a System user without password" do
+ it "raises error" do
+ subject.interactive_enabled true
+ subject.frequency :onstart
+ expect { subject.after_created }.to raise_error("Please provide the password when attempting to set interactive/non-interactive.")
+ end
+ end
+
+ context "when frequency_modifier > 1439 is passed for frequency=:minute" do
+ it "raises error" do
+ subject.frequency_modifier 1450
+ subject.frequency :minute
+ expect { subject.after_created }.to raise_error("frequency_modifier value 1450 is invalid. Valid values for :minute frequency are 1 - 1439.")
+ end
+ end
+
+ context "when frequency_modifier > 23 is passed for frequency=:minute" do
+ it "raises error" do
+ subject.frequency_modifier 24
+ subject.frequency :hourly
+ expect { subject.after_created }.to raise_error("frequency_modifier value 24 is invalid. Valid values for :hourly frequency are 1 - 23.")
+ end
+ end
+
+ context "when frequency_modifier > 23 is passed for frequency=:minute" do
+ it "raises error" do
+ subject.frequency_modifier 366
+ subject.frequency :daily
+ expect { subject.after_created }.to raise_error("frequency_modifier value 366 is invalid. Valid values for :daily frequency are 1 - 365.")
+ end
+ end
+
+ context "when frequency_modifier > 52 is passed for frequency=:minute" do
+ it "raises error" do
+ subject.frequency_modifier 53
+ subject.frequency :weekly
+ expect { subject.after_created }.to raise_error("frequency_modifier value 53 is invalid. Valid values for :weekly frequency are 1 - 52.")
+ end
+ end
+
+ context "when invalid frequency_modifier is passed for :monthly frequency" do
+ it "raises error" do
+ subject.frequency :monthly
+ subject.frequency_modifier "13"
+ expect { subject.after_created }.to raise_error("frequency_modifier value 13 is invalid. Valid values for :monthly frequency are 1 - 12, 'FIRST', 'SECOND', 'THIRD', 'FOURTH', 'LAST'.")
+ end
+ end
+
+ context "when invalid frequency_modifier is passed for :monthly frequency" do
+ it "raises error" do
+ subject.frequency :monthly
+ subject.frequency_modifier "xyz"
+ expect { subject.after_created }.to raise_error("frequency_modifier value xyz is invalid. Valid values for :monthly frequency are 1 - 12, 'FIRST', 'SECOND', 'THIRD', 'FOURTH', 'LAST'.")
+ end
+ end
+
+ context "when invalid months are passed" do
+ it "raises error" do
+ subject.months "xyz"
+ subject.frequency :monthly
+ expect { subject.after_created }.to raise_error("months property invalid. Only valid values are: JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC, *. Multiple values must be separated by a comma.")
+ end
+ end
+
+ context "when idle_time > 999 is passed" do
+ it "raises error" do
+ subject.idle_time 1000
+ subject.frequency :on_idle
+ expect { subject.after_created }.to raise_error("idle_time value 1000 is invalid. Valid values for :on_idle frequency are 1 - 999.")
+ end
+ end
+
+ context "when idle_time is passed for frequency=:monthly" do
+ it "raises error" do
+ subject.idle_time 300
+ subject.frequency :monthly
+ expect { subject.after_created }.to raise_error("idle_time property is only valid for tasks that run on_idle")
+ end
+ end
+ end
+
+ describe "action :delete" do
+ subject do
+ new_resource = Chef::Resource::WindowsTask.new(task_name, run_context)
+ new_resource.command task_name
+ new_resource.execution_time_limit = 259200 / 60 # converting "PT72H" into minutes and passing here since win32-taskscheduler accespts this
+ new_resource.frequency :hourly
+ new_resource
+ end
+
+ it "does not converge the resource if it is already converged" do
+ subject.run_action(:create)
+ subject.run_action(:delete)
+ subject.run_action(:delete)
+ expect(subject).not_to be_updated_by_last_action
+ end
+
+ it "does not converge the resource if it is already converged" do
+ subject.run_action(:create)
+ subject.run_action(:delete)
+ subject.run_action(:delete)
+ expect(subject).not_to be_updated_by_last_action
+ end
+ end
+
+ describe "action :run" do
+ after { delete_task }
+
+ subject do
+ new_resource = Chef::Resource::WindowsTask.new(task_name, run_context)
+ new_resource.command "dir"
+ new_resource.run_level :highest
+ new_resource.execution_time_limit = 259200 / 60 # converting "PT72H" into minutes and passing here since
+ new_resource.frequency :hourly
+ new_resource
+ end
+
+ it "runs the existing task" do
+ subject.run_action(:create)
+ subject.run_action(:run)
+ current_resource = call_for_load_current_resource
+ expect(current_resource.task.status).to eq("queued").or eq("running").or eq("ready") # queued or can be running
+ end
+ end
+
+ describe "action :end", :volatile do
+ after { delete_task }
+
+ subject do
+ new_resource = Chef::Resource::WindowsTask.new(task_name, run_context)
+ new_resource.command "dir"
+ new_resource.run_level :highest
+ new_resource.execution_time_limit = 259200 / 60 # converting "PT72H" into minutes and passing here since
+ new_resource
+ end
+
+ it "ends the running task" do
+ subject.run_action(:create)
+ subject.run_action(:run)
+ subject.run_action(:end)
+ current_resource = call_for_load_current_resource
+ expect(current_resource.task.status).to eq("queued").or eq("ready") #queued or can be ready
+ end
+ end
+
+ describe "action :enable" do
+ after { delete_task }
+
+ subject do
+ new_resource = Chef::Resource::WindowsTask.new(task_name, run_context)
+ new_resource.command task_name
+ new_resource.execution_time_limit = 259200 / 60 # converting "PT72H" into minutes and passing here since
+ new_resource.frequency :hourly
+ new_resource
+ end
+
+ it "enables the disabled task" do
+ subject.run_action(:create)
+ subject.run_action(:disable)
+ current_resource = call_for_load_current_resource
+ expect(current_resource.task.status).to eq("not scheduled")
+ subject.run_action(:enable)
+ current_resource = call_for_load_current_resource
+ expect(current_resource.task.status).to eq("ready")
+ end
+ end
+
+ describe "action :disable" do
+ after { delete_task }
+
+ subject do
+ new_resource = Chef::Resource::WindowsTask.new(task_name, run_context)
+ new_resource.command task_name
+ new_resource.execution_time_limit = 259200 / 60 # converting "PT72H" into minutes and passing here since
+ new_resource.frequency :hourly
+ new_resource
+ end
+
+ it "disables the task" do
+ subject.run_action(:create)
+ subject.run_action(:disable)
+ current_resource = call_for_load_current_resource
+ expect(current_resource.task.status).to eq("not scheduled")
+ end
+ end
+
+ describe "action :change" do
+ after { delete_task }
+ subject do
+ new_resource = Chef::Resource::WindowsTask.new(task_name, run_context)
+ new_resource.command task_name
+ new_resource.execution_time_limit = 259200 / 60 # converting "PT72H" into minutes and passing here since
+ new_resource.frequency :hourly
+ new_resource
+ end
+
+ it "call action_create since change action is alias for create" do
+ subject.run_action(:change)
+ expect(subject).to be_updated_by_last_action
+ end
+ end
+
+ def delete_task
+ task_to_delete = Chef::Resource::WindowsTask.new(task_name, run_context)
+ task_to_delete.run_action(:delete)
+ end
+
+ def call_for_create_action
+ current_resource = call_for_load_current_resource
+ expect(current_resource.exists).to eq(false)
+ subject.run_action(:create)
+ expect(subject).to be_updated_by_last_action
+ end
+
+ def call_for_load_current_resource
+ windows_task_provider.send(:load_current_resource)
+ end
+end
diff --git a/spec/functional/resource/yum_package_spec.rb b/spec/functional/resource/yum_package_spec.rb
new file mode 100644
index 0000000000..7c45a64ae5
--- /dev/null
+++ b/spec/functional/resource/yum_package_spec.rb
@@ -0,0 +1,957 @@
+#
+# Copyright:: Copyright 2016-2018, 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 "functional/resource/base"
+require "chef/mixin/shell_out"
+
+# run this test only for following platforms.
+exclude_test = !(%w{rhel fedora}.include?(ohai[:platform_family]) && !File.exist?("/usr/bin/dnf"))
+describe Chef::Resource::YumPackage, :requires_root, :external => exclude_test do
+ include Chef::Mixin::ShellOut
+
+ # NOTE: every single test here either needs to explicitly call flush_cache or needs to explicitly
+ # call preinstall (which explicitly calls flush_cache). It is your responsibility to do one or the
+ # other in order to minimize calling flush_cache a half dozen times per test.
+
+ def flush_cache
+ Chef::Resource::YumPackage.new("shouldnt-matter", run_context).run_action(:flush_cache)
+ end
+
+ def preinstall(*rpms)
+ rpms.each do |rpm|
+ shell_out!("rpm -ivh #{CHEF_SPEC_ASSETS}/yumrepo/#{rpm}")
+ end
+ flush_cache
+ end
+
+ before(:all) do
+ shell_out!("yum -y install yum-utils")
+ end
+
+ before(:each) do
+ File.open("/etc/yum.repos.d/chef-yum-localtesting.repo", "w+") do |f|
+ f.write <<-EOF
+[chef-yum-localtesting]
+name=Chef DNF spec testing repo
+baseurl=file://#{CHEF_SPEC_ASSETS}/yumrepo
+enable=1
+gpgcheck=0
+ EOF
+ end
+ shell_out!("rpm -qa --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' | grep chef_rpm | xargs -r rpm -e")
+ # next line is useful cleanup if you happen to have been testing both yum + dnf func tests on the same box and
+ # have some dnf garbage left around
+ FileUtils.rm_f "/etc/yum.repos.d/chef-dnf-localtesting.repo"
+ end
+
+ after(:all) do
+ shell_out!("rpm -qa --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' | grep chef_rpm | xargs -r rpm -e")
+ FileUtils.rm_f "/etc/yum.repos.d/chef-yum-localtesting.repo"
+ end
+
+ let(:package_name) { "chef_rpm" }
+ let(:yum_package) do
+ r = Chef::Resource::YumPackage.new(package_name, run_context)
+ r.options("--nogpgcheck")
+ r
+ end
+
+ def pkg_arch
+ ohai[:kernel][:machine]
+ end
+
+ describe ":install" do
+ context "vanilla use case" do
+ let(:package_name) { "chef_rpm" }
+
+ it "installs if the package is not installed" do
+ flush_cache
+ yum_package.run_action(:install)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.10-1.#{pkg_arch}$")
+ end
+
+ it "does not install if the package is installed" do
+ preinstall("chef_rpm-1.10-1.#{pkg_arch}.rpm")
+ yum_package.run_action(:install)
+ expect(yum_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.10-1.#{pkg_arch}$")
+ end
+
+ it "does not install twice" do
+ flush_cache
+ yum_package.run_action(:install)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.10-1.#{pkg_arch}$")
+ yum_package.run_action(:install)
+ expect(yum_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.10-1.#{pkg_arch}$")
+ end
+
+ it "does not install if the prior version package is installed" do
+ preinstall("chef_rpm-1.2-1.#{pkg_arch}.rpm")
+ yum_package.run_action(:install)
+ expect(yum_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.2-1.#{pkg_arch}$")
+ end
+
+ it "does not install if the i686 package is installed", :intel_64bit do
+ skip "FIXME: do nothing, or install the #{pkg_arch} version?"
+ preinstall("chef_rpm-1.10-1.i686.rpm")
+ yum_package.run_action(:install)
+ expect(yum_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.10-1.i686$")
+ end
+
+ it "does not install if the prior version i686 package is installed", :intel_64bit do
+ skip "FIXME: do nothing, or install the #{pkg_arch} version?"
+ preinstall("chef_rpm-1.2-1.i686.rpm")
+ yum_package.run_action(:install)
+ expect(yum_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.2-1.i686$")
+ end
+ end
+
+ context "with versions or globs in the name" do
+ it "works with a version" do
+ flush_cache
+ yum_package.package_name("chef_rpm-1.10")
+ yum_package.run_action(:install)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.10-1.#{pkg_arch}$")
+ end
+
+ it "works with an older version" do
+ flush_cache
+ yum_package.package_name("chef_rpm-1.2")
+ yum_package.run_action(:install)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.2-1.#{pkg_arch}$")
+ end
+
+ it "works with an evra" do
+ flush_cache
+ yum_package.package_name("chef_rpm-0:1.2-1.#{pkg_arch}")
+ yum_package.run_action(:install)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.2-1.#{pkg_arch}$")
+ end
+
+ it "works with version and release" do
+ flush_cache
+ yum_package.package_name("chef_rpm-1.2-1")
+ yum_package.run_action(:install)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.2-1.#{pkg_arch}$")
+ end
+
+ it "works with a version glob" do
+ flush_cache
+ yum_package.package_name("chef_rpm-1*")
+ yum_package.run_action(:install)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.10-1.#{pkg_arch}$")
+ end
+
+ it "works with a name glob + version glob" do
+ flush_cache
+ yum_package.package_name("chef_rp*-1*")
+ yum_package.run_action(:install)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.10-1.#{pkg_arch}$")
+ end
+
+ it "upgrades when the installed version does not match the version string" do
+ preinstall("chef_rpm-1.2-1.#{pkg_arch}.rpm")
+ yum_package.package_name("chef_rpm-1.10")
+ yum_package.run_action(:install)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.10-1.#{pkg_arch}")
+ end
+
+ it "downgrades when the installed version is higher than the package_name version" do
+ preinstall("chef_rpm-1.10-1.#{pkg_arch}.rpm")
+ yum_package.allow_downgrade true
+ yum_package.package_name("chef_rpm-1.2")
+ yum_package.run_action(:install)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.2-1.#{pkg_arch}$")
+ end
+ end
+
+ # version only matches the actual yum version, does not work with epoch or release or combined evr
+ context "with version property" do
+ it "matches the full version" do
+ flush_cache
+ yum_package.package_name("chef_rpm")
+ yum_package.version("1.10")
+ yum_package.run_action(:install)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.10-1.#{pkg_arch}$")
+ end
+
+ it "matches with a glob" do
+ # we are unlikely to ever fix this. if you've found this comment you should use e.g. "tcpdump-4*" in
+ # the name field rather than trying to use a name of "tcpdump" and a version of "4*".
+ pending "this does not work, is not easily supported by the underlying yum libraries, but does work in the new dnf_package provider"
+ flush_cache
+ yum_package.package_name("chef_rpm")
+ yum_package.version("1*")
+ yum_package.run_action(:install)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.10-1.#{pkg_arch}$")
+ end
+
+ it "matches the vr" do
+ flush_cache
+ yum_package.package_name("chef_rpm")
+ yum_package.version("1.10-1")
+ yum_package.run_action(:install)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.10-1.#{pkg_arch}$")
+ end
+
+ it "matches the evr" do
+ flush_cache
+ yum_package.package_name("chef_rpm")
+ yum_package.version("0:1.10-1")
+ yum_package.run_action(:install)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.10-1.#{pkg_arch}$")
+ end
+
+ it "matches with a vr glob" do
+ pending "doesn't work on command line either"
+ flush_cache
+ yum_package.package_name("chef_rpm")
+ yum_package.version("1.10-1*")
+ yum_package.run_action(:install)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.10-1.#{pkg_arch}$")
+ end
+
+ it "matches with an evr glob" do
+ pending "doesn't work on command line either"
+ flush_cache
+ yum_package.package_name("chef_rpm")
+ yum_package.version("0:1.10-1*")
+ yum_package.run_action(:install)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.10-1.#{pkg_arch}$")
+ end
+ end
+
+ context "downgrades" do
+ it "downgrades the package when allow_downgrade" do
+ flush_cache
+ preinstall("chef_rpm-1.10-1.#{pkg_arch}.rpm")
+ yum_package.package_name("chef_rpm")
+ yum_package.allow_downgrade true
+ yum_package.version("1.2-1")
+ yum_package.run_action(:install)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.2-1.#{pkg_arch}$")
+ end
+ end
+
+ context "with arches", :intel_64bit do
+ it "installs with 64-bit arch in the name" do
+ flush_cache
+ yum_package.package_name("chef_rpm.#{pkg_arch}")
+ yum_package.run_action(:install)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.10-1.#{pkg_arch}$")
+ end
+
+ it "installs with 32-bit arch in the name" do
+ flush_cache
+ yum_package.package_name("chef_rpm.i686")
+ yum_package.run_action(:install)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.10-1.i686$")
+ end
+
+ it "installs with 64-bit arch in the property" do
+ flush_cache
+ yum_package.package_name("chef_rpm")
+ yum_package.arch("#{pkg_arch}")
+ yum_package.run_action(:install)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.10-1.#{pkg_arch}$")
+ end
+
+ it "installs with 32-bit arch in the property" do
+ flush_cache
+ yum_package.package_name("chef_rpm")
+ yum_package.arch("i686")
+ yum_package.run_action(:install)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.10-1.i686$")
+ end
+ end
+
+ context "with constraints" do
+ it "with nothing installed, it installs the latest version", not_rhel5: true do
+ flush_cache
+ yum_package.package_name("chef_rpm >= 1.2")
+ yum_package.run_action(:install)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.10-1.#{pkg_arch}$")
+ end
+
+ it "when it is met, it does nothing", not_rhel5: true do
+ preinstall("chef_rpm-1.2-1.#{pkg_arch}.rpm")
+ yum_package.package_name("chef_rpm >= 1.2")
+ yum_package.run_action(:install)
+ expect(yum_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.2-1.#{pkg_arch}$")
+ end
+
+ it "when it is met, it does nothing", not_rhel5: true do
+ preinstall("chef_rpm-1.10-1.#{pkg_arch}.rpm")
+ yum_package.package_name("chef_rpm >= 1.2")
+ yum_package.run_action(:install)
+ expect(yum_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.10-1.#{pkg_arch}$")
+ end
+
+ it "with nothing intalled, it installs the latest version", not_rhel5: true do
+ flush_cache
+ yum_package.package_name("chef_rpm > 1.2")
+ yum_package.run_action(:install)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.10-1.#{pkg_arch}$")
+ end
+
+ it "when it is not met by an installed rpm, it upgrades", not_rhel5: true do
+ preinstall("chef_rpm-1.2-1.#{pkg_arch}.rpm")
+ yum_package.package_name("chef_rpm > 1.2")
+ yum_package.run_action(:install)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.10-1.#{pkg_arch}$")
+ end
+
+ it "with an equality constraint, when it is not met by an installed rpm, it upgrades", not_rhel5: true do
+ preinstall("chef_rpm-1.2-1.#{pkg_arch}.rpm")
+ yum_package.package_name("chef_rpm = 1.10")
+ yum_package.run_action(:install)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.10-1.#{pkg_arch}$")
+ end
+
+ it "with an equality constraint, when it is met by an installed rpm, it does nothing", not_rhel5: true do
+ preinstall("chef_rpm-1.2-1.#{pkg_arch}.rpm")
+ yum_package.package_name("chef_rpm = 1.2")
+ yum_package.run_action(:install)
+ expect(yum_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.2-1.#{pkg_arch}$")
+ end
+
+ it "when it is met by an installed rpm, it does nothing", not_rhel5: true do
+ preinstall("chef_rpm-1.10-1.#{pkg_arch}.rpm")
+ yum_package.package_name("chef_rpm > 1.2")
+ yum_package.run_action(:install)
+ expect(yum_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.10-1.#{pkg_arch}$")
+ end
+
+ it "when there is no solution to the contraint", not_rhel5: true do
+ flush_cache
+ yum_package.package_name("chef_rpm > 2.0")
+ expect { yum_package.run_action(:install) }.to raise_error(Chef::Exceptions::Package, /No candidate version available/)
+ end
+
+ it "when there is no solution to the contraint but an rpm is preinstalled", not_rhel5: true do
+ preinstall("chef_rpm-1.10-1.#{pkg_arch}.rpm")
+ yum_package.package_name("chef_rpm > 2.0")
+ expect { yum_package.run_action(:install) }.to raise_error(Chef::Exceptions::Package, /No candidate version available/)
+ end
+
+ it "with a less than constraint, when nothing is installed, it installs", not_rhel5: true do
+ flush_cache
+ yum_package.allow_downgrade true
+ yum_package.package_name("chef_rpm < 1.10")
+ yum_package.run_action(:install)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.2-1.#{pkg_arch}$")
+ end
+
+ it "with a less than constraint, when the install version matches, it does nothing", not_rhel5: true do
+ preinstall("chef_rpm-1.2-1.#{pkg_arch}.rpm")
+ yum_package.allow_downgrade true
+ yum_package.package_name("chef_rpm < 1.10")
+ yum_package.run_action(:install)
+ expect(yum_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.2-1.#{pkg_arch}$")
+ end
+
+ it "with a less than constraint, when the install version fails, it should downgrade", not_rhel5: true do
+ preinstall("chef_rpm-1.10-1.#{pkg_arch}.rpm")
+ yum_package.allow_downgrade true
+ yum_package.package_name("chef_rpm < 1.10")
+ yum_package.run_action(:install)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.2-1.#{pkg_arch}$")
+ end
+ end
+
+ context "with source arguments" do
+ it "raises an exception when the package does not exist" do
+ flush_cache
+ yum_package.package_name("#{CHEF_SPEC_ASSETS}/yumrepo/this-file-better-not-exist.rpm")
+ expect { yum_package.run_action(:install) }.to raise_error(Chef::Exceptions::Package, /No candidate version available/)
+ end
+
+ it "does not raise a hard exception in why-run mode when the package does not exist" do
+ Chef::Config[:why_run] = true
+ flush_cache
+ yum_package.package_name("#{CHEF_SPEC_ASSETS}/yumrepo/this-file-better-not-exist.rpm")
+ yum_package.run_action(:install)
+ expect { yum_package.run_action(:install) }.not_to raise_error
+ end
+
+ it "installs the package when using the source argument" do
+ flush_cache
+ yum_package.name "something"
+ yum_package.package_name "somethingelse"
+ yum_package.source("#{CHEF_SPEC_ASSETS}/yumrepo/chef_rpm-1.2-1.#{pkg_arch}.rpm")
+ yum_package.run_action(:install)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.2-1.#{pkg_arch}$")
+ end
+
+ it "installs the package when the name is a path to a file" do
+ flush_cache
+ yum_package.package_name("#{CHEF_SPEC_ASSETS}/yumrepo/chef_rpm-1.2-1.#{pkg_arch}.rpm")
+ yum_package.run_action(:install)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.2-1.#{pkg_arch}$")
+ end
+
+ it "downgrade on a local file raises an error", not_rhel5: true do
+ preinstall("chef_rpm-1.10-1.#{pkg_arch}.rpm")
+ yum_package.version "1.2-1"
+ yum_package.package_name("#{CHEF_SPEC_ASSETS}/yumrepo/chef_rpm-1.2-1.#{pkg_arch}.rpm")
+ expect { yum_package.run_action(:install) }.to raise_error(Mixlib::ShellOut::ShellCommandFailed)
+ end
+
+ it "downgrade on a local file with allow_downgrade true works" do
+ preinstall("chef_rpm-1.10-1.#{pkg_arch}.rpm")
+ yum_package.version "1.2-1"
+ yum_package.allow_downgrade true
+ yum_package.package_name("#{CHEF_SPEC_ASSETS}/yumrepo/chef_rpm-1.2-1.#{pkg_arch}.rpm")
+ yum_package.run_action(:install)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.2-1.#{pkg_arch}$")
+ end
+
+ it "does not downgrade the package with :install" do
+ preinstall("chef_rpm-1.10-1.#{pkg_arch}.rpm")
+ yum_package.package_name("#{CHEF_SPEC_ASSETS}/yumrepo/chef_rpm-1.2-1.#{pkg_arch}.rpm")
+ yum_package.run_action(:install)
+ expect(yum_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.10-1.#{pkg_arch}$")
+ end
+
+ it "does not upgrade the package with :install" do
+ preinstall("chef_rpm-1.2-1.#{pkg_arch}.rpm")
+ yum_package.package_name("#{CHEF_SPEC_ASSETS}/yumrepo/chef_rpm-1.10-1.#{pkg_arch}.rpm")
+ yum_package.run_action(:install)
+ expect(yum_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.2-1.#{pkg_arch}$")
+ end
+
+ it "is idempotent when the package is already installed" do
+ preinstall("chef_rpm-1.2-1.#{pkg_arch}.rpm")
+ yum_package.package_name("#{CHEF_SPEC_ASSETS}/yumrepo/chef_rpm-1.2-1.#{pkg_arch}.rpm")
+ yum_package.run_action(:install)
+ expect(yum_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.2-1.#{pkg_arch}$")
+ end
+ end
+
+ context "with no available version" do
+ it "works when a package is installed" do
+ FileUtils.rm_f "/etc/yum.repos.d/chef-yum-localtesting.repo"
+ preinstall("chef_rpm-1.2-1.#{pkg_arch}.rpm")
+ yum_package.run_action(:install)
+ expect(yum_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.2-1.#{pkg_arch}$")
+ end
+
+ it "works with a local source" do
+ FileUtils.rm_f "/etc/yum.repos.d/chef-yum-localtesting.repo"
+ flush_cache
+ yum_package.package_name("#{CHEF_SPEC_ASSETS}/yumrepo/chef_rpm-1.2-1.#{pkg_arch}.rpm")
+ yum_package.run_action(:install)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.2-1.#{pkg_arch}$")
+ end
+ end
+
+ context "multipackage with arches", :intel_64bit do
+ it "installs two rpms" do
+ flush_cache
+ yum_package.package_name([ "chef_rpm.#{pkg_arch}", "chef_rpm.i686" ] )
+ yum_package.run_action(:install)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match(/^chef_rpm-1.10-1.#{pkg_arch}$/)
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match(/^chef_rpm-1.10-1.i686$/)
+ end
+
+ it "does nothing if both are installed" do
+ preinstall("chef_rpm-1.10-1.#{pkg_arch}.rpm", "chef_rpm-1.10-1.i686.rpm")
+ flush_cache
+ yum_package.package_name([ "chef_rpm.#{pkg_arch}", "chef_rpm.i686" ] )
+ yum_package.run_action(:install)
+ expect(yum_package.updated_by_last_action?).to be false
+ end
+
+ it "installs the second rpm if the first is installed" do
+ preinstall("chef_rpm-1.10-1.#{pkg_arch}.rpm")
+ yum_package.package_name([ "chef_rpm.#{pkg_arch}", "chef_rpm.i686" ] )
+ yum_package.run_action(:install)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match(/^chef_rpm-1.10-1.#{pkg_arch}$/)
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match(/^chef_rpm-1.10-1.i686$/)
+ end
+
+ it "installs the first rpm if the second is installed" do
+ preinstall("chef_rpm-1.10-1.i686.rpm")
+ yum_package.package_name([ "chef_rpm.#{pkg_arch}", "chef_rpm.i686" ] )
+ yum_package.run_action(:install)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match(/^chef_rpm-1.10-1.#{pkg_arch}$/)
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match(/^chef_rpm-1.10-1.i686$/)
+ end
+
+ # unlikely to work consistently correct, okay to deprecate the arch-array in favor of the arch in the name
+ it "installs two rpms with multi-arch" do
+ flush_cache
+ yum_package.package_name(%w{chef_rpm chef_rpm} )
+ yum_package.arch([pkg_arch, "i686"])
+ yum_package.run_action(:install)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match(/^chef_rpm-1.10-1.#{pkg_arch}$/)
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match(/^chef_rpm-1.10-1.i686$/)
+ end
+
+ # unlikely to work consistently correct, okay to deprecate the arch-array in favor of the arch in the name
+ it "installs the second rpm if the first is installed (muti-arch)" do
+ preinstall("chef_rpm-1.10-1.#{pkg_arch}.rpm")
+ yum_package.package_name(%w{chef_rpm chef_rpm} )
+ yum_package.arch([pkg_arch, "i686"])
+ yum_package.run_action(:install)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match(/^chef_rpm-1.10-1.#{pkg_arch}$/)
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match(/^chef_rpm-1.10-1.i686$/)
+ end
+
+ # unlikely to work consistently correct, okay to deprecate the arch-array in favor of the arch in the name
+ it "installs the first rpm if the second is installed (muti-arch)" do
+ preinstall("chef_rpm-1.10-1.#{pkg_arch}.rpm")
+ yum_package.package_name(%w{chef_rpm chef_rpm} )
+ yum_package.arch([pkg_arch, "i686"])
+ yum_package.run_action(:install)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match(/^chef_rpm-1.10-1.#{pkg_arch}$/)
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match(/^chef_rpm-1.10-1.i686$/)
+ end
+
+ # unlikely to work consistently correct, okay to deprecate the arch-array in favor of the arch in the name
+ it "does nothing if both are installed (muti-arch)" do
+ preinstall("chef_rpm-1.10-1.#{pkg_arch}.rpm", "chef_rpm-1.10-1.i686.rpm")
+ yum_package.package_name(%w{chef_rpm chef_rpm} )
+ yum_package.arch([pkg_arch, "i686"])
+ yum_package.run_action(:install)
+ expect(yum_package.updated_by_last_action?).to be false
+ end
+ end
+
+ context "repo controls" do
+ it "should fail with the repo disabled" do
+ flush_cache
+ yum_package.options("--disablerepo=chef-yum-localtesting")
+ expect { yum_package.run_action(:install) }.to raise_error(Chef::Exceptions::Package, /No candidate version available/)
+ end
+
+ it "should work with disablerepo first" do
+ flush_cache
+ yum_package.options(["--disablerepo=*", "--enablerepo=chef-yum-localtesting"])
+ yum_package.run_action(:install)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.10-1.#{pkg_arch}$")
+ end
+
+ it "should work to enable a disabled repo", not_rhel5: true do
+ shell_out!("yum-config-manager --disable chef-yum-localtesting")
+ flush_cache
+ expect { yum_package.run_action(:install) }.to raise_error(Chef::Exceptions::Package, /No candidate version available/)
+ flush_cache
+ yum_package.options("--enablerepo=chef-yum-localtesting")
+ yum_package.run_action(:install)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.10-1.#{pkg_arch}$")
+ end
+
+ it "when an idempotent install action is run, does not leave repos disabled" do
+ flush_cache
+ # this is a bit tricky -- we need this action to be idempotent, so that it doesn't recycle any
+ # caches, but need it to hit whatavailable with the repo disabled. using :upgrade like this
+ # accomplishes both those goals (it would be easier if we had other rpms in this repo, but with
+ # one rpm we neeed to do this).
+ preinstall("chef_rpm-1.2-1.#{pkg_arch}.rpm")
+ yum_package.options("--disablerepo=chef-yum-localtesting")
+ yum_package.run_action(:upgrade)
+ expect(yum_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.2-1.#{pkg_arch}$")
+ # now we're still using the same cache in the yum_helper.py cache and we test to see if the
+ # repo that we temporarily disabled is enabled on this pass.
+ yum_package.package_name("chef_rpm-1.10-1.#{pkg_arch}")
+ yum_package.options(nil)
+ yum_package.run_action(:install)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.10-1.#{pkg_arch}$")
+ end
+ end
+ end
+
+ describe ":upgrade" do
+
+ context "with source arguments" do
+ it "installs the package when using the source argument" do
+ flush_cache
+ yum_package.name "something"
+ yum_package.package_name "somethingelse"
+ yum_package.source("#{CHEF_SPEC_ASSETS}/yumrepo/chef_rpm-1.2-1.#{pkg_arch}.rpm")
+ yum_package.run_action(:upgrade)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.2-1.#{pkg_arch}$")
+ end
+
+ it "installs the package when the name is a path to a file" do
+ flush_cache
+ yum_package.package_name("#{CHEF_SPEC_ASSETS}/yumrepo/chef_rpm-1.2-1.#{pkg_arch}.rpm")
+ yum_package.run_action(:upgrade)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.2-1.#{pkg_arch}$")
+ end
+
+ it "downgrades the package when allow_downgrade is true" do
+ preinstall("chef_rpm-1.10-1.#{pkg_arch}.rpm")
+ yum_package.allow_downgrade true
+ yum_package.package_name("#{CHEF_SPEC_ASSETS}/yumrepo/chef_rpm-1.2-1.#{pkg_arch}.rpm")
+ yum_package.run_action(:upgrade)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.2-1.#{pkg_arch}$")
+ end
+
+ it "upgrades the package" do
+ preinstall("chef_rpm-1.2-1.#{pkg_arch}.rpm")
+ yum_package.package_name("#{CHEF_SPEC_ASSETS}/yumrepo/chef_rpm-1.10-1.#{pkg_arch}.rpm")
+ yum_package.run_action(:upgrade)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.10-1.#{pkg_arch}$")
+ end
+
+ it "is idempotent when the package is already installed" do
+ preinstall("chef_rpm-1.2-1.#{pkg_arch}.rpm")
+ yum_package.package_name("#{CHEF_SPEC_ASSETS}/yumrepo/chef_rpm-1.2-1.#{pkg_arch}.rpm")
+ yum_package.run_action(:upgrade)
+ expect(yum_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.2-1.#{pkg_arch}$")
+ end
+ end
+
+ context "with no available version" do
+ it "works when a package is installed" do
+ FileUtils.rm_f "/etc/yum.repos.d/chef-yum-localtesting.repo"
+ preinstall("chef_rpm-1.2-1.#{pkg_arch}.rpm")
+ yum_package.package_name("#{CHEF_SPEC_ASSETS}/yumrepo/chef_rpm-1.2-1.#{pkg_arch}.rpm")
+ yum_package.run_action(:upgrade)
+ expect(yum_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.2-1.#{pkg_arch}$")
+ end
+
+ it "works with a local source" do
+ FileUtils.rm_f "/etc/yum.repos.d/chef-yum-localtesting.repo"
+ flush_cache
+ yum_package.package_name("#{CHEF_SPEC_ASSETS}/yumrepo/chef_rpm-1.2-1.#{pkg_arch}.rpm")
+ yum_package.run_action(:upgrade)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.2-1.#{pkg_arch}$")
+ end
+ end
+
+ context "version pinning" do
+ it "with an equality pin in the name it upgrades a prior package" do
+ preinstall("chef_rpm-1.2-1.#{pkg_arch}.rpm")
+ yum_package.package_name("chef_rpm-1.10")
+ yum_package.run_action(:upgrade)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.10-1.#{pkg_arch}$")
+ end
+
+ it "with a prco equality pin in the name it upgrades a prior package", not_rhel5: true do
+ preinstall("chef_rpm-1.2-1.#{pkg_arch}.rpm")
+ yum_package.package_name("chef_rpm == 1.10")
+ yum_package.run_action(:upgrade)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.10-1.#{pkg_arch}$")
+ end
+
+ it "with an equality pin in the name it downgrades a later package" do
+ preinstall("chef_rpm-1.10-1.#{pkg_arch}.rpm")
+ yum_package.allow_downgrade true
+ yum_package.package_name("chef_rpm-1.2")
+ yum_package.run_action(:upgrade)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.2-1.#{pkg_arch}$")
+ end
+
+ it "with a prco equality pin in the name it downgrades a later package", not_rhel5: true do
+ preinstall("chef_rpm-1.10-1.#{pkg_arch}.rpm")
+ yum_package.allow_downgrade true
+ yum_package.package_name("chef_rpm == 1.2")
+ yum_package.run_action(:upgrade)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.2-1.#{pkg_arch}$")
+ end
+
+ it "with a > pin in the name and no rpm installed it installs", not_rhel5: true do
+ flush_cache
+ yum_package.package_name("chef_rpm > 1.2")
+ yum_package.run_action(:upgrade)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.10-1.#{pkg_arch}$")
+ end
+
+ it "with a < pin in the name and no rpm installed it installs", not_rhel5: true do
+ flush_cache
+ yum_package.package_name("chef_rpm < 1.10")
+ yum_package.run_action(:upgrade)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.2-1.#{pkg_arch}$")
+ end
+
+ it "with a > pin in the name and matching rpm installed it does nothing", not_rhel5: true do
+ preinstall("chef_rpm-1.10-1.#{pkg_arch}.rpm")
+ yum_package.package_name("chef_rpm > 1.2")
+ yum_package.run_action(:upgrade)
+ expect(yum_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.10-1.#{pkg_arch}$")
+ end
+
+ it "with a < pin in the name and no rpm installed it installs", not_rhel5: true do
+ preinstall("chef_rpm-1.2-1.#{pkg_arch}.rpm")
+ yum_package.package_name("chef_rpm < 1.10")
+ yum_package.run_action(:upgrade)
+ expect(yum_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.2-1.#{pkg_arch}$")
+ end
+
+ it "with a > pin in the name and non-matching rpm installed it upgrades", not_rhel5: true do
+ preinstall("chef_rpm-1.2-1.#{pkg_arch}.rpm")
+ yum_package.package_name("chef_rpm > 1.2")
+ yum_package.run_action(:upgrade)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.10-1.#{pkg_arch}$")
+ end
+
+ it "with a < pin in the name and non-matching rpm installed it downgrades", not_rhel5: true do
+ preinstall("chef_rpm-1.10-1.#{pkg_arch}.rpm")
+ yum_package.allow_downgrade true
+ yum_package.package_name("chef_rpm < 1.10")
+ yum_package.run_action(:upgrade)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.2-1.#{pkg_arch}$")
+ end
+ end
+ end
+
+ describe ":remove" do
+ context "vanilla use case" do
+ let(:package_name) { "chef_rpm" }
+ it "does nothing if the package is not installed" do
+ flush_cache
+ yum_package.run_action(:remove)
+ expect(yum_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^package chef_rpm is not installed$")
+ end
+
+ it "removes the package if the package is installed" do
+ preinstall("chef_rpm-1.10-1.#{pkg_arch}.rpm")
+ yum_package.run_action(:remove)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^package chef_rpm is not installed$")
+ end
+
+ it "does not remove the package twice" do
+ preinstall("chef_rpm-1.10-1.#{pkg_arch}.rpm")
+ yum_package.run_action(:remove)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^package chef_rpm is not installed$")
+ yum_package.run_action(:remove)
+ expect(yum_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^package chef_rpm is not installed$")
+ end
+
+ it "removes the package if the prior version package is installed" do
+ preinstall("chef_rpm-1.2-1.#{pkg_arch}.rpm")
+ yum_package.run_action(:remove)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^package chef_rpm is not installed$")
+ end
+
+ it "removes the package if the i686 package is installed", :intel_64bit do
+ skip "FIXME: should this be fixed or is the current behavior correct?"
+ preinstall("chef_rpm-1.10-1.i686.rpm")
+ yum_package.run_action(:remove)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^package chef_rpm is not installed$")
+ end
+
+ it "removes the package if the prior version i686 package is installed", :intel_64bit do
+ skip "FIXME: should this be fixed or is the current behavior correct?"
+ preinstall("chef_rpm-1.2-1.i686.rpm")
+ yum_package.run_action(:remove)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^package chef_rpm is not installed$")
+ end
+ end
+
+ context "with 64-bit arch", :intel_64bit do
+ let(:package_name) { "chef_rpm.#{pkg_arch}" }
+ it "does nothing if the package is not installed" do
+ flush_cache
+ yum_package.run_action(:remove)
+ expect(yum_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^package chef_rpm is not installed$")
+ end
+
+ it "removes the package if the package is installed" do
+ preinstall("chef_rpm-1.10-1.#{pkg_arch}.rpm")
+ yum_package.run_action(:remove)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^package chef_rpm is not installed$")
+ end
+
+ it "removes the package if the prior version package is installed" do
+ preinstall("chef_rpm-1.2-1.#{pkg_arch}.rpm")
+ yum_package.run_action(:remove)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^package chef_rpm is not installed$")
+ end
+
+ it "does nothing if the i686 package is installed" do
+ preinstall("chef_rpm-1.10-1.i686.rpm")
+ yum_package.run_action(:remove)
+ expect(yum_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.10-1.i686$")
+ end
+
+ it "does nothing if the prior version i686 package is installed" do
+ preinstall("chef_rpm-1.2-1.i686.rpm")
+ yum_package.run_action(:remove)
+ expect(yum_package.updated_by_last_action?).to be false
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.2-1.i686$")
+ end
+ end
+
+ context "with 32-bit arch", :intel_64bit do
+ let(:package_name) { "chef_rpm.i686" }
+ it "removes only the 32-bit arch if both are installed" do
+ preinstall("chef_rpm-1.10-1.#{pkg_arch}.rpm", "chef_rpm-1.10-1.i686.rpm")
+ yum_package.run_action(:remove)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^chef_rpm-1.10-1.#{pkg_arch}$")
+ end
+ end
+
+ context "with no available version" do
+ it "works when a package is installed" do
+ FileUtils.rm_f "/etc/yum.repos.d/chef-yum-localtesting.repo"
+ preinstall("chef_rpm-1.2-1.#{pkg_arch}.rpm")
+ yum_package.run_action(:remove)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("rpm -q --queryformat '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' chef_rpm").stdout.chomp).to match("^package chef_rpm is not installed$")
+ end
+ end
+ end
+
+ describe ":lock and :unlock" do
+ before(:all) do
+ shell_out!("yum -y install yum-versionlock")
+ end
+
+ before(:each) do
+ shell_out("yum versionlock delete '*:chef_rpm-*'") # will exit with error when nothing is locked, we don't care
+ end
+
+ it "locks an rpm" do
+ flush_cache
+ yum_package.package_name("chef_rpm")
+ yum_package.run_action(:lock)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("yum versionlock list").stdout.chomp).to match("^0:chef_rpm-")
+ end
+
+ it "does not lock if its already locked" do
+ flush_cache
+ shell_out!("yum versionlock add chef_rpm")
+ yum_package.package_name("chef_rpm")
+ yum_package.run_action(:lock)
+ expect(yum_package.updated_by_last_action?).to be false
+ expect(shell_out("yum versionlock list").stdout.chomp).to match("^0:chef_rpm-")
+ end
+
+ it "unlocks an rpm" do
+ flush_cache
+ shell_out!("yum versionlock add chef_rpm")
+ yum_package.package_name("chef_rpm")
+ yum_package.run_action(:unlock)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("yum versionlock list").stdout.chomp).not_to match("^0:chef_rpm-")
+ end
+
+ it "does not unlock an already locked rpm" do
+ flush_cache
+ yum_package.package_name("chef_rpm")
+ yum_package.run_action(:unlock)
+ expect(yum_package.updated_by_last_action?).to be false
+ expect(shell_out("yum versionlock list").stdout.chomp).not_to match("^0:chef_rpm-")
+ end
+
+ it "check that we can lock based on provides" do
+ flush_cache
+ yum_package.package_name("chef_rpm_provides")
+ yum_package.run_action(:lock)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("yum versionlock list").stdout.chomp).to match("^0:chef_rpm-")
+ end
+
+ it "check that we can unlock based on provides" do
+ flush_cache
+ shell_out!("yum versionlock add chef_rpm")
+ yum_package.package_name("chef_rpm_provides")
+ yum_package.run_action(:unlock)
+ expect(yum_package.updated_by_last_action?).to be true
+ expect(shell_out("yum versionlock list").stdout.chomp).not_to match("^0:chef_rpm-")
+ end
+ end
+end