From 79ae72991b6fa131c7a7a387cecfe2854467719b Mon Sep 17 00:00:00 2001 From: Baptiste Courtois Date: Sat, 28 Nov 2015 17:05:22 +0100 Subject: [PATCH 1/6] Use all-in-one ms_dotnet cookbook ms_dotnet is a 'all-in-one' cookbook allowing you to configure almost all .NET versions; It has been written following the same model as this powershell cookbook and is actively maintained by @criteo. Reason for this migration: * Having a single dependency to setup .NET is better than multiple ones. * ms_dotnet is more up-to-date than others cookbooks * ms_dotnet is going to support .NET 4.6 soon * ms_dotnet is rspec testable on linux using ohais instead of Win32 API Other changes: * Because a single recipe takes care of .NET 4 & 4.5, if attributes are not set properly powershell4 recipe which require .NET 4.5 will throw an exception. Some lines of code reimplementing .NET activation have been removed. --- README.md | 4 +--- metadata.rb | 4 +--- recipes/powershell2.rb | 38 ++++++++++---------------------------- recipes/powershell3.rb | 12 +++++++----- recipes/powershell4.rb | 13 ++++++++----- recipes/powershell5.rb | 9 +++------ 6 files changed, 30 insertions(+), 50 deletions(-) diff --git a/README.md b/README.md index df3653d..e6ad4a9 100644 --- a/README.md +++ b/README.md @@ -72,9 +72,7 @@ Not every version of Windows supports every version of Powershell. The following PowerShell also requires the appropriate version of the Microsoft .NET Framework to be installed, if the operating system does not ship with that version. The following community cookbooks are used to install the correct version of the .NET Framework: -* ms_dotnet2 -* ms_dotnet4 -* ms_dotnet45 +* ms_dotnet Resource/Provider ----------------- diff --git a/metadata.rb b/metadata.rb index 4fd47d7..9567c28 100644 --- a/metadata.rb +++ b/metadata.rb @@ -16,9 +16,7 @@ supports 'windows' depends 'windows', '>= 1.2.8' -depends 'ms_dotnet45' -depends 'ms_dotnet4' -depends 'ms_dotnet2' +depends 'ms_dotnet', '>= 2.6' depends 'chef_handler' source_url 'https://github.com/chef-cookbooks/powershell' if respond_to?(:source_url) diff --git a/recipes/powershell2.rb b/recipes/powershell2.rb index 7c5fef0..5a0ed1b 100644 --- a/recipes/powershell2.rb +++ b/recipes/powershell2.rb @@ -23,44 +23,26 @@ case node['platform'] when 'windows' + nt_version = ::Windows::VersionHelper.nt_version(node) - require 'chef/win32/version' - windows_version = Chef::ReservedNames::Win32::Version.new + include_recipe 'ms_dotnet::ms_dotnet2' - if (windows_version.windows_server_2012? || windows_version.windows_8?) && windows_version.core? - # Windows Server 2012 Core does not come with Powershell 2.0 enabled + if nt_version.between?(6.1, 6.2) && ::Windows::VersionHelper.core_version?(node) + feature_suffix = 'V2' if nt_version == 6.2 - windows_feature 'MicrosoftWindowsPowerShellV2' do + windows_feature "MicrosoftWindowsPowerShell#{feature_suffix}" do action :install end - windows_feature 'MicrosoftWindowsPowerShellV2-WOW64' do - action :install - only_if { node['kernel']['machine'] == 'x86_64' } - end - - elsif (windows_version.windows_server_2008_r2? || windows_version.windows_7?) && windows_version.core? - # Windows Server 2008 R2 Core does not come with .NET or Powershell 2.0 enabled - windows_feature 'NetFx2-ServerCore' do - action :install - end - windows_feature 'NetFx2-ServerCore-WOW64' do + windows_feature "MicrosoftWindowsPowerShell#{feature_suffix}-WOW64" do action :install only_if { node['kernel']['machine'] == 'x86_64' } end - windows_feature 'MicrosoftWindowsPowerShell' do - action :install - end - windows_feature 'MicrosoftWindowsPowerShell-WOW64' do - action :install - only_if { node['kernel']['machine'] == 'x86_64' } - end - - elsif windows_version.windows_server_2008? || windows_version.windows_server_2003_r2? || - windows_version.windows_server_2003? || windows_version.windows_xp? - - include_recipe 'ms_dotnet2' + # WMF 2.0 is required and only compatible with: + # * Windows NT 5.1 & 5.2 (Windows Server 2003 & Windows XP) + # * Windows NT 6.0 server (Windows Server 2008 SP2 not vista) + elsif nt_version.between?(5.1, 5.2) || (nt_version == 6.0 && ::Windows::VersionHelper.server_version?(node)) # Reboot if user specifies doesn't specify no_reboot include_recipe 'powershell::windows_reboot' unless node['powershell']['installation_reboot_mode'] == 'no_reboot' diff --git a/recipes/powershell3.rb b/recipes/powershell3.rb index b1786a4..5b6e921 100644 --- a/recipes/powershell3.rb +++ b/recipes/powershell3.rb @@ -24,13 +24,15 @@ case node['platform'] when 'windows' - require 'chef/win32/version' - windows_version = Chef::ReservedNames::Win32::Version.new + nt_version = ::Windows::VersionHelper.nt_version(node) - if windows_version.windows_server_2008? || windows_version.windows_server_2008_r2? || windows_version.windows_7? + # Powershell 3.0 is only compatible with: + # * Windows NT 6.0 server (Windows Server 2008 SP2 not vista) + # * Windows NT 6.1 (Windows Server 2008R2 & Windows 7.1) + if (nt_version == 6.0 && ::Windows::VersionHelper.server_version?(node)) || nt_version == 6.1 # For Windows Server 2008 ensure that Powershell 2 is already installed and so is BITS 4.0 - if windows_version.windows_server_2008? + if nt_version == 6.0 && ::Windows::VersionHelper.server_version?(node) include_recipe 'powershell::powershell2' windows_package 'Windows Management Framework Bits' do @@ -43,7 +45,7 @@ end # WMF 3.0 requires .NET 4.0 - include_recipe 'ms_dotnet4' + include_recipe 'ms_dotnet::ms_dotnet4' # Reboot if user specifies doesn't specify no_reboot include_recipe 'powershell::windows_reboot' unless node['powershell']['installation_reboot_mode'] == 'no_reboot' diff --git a/recipes/powershell4.rb b/recipes/powershell4.rb index a9008a2..ade4ee2 100644 --- a/recipes/powershell4.rb +++ b/recipes/powershell4.rb @@ -22,13 +22,16 @@ # http://www.microsoft.com/en-us/download/details.aspx?id=40855 if node['platform'] == 'windows' - require 'chef/win32/version' - windows_version = Chef::ReservedNames::Win32::Version.new - if windows_version.windows_server_2008_r2? || windows_version.windows_7? || windows_version.windows_server_2012? + nt_version = ::Windows::VersionHelper.nt_version(node) + # WMF 4.0 is only compatible with: + # * Windows NT 6.1 (Windows Server 2008R2 & Windows 7.1) + # * Windows NT 6.2 Server (Windows Server 2012 not Windows 8) + if nt_version == 6.1 || (nt_version == 6.2 && ::Windows::VersionHelper.server_version?(node)) - # Ensure .NET 4.5 is installed or installation will fail silently per Microsoft. Only necessary for Windows 2008R2 or 7. - include_recipe 'ms_dotnet45' if windows_version.windows_server_2008_r2? || windows_version.windows_7? + # Ensure .NET 4.5 is installed or installation will fail silently per Microsoft. + fail 'Attribute ms_dotnet.v4.version is not configured to install .NET4.5 as required for Powershell4' if node['ms_dotnet']['v4']['version'] < '4.5' + include_recipe 'ms_dotnet::ms_dotnet4' # Reboot if user specifies doesn't specify no_reboot include_recipe 'powershell::windows_reboot' unless node['powershell']['installation_reboot_mode'] == 'no_reboot' diff --git a/recipes/powershell5.rb b/recipes/powershell5.rb index 2ccda0f..2d8e758 100644 --- a/recipes/powershell5.rb +++ b/recipes/powershell5.rb @@ -21,15 +21,12 @@ # PowerShell 5.0 Preview Download Page # http://www.microsoft.com/en-us/download/details.aspx?id=42316 -include_recipe 'powershell::powershell2' - case node['platform'] when 'windows' - require 'chef/win32/version' - windows_version = Chef::ReservedNames::Win32::Version.new - - if windows_version.windows_server_2012_r2? || windows_version.windows_8_1? + # Handle WMFC install on 2012R2 and 8.1 only (yet) + if ::Windows::VersionHelper.nt_version(node) == 6.3 + include_recipe 'powershell::powershell2' include_recipe 'powershell::windows_reboot' unless node['powershell']['installation_reboot_mode'] == 'no_reboot' From c4db2d6bbcb639781070c60667d03001977756ce Mon Sep 17 00:00:00 2001 From: Baptiste Courtois Date: Sat, 28 Nov 2015 16:11:31 +0100 Subject: [PATCH 2/6] Fix rubocop violations * Ignore foodcritic rule #009 for windows package success_codes * Refactor winrm recipe's if statements to remove one nested block * Fix `NoMethodError: undefined method `empty' for nil:NilClass` when powershell.winrm.thumbprint is nil --- recipes/powershell2.rb | 2 +- recipes/powershell3.rb | 2 +- recipes/powershell4.rb | 2 +- recipes/powershell5.rb | 2 +- recipes/winrm.rb | 16 +++++++--------- 5 files changed, 11 insertions(+), 13 deletions(-) diff --git a/recipes/powershell2.rb b/recipes/powershell2.rb index 5a0ed1b..5914e51 100644 --- a/recipes/powershell2.rb +++ b/recipes/powershell2.rb @@ -46,7 +46,7 @@ # Reboot if user specifies doesn't specify no_reboot include_recipe 'powershell::windows_reboot' unless node['powershell']['installation_reboot_mode'] == 'no_reboot' - windows_package 'Windows Management Framework Core' do + windows_package 'Windows Management Framework Core' do # ~FC009 source node['powershell']['powershell2']['url'] checksum node['powershell']['powershell2']['checksum'] installer_type :custom diff --git a/recipes/powershell3.rb b/recipes/powershell3.rb index 5b6e921..ed983b2 100644 --- a/recipes/powershell3.rb +++ b/recipes/powershell3.rb @@ -50,7 +50,7 @@ # Reboot if user specifies doesn't specify no_reboot include_recipe 'powershell::windows_reboot' unless node['powershell']['installation_reboot_mode'] == 'no_reboot' - windows_package 'Windows Management Framework Core 3.0' do + windows_package 'Windows Management Framework Core 3.0' do # ~FC009 source node['powershell']['powershell3']['url'] checksum node['powershell']['powershell3']['checksum'] installer_type :custom diff --git a/recipes/powershell4.rb b/recipes/powershell4.rb index ade4ee2..4e2915e 100644 --- a/recipes/powershell4.rb +++ b/recipes/powershell4.rb @@ -36,7 +36,7 @@ # Reboot if user specifies doesn't specify no_reboot include_recipe 'powershell::windows_reboot' unless node['powershell']['installation_reboot_mode'] == 'no_reboot' - windows_package 'Windows Management Framework Core4.0' do + windows_package 'Windows Management Framework Core 4.0' do # ~FC009 source node['powershell']['powershell4']['url'] checksum node['powershell']['powershell4']['checksum'] installer_type :custom diff --git a/recipes/powershell5.rb b/recipes/powershell5.rb index 2d8e758..c5a643a 100644 --- a/recipes/powershell5.rb +++ b/recipes/powershell5.rb @@ -30,7 +30,7 @@ include_recipe 'powershell::windows_reboot' unless node['powershell']['installation_reboot_mode'] == 'no_reboot' - windows_package 'Windows Management Framework Core 5.0' do + windows_package 'Windows Management Framework Core 5.0' do # ~FC009 source node['powershell']['powershell5']['url'] checksum node['powershell']['powershell5']['checksum'] installer_type :custom diff --git a/recipes/winrm.rb b/recipes/winrm.rb index 1b7875e..9ff973b 100644 --- a/recipes/winrm.rb +++ b/recipes/winrm.rb @@ -34,15 +34,13 @@ shell_out = Mixlib::ShellOut.new(winrm_cmd) shell_out.run_command - if !shell_out.stdout.include? 'Transport = HTTPS' - # Create HTTPS listener - if node['powershell']['winrm']['enable_https_transport'] - if node['powershell']['winrm']['thumbprint'].empty? || node['powershell']['winrm']['thumbprint'].nil? - Chef::Log.error('Please specify thumbprint in default attributes for enabling https transport.') - else - powershell_script 'winrm-create-https-listener' do - code "winrm create 'winrm/config/Listener?Address=*+Transport=HTTPS' '@{Hostname=\"#{node['powershell']['winrm']['hostname']}\"; CertificateThumbprint=\"#{node['powershell']['winrm']['thumbprint']}\"}'" - end + # Create HTTPS listener + if !shell_out.stdout.include?('Transport = HTTPS') && node['powershell']['winrm']['enable_https_transport'] + if node['powershell']['winrm']['thumbprint'].nil? || node['powershell']['winrm']['thumbprint'].empty? + Chef::Log.error('Please specify thumbprint in default attributes for enabling https transport.') + else + powershell_script 'winrm-create-https-listener' do + code "winrm create 'winrm/config/Listener?Address=*+Transport=HTTPS' '@{Hostname=\"#{node['powershell']['winrm']['hostname']}\"; CertificateThumbprint=\"#{node['powershell']['winrm']['thumbprint']}\"}'" end end else From 2e9ecc8d775e1108e3388478be6c4859907277d1 Mon Sep 17 00:00:00 2001 From: Baptiste Courtois Date: Sat, 28 Nov 2015 17:06:26 +0100 Subject: [PATCH 3/6] Fix specs for powershell recipes * Update powershell's recipes' specs to test the new code. * Removed useless tests - e.g. windows 7 Core does not exist. * Tests factorization to avoid code/mistake duplication. --- spec/recipes/powershell2_spec.rb | 96 ++++------ spec/recipes/powershell3_spec.rb | 133 ++++++-------- spec/recipes/powershell4_spec.rb | 296 ++++++------------------------- spec/recipes/powershell5_spec.rb | 65 +++---- 4 files changed, 172 insertions(+), 418 deletions(-) diff --git a/spec/recipes/powershell2_spec.rb b/spec/recipes/powershell2_spec.rb index d008b23..dccf35f 100644 --- a/spec/recipes/powershell2_spec.rb +++ b/spec/recipes/powershell2_spec.rb @@ -1,18 +1,11 @@ require 'spec_helper' -require 'chef/win32/version' describe 'powershell::powershell2' do - let(:chef_run) do - ChefSpec::SoloRunner.new(platform: 'windows', version: '2012') do |node| - node.set['powershell']['powershell2']['url'] = 'https://powershelltest.com' - node.set['powershell']['powershell2']['checksum'] = '12345' - end.converge(described_recipe) - end - - context 'when windows_version is windows_server_2012 and windows_version is core ' do - before do - @windows_version = double(windows_server_2012?: true, windows_8?: false, core?: true) - allow(Chef::ReservedNames::Win32::Version).to receive(:new).and_return(@windows_version) + context 'on Windows Server 2012 Core' do + let(:chef_run) do + ChefSpec::SoloRunner.new(platform: 'windows', version: '2012') do |node| + node.automatic['kernel']['os_info']['operating_system_sku'] = 0x0D + end.converge(described_recipe) end it 'installs windows features' do @@ -21,25 +14,14 @@ end end - context 'when windows_version is windows_8 and windows_version is core ' do - before do - @windows_version = double(windows_server_2012?: false, windows_8?: true, core?: true) - allow(Chef::ReservedNames::Win32::Version).to receive(:new).and_return(@windows_version) + context 'on Windows Server 2008R2 Core' do + let(:chef_run) do + ChefSpec::SoloRunner.new(platform: 'windows', version: '2008R2') do |node| + node.automatic['kernel']['os_info']['operating_system_sku'] = 0x0D + end.converge(described_recipe) end it 'installs windows features' do - expect(chef_run).to install_windows_feature('MicrosoftWindowsPowerShellV2') - expect(chef_run).to install_windows_feature('MicrosoftWindowsPowerShellV2-WOW64') - end - end - - context 'when windows_version is windows_server_2008_r2 and windows_version is core ' do - before do - @windows_version = double(windows_server_2008_r2?: true, windows_7?: false, core?: true, windows_server_2012?: false, windows_8?: false) - allow(Chef::ReservedNames::Win32::Version).to receive(:new).and_return(@windows_version) - end - - it 'installs windows feature' do expect(chef_run).to install_windows_feature('NetFx2-ServerCore') expect(chef_run).to install_windows_feature('NetFx2-ServerCore-WOW64') expect(chef_run).to install_windows_feature('MicrosoftWindowsPowerShell') @@ -47,46 +29,36 @@ end end - context 'when windows_version is windows_7 and windows_version is core' do - before do - @windows_version = double(windows_server_2008_r2?: false, windows_7?: true, core?: true, windows_server_2012?: false, windows_8?: false) - allow(Chef::ReservedNames::Win32::Version).to receive(:new).and_return(@windows_version) + context 'on Windows Server 2008' do + let(:chef_run) do + # There is no fauxhai info for windows server 2008, so we use 2008R2 and change the platform version + ChefSpec::SoloRunner.new(platform: 'windows', version: '2008R2') do |node| + node.automatic['platform_version'] = '6.0.6001' + node.set['powershell']['powershell2']['url'] = 'https://powershelltest.com' + node.set['powershell']['powershell2']['checksum'] = '12345' + end.converge(described_recipe) end - it 'installs windows feature' do - expect(chef_run).to install_windows_feature('NetFx2-ServerCore') - expect(chef_run).to install_windows_feature('NetFx2-ServerCore-WOW64') - expect(chef_run).to install_windows_feature('MicrosoftWindowsPowerShell') - expect(chef_run).to install_windows_feature('MicrosoftWindowsPowerShell-WOW64') - end - end + context 'when powershell2 does not exist' do + before do + allow(Chef::Win32::Registry).to receive(:new).and_return double('registry', data_exists?: false, value_exists?: false, key_exists?: false) + end - context 'when windows_version is windows_server_2008' do - before do - @windows_version = double(windows_server_2008?: true, windows_server_2003_r2?: false, windows_server_2003?: false, windows_xp?: false, windows_server_2008_r2?: false, windows_7?: false, core?: false, windows_server_2012?: false, windows_8?: false) - allow(Chef::ReservedNames::Win32::Version).to receive(:new).and_return(@windows_version) - registry = double - allow(Chef::Win32::Registry).to receive(:new).and_return(registry) - allow(registry).to receive(:data_exists?).and_return(false) + it 'installs windows package' do + expect(chef_run).to include_recipe('ms_dotnet::ms_dotnet2') + expect(chef_run).to install_windows_package('Windows Management Framework Core').with(source: 'https://powershelltest.com', checksum: '12345', installer_type: :custom, options: '/quiet /norestart') + end end - it 'installs windows package when powershell2 doesnot exist' do - expect(chef_run).to include_recipe('ms_dotnet2') - expect(chef_run).to install_windows_package('Windows Management Framework Core').with(source: 'https://powershelltest.com', checksum: '12345', installer_type: :custom, options: '/quiet /norestart') - end - end - - context 'when windows_version is windows_server_2008' do - before do - @windows_version = double(windows_server_2008?: true, windows_server_2003_r2?: false, windows_server_2003?: false, windows_xp?: false, windows_server_2008_r2?: false, windows_7?: false, core?: false, windows_server_2012?: false, windows_8?: false) - allow(Chef::ReservedNames::Win32::Version).to receive(:new).and_return(@windows_version) - registry = double - allow(Chef::Win32::Registry).to receive(:new).and_return(registry) - allow(registry).to receive(:data_exists?).and_return(true) - end + context 'when powershell2 exist' do + before do + allow(Chef::Win32::Registry).to receive(:new).and_return double('registry', data_exists?: true, value_exists?: true) + end - it 'only includes ms_dotnet2 when powershell2 exist' do - expect(chef_run).to include_recipe('ms_dotnet2') + it 'only includes ms_dotnet2' do + expect(chef_run).to include_recipe('ms_dotnet::ms_dotnet2') + expect(chef_run).to_not install_windows_package('Windows Management Framework Core') + end end end end diff --git a/spec/recipes/powershell3_spec.rb b/spec/recipes/powershell3_spec.rb index 095a145..5fa5d2a 100644 --- a/spec/recipes/powershell3_spec.rb +++ b/spec/recipes/powershell3_spec.rb @@ -1,87 +1,58 @@ require 'spec_helper' -require 'chef/win32/version' describe 'powershell::powershell3' do - let(:chef_run) do - ChefSpec::SoloRunner.new(platform: 'windows', version: '2012') do |node| - node.set['powershell']['powershell3']['url'] = 'https://powershelltest.com' - node.set['powershell']['powershell3']['checksum'] = '12345' - node.set['powershell']['bits_4']['url'] = 'https://powershellbits.com' - node.set['powershell']['bits_4']['checksum'] = '99999' - end.converge(described_recipe) - end - - context 'when windows_version is windows_server_2008' do - before do - @windows_version = double(windows_server_2008?: true, windows_server_2008_r2?: false, windows_7?: false) - allow(Chef::ReservedNames::Win32::Version).to receive(:new).and_return(@windows_version) - registry = double - allow(Chef::Win32::Registry).to receive(:new).and_return(registry) - allow(registry).to receive(:data_exists?).and_return(false) - allow_any_instance_of(Chef::Recipe).to receive(:include_recipe).and_return(true) - end - - it 'installs windows package windows managemet framework bits and windows management framework core 3.0' do - expect(chef_run).to install_windows_package('Windows Management Framework Bits').with(source: 'https://powershellbits.com', checksum: '99999', installer_type: :custom, options: '/quiet /norestart') - expect(chef_run).to install_windows_package('Windows Management Framework Core 3.0').with(source: 'https://powershelltest.com', checksum: '12345', installer_type: :custom, options: '/quiet /norestart') - end - end - - context 'when windows_version is windows_server_2008_r2' do - before do - @windows_version = double(windows_server_2008?: false, windows_server_2008_r2?: true, windows_7?: false) - allow(Chef::ReservedNames::Win32::Version).to receive(:new).and_return(@windows_version) - registry = double - allow(Chef::Win32::Registry).to receive(:new).and_return(registry) - allow(registry).to receive(:data_exists?).and_return(true) - end - - it 'only include ms_dotnet4 when powershell 3 is installed' do - expect(chef_run).to include_recipe('ms_dotnet4') - end - end - - context 'when windows_version is windows_server_2008_r2' do - before do - @windows_version = double(windows_server_2008?: false, windows_server_2008_r2?: true, windows_7?: false) - allow(Chef::ReservedNames::Win32::Version).to receive(:new).and_return(@windows_version) - registry = double - allow(Chef::Win32::Registry).to receive(:new).and_return(registry) - allow(registry).to receive(:data_exists?).and_return(false) - end - - it 'installs windows package windows management framework core 3.0 when powershell 3 doesnot exist' do - expect(chef_run).to include_recipe('ms_dotnet4') - expect(chef_run).to install_windows_package('Windows Management Framework Core 3.0').with(source: 'https://powershelltest.com', checksum: '12345', installer_type: :custom, options: '/quiet /norestart') - end - end - - context 'when windows_version is windows_7' do - before do - @windows_version = double(windows_server_2008?: false, windows_server_2008_r2?: false, windows_7?: true) - allow(Chef::ReservedNames::Win32::Version).to receive(:new).and_return(@windows_version) - registry = double - allow(Chef::Win32::Registry).to receive(:new).and_return(registry) - allow(registry).to receive(:data_exists?).and_return(true) - end - - it 'only include ms_dotnet4 when powershell 3 is installed' do - expect(chef_run).to include_recipe('ms_dotnet4') - end - end - - context 'when windows_version is windows_7' do - before do - @windows_version = double(windows_server_2008?: false, windows_server_2008_r2?: false, windows_7?: true) - allow(Chef::ReservedNames::Win32::Version).to receive(:new).and_return(@windows_version) - registry = double - allow(Chef::Win32::Registry).to receive(:new).and_return(registry) - allow(registry).to receive(:data_exists?).and_return(false) - end - - it 'installs windows package windows management framework core 3.0 when powershell 3 doesnot exist' do - expect(chef_run).to include_recipe('ms_dotnet4') - expect(chef_run).to install_windows_package('Windows Management Framework Core 3.0').with(source: 'https://powershelltest.com', checksum: '12345', installer_type: :custom, options: '/quiet /norestart') + { + 'Windows Server 2008R2' => { fauxhai_version: '2008R2', should_install_bits: false }, + # There is no fauxhai info for windows server 2008, so we use 2008R2 and change the platform version + 'Windows Server 2008' => { fauxhai_version: '2008R2', platform_version: '6.0.6001', should_install_bits: true }, + # There is no fauxhai info for windows 7, so we use 2008R2 and change the product type from server to workstation + 'Windows 7' => { fauxhai_version: '2008R2', product_type: 1, should_install_bits: false } + }.each do |windows_version, test_conf| + context "on #{windows_version}" do + let(:chef_run) do + ChefSpec::SoloRunner.new(platform: 'windows', version: test_conf[:fauxhai_version]) do |node| + node.automatic['platform_version'] = test_conf[:platform_version] if test_conf[:platform_version] + node.automatic['kernel']['os_info']['product_type'] = test_conf[:product_type] if test_conf[:product_type] + node.set['powershell']['powershell3']['url'] = 'https://powershelltest.com' + node.set['powershell']['powershell3']['checksum'] = '12345' + node.set['powershell']['bits_4']['url'] = 'https://powershellbits.com' + node.set['powershell']['bits_4']['checksum'] = '99999' + end.converge(described_recipe) + end + + if test_conf[:should_install_bits] + it 'installs windows package Windows Management Framework Bits' do + allow(Chef::Win32::Registry).to receive(:new).and_return double('registry', data_exists?: true, value_exists?: true) + expect(chef_run).to install_windows_package('Windows Management Framework Bits').with(source: 'https://powershellbits.com', checksum: '99999', installer_type: :custom, options: '/quiet /norestart') + end + else + it 'does not install windows package Windows Management Framework Bits' do + allow(Chef::Win32::Registry).to receive(:new).and_return double('registry', data_exists?: true, value_exists?: true) + expect(chef_run).to_not install_windows_package('Windows Management Framework Bits') + end + end + + context 'when powershell 3 is installed' do + before do + allow(Chef::Win32::Registry).to receive(:new).and_return double('registry', data_exists?: true, value_exists?: true) + end + + it 'only include ms_dotnet4' do + expect(chef_run).to include_recipe('ms_dotnet::ms_dotnet4') + expect(chef_run).to_not install_windows_package('Windows Management Framework Core 3.0') + end + end + + context 'when powershell 3 does not exist' do + before do + allow(Chef::Win32::Registry).to receive(:new).and_return double('registry', data_exists?: false, value_exists?: false, key_exists?: false) + end + + it 'installs windows package windows management framework core 3.0' do + expect(chef_run).to include_recipe('ms_dotnet::ms_dotnet4') + expect(chef_run).to install_windows_package('Windows Management Framework Core 3.0').with(source: 'https://powershelltest.com', checksum: '12345', installer_type: :custom, options: '/quiet /norestart') + end + end end end end diff --git a/spec/recipes/powershell4_spec.rb b/spec/recipes/powershell4_spec.rb index 7899573..7bece4f 100644 --- a/spec/recipes/powershell4_spec.rb +++ b/spec/recipes/powershell4_spec.rb @@ -1,249 +1,59 @@ require 'spec_helper' -require 'chef/win32/version' describe 'powershell::powershell4' do - context 'when installation_reboot_mode is no_reboot' do - let(:chef_run) do - ChefSpec::SoloRunner.new(platform: 'windows', version: '2012') do |node| - node.set['powershell']['powershell4']['url'] = 'https://powershelltest.com' - node.set['powershell']['powershell4']['checksum'] = '12345' - node.set['powershell']['installation_reboot_mode'] = 'no_reboot' - end.converge(described_recipe) - end - - context 'when windows_version is windows_server_2008_r2' do - before do - @windows_version = double(windows_server_2008_r2?: true, windows_7?: false, windows_server_2012?: false) - allow(Chef::ReservedNames::Win32::Version).to receive(:new).and_return(@windows_version) - registry = double - allow(Chef::Win32::Registry).to receive(:new).and_return(registry) - allow(registry).to receive(:data_exists?).and_return(true) - end - - it 'only includes ms_dotnet45 when powershell 4 is installed' do - expect(chef_run).to include_recipe('ms_dotnet45') - end - end - - context 'when windows_version is windows_server_2008_r2' do - before do - @windows_version = double(windows_server_2008_r2?: true, windows_7?: false, windows_server_2012?: false) - allow(Chef::ReservedNames::Win32::Version).to receive(:new).and_return(@windows_version) - registry = double - allow(Chef::Win32::Registry).to receive(:new).and_return(registry) - allow(registry).to receive(:data_exists?).and_return(false) - end - - it 'installs windows package windows managemet framework core 4.0 when powershell 4 is not installed' do - expect(chef_run).to include_recipe('ms_dotnet45') - expect(chef_run).to install_windows_package('Windows Management Framework Core4.0').with(source: 'https://powershelltest.com', checksum: '12345', installer_type: :custom) - end - end - - context 'when windows_version is windows_7' do - before do - @windows_version = double(windows_server_2008_r2?: false, windows_7?: true, windows_server_2012?: false) - allow(Chef::ReservedNames::Win32::Version).to receive(:new).and_return(@windows_version) - registry = double - allow(Chef::Win32::Registry).to receive(:new).and_return(registry) - allow(registry).to receive(:data_exists?).and_return(true) - end - - it 'only includes ms_dotnet45 when powershell 4 is installed' do - expect(chef_run).to include_recipe('ms_dotnet45') - end - end - - context 'when windows_version is windows_7' do - before do - @windows_version = double(windows_server_2008_r2?: false, windows_7?: true, windows_server_2012?: false) - allow(Chef::ReservedNames::Win32::Version).to receive(:new).and_return(@windows_version) - registry = double - allow(Chef::Win32::Registry).to receive(:new).and_return(registry) - allow(registry).to receive(:data_exists?).and_return(false) - end - - it 'installs windows package windows managemet framework core 4.0 when powershell 4 is not installed' do - expect(chef_run).to include_recipe('ms_dotnet45') - expect(chef_run).to install_windows_package('Windows Management Framework Core4.0').with(source: 'https://powershelltest.com', checksum: '12345', installer_type: :custom) - end - end - - context 'when windows_version is windows_server_2012' do - before do - @windows_version = double(windows_server_2008_r2?: false, windows_7?: false, windows_server_2012?: true) - allow(Chef::ReservedNames::Win32::Version).to receive(:new).and_return(@windows_version) - registry = double - allow(Chef::Win32::Registry).to receive(:new).and_return(registry) - allow(registry).to receive(:data_exists?).and_return(false) - end - - it 'installs windows package windows managemet framework core 4.0' do - expect(chef_run).to install_windows_package('Windows Management Framework Core4.0').with(source: 'https://powershelltest.com', checksum: '12345', installer_type: :custom) - end - end - end - - context 'when installation_reboot_mode is delayed_reboot' do - let(:chef_run) do - ChefSpec::SoloRunner.new(platform: 'windows', version: '2012') do |node| - node.set['powershell']['powershell4']['url'] = 'https://powershelltest.com' - node.set['powershell']['powershell4']['checksum'] = '12345' - node.set['powershell']['installation_reboot_mode'] = 'delayed_reboot' - end.converge(described_recipe) - end - - context 'when windows_version is windows_server_2008_r2' do - before do - @windows_version = double(windows_server_2008_r2?: true, windows_7?: false, windows_server_2012?: false) - allow(Chef::ReservedNames::Win32::Version).to receive(:new).and_return(@windows_version) - registry = double - allow(Chef::Win32::Registry).to receive(:new).and_return(registry) - allow(registry).to receive(:data_exists?).and_return(true) - end - - it 'only includes ms_dotnet45 when powershell 4 is installed' do - expect(chef_run).to include_recipe('ms_dotnet45') - end - end - - context 'when windows_version is windows_server_2008_r2' do - before do - @windows_version = double(windows_server_2008_r2?: true, windows_7?: false, windows_server_2012?: false) - allow(Chef::ReservedNames::Win32::Version).to receive(:new).and_return(@windows_version) - registry = double - allow(Chef::Win32::Registry).to receive(:new).and_return(registry) - allow(registry).to receive(:data_exists?).and_return(false) - end - - it 'installs windows package windows managemet framework core 4.0 when powershell 4 is not installed' do - expect(chef_run).to include_recipe('ms_dotnet45') - expect(chef_run).to install_windows_package('Windows Management Framework Core4.0').with(source: 'https://powershelltest.com', checksum: '12345', installer_type: :custom) - end - end - - context 'when windows_version is windows_7' do - before do - @windows_version = double(windows_server_2008_r2?: false, windows_7?: true, windows_server_2012?: false) - allow(Chef::ReservedNames::Win32::Version).to receive(:new).and_return(@windows_version) - registry = double - allow(Chef::Win32::Registry).to receive(:new).and_return(registry) - allow(registry).to receive(:data_exists?).and_return(true) - end - - it 'only includes ms_dotnet45 when powershell 4 is installed' do - expect(chef_run).to include_recipe('ms_dotnet45') - end - end - - context 'when windows_version is windows_7' do - before do - @windows_version = double(windows_server_2008_r2?: false, windows_7?: true, windows_server_2012?: false) - allow(Chef::ReservedNames::Win32::Version).to receive(:new).and_return(@windows_version) - registry = double - allow(Chef::Win32::Registry).to receive(:new).and_return(registry) - allow(registry).to receive(:data_exists?).and_return(false) - end - - it 'installs windows package windows managemet framework core 4.0 when powershell 4 is not installed' do - expect(chef_run).to include_recipe('ms_dotnet45') - expect(chef_run).to install_windows_package('Windows Management Framework Core4.0').with(source: 'https://powershelltest.com', checksum: '12345', installer_type: :custom) - end - end - - context 'when windows_version is windows_server_2012' do - before do - @windows_version = double(windows_server_2008_r2?: false, windows_7?: false, windows_server_2012?: true) - allow(Chef::ReservedNames::Win32::Version).to receive(:new).and_return(@windows_version) - registry = double - allow(Chef::Win32::Registry).to receive(:new).and_return(registry) - allow(registry).to receive(:data_exists?).and_return(false) - end - - it 'installs windows package windows managemet framework core 4.0' do - expect(chef_run).to install_windows_package('Windows Management Framework Core4.0').with(source: 'https://powershelltest.com', checksum: '12345', installer_type: :custom) - end - end - end - - context 'when installation_reboot_mode is immediate_reboot' do - let(:chef_run) do - ChefSpec::SoloRunner.new(platform: 'windows', version: '2012') do |node| - node.set['powershell']['powershell4']['url'] = 'https://powershelltest.com' - node.set['powershell']['powershell4']['checksum'] = '12345' - node.set['powershell']['installation_reboot_mode'] = 'immediate_reboot' - end.converge(described_recipe) - end - - context 'when windows_version is windows_server_2008_r2' do - before do - @windows_version = double(windows_server_2008_r2?: true, windows_7?: false, windows_server_2012?: false) - allow(Chef::ReservedNames::Win32::Version).to receive(:new).and_return(@windows_version) - registry = double - allow(Chef::Win32::Registry).to receive(:new).and_return(registry) - allow(registry).to receive(:data_exists?).and_return(true) - end - - it 'only includes ms_dotnet45 when powershell 4 is installed' do - expect(chef_run).to include_recipe('ms_dotnet45') - end - end - - context 'when windows_version is windows_server_2008_r2' do - before do - @windows_version = double(windows_server_2008_r2?: true, windows_7?: false, windows_server_2012?: false) - allow(Chef::ReservedNames::Win32::Version).to receive(:new).and_return(@windows_version) - registry = double - allow(Chef::Win32::Registry).to receive(:new).and_return(registry) - allow(registry).to receive(:data_exists?).and_return(false) - end - - it 'installs windows package windows managemet framework core 4.0 when powershell 4 is not installed' do - expect(chef_run).to include_recipe('ms_dotnet45') - expect(chef_run).to install_windows_package('Windows Management Framework Core4.0').with(source: 'https://powershelltest.com', checksum: '12345', installer_type: :custom) - end - end - - context 'when windows_version is windows_7' do - before do - @windows_version = double(windows_server_2008_r2?: false, windows_7?: true, windows_server_2012?: false) - allow(Chef::ReservedNames::Win32::Version).to receive(:new).and_return(@windows_version) - registry = double - allow(Chef::Win32::Registry).to receive(:new).and_return(registry) - allow(registry).to receive(:data_exists?).and_return(true) - end - - it 'only includes ms_dotnet45 when powershell 4 is installed' do - expect(chef_run).to include_recipe('ms_dotnet45') - end - end - - context 'when windows_version is windows_7' do - before do - @windows_version = double(windows_server_2008_r2?: false, windows_7?: true, windows_server_2012?: false) - allow(Chef::ReservedNames::Win32::Version).to receive(:new).and_return(@windows_version) - registry = double - allow(Chef::Win32::Registry).to receive(:new).and_return(registry) - allow(registry).to receive(:data_exists?).and_return(false) - end - - it 'installs windows package windows managemet framework core 4.0 when powershell 4 is not installed' do - expect(chef_run).to include_recipe('ms_dotnet45') - expect(chef_run).to install_windows_package('Windows Management Framework Core4.0').with(source: 'https://powershelltest.com', checksum: '12345', installer_type: :custom) - end - end - - context 'when windows_version is windows_server_2012' do - before do - @windows_version = double(windows_server_2008_r2?: false, windows_7?: false, windows_server_2012?: true) - allow(Chef::ReservedNames::Win32::Version).to receive(:new).and_return(@windows_version) - registry = double - allow(Chef::Win32::Registry).to receive(:new).and_return(registry) - allow(registry).to receive(:data_exists?).and_return(false) - end - - it 'installs windows package windows managemet framework core 4.0' do - expect(chef_run).to install_windows_package('Windows Management Framework Core4.0').with(source: 'https://powershelltest.com', checksum: '12345', installer_type: :custom) + { + # There is no fauxhai info for windows 7, so we use windows 2008R2 and change the product type from server to workstation + 'Windows 7' => { fauxhai_version: '2008R2', product_type: 1 }, + 'Windows Server 2008R2' => { fauxhai_version: '2008R2' }, + 'Windows Server 2012' => { fauxhai_version: '2012' } + }.each do |windows_version, test_conf| + context "on #{windows_version}" do + let(:normal_attributes) { ::Chef::Node::VividMash.new(double('fake_node').as_null_object) } + let(:chef_run) do + ChefSpec::SoloRunner.new(platform: 'windows', version: test_conf[:fauxhai_version]) do |node| + node.automatic['kernel']['os_info']['product_type'] = test_conf[:product_type] if test_conf[:product_type] + normal_attributes.each { |k, v| node.set[k] = v } + end.converge(described_recipe) + end + + context 'when ms_dotnet::ms_dotnet4 is not configured for .NET 4.5' do + before { normal_attributes['ms_dotnet']['v4']['version'] = '4.0' } + it 'fails' do + expect { chef_run }.to raise_error + end + end + + context 'when ms_dotnet::ms_dotnet4 is configured for .NET 4.5' do + before { normal_attributes['ms_dotnet']['v4']['version'] = '4.5' } + + context 'when powershell 4 is installed' do + before do + allow_any_instance_of(::Chef::Resource).to receive(:reboot_pending?).and_return false + expect_any_instance_of(::Chef::Resource).to receive(:registry_data_exists?).with('HKLM\SOFTWARE\Microsoft\PowerShell\3\PowerShellEngine', name: 'PowerShellVersion', type: :string, data: '4.0').and_return true + end + it 'includes ms_dotnet::ms_dotnet4' do + expect(chef_run).to include_recipe('ms_dotnet::ms_dotnet4') + end + it 'does not install windows package WMFC 4.0' do + expect(chef_run).to_not install_windows_package('Windows Management Framework Core 4.0') + end + end + + context 'when powershell 4 does not exist' do + before do + normal_attributes['powershell']['powershell4']['url'] = 'https://powershelltest.com' + normal_attributes['powershell']['powershell4']['checksum'] = '12345' + normal_attributes['powershell']['installation_reboot_mode'] = 'no_reboot' + allow_any_instance_of(::Chef::Resource).to receive(:reboot_pending?).and_return false + allow_any_instance_of(::Chef::Resource).to receive(:registry_data_exists?).with('HKLM\SOFTWARE\Microsoft\PowerShell\3\PowerShellEngine', name: 'PowerShellVersion', type: :string, data: '4.0').and_return false + end + it 'includes ms_dotnet::ms_dotnet4' do + expect(chef_run).to include_recipe('ms_dotnet::ms_dotnet4') + end + it 'installs windows package WMFC 4.0' do + expect(chef_run).to install_windows_package('Windows Management Framework Core 4.0').with(source: 'https://powershelltest.com', checksum: '12345', installer_type: :custom) + end + end end end end diff --git a/spec/recipes/powershell5_spec.rb b/spec/recipes/powershell5_spec.rb index b69ef4d..7e83ed9 100644 --- a/spec/recipes/powershell5_spec.rb +++ b/spec/recipes/powershell5_spec.rb @@ -1,43 +1,44 @@ require 'spec_helper' -require 'chef/win32/version' describe 'powershell::powershell5' do - let(:chef_run) do - ChefSpec::SoloRunner.new(platform: 'windows', version: '2012') do |node| - node.set['powershell']['powershell5']['url'] = 'https://powershelltest.com' - node.set['powershell']['powershell5']['checksum'] = '12345' - end.converge(described_recipe) - end + { + # There is no fauxhai info for windows 8, so we use windows 2012R2 and change the product type from server to workstation + 'Windows 8.1' => { fauxhai_version: '2012R2', product_type: 1 }, + 'Windows Server 2012R2' => { fauxhai_version: '2012R2' } + }.each do |windows_version, test_conf| + context "on #{windows_version}" do + let(:chef_run) do + ChefSpec::SoloRunner.new(platform: 'windows', version: test_conf[:fauxhai_version]) do |node| + node.automatic['kernel']['os_info']['product_type'] = test_conf[:product_type] if test_conf[:product_type] + node.set['powershell']['powershell5']['url'] = 'https://powershelltest.com' + node.set['powershell']['powershell5']['checksum'] = '12345' + end.converge(described_recipe) + end - before do - allow_any_instance_of(Chef::Recipe).to receive(:include_recipe).with('powershell::powershell2').and_return(true) - end + it 'includes powershell 2 recipe' do + allow(Chef::Win32::Registry).to receive(:new).and_return double('registry', data_exists?: false, value_exists?: false, key_exists?: false) + expect(chef_run).to include_recipe('powershell::powershell2') + end - context 'when windows_version is windows_server_2012_r2' do - before do - @windows_version = double(windows_server_2012_r2?: true, windows_8_1?: false) - allow(Chef::ReservedNames::Win32::Version).to receive(:new).and_return(@windows_version) - registry = double - allow(Chef::Win32::Registry).to receive(:new).and_return(registry) - allow(registry).to receive(:data_exists?).and_return(false) - end + context 'when powershell is installed' do + before do + allow(Chef::Win32::Registry).to receive(:new).and_return double('registry', data_exists?: true, value_exists?: true) + end - it 'installs windows package windows managemet framework core 5.0 if powershell 5 not installed' do - expect(chef_run).to install_windows_package('Windows Management Framework Core 5.0').with(source: 'https://powershelltest.com', checksum: '12345', installer_type: :custom, options: '/quiet /norestart') - end - end + it 'does not install WMF 5' do + expect(chef_run).to_not install_windows_package('Windows Management Framework Core 5.0') + end + end - context 'when windows_version is windows_8_1' do - before do - @windows_version = double(windows_server_2012_r2?: false, windows_8_1?: true) - allow(Chef::ReservedNames::Win32::Version).to receive(:new).and_return(@windows_version) - registry = double - allow(Chef::Win32::Registry).to receive(:new).and_return(registry) - allow(registry).to receive(:data_exists?).and_return(false) - end + context 'when powershell does not exist' do + before do + allow(Chef::Win32::Registry).to receive(:new).and_return double('registry', data_exists?: false, value_exists?: false, key_exists?: false) + end - it 'installs windows package windows managemet framework core 5.0 if powershell not installed' do - expect(chef_run).to install_windows_package('Windows Management Framework Core 5.0').with(source: 'https://powershelltest.com', checksum: '12345', installer_type: :custom, options: '/quiet /norestart') + it 'installs windows package windows management framework core 5.0' do + expect(chef_run).to install_windows_package('Windows Management Framework Core 5.0').with(source: 'https://powershelltest.com', checksum: '12345', installer_type: :custom, options: '/quiet /norestart') + end + end end end end From a7d14e2165ce9f43441ccc61a3bf9db6e9685074 Mon Sep 17 00:00:00 2001 From: Baptiste Courtois Date: Sat, 28 Nov 2015 16:13:59 +0100 Subject: [PATCH 4/6] Fix specs for winrm recipe Update winrm's specs to be able to test on linux/travis: * Remove references to `chef/winr32/version` * Mock shellout commands --- spec/recipes/winrm_spec.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/spec/recipes/winrm_spec.rb b/spec/recipes/winrm_spec.rb index 6bdb490..9f08bc2 100644 --- a/spec/recipes/winrm_spec.rb +++ b/spec/recipes/winrm_spec.rb @@ -1,11 +1,15 @@ require 'spec_helper' -require 'chef/win32/version' describe 'powershell::winrm' do let(:chef_run) do ChefSpec::SoloRunner.new(platform: 'windows', version: '2012').converge(described_recipe) end + before do + winrm_cmd = double('winrm_cmd', run_command: nil, stdout: 'Transport = HTTPS') + allow(Mixlib::ShellOut).to receive(:new).with('powershell.exe winrm enumerate winrm/config/listener').and_return winrm_cmd + end + it 'installs windows package windows managemet framework core 5.0' do expect(chef_run).to run_powershell_script('enable winrm').with(code: " winrm quickconfig -q\n") end From 2d48a00aad4e5c1f51ff2c137d265bce1c864162 Mon Sep 17 00:00:00 2001 From: Baptiste Courtois Date: Sat, 28 Nov 2015 16:14:32 +0100 Subject: [PATCH 5/6] Fix specs for dsc recipe Update dsc's specs to comply with powershell::powershell4 changes. Mock properly shellout commands. --- spec/recipes/dsc_spec.rb | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/spec/recipes/dsc_spec.rb b/spec/recipes/dsc_spec.rb index 8cef16c..053fbf1 100644 --- a/spec/recipes/dsc_spec.rb +++ b/spec/recipes/dsc_spec.rb @@ -2,16 +2,22 @@ require 'mixlib/shellout' describe 'powershell::dsc' do - let(:chef_run) { ChefSpec::SoloRunner.new(platform: 'windows', version: '2012').converge(described_recipe) } + let(:chef_run) do + ChefSpec::SoloRunner.new(platform: 'windows', version: '2012')do |node| + node.set['ms_dotnet']['v4']['version'] = '4.5' + end.converge(described_recipe) + end + + before do + winrm_cmd = double('winrm_cmd', run_command: nil, stdout: 'Transport = HTTPS') + allow(Mixlib::ShellOut).to receive(:new).with('powershell.exe winrm enumerate winrm/config/listener').and_return winrm_cmd + allow(Chef::Win32::Registry).to receive(:new).and_return double('registry', data_exists?: false, value_exists?: false, key_exists?: false) + end context 'When listener is enabled' do before do - command = 'powershell.exe winrm get winrm/config/listener?Address=*+Transport=HTTP' - - shell_obj = instance_double('Mixlib::ShellOut') - allow(Mixlib::ShellOut).to receive(:new).with(command).and_return(shell_obj) - allow(shell_obj).to receive(:run_command) - allow(shell_obj).to receive(:exitstatus).and_return(1) + dsc_cmd = double('dsc_cmd', run_command: nil, exitstatus: 1) + allow(Mixlib::ShellOut).to receive(:new).with('powershell.exe winrm get winrm/config/listener?Address=*+Transport=HTTP').and_return dsc_cmd end it 'runs dsc_script' do @@ -22,12 +28,8 @@ context 'When listener is disabled' do before do - command = 'powershell.exe winrm get winrm/config/listener?Address=*+Transport=HTTP' - - shell_obj = instance_double('Mixlib::ShellOut') - allow(Mixlib::ShellOut).to receive(:new).with(command).and_return(shell_obj) - allow(shell_obj).to receive(:run_command) - allow(shell_obj).to receive(:exitstatus).and_return(0) + dsc_cmd = double('dsc_cmd', run_command: nil, exitstatus: 0) + allow(Mixlib::ShellOut).to receive(:new).with('powershell.exe winrm get winrm/config/listener?Address=*+Transport=HTTP').and_return dsc_cmd end it 'runs dsc_script' do From 792771710ddec1c551d396da6a9a74caeb59d1d2 Mon Sep 17 00:00:00 2001 From: Baptiste Courtois Date: Sat, 28 Nov 2015 16:32:46 +0100 Subject: [PATCH 6/6] Fix specs for powershell_module provider Clean up powershell_module provider specs: * Mock file system operations and remove all actual IO from the tests! * Remove use of environment variable Theses tests were relying on the test machine file system: * It was expecting the test machine to be windows with powershell etc. * It was also creating "temporary" files and folders. --- .../powershell_module_provider_spec.rb | 113 ++++++------------ 1 file changed, 38 insertions(+), 75 deletions(-) diff --git a/spec/libraries/powershell_module_provider_spec.rb b/spec/libraries/powershell_module_provider_spec.rb index 768e6d6..bb5862a 100644 --- a/spec/libraries/powershell_module_provider_spec.rb +++ b/spec/libraries/powershell_module_provider_spec.rb @@ -17,14 +17,17 @@ # require_relative '../../libraries/powershell_module_provider' -require 'tmpdir' describe 'PowershellModuleProvider' do before do + allow(Chef::Config).to receive(:[]).with(:file_cache_path).and_return 'C:/tmp' + allow(Chef::Config).to receive(:[]).with(:why_run).and_return false + @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @new_resource = PowershellModule.new('testmodule', @run_context) + @new_resource.destination '/' @provider = PowershellModuleProvider.new(@new_resource, @run_context) end @@ -37,7 +40,7 @@ describe 'action_uninstall:' do it 'uninstall module' do - @provider.should_receive(:uninstall_module) + expect(@provider).to receive(:uninstall_module) expect { @provider.run_action(:uninstall) }.to_not raise_error end end @@ -67,78 +70,51 @@ end describe 'download_extract_module:' do - context 'when download_url and target are nil' do - before do - ENV['PROGRAMW6432'] = 'C:\\PROGRAMW6432' - @ps_cmd = double - end + before do + allow(@provider).to receive(:module_exists?).and_return false + end + context 'when download_url and target are nil' do it 'downloads the package' do - expect(Dir).to receive(:mktmpdir).and_return('C:/tmp/') - cmd_str = "powershell.exe Invoke-WebRequest testmodule -OutFile C:/tmp/testmodule.zip; $shell = new-object -com shell.application;$zip = $shell.NameSpace('C:\\tmp\\testmodule.zip'); $shell.Namespace('C:\\PROGRAMW6432\\WindowsPowerShell\\Modules').copyhere($zip.items(), 0x14);write-host $shell" - expect(Mixlib::ShellOut).to receive(:new).with(cmd_str).and_return(@ps_cmd) - expect(@ps_cmd).to receive(:run_command) + cmd_str = "powershell.exe Invoke-WebRequest testmodule -OutFile C:/tmp/testmodule.zip; $shell = new-object -com shell.application;$zip = $shell.NameSpace('C:\\tmp\\testmodule.zip'); $shell.Namespace('\\').copyhere($zip.items(), 0x14);write-host $shell" + expect(Mixlib::ShellOut).to receive(:new).with(cmd_str).and_return(double('ps_cmd', run_command: nil)) expect(@provider.send(:download_extract_module)).to eq('C:/tmp/testmodule.zip') end end context 'when download_url is provided and target is nil' do - before do - ENV['PROGRAMW6432'] = 'C:\\PROGRAMW6432' - @ps_cmd = double - end - it 'downloads the package' do - expect(Dir).to receive(:mktmpdir).and_return('C:/tmp/') - cmd_str = "powershell.exe Invoke-WebRequest https://temp_download.com -OutFile C:/tmp/testmodule.zip; $shell = new-object -com shell.application;$zip = $shell.NameSpace('C:\\tmp\\testmodule.zip'); $shell.Namespace('C:\\PROGRAMW6432\\WindowsPowerShell\\Modules').copyhere($zip.items(), 0x14);write-host $shell" - expect(Mixlib::ShellOut).to receive(:new).with(cmd_str).and_return(@ps_cmd) - expect(@ps_cmd).to receive(:run_command) + cmd_str = "powershell.exe Invoke-WebRequest https:/temp_download.com -OutFile C:/tmp/testmodule.zip; $shell = new-object -com shell.application;$zip = $shell.NameSpace('C:\\tmp\\testmodule.zip'); $shell.Namespace('\\').copyhere($zip.items(), 0x14);write-host $shell" + expect(Mixlib::ShellOut).to receive(:new).with(cmd_str).and_return(double('ps_cmd', run_command: nil)) - expect(@provider.send(:download_extract_module, 'https://temp_download.com')).to eq('C:/tmp/testmodule.zip') + expect(@provider.send(:download_extract_module, 'https:/temp_download.com')).to eq('C:/tmp/testmodule.zip') end end context 'when download_url is nil and target is provided' do - before do - ENV['PROGRAMW6432'] = 'C:\\PROGRAMW6432' - @ps_cmd = double - end - it 'downloads the package' do - cmd_str = "powershell.exe Invoke-WebRequest testmodule -OutFile tmp/target1.zip; $shell = new-object -com shell.application;$zip = $shell.NameSpace('tmp\\target1.zip'); $shell.Namespace('C:\\PROGRAMW6432\\WindowsPowerShell\\Modules').copyhere($zip.items(), 0x14);write-host $shell" - expect(Mixlib::ShellOut).to receive(:new).with(cmd_str).and_return(@ps_cmd) - expect(@ps_cmd).to receive(:run_command) + cmd_str = "powershell.exe Invoke-WebRequest testmodule -OutFile tmp/target1.zip; $shell = new-object -com shell.application;$zip = $shell.NameSpace('tmp\\target1.zip'); $shell.Namespace('\\').copyhere($zip.items(), 0x14);write-host $shell" + expect(Mixlib::ShellOut).to receive(:new).with(cmd_str).and_return(double('ps_cmd', run_command: nil)) expect(@provider.send(:download_extract_module, nil, 'tmp/target1.zip')).to eq('tmp/target1.zip') end end context 'when download_url and target are provided' do - before do - ENV['PROGRAMW6432'] = 'C:\\PROGRAMW6432' - @ps_cmd = double - end - it 'downloads the package' do - cmd_str = "powershell.exe Invoke-WebRequest https://temp_download.com -OutFile tmp/target1.zip; $shell = new-object -com shell.application;$zip = $shell.NameSpace('tmp\\target1.zip'); $shell.Namespace('C:\\PROGRAMW6432\\WindowsPowerShell\\Modules').copyhere($zip.items(), 0x14);write-host $shell" - expect(Mixlib::ShellOut).to receive(:new).with(cmd_str).and_return(@ps_cmd) - expect(@ps_cmd).to receive(:run_command) + cmd_str = "powershell.exe Invoke-WebRequest https:/temp_download.com -OutFile tmp/target1.zip; $shell = new-object -com shell.application;$zip = $shell.NameSpace('tmp\\target1.zip'); $shell.Namespace('\\').copyhere($zip.items(), 0x14);write-host $shell" + expect(Mixlib::ShellOut).to receive(:new).with(cmd_str).and_return(double('ps_cmd', run_command: nil)) - expect(@provider.send(:download_extract_module, 'https://temp_download.com', 'tmp/target1.zip')).to eq('tmp/target1.zip') + expect(@provider.send(:download_extract_module, 'https:/temp_download.com', 'tmp/target1.zip')).to eq('tmp/target1.zip') end end end describe 'uninstall_module:' do context 'when module directory exists' do - before do - ENV['PROGRAMW6432'] = 'C:/PROGRAMW6432' - @ps_cmd = double - end - it 'uninstalls module' do - module_dir = 'C:/PROGRAMW6432/WindowsPowerShell/Modules/testmodule' + module_dir = '/testmodule' expect(Dir).to receive(:exist?).with(module_dir).and_return(true) expect(FileUtils).to receive(:rm_rf).with(module_dir) expect(Chef::Log).to receive(:info).with("Powershell Module 'testmodule' uninstallation completed successfully") @@ -148,13 +124,8 @@ end context 'when module directory does not exist' do - before do - ENV['PROGRAMW6432'] = 'C:/PROGRAMW6432' - @ps_cmd = double - end - it 'logs message' do - module_dir = 'C:/PROGRAMW6432/WindowsPowerShell/Modules/testmodule' + module_dir = '/testmodule' expect(Dir).to receive(:exist?).with(module_dir).and_return(false) expect(Chef::Log).to receive(:info).with("Unable to locate module 'testmodule'") @@ -164,32 +135,18 @@ end describe 'install_module:' do - before do - ENV['PROGRAMW6432'] = 'C:/PROGRAMW6432' - @ps_cmd = double - end - context 'install from local source' do - before do - @dir = Dir.tmpdir + '/testmodule' - FileUtils.mkdir_p(@dir) unless File.directory?(@dir) - @module_files = ["#{@dir}/test.psd1", "#{@dir}/test.psm1", "#{@dir}/test.dll"] - @module_files.each do |file| - File.new("#{file}", 'w+') - end - end - - after do - FileUtils.rm_rf(@dir) if File.directory?(@dir) - end - it 'copies module from source to ps module path' do - @new_resource.source(@dir) - ps_module_path = 'C:/PROGRAMW6432/WindowsPowerShell/Modules/testmodule' - expect(Dir).to receive(:exist?).with('/tmp/testmodule').and_return(true) + ps_module_path = '/testmodule' + @new_resource.source(ps_module_path) + + module_files = %W(#{ps_module_path}/*.psd1 #{ps_module_path}/*.psm1 #{ps_module_path}/*.dll) + expect(Dir).to receive(:exist?).with(ps_module_path).and_return(true) expect(FileUtils).to receive(:mkdir_p).with(ps_module_path).and_return(["#{ps_module_path}"]) - @module_files.each do |filename| + expect(Dir).to receive(:[]).with(*module_files).and_return module_files + + module_files.each do |filename| expect(FileUtils).to receive(:cp).with(filename, ps_module_path) end @@ -198,9 +155,15 @@ end context 'source is a url' do it 'downloads module from source and install' do - @new_resource.source('https://testmodule.com') - expect(@provider).to receive(:download_extract_module).and_return('C:/tmp/testmodule') - expect(FileUtils).to receive(:rm_rf).with('C:/tmp') + source = 'https:/testmodule.com' + destination = 'C:/tmp/testmodule' + @new_resource.source source + + expect(Dir).to receive(:exist?).with(source).and_return(false) + expect(@provider).to receive(:download_extract_module).and_return(destination) + expect(File).to receive(:exist?).with(destination).and_return(true) + expect(FileUtils).to receive(:rm_f).with(destination) + @provider.send(:install_module) end end