summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorNimishaS <nimisha.sharad@msystechnologies.com>2016-10-07 09:01:00 +0000
committerNimishaS <nimisha.sharad@msystechnologies.com>2016-11-16 10:04:58 +0000
commit767b66e13f2989693f7adf1b3cebed2e6da6a12d (patch)
tree449b11fe6c5f1c41263c9287f744bbdc67cc9e86 /spec
parentbedcbd5f52448d24fdd7ab26ab79185c011beee3 (diff)
downloadchef-767b66e13f2989693f7adf1b3cebed2e6da6a12d.tar.gz
msu_package resource for Microsoft Update packages
Signed-off-by: NimishaS <nimisha.sharad@msystechnologies.com> Signed-off-by: NimishaS <nimisha.sharad@msystechnologies.com>
Diffstat (limited to 'spec')
-rw-r--r--spec/data/sample_msu1.xml10
-rw-r--r--spec/data/sample_msu2.xml14
-rw-r--r--spec/data/sample_msu3.xml16
-rw-r--r--spec/functional/resource/msu_package_spec.rb84
-rw-r--r--spec/spec_helper.rb1
-rw-r--r--spec/support/platform_helpers.rb24
-rw-r--r--spec/unit/provider/package/msu_spec.rb284
-rw-r--r--spec/unit/resource/msu_package_spec.rb49
8 files changed, 474 insertions, 8 deletions
diff --git a/spec/data/sample_msu1.xml b/spec/data/sample_msu1.xml
new file mode 100644
index 0000000000..cc68dbf060
--- /dev/null
+++ b/spec/data/sample_msu1.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<unattend xmlns="urn:schemas-microsoft-com:unattend">
+ <servicing>
+ <package action="install">
+ <assemblyIdentity name="Package_for_KB2859903" version="10.2.1.0" language="neutral" processorArchitecture="x86" publicKeyToken="31bf3856ad364e35"/>
+ <source location="%configsetroot%\IE10-Windows6.1-KB2859903-x86.CAB" />
+ </package>
+ </servicing>
+</unattend>
+
diff --git a/spec/data/sample_msu2.xml b/spec/data/sample_msu2.xml
new file mode 100644
index 0000000000..6f95e04f93
--- /dev/null
+++ b/spec/data/sample_msu2.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<unattend xmlns="urn:schemas-microsoft-com:unattend">
+ <servicing>
+ <package action="install">
+ <assemblyIdentity name="Package_for_KB2859903" version="10.2.1.0" language="neutral" processorArchitecture="x86" publicKeyToken="31bf3856ad364e35"/>
+ <source location="%configsetroot%\IE10-Windows6.1-KB2859903-x86.CAB" />
+ </package>
+ <package action="install">
+ <assemblyIdentity name="Package_for_abc" version="10.2.1.0" language="neutral" processorArchitecture="x86" publicKeyToken="31bf3856ad364e35"/>
+ <source location="%configsetroot%\abc.CAB" />
+ </package>
+ </servicing>
+</unattend>
+
diff --git a/spec/data/sample_msu3.xml b/spec/data/sample_msu3.xml
new file mode 100644
index 0000000000..0ef09da206
--- /dev/null
+++ b/spec/data/sample_msu3.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<unattend xmlns="urn:schemas-microsoft-com:unattend">
+ <servicing>
+ <package action="install">
+ <assemblyIdentity name="Package_for_KB2859903" version="10.2.1.0" language="neutral" processorArchitecture="x86" publicKeyToken="31bf3856ad364e35"/>
+ <source location="%configsetroot%\IE10-Windows6.1-KB2859903-x86.CAB" />
+ </package>
+ </servicing>
+ <servicing>
+ <package action="install">
+ <assemblyIdentity name="Package_for_abc" version="10.2.1.0" language="neutral" processorArchitecture="x86" publicKeyToken="31bf3856ad364e35"/>
+ <source location="%configsetroot%\abc.CAB" />
+ </package>
+ </servicing>
+</unattend>
+
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/spec_helper.rb b/spec/spec_helper.rb
index 7559e797bc..aac5a82f2a 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -139,6 +139,7 @@ RSpec.configure do |config|
config.filter_run_excluding :not_supported_on_gce => true if gce?
config.filter_run_excluding :not_supported_on_nano => true if windows_nano_server?
config.filter_run_excluding :win2k3_only => true unless windows_win2k3?
+ config.filter_run_excluding :win2012r2_only => true unless windows_2012r2?
config.filter_run_excluding :windows_2008r2_or_later => true unless windows_2008r2_or_later?
config.filter_run_excluding :windows64_only => true unless windows64?
config.filter_run_excluding :windows32_only => true unless windows32?
diff --git a/spec/support/platform_helpers.rb b/spec/support/platform_helpers.rb
index 62b262b8a7..14f883da74 100644
--- a/spec/support/platform_helpers.rb
+++ b/spec/support/platform_helpers.rb
@@ -50,23 +50,31 @@ end
def windows_win2k3?
return false unless windows?
- wmi = WmiLite::Wmi.new
- host = wmi.first_of("Win32_OperatingSystem")
- (host["version"] && host["version"].start_with?("5.2"))
+ (host_version && host_version.start_with?("5.2"))
end
def windows_2008r2_or_later?
return false unless windows?
- wmi = WmiLite::Wmi.new
- host = wmi.first_of("Win32_OperatingSystem")
- version = host["version"]
- return false unless version
- components = version.split(".").map do |component|
+ return false unless host_version
+ components = host_version.split(".").map do |component|
component.to_i
end
components.length >= 2 && components[0] >= 6 && components[1] >= 1
end
+def windows_2012r2?
+ return false unless windows?
+ (host_version && host_version.start_with?("6.3"))
+end
+
+def host_version
+ @host_version ||= begin
+ wmi = WmiLite::Wmi.new
+ host = wmi.first_of("Win32_OperatingSystem")
+ host["version"]
+ end
+end
+
def windows_powershell_dsc?
return false unless windows?
supports_dsc = false
diff --git a/spec/unit/provider/package/msu_spec.rb b/spec/unit/provider/package/msu_spec.rb
new file mode 100644
index 0000000000..d9b97aaee6
--- /dev/null
+++ b/spec/unit/provider/package/msu_spec.rb
@@ -0,0 +1,284 @@
+#
+# Author:: Nimisha Sharad (<nimisha.sharad@msystechnologies.com>)
+# Copyright:: Copyright 2008-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::Provider::Package::Msu, :windows_only do
+ let(:timeout) {}
+
+ let(:new_resource) { Chef::Resource::MsuPackage.new("windows_test_pkg") }
+
+ let(:provider) do
+ node = Chef::Node.new
+ events = Chef::EventDispatch::Dispatcher.new
+ run_context = Chef::RunContext.new(node, {}, events)
+ Chef::Provider::Package::Msu.new(new_resource, run_context)
+ end
+
+ let(:installed_package_list_stdout) do
+ <<-EOF
+Packages listing:
+Package Identity : Package_for_KB2999486~31bf3856ad364e35~amd64~~6.1.9768.0
+Package Identity : Package_for_KB2994825~31bf3856ad364e35~amd64~~6.1.7601.0
+ EOF
+ end
+
+ let(:package_version_stdout) do
+ <<-EOF
+Package information:
+Package Identity : Package_for_KB2664825~31bf3856ad364e35~amd64~~6.1.3.0
+State : Installed
+Dependency : Language Pack
+The operation completed successfully
+ EOF
+ end
+
+ let(:get_package_info_stdout) do
+ <<-EOF
+Deployment Image Servicing and Management tool
+Version: 6.1.7600.16385
+
+Image Version: 6.1.7600.16385
+
+Package information:
+Package Identity : Package_for_KB2664825~31bf3856ad364e35~amd64~~6.1.3.0
+Applicable : Yes
+Copyright : Microsoft Corporation
+Company : Microsoft Corporation
+State : Installed
+Dependency : Language Pack
+The operation completed successfully
+ EOF
+ end
+
+ def allow_get_packages
+ get_packages_stdout = <<-EOF
+Deployment Image Servicing and Management tool
+Version: 6.1.7600.16385
+
+Image Version: 6.1.7600.16385
+
+Packages listing:
+
+Package Identity : Package_for_KB2999486~31bf3856ad364e35~amd64~~6.1.9768.0
+State : Installed
+Release Type : Language Pack
+Install Time : 2/11/2015 11:33 PM
+
+Package Identity : Package_for_KB2994825~31bf3856ad364e35~amd64~~6.1.7601.0
+State : Installed
+Release Type : Language Pack
+Install Time : 2/11/2015 11:33 PM
+
+Package Identity : Package_for_KB2664825~31bf3856ad364e35~amd64~~6.1.3.0
+State : Installed
+Release Type : Feature Pack
+Install Time : 11/21/2010 3:40 AM
+
+The operation completed successfully.
+ EOF
+ get_packages_obj = double(stdout: get_packages_stdout)
+ allow_any_instance_of(Chef::Provider::Package::Cab).to receive(:dism_command).with("/Get-Packages").and_return(get_packages_obj)
+ end
+
+ before do
+ allow(Dir).to receive(:mktmpdir)
+ allow(provider).to receive(:cleanup_after_converge)
+ end
+
+ describe "#initialize" do
+ it "returns the correct class" do
+ expect(provider).to be_kind_of(Chef::Provider::Package::Msu)
+ end
+ end
+
+ describe "#load_current_resource" do
+ before do
+ new_resource.source = "C:\\Temp\\Test6.1-KB2664825-v3-x64.msu"
+ cab_file = "c:\\temp\\test6.1-kb2664825-v3-x64.cab"
+ allow(provider).to receive(:extract_msu_contents)
+ allow(provider).to receive(:read_cab_files_from_xml).and_return([cab_file])
+ installed_package_list_obj = double(stdout: installed_package_list_stdout)
+ allow_any_instance_of(Chef::Provider::Package::Cab).to receive(:dism_command).with("/Get-Packages").and_return(installed_package_list_obj)
+ package_version_obj = double(stdout: package_version_stdout)
+ allow_any_instance_of(Chef::Provider::Package::Cab).to receive(:dism_command).with("/Get-PackageInfo /PackagePath:\"#{cab_file}\"").and_return(package_version_obj)
+ end
+
+ it "returns a current_resource" do
+ expect(provider.load_current_resource).to be_kind_of(Chef::Resource::MsuPackage)
+ end
+
+ it "sets the current_resource.version to nil when the package is not installed" do
+ provider.load_current_resource
+ expect(provider.current_resource.version).to eql([nil])
+ end
+
+ it "calls download_source_file method if source is a URL" do
+ new_resource.source = "https://www.something.com/Test6.1-KB2664825-v3-x64.msu"
+ expect(provider).to receive(:download_source_file)
+ provider.load_current_resource
+ end
+ end
+
+ describe "#source_resource" do
+ before do
+ new_resource.source = "C:\\Temp\\Test6.1-KB2664825-v3-x64.msu"
+ new_resource.cookbook_name = "Msu_package"
+ end
+
+ it "sets the desired parameters of downloades msu file" do
+ allow(provider).to receive(:default_download_cache_path).and_return("C:\\chef\\cache\\package")
+ source_resource = provider.source_resource
+ expect(source_resource.path).to be == "C:\\chef\\cache\\package"
+ expect(source_resource.name).to be == "windows_test_pkg"
+ expect(source_resource.source).to be == [new_resource.source]
+ expect(source_resource.cookbook_name).to be == "Msu_package"
+ expect(source_resource.checksum).to be == nil
+ end
+ end
+
+ describe "#default_download_cache_path" do
+ before do
+ new_resource.source = "https://www.something.com/Test6.1-KB2664825-v3-x64.msu"
+ end
+
+ it "returns a clean cache path where the msu file is downloaded" do
+ allow(Chef::FileCache).to receive(:create_cache_path).and_return("C:\\chef\\abc\\package")
+ path = provider.default_download_cache_path
+ expect(path).to be == "C:\\chef\\abc\\package\\Test6.1-KB2664825-v3-x64.msu"
+ end
+ end
+
+ describe "action specs" do
+ before do
+ new_resource.source = "C:\\Temp\\Test6.1-KB2664825-v3-x64.msu"
+ cab_file = "c:\\temp\\test6.1-kb2664825-v3-x64.cab"
+ allow(provider).to receive(:extract_msu_contents)
+ allow(provider).to receive(:read_cab_files_from_xml).and_return([cab_file])
+ installed_package_list_obj = double(stdout: installed_package_list_stdout)
+ allow_any_instance_of(Chef::Provider::Package::Cab).to receive(:dism_command).with("/Get-Packages").and_return(installed_package_list_obj)
+ package_version_obj = double(stdout: package_version_stdout)
+ allow_any_instance_of(Chef::Provider::Package::Cab).to receive(:dism_command).with("/Get-PackageInfo /PackagePath:\"#{cab_file}\"").and_return(package_version_obj)
+ end
+
+ describe "#action_install" do
+ it "installs package if not already installed" do
+ provider.load_current_resource
+ expect(provider.current_resource.version).to eql([nil])
+ expect(provider).to receive(:install_package)
+ provider.run_action(:install)
+ expect(new_resource).to be_updated_by_last_action
+ end
+
+ it "does not install package if already installed" do
+ get_package_info_obj = double(stdout: get_package_info_stdout)
+ allow_any_instance_of(Chef::Provider::Package::Cab).to receive(:dism_command).with("/Get-PackageInfo /PackagePath:\"#{new_resource.source}\"").and_return(get_package_info_obj)
+ allow_get_packages
+ allow_any_instance_of(Chef::Provider::Package::Cab).to receive(:dism_command).with("/Get-PackageInfo /PackageName:\"Package_for_KB2664825~31bf3856ad364e35~amd64~~6.1.3.0\"").and_return(get_package_info_obj)
+ provider.load_current_resource
+ expect(provider.current_resource.version).to eql(["6.1.3.0"])
+ expect(provider).not_to receive(:install_package)
+ provider.run_action(:install)
+ expect(new_resource).not_to be_updated_by_last_action
+ end
+ end
+
+ describe "#action_remove" do
+ it "does nothing when the package is not present" do
+ provider.load_current_resource
+ expect(provider).not_to receive(:remove_package)
+ provider.run_action(:remove)
+ expect(new_resource).not_to be_updated_by_last_action
+ end
+
+ it "removes packages if package is installed" do
+ get_package_info_obj = double(stdout: get_package_info_stdout)
+ allow_any_instance_of(Chef::Provider::Package::Cab).to receive(:dism_command).with("/Get-PackageInfo /PackagePath:\"#{new_resource.source}\"").and_return(get_package_info_obj)
+ allow_get_packages
+ allow_any_instance_of(Chef::Provider::Package::Cab).to receive(:dism_command).with("/Get-PackageInfo /PackageName:\"Package_for_KB2664825~31bf3856ad364e35~amd64~~6.1.3.0\"").and_return(get_package_info_obj)
+ provider.load_current_resource
+ expect(provider.current_resource.version).to eql(["6.1.3.0"])
+ expect(provider).to receive(:remove_package)
+ provider.run_action(:remove)
+ expect(new_resource).to be_updated_by_last_action
+ end
+ end
+
+ context "Invalid package source" do
+ def package_version_stdout
+ package_version_stdout = <<-EOF
+
+ Deployment Image Servicing and Management tool
+ Version: 6.1.7600.16385
+
+ Image Version: 6.1.7600.16385
+
+ An error occurred trying to open - c:\\temp\\test6.1-KB2664825-v3-x64.cab Error: 0x80070003
+ Error: 3
+ The system cannot find the path specified.
+ The DISM log file can be found at C:\\Windows\\Logs\\DISM\\dism.log.
+ EOF
+ end
+
+ it "raises error for invalid source path or file" do
+ expect { provider.load_current_resource }.to raise_error(Chef::Exceptions::Package, "DISM: The system cannot find the path or file specified.")
+ end
+ end
+ end
+
+ describe "#extract_msu_contents" do
+ it "extracts the msu contents by using mixlib shellout" do
+ expect(Mixlib::ShellOut).to receive(:new).with("expand -f:* msu_file destination", { :timeout => new_resource.timeout })
+ expect(provider).to receive(:with_os_architecture)
+ provider.extract_msu_contents("msu_file", "destination")
+ end
+ end
+
+ describe "#read_cab_files_from_xml" do
+ it "raises error if the xml file is not present" do
+ allow(Dir).to receive(:glob).and_return([])
+ expect { provider.read_cab_files_from_xml("msu_dir") }.to raise_error(Chef::Exceptions::Package)
+ end
+
+ it "parses xml file with single cab file" do
+ xml_file = File.join(CHEF_SPEC_DATA, "sample_msu1.xml")
+ allow(Dir).to receive(:glob).and_return([xml_file])
+ cab_files = provider.read_cab_files_from_xml("msu_dir")
+ expect(cab_files).to eql(["msu_dir/IE10-Windows6.1-KB2859903-x86.CAB"])
+ end
+
+# We couldn't find any msu file with multiple cab files in it.
+# So we are not 100% sure about the structure of XML file in this case
+# The specs below cover 2 possible XML formats
+ context "handles different xml formats for multiple cab files in the msu package" do
+ it "parses xml file with multiple <package> tags" do
+ xml_file = File.join(CHEF_SPEC_DATA, "sample_msu2.xml")
+ allow(Dir).to receive(:glob).and_return([xml_file])
+ cab_files = provider.read_cab_files_from_xml("msu_dir")
+ expect(cab_files).to eql(["msu_dir/IE10-Windows6.1-KB2859903-x86.CAB", "msu_dir/abc.CAB"])
+ end
+
+ it "parses xml file with multiple <servicing> tags" do
+ xml_file = File.join(CHEF_SPEC_DATA, "sample_msu3.xml")
+ allow(Dir).to receive(:glob).and_return([xml_file])
+ cab_files = provider.read_cab_files_from_xml("msu_dir")
+ expect(cab_files).to eql(["msu_dir/IE10-Windows6.1-KB2859903-x86.CAB", "msu_dir/abc.CAB"])
+ end
+ end
+ end
+end
diff --git a/spec/unit/resource/msu_package_spec.rb b/spec/unit/resource/msu_package_spec.rb
new file mode 100644
index 0000000000..349a382b31
--- /dev/null
+++ b/spec/unit/resource/msu_package_spec.rb
@@ -0,0 +1,49 @@
+#
+# Author:: Nimisha Sharad (<nimisha.sharad@msystechnologies.com>)
+# Copyright:: Copyright 2008-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::MsuPackage do
+ let(:resource) { Chef::Resource::MsuPackage.new("test_pkg") }
+
+ it "creates a new Chef::Resource::MsuPackage" do
+ expect(resource).to be_a_kind_of(Chef::Resource)
+ expect(resource).to be_a_kind_of(Chef::Resource::Package)
+ expect(resource).to be_a_instance_of(Chef::Resource::MsuPackage)
+ end
+
+ it "sets resource name as :msu_package" do
+ expect(resource.resource_name).to eql(:msu_package)
+ end
+
+ it "sets the source as it's name" do
+ expect(resource.source).to eql("test_pkg")
+ end
+
+ it "sets the default action as :install" do
+ expect(resource.action).to eql(:install)
+ end
+
+ it "raises error if invalid action is given" do
+ expect { resource.action "abc" }.to raise_error(Chef::Exceptions::ValidationFailed)
+ end
+
+ it "coerce its name to a package_name" do
+ expect(resource.package_name).to eql("test_pkg")
+ end
+end