# # Author:: Bryan McLellan # Copyright:: Copyright 2014-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" require "chef/provider/package/windows/msi" describe Chef::Provider::Package::Windows::MSI do let(:node) { double("Chef::Node") } let(:events) { double("Chef::Events").as_null_object } # mock all the methods let(:run_context) { double("Chef::RunContext", node: node, events: events) } let(:package_name) { "calculator" } let(:resource_source) { "calculator.msi" } let(:resource_version) { nil } let(:new_resource) do new_resource = Chef::Resource::WindowsPackage.new(package_name) new_resource.source(resource_source) new_resource.version(resource_version) new_resource end let(:uninstall_hash) do [{ "DisplayVersion" => "outdated", "UninstallString" => "MsiExec.exe /X{guid}", }] end let(:uninstall_entry) do entries = [] uninstall_hash.each do |entry| entries.push(Chef::Provider::Package::Windows::RegistryUninstallEntry.new("hive", "key", entry)) end entries end let(:provider) { Chef::Provider::Package::Windows::MSI.new(new_resource, uninstall_entry) } before do allow(::File).to receive(:exist?).with(Chef::Util::PathHelper.canonical_path(resource_source, false)).and_return(true) end it "responds to shell_out!" do expect(provider).to respond_to(:shell_out!) end describe "expand_options" do it "returns an empty string if passed no options" do expect(provider.expand_options(nil)).to eql "" end it "returns a string with a leading space if passed options" do expect(provider.expand_options("--train nope --town no_way")).to eql(" --train nope --town no_way") end end describe "installed_version" do it "returns the installed version" do allow(provider).to receive(:get_product_property).and_return("{23170F69-40C1-2702-0920-000001000000}") allow(provider).to receive(:get_installed_version).with("{23170F69-40C1-2702-0920-000001000000}").and_return("3.14159.1337.42") expect(provider.installed_version).to eql("3.14159.1337.42") end it "returns the installed version in the registry when install file not present" do allow(::File).to receive(:exist?).with(Chef::Util::PathHelper.canonical_path(resource_source, false)).and_return(false) expect(provider.installed_version).to eql(["outdated"]) end end describe "package_version" do it "returns the version of a package" do allow(provider).to receive(:get_product_property).with(/calculator.msi$/, "ProductVersion").and_return(42) expect(provider.package_version).to eql(42) end context "version is explicitly provided" do let(:resource_version) { "given_version" } it "returns the given version" do expect(provider.package_version).to eql("given_version") end end context "no source or version is given" do before do allow(::File).to receive(:exist?).with(Chef::Util::PathHelper.canonical_path(resource_source, false)).and_return(false) end it "returns nil" do expect(provider.package_version).to eql(nil) end end end describe "install_package" do it "calls msiexec /qn /i" do expect(provider).to receive(:shell_out!).with(%r{msiexec /qn /i \"#{Regexp.quote(new_resource.source)}\"}, kind_of(Hash)) provider.install_package end end describe "remove_package" do it "calls msiexec /qn /x" do expect(provider).to receive(:shell_out!).with(%r{msiexec /qn /x \"#{Regexp.quote(new_resource.source)}\"}, kind_of(Hash)) provider.remove_package end context "no source is provided" do before do allow(::File).to receive(:exist?).with(Chef::Util::PathHelper.canonical_path(resource_source, false)).and_return(false) end it "removes installed package" do expect(provider).to receive(:shell_out!).with(%r{msiexec /x {guid} /q}, kind_of(Hash)) provider.remove_package end context "there are multiple installs" do let(:uninstall_hash) do [ { "DisplayVersion" => "outdated", "UninstallString" => "MsiExec.exe /X{guid}", }, { "DisplayVersion" => "really_outdated", "UninstallString" => "MsiExec.exe /X{guid2}", }, ] end it "removes both installed package" do expect(provider).to receive(:shell_out!).with(%r{msiexec /x {guid} /q}, kind_of(Hash)) expect(provider).to receive(:shell_out!).with(%r{msiexec /x {guid2} /q}, kind_of(Hash)) provider.remove_package end end context "custom options includes /Q" do before do new_resource.options("/Q") end it "does not duplicate quiet switch" do expect(provider).to receive(:shell_out!).with(%r{msiexec /x {guid} /Q}, kind_of(Hash)) provider.remove_package end end context "custom options includes /qn" do before do new_resource.options("/qn") end it "does not duplicate quiet switch" do expect(provider).to receive(:shell_out!).with(%r{msiexec /x {guid} /qn}, kind_of(Hash)) provider.remove_package end end end end end