chef 12.5.1-universal-mingw32 → 12.6.0-universal-mingw32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (221) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +6 -1
  3. data/README.md +6 -4
  4. data/Rakefile +1 -4
  5. data/chef-windows.gemspec +21 -0
  6. data/chef.gemspec +58 -0
  7. data/lib/chef/api_client/registration.rb +9 -4
  8. data/lib/chef/application.rb +3 -84
  9. data/lib/chef/application/apply.rb +9 -2
  10. data/lib/chef/application/client.rb +8 -3
  11. data/lib/chef/application/solo.rb +7 -1
  12. data/lib/chef/application/windows_service.rb +21 -6
  13. data/lib/chef/application/windows_service_manager.rb +2 -3
  14. data/lib/chef/audit/runner.rb +1 -0
  15. data/lib/chef/chef_class.rb +1 -11
  16. data/lib/chef/chef_fs/chef_fs_data_store.rb +181 -2
  17. data/lib/chef/chef_fs/file_system/cookbook_subdir.rb +5 -0
  18. data/lib/chef/chef_fs/file_system/file_system_entry.rb +11 -7
  19. data/lib/chef/client.rb +28 -1
  20. data/lib/chef/cookbook/cookbook_collection.rb +14 -1
  21. data/lib/chef/cookbook/cookbook_version_loader.rb +1 -1
  22. data/lib/chef/cookbook/metadata.rb +115 -9
  23. data/lib/chef/cookbook/remote_file_vendor.rb +1 -1
  24. data/lib/chef/cookbook_version.rb +6 -2
  25. data/lib/chef/data_bag.rb +1 -1
  26. data/lib/chef/data_bag_item.rb +1 -1
  27. data/lib/chef/digester.rb +5 -1
  28. data/lib/chef/dsl/chef_provisioning.rb +57 -0
  29. data/lib/chef/dsl/cheffish.rb +64 -0
  30. data/lib/chef/dsl/declare_resource.rb +108 -0
  31. data/lib/chef/dsl/platform_introspection.rb +3 -3
  32. data/lib/chef/dsl/recipe.rb +3 -73
  33. data/lib/chef/dsl/resources.rb +27 -1
  34. data/lib/chef/event_dispatch/base.rb +3 -0
  35. data/lib/chef/event_dispatch/dispatcher.rb +5 -0
  36. data/lib/chef/event_dispatch/events_output_stream.rb +8 -0
  37. data/lib/chef/exceptions.rb +21 -1
  38. data/lib/chef/file_access_control/unix.rb +12 -12
  39. data/lib/chef/file_content_management/deploy/cp.rb +2 -2
  40. data/lib/chef/file_content_management/deploy/mv_unix.rb +4 -4
  41. data/lib/chef/file_content_management/deploy/mv_windows.rb +1 -1
  42. data/lib/chef/formatters/base.rb +7 -0
  43. data/lib/chef/formatters/error_inspectors/compile_error_inspector.rb +2 -2
  44. data/lib/chef/formatters/indentable_output_stream.rb +5 -0
  45. data/lib/chef/http.rb +19 -3
  46. data/lib/chef/http/decompressor.rb +2 -2
  47. data/lib/chef/json_compat.rb +1 -0
  48. data/lib/chef/knife.rb +16 -2
  49. data/lib/chef/knife/bootstrap.rb +55 -10
  50. data/lib/chef/knife/cookbook_site_install.rb +5 -1
  51. data/lib/chef/knife/core/bootstrap_context.rb +2 -1
  52. data/lib/chef/knife/core/node_presenter.rb +1 -1
  53. data/lib/chef/knife/ssh.rb +30 -16
  54. data/lib/chef/knife/ssl_check.rb +4 -2
  55. data/lib/chef/knife/ssl_fetch.rb +3 -2
  56. data/lib/chef/knife/status.rb +14 -1
  57. data/lib/chef/log.rb +14 -0
  58. data/lib/chef/mixin/get_source_from_package.rb +7 -2
  59. data/lib/chef/mixin/properties.rb +302 -0
  60. data/lib/chef/mixin/proxified_socket.rb +38 -0
  61. data/lib/chef/mixin/subclass_directive.rb +37 -0
  62. data/lib/chef/node.rb +13 -5
  63. data/lib/chef/platform/query_helpers.rb +14 -3
  64. data/lib/chef/platform/service_helpers.rb +20 -38
  65. data/lib/chef/policy_builder/expand_node_object.rb +3 -0
  66. data/lib/chef/policy_builder/policyfile.rb +1 -0
  67. data/lib/chef/property.rb +51 -12
  68. data/lib/chef/provider.rb +40 -35
  69. data/lib/chef/provider/deploy.rb +1 -1
  70. data/lib/chef/provider/dsc_resource.rb +54 -20
  71. data/lib/chef/provider/execute.rb +25 -4
  72. data/lib/chef/provider/group.rb +1 -1
  73. data/lib/chef/provider/lwrp_base.rb +1 -0
  74. data/lib/chef/provider/package.rb +76 -30
  75. data/lib/chef/provider/package/dpkg.rb +152 -69
  76. data/lib/chef/provider/package/openbsd.rb +6 -8
  77. data/lib/chef/provider/package/solaris.rb +2 -0
  78. data/lib/chef/provider/package/windows.rb +95 -14
  79. data/lib/chef/provider/package/windows/exe.rb +129 -0
  80. data/lib/chef/provider/package/windows/msi.rb +37 -13
  81. data/lib/chef/provider/package/windows/registry_uninstall_entry.rb +89 -0
  82. data/lib/chef/provider/package/yum.rb +13 -3
  83. data/lib/chef/provider/powershell_script.rb +3 -0
  84. data/lib/chef/provider/remote_file/cache_control_data.rb +37 -4
  85. data/lib/chef/provider/remote_file/http.rb +1 -1
  86. data/lib/chef/provider/script.rb +1 -0
  87. data/lib/chef/provider/service.rb +13 -10
  88. data/lib/chef/provider/service/solaris.rb +43 -17
  89. data/lib/chef/provider/service/upstart.rb +3 -3
  90. data/lib/chef/provider/user.rb +1 -1
  91. data/lib/chef/provider/user/dscl.rb +111 -100
  92. data/lib/chef/provider/user/windows.rb +5 -3
  93. data/lib/chef/recipe.rb +3 -5
  94. data/lib/chef/resource.rb +77 -320
  95. data/lib/chef/resource/action_class.rb +4 -0
  96. data/lib/chef/resource/dpkg_package.rb +4 -3
  97. data/lib/chef/resource/dsc_resource.rb +40 -2
  98. data/lib/chef/resource/execute.rb +9 -1
  99. data/lib/chef/resource/ksh.rb +32 -0
  100. data/lib/chef/resource/lwrp_base.rb +6 -10
  101. data/lib/chef/resource/package.rb +8 -9
  102. data/lib/chef/resource/registry_key.rb +1 -1
  103. data/lib/chef/resource/resource_notification.rb +14 -1
  104. data/lib/chef/resource/script.rb +1 -1
  105. data/lib/chef/resource/windows_package.rb +1 -1
  106. data/lib/chef/resource_builder.rb +14 -7
  107. data/lib/chef/resource_reporter.rb +6 -0
  108. data/lib/chef/resources.rb +1 -7
  109. data/lib/chef/rest.rb +1 -1
  110. data/lib/chef/run_context.rb +45 -2
  111. data/lib/chef/run_list/run_list_expansion.rb +47 -0
  112. data/lib/chef/runner.rb +25 -0
  113. data/lib/chef/search/query.rb +16 -2
  114. data/lib/chef/util/diff.rb +2 -2
  115. data/lib/chef/util/powershell/ps_credential.rb +2 -3
  116. data/lib/chef/version.rb +1 -1
  117. data/lib/chef/win32/api/file.rb +51 -1
  118. data/lib/chef/win32/file.rb +5 -0
  119. data/lib/chef/win32/file/version_info.rb +93 -0
  120. data/lib/chef/win32/mutex.rb +1 -1
  121. data/spec/data/apt/chef-integration-test2-1.0/debian/changelog +5 -0
  122. data/spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2.debhelper.log +45 -0
  123. data/spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2.substvars +1 -0
  124. data/spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2/DEBIAN/conffiles +1 -0
  125. data/spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2/DEBIAN/control +10 -0
  126. data/spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2/DEBIAN/md5sums +1 -0
  127. data/spec/data/apt/chef-integration-test2-1.0/debian/compat +1 -0
  128. data/spec/data/apt/chef-integration-test2-1.0/debian/conffiles +1 -0
  129. data/spec/data/apt/chef-integration-test2-1.0/debian/control +13 -0
  130. data/spec/data/apt/chef-integration-test2-1.0/debian/copyright +34 -0
  131. data/spec/data/apt/chef-integration-test2-1.0/debian/files +1 -0
  132. data/spec/data/apt/chef-integration-test2-1.0/debian/rules +13 -0
  133. data/spec/data/apt/chef-integration-test2-1.0/debian/source/format +1 -0
  134. data/spec/data/apt/chef-integration-test2_1.0-1.debian.tar.gz +0 -0
  135. data/spec/data/apt/chef-integration-test2_1.0-1.dsc +18 -0
  136. data/spec/data/apt/chef-integration-test2_1.0-1_amd64.build +91 -0
  137. data/spec/data/apt/chef-integration-test2_1.0-1_amd64.changes +31 -0
  138. data/spec/data/apt/chef-integration-test2_1.0-1_amd64.deb +0 -0
  139. data/spec/data/apt/chef-integration-test2_1.0.orig.tar.gz +0 -0
  140. data/spec/functional/application_spec.rb +1 -1
  141. data/spec/functional/audit/runner_spec.rb +4 -0
  142. data/spec/functional/knife/ssh_spec.rb +5 -5
  143. data/spec/functional/notifications_spec.rb +74 -4
  144. data/spec/functional/resource/aix_service_spec.rb +2 -2
  145. data/spec/functional/resource/dpkg_package_spec.rb +339 -0
  146. data/spec/functional/resource/ifconfig_spec.rb +3 -1
  147. data/spec/functional/resource/mount_spec.rb +5 -2
  148. data/spec/functional/resource/package_spec.rb +1 -1
  149. data/spec/functional/resource/user/windows_spec.rb +8 -0
  150. data/spec/functional/resource/windows_package_spec.rb +177 -0
  151. data/spec/functional/win32/version_info_spec.rb +50 -0
  152. data/spec/integration/client/client_spec.rb +80 -0
  153. data/spec/integration/knife/download_spec.rb +9 -0
  154. data/spec/integration/knife/upload_spec.rb +28 -1
  155. data/spec/integration/recipes/lwrp_inline_resources_spec.rb +93 -23
  156. data/spec/integration/recipes/resource_action_spec.rb +211 -116
  157. data/spec/integration/recipes/resource_converge_if_changed_spec.rb +72 -0
  158. data/spec/integration/solo/solo_spec.rb +34 -0
  159. data/spec/spec_helper.rb +11 -1
  160. data/spec/support/platform_helpers.rb +8 -0
  161. data/spec/support/shared/integration/integration_helper.rb +6 -0
  162. data/spec/support/shared/unit/execute_resource.rb +5 -0
  163. data/spec/support/shared/unit/platform_introspector.rb +7 -0
  164. data/spec/tiny_server.rb +6 -2
  165. data/spec/unit/api_client/registration_spec.rb +5 -4
  166. data/spec/unit/application_spec.rb +1 -181
  167. data/spec/unit/chef_fs/file_system/cookbook_subdir_spec.rb +34 -0
  168. data/spec/unit/cookbook/metadata_spec.rb +122 -2
  169. data/spec/unit/http_spec.rb +102 -0
  170. data/spec/unit/knife/bootstrap_spec.rb +55 -13
  171. data/spec/unit/knife/core/bootstrap_context_spec.rb +10 -3
  172. data/spec/unit/knife/ssl_check_spec.rb +7 -3
  173. data/spec/unit/knife/ssl_fetch_spec.rb +2 -2
  174. data/spec/unit/knife/status_spec.rb +13 -13
  175. data/spec/unit/knife_spec.rb +26 -2
  176. data/spec/unit/lwrp_spec.rb +1 -1
  177. data/spec/unit/mixin/properties_spec.rb +97 -0
  178. data/spec/unit/mixin/proxified_socket_spec.rb +94 -0
  179. data/spec/unit/mixin/subclass_directive_spec.rb +45 -0
  180. data/spec/unit/node_spec.rb +9 -1
  181. data/spec/unit/policy_builder/policyfile_spec.rb +2 -0
  182. data/spec/unit/property/validation_spec.rb +14 -12
  183. data/spec/unit/property_spec.rb +56 -0
  184. data/spec/unit/provider/deploy_spec.rb +1 -1
  185. data/spec/unit/provider/dsc_resource_spec.rb +63 -24
  186. data/spec/unit/provider/execute_spec.rb +95 -28
  187. data/spec/unit/provider/package/dpkg_spec.rb +185 -96
  188. data/spec/unit/provider/package/windows/exe_spec.rb +251 -0
  189. data/spec/unit/provider/package/windows/msi_spec.rb +94 -10
  190. data/spec/unit/provider/package/windows_spec.rb +227 -26
  191. data/spec/unit/provider/package/yum_spec.rb +6 -0
  192. data/spec/unit/provider/package_spec.rb +495 -366
  193. data/spec/unit/provider/remote_file/cache_control_data_spec.rb +62 -36
  194. data/spec/unit/provider/script_spec.rb +2 -2
  195. data/spec/unit/provider/service/solaris_smf_service_spec.rb +110 -39
  196. data/spec/unit/provider/service/upstart_service_spec.rb +19 -0
  197. data/spec/unit/provider/user/dscl_spec.rb +14 -0
  198. data/spec/unit/provider/user/windows_spec.rb +2 -2
  199. data/spec/unit/provider/user_spec.rb +9 -0
  200. data/spec/unit/provider_resolver_spec.rb +6 -30
  201. data/spec/unit/recipe_spec.rb +46 -20
  202. data/spec/unit/resource/chef_gem_spec.rb +1 -1
  203. data/spec/unit/resource/dsc_resource_spec.rb +14 -3
  204. data/spec/unit/resource/ksh_spec.rb +40 -0
  205. data/spec/unit/resource/registry_key_spec.rb +2 -2
  206. data/spec/unit/resource/resource_notification_spec.rb +44 -45
  207. data/spec/unit/resource_reporter_spec.rb +7 -0
  208. data/spec/unit/resource_spec.rb +268 -253
  209. data/spec/unit/rest_spec.rb +2 -2
  210. data/spec/unit/run_list/run_list_expansion_spec.rb +18 -3
  211. data/spec/unit/search/query_spec.rb +19 -1
  212. data/spec/unit/util/powershell/ps_credential_spec.rb +8 -1
  213. data/spec/unit/windows_service_spec.rb +83 -38
  214. data/tasks/external_tests.rb +19 -9
  215. data/tasks/rspec.rb +1 -1
  216. metadata +70 -21
  217. data/spec/support/pedant/Gemfile +0 -3
  218. data/spec/support/pedant/pedant_config.rb +0 -129
  219. data/spec/support/pedant/run_pedant.rb +0 -63
  220. data/spec/support/pedant/stickywicket.pem +0 -27
  221. data/spec/unit/provider/package_spec.rbe +0 -0
@@ -0,0 +1,251 @@
1
+ #
2
+ # Author:: Matt Wrock <matt@mattwrock.com>
3
+ # Copyright:: Copyright (c) 2015 Chef Software, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require 'spec_helper'
20
+ require 'chef/provider/package/windows/exe'
21
+
22
+ unless Chef::Platform.windows?
23
+ class Chef
24
+ module ReservedNames::Win32
25
+ class File
26
+ def version_info
27
+ nil
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+
34
+ describe Chef::Provider::Package::Windows::Exe do
35
+ let(:package_name) { "calculator" }
36
+ let(:resource_source) { "calculator.exe" }
37
+ let(:new_resource) do
38
+ new_resource = Chef::Resource::WindowsPackage.new(package_name)
39
+ new_resource.source(resource_source)
40
+ new_resource
41
+ end
42
+ let(:uninstall_hash) do
43
+ [{
44
+ 'DisplayVersion' => 'outdated',
45
+ 'UninstallString' => File.join("uninst_dir", "uninst_file")
46
+ }]
47
+ end
48
+ let(:uninstall_entry) do
49
+ entries = []
50
+ uninstall_hash.each do |entry|
51
+ entries.push(Chef::Provider::Package::Windows::RegistryUninstallEntry.new('hive', 'key', entry))
52
+ end
53
+ entries
54
+ end
55
+ let(:provider) { Chef::Provider::Package::Windows::Exe.new(new_resource, :nsis, uninstall_entry) }
56
+ let(:file_version) { nil }
57
+ let(:product_version) { nil }
58
+ let(:version_info) { instance_double("Chef::ReservedNames::Win32::File::Version_info", FileVersion: file_version, ProductVersion: product_version) }
59
+
60
+ before(:each) do
61
+ allow(Chef::ReservedNames::Win32::File).to receive(:version_info).and_return(version_info)
62
+ allow(::File).to receive(:exist?).with(Chef::Util::PathHelper.canonical_path(resource_source, false)).and_return(true)
63
+ end
64
+
65
+ it "responds to shell_out!" do
66
+ expect(provider).to respond_to(:shell_out!)
67
+ end
68
+
69
+ describe "expand_options" do
70
+ it "returns an empty string if passed no options" do
71
+ expect(provider.expand_options(nil)).to eql ""
72
+ end
73
+
74
+ it "returns a string with a leading space if passed options" do
75
+ expect(provider.expand_options("--train nope --town no_way")).to eql(" --train nope --town no_way")
76
+ end
77
+ end
78
+
79
+ describe "installed_version" do
80
+ it "returns the installed version" do
81
+ expect(provider.installed_version).to eql(["outdated"])
82
+ end
83
+
84
+ context "no versions installed" do
85
+ let(:uninstall_hash) { [] }
86
+
87
+ it "returns the installed version" do
88
+ expect(provider.installed_version).to eql(nil)
89
+ end
90
+ end
91
+ end
92
+
93
+ describe "package_version" do
94
+ before { new_resource.version(nil) }
95
+
96
+ context "source file does not exist" do
97
+ before do
98
+ allow(::File).to receive(:exist?).with(Chef::Util::PathHelper.canonical_path(resource_source, false)).and_return(false)
99
+ end
100
+
101
+ it "returns nil" do
102
+ expect(provider.package_version).to eql(nil)
103
+ end
104
+ end
105
+
106
+ context "file version is empty" do
107
+ let(:file_version) { '' }
108
+
109
+ it "returns nil" do
110
+ expect(provider.package_version).to eql(nil)
111
+ end
112
+
113
+ it "returns the version of a package if given" do
114
+ new_resource.version('v55555')
115
+ expect(provider.package_version).to eql('v55555')
116
+ end
117
+ end
118
+
119
+ context "both file and product version are in installer" do
120
+ let(:file_version) { '1.1.1' }
121
+ let(:product_version) { '1.1' }
122
+
123
+ it "returns the file version" do
124
+ expect(provider.package_version).to eql('1.1.1')
125
+ end
126
+
127
+ it "returns the version of a package if given" do
128
+ new_resource.version('v55555')
129
+ expect(provider.package_version).to eql('v55555')
130
+ end
131
+ end
132
+
133
+ context "only file version is in installer" do
134
+ let(:file_version) { '1.1.1' }
135
+
136
+ it "returns the file version" do
137
+ expect(provider.package_version).to eql('1.1.1')
138
+ end
139
+
140
+ it "returns the version of a package if given" do
141
+ new_resource.version('v55555')
142
+ expect(provider.package_version).to eql('v55555')
143
+ end
144
+ end
145
+
146
+ context "only product version is in installer" do
147
+ let(:product_version) { '1.1' }
148
+
149
+ it "returns the product version" do
150
+ expect(provider.package_version).to eql('1.1')
151
+ end
152
+
153
+ it "returns the version of a package if given" do
154
+ new_resource.version('v55555')
155
+ expect(provider.package_version).to eql('v55555')
156
+ end
157
+ end
158
+
159
+ context "no version info is in installer" do
160
+ let(:file_version) { nil }
161
+ let(:product_version) { nil }
162
+
163
+ it "returns the version of a package" do
164
+ new_resource.version('v55555')
165
+ expect(provider.package_version).to eql('v55555')
166
+ end
167
+ end
168
+
169
+ context "no version info is in installer and none in attribute" do
170
+ it "returns the version of a package" do
171
+ expect(provider.package_version).to eql(nil)
172
+ end
173
+ end
174
+ end
175
+
176
+ describe "remove_package" do
177
+ context "no version given and one package installed" do
178
+ it "removes installed package" do
179
+ expect(provider).to receive(:shell_out!).with(/start \"\" \/wait \/d\"uninst_dir\" uninst_file \/S \/NCRC & exit %%%%ERRORLEVEL%%%%/, kind_of(Hash))
180
+ provider.remove_package
181
+ end
182
+ end
183
+
184
+ context "several packages installed" do
185
+ let(:uninstall_hash) do
186
+ [
187
+ {
188
+ 'DisplayVersion' => 'v1',
189
+ 'UninstallString' => File.join("uninst_dir1", "uninst_file1")
190
+ },
191
+ {
192
+ 'DisplayVersion' => 'v2',
193
+ 'UninstallString' => File.join("uninst_dir2", "uninst_file2")
194
+ }
195
+ ]
196
+ end
197
+
198
+ context "version given and installed" do
199
+ it "removes given version" do
200
+ new_resource.version('v2')
201
+ expect(provider).to receive(:shell_out!).with(/start \"\" \/wait \/d\"uninst_dir2\" uninst_file2 \/S \/NCRC & exit %%%%ERRORLEVEL%%%%/, kind_of(Hash))
202
+ provider.remove_package
203
+ end
204
+ end
205
+
206
+ context "no version given" do
207
+ it "removes both versions" do
208
+ expect(provider).to receive(:shell_out!).with(/start \"\" \/wait \/d\"uninst_dir1\" uninst_file1 \/S \/NCRC & exit %%%%ERRORLEVEL%%%%/, kind_of(Hash))
209
+ expect(provider).to receive(:shell_out!).with(/start \"\" \/wait \/d\"uninst_dir2\" uninst_file2 \/S \/NCRC & exit %%%%ERRORLEVEL%%%%/, kind_of(Hash))
210
+ provider.remove_package
211
+ end
212
+ end
213
+ end
214
+ end
215
+
216
+ context "installs nsis installer" do
217
+ let(:provider) { Chef::Provider::Package::Windows::Exe.new(new_resource, :nsis, uninstall_entry) }
218
+
219
+ it "calls installer with the correct flags" do
220
+ expect(provider).to receive(:shell_out!).with(/start \"\" \/wait \"#{Regexp.quote(new_resource.source)}\" \/S \/NCRC & exit %%%%ERRORLEVEL%%%%/, kind_of(Hash))
221
+ provider.install_package
222
+ end
223
+ end
224
+
225
+ context "installs installshield installer" do
226
+ let(:provider) { Chef::Provider::Package::Windows::Exe.new(new_resource, :installshield, uninstall_entry) }
227
+
228
+ it "calls installer with the correct flags" do
229
+ expect(provider).to receive(:shell_out!).with(/start \"\" \/wait \"#{Regexp.quote(new_resource.source)}\" \/s \/sms & exit %%%%ERRORLEVEL%%%%/, kind_of(Hash))
230
+ provider.install_package
231
+ end
232
+ end
233
+
234
+ context "installs inno installer" do
235
+ let(:provider) { Chef::Provider::Package::Windows::Exe.new(new_resource, :inno, uninstall_entry) }
236
+
237
+ it "calls installer with the correct flags" do
238
+ expect(provider).to receive(:shell_out!).with(/start \"\" \/wait \"#{Regexp.quote(new_resource.source)}\" \/VERYSILENT \/SUPPRESSMSGBOXES \/NORESTART & exit %%%%ERRORLEVEL%%%%/, kind_of(Hash))
239
+ provider.install_package
240
+ end
241
+ end
242
+
243
+ context "installs wise installer" do
244
+ let(:provider) { Chef::Provider::Package::Windows::Exe.new(new_resource, :wise, uninstall_entry) }
245
+
246
+ it "calls installer with the correct flags" do
247
+ expect(provider).to receive(:shell_out!).with(/start \"\" \/wait \"#{Regexp.quote(new_resource.source)}\" \/s & exit %%%%ERRORLEVEL%%%%/, kind_of(Hash))
248
+ provider.install_package
249
+ end
250
+ end
251
+ end
@@ -17,17 +17,37 @@
17
17
  #
18
18
 
19
19
  require 'spec_helper'
20
+ require 'chef/provider/package/windows/msi'
20
21
 
21
22
  describe Chef::Provider::Package::Windows::MSI do
22
23
  let(:node) { double('Chef::Node') }
23
24
  let(:events) { double('Chef::Events').as_null_object } # mock all the methods
24
25
  let(:run_context) { double('Chef::RunContext', :node => node, :events => events) }
25
- let(:new_resource) { Chef::Resource::WindowsPackage.new("calculator.msi") }
26
- let(:provider) { Chef::Provider::Package::Windows::MSI.new(new_resource) }
27
-
28
- before(:each) do
29
- stub_const("File::ALT_SEPARATOR", "\\")
30
- allow(::File).to receive(:absolute_path).with("calculator.msi").and_return("calculator.msi")
26
+ let(:package_name) { "calculator" }
27
+ let(:resource_source) { "calculator.msi" }
28
+ let(:resource_version) { nil }
29
+ let(:new_resource) do
30
+ new_resource = Chef::Resource::WindowsPackage.new(package_name)
31
+ new_resource.source(resource_source)
32
+ new_resource.version(resource_version)
33
+ new_resource
34
+ end
35
+ let(:uninstall_hash) do
36
+ [{
37
+ 'DisplayVersion' => 'outdated',
38
+ 'UninstallString' => "MsiExec.exe /X{guid}"
39
+ }]
40
+ end
41
+ let(:uninstall_entry) do
42
+ entries = []
43
+ uninstall_hash.each do |entry|
44
+ entries.push(Chef::Provider::Package::Windows::RegistryUninstallEntry.new('hive', 'key', entry))
45
+ end
46
+ entries
47
+ end
48
+ let(:provider) { Chef::Provider::Package::Windows::MSI.new(new_resource, uninstall_entry) }
49
+ before do
50
+ allow(::File).to receive(:exist?).with(Chef::Util::PathHelper.canonical_path(resource_source, false)).and_return(true)
31
51
  end
32
52
 
33
53
  it "responds to shell_out!" do
@@ -50,6 +70,11 @@ describe Chef::Provider::Package::Windows::MSI do
50
70
  allow(provider).to receive(:get_installed_version).with("{23170F69-40C1-2702-0920-000001000000}").and_return("3.14159.1337.42")
51
71
  expect(provider.installed_version).to eql("3.14159.1337.42")
52
72
  end
73
+
74
+ it "returns the installed version in the registry when install file not present" do
75
+ allow(::File).to receive(:exist?).with(Chef::Util::PathHelper.canonical_path(resource_source, false)).and_return(false)
76
+ expect(provider.installed_version).to eql(["outdated"])
77
+ end
53
78
  end
54
79
 
55
80
  describe "package_version" do
@@ -57,19 +82,78 @@ describe Chef::Provider::Package::Windows::MSI do
57
82
  allow(provider).to receive(:get_product_property).with(/calculator.msi$/, "ProductVersion").and_return(42)
58
83
  expect(provider.package_version).to eql(42)
59
84
  end
85
+
86
+ context "version is explicitly provided" do
87
+ let(:resource_version) { "given_version" }
88
+
89
+ it "returns the given version" do
90
+ expect(provider.package_version).to eql("given_version")
91
+ end
92
+ end
93
+
94
+ context "no source or version is given" do
95
+ before do
96
+ allow(::File).to receive(:exist?).with(Chef::Util::PathHelper.canonical_path(resource_source, false)).and_return(false)
97
+ end
98
+
99
+ it "returns nil" do
100
+ expect(provider.package_version).to eql(nil)
101
+ end
102
+ end
60
103
  end
61
104
 
62
105
  describe "install_package" do
63
106
  it "calls msiexec /qn /i" do
64
- expect(provider).to receive(:shell_out!).with(/msiexec \/qn \/i \"calculator.msi\"/, kind_of(Hash))
65
- provider.install_package("unused", "unused")
107
+ expect(provider).to receive(:shell_out!).with(/msiexec \/qn \/i \"#{Regexp.quote(new_resource.source)}\"/, kind_of(Hash))
108
+ provider.install_package
66
109
  end
67
110
  end
68
111
 
69
112
  describe "remove_package" do
70
113
  it "calls msiexec /qn /x" do
71
- expect(provider).to receive(:shell_out!).with(/msiexec \/qn \/x \"calculator.msi\"/, kind_of(Hash))
72
- provider.remove_package("unused", "unused")
114
+ expect(provider).to receive(:shell_out!).with(/msiexec \/qn \/x \"#{Regexp.quote(new_resource.source)}\"/, kind_of(Hash))
115
+ provider.remove_package
116
+ end
117
+
118
+ context "no source is provided" do
119
+ before do
120
+ allow(::File).to receive(:exist?).with(Chef::Util::PathHelper.canonical_path(resource_source, false)).and_return(false)
121
+ end
122
+
123
+ it "removes installed package" do
124
+ expect(provider).to receive(:shell_out!).with(/MsiExec.exe \/X{guid} \/Q/, kind_of(Hash))
125
+ provider.remove_package
126
+ end
127
+
128
+ context "there are multiple installs" do
129
+ let(:uninstall_hash) do
130
+ [
131
+ {
132
+ 'DisplayVersion' => 'outdated',
133
+ 'UninstallString' => "MsiExec.exe /X{guid}"
134
+ },
135
+ {
136
+ 'DisplayVersion' => 'really_outdated',
137
+ 'UninstallString' => "MsiExec.exe /X{guid2}"
138
+ }
139
+ ]
140
+ end
141
+
142
+ it "removes both installed package" do
143
+ expect(provider).to receive(:shell_out!).with(/MsiExec.exe \/X{guid} \/Q/, kind_of(Hash))
144
+ expect(provider).to receive(:shell_out!).with(/MsiExec.exe \/X{guid2} \/Q/, kind_of(Hash))
145
+ provider.remove_package
146
+ end
147
+ end
148
+
149
+ context "custom options includes /Q" do
150
+ before { new_resource.options("/Q") }
151
+
152
+ it "does not duplicate quiet switch" do
153
+ expect(provider).to receive(:shell_out!).with(/MsiExec.exe \/X{guid} \/Q/, kind_of(Hash))
154
+ provider.remove_package
155
+ end
156
+ end
73
157
  end
74
158
  end
75
159
  end
@@ -17,6 +17,8 @@
17
17
  #
18
18
 
19
19
  require 'spec_helper'
20
+ require 'chef/provider/package/windows/exe'
21
+ require 'chef/provider/package/windows/msi'
20
22
 
21
23
  describe Chef::Provider::Package::Windows, :windows_only do
22
24
  before(:each) do
@@ -28,10 +30,19 @@ describe Chef::Provider::Package::Windows, :windows_only do
28
30
  let(:events) { double('Chef::Events').as_null_object } # mock all the methods
29
31
  let(:run_context) { double('Chef::RunContext', :node => node, :events => events) }
30
32
  let(:resource_source) { 'calculator.msi' }
31
- let(:new_resource) { Chef::Resource::WindowsPackage.new(resource_source) }
33
+ let(:resource_name) { 'calculator' }
34
+ let(:new_resource) do
35
+ new_resource = Chef::Resource::WindowsPackage.new(resource_name)
36
+ new_resource.source(resource_source)
37
+ new_resource
38
+ end
32
39
  let(:provider) { Chef::Provider::Package::Windows.new(new_resource, run_context) }
33
40
  let(:cache_path) { 'c:\\cache\\' }
34
41
 
42
+ before(:each) do
43
+ allow(::File).to receive(:exist?).with(provider.new_resource.source).and_return(true)
44
+ end
45
+
35
46
  describe "load_current_resource" do
36
47
  shared_examples "a local file" do
37
48
  before(:each) do
@@ -43,7 +54,7 @@ describe Chef::Provider::Package::Windows, :windows_only do
43
54
  it "creates a current resource with the name of the new resource" do
44
55
  provider.load_current_resource
45
56
  expect(provider.current_resource).to be_a(Chef::Resource::WindowsPackage)
46
- expect(provider.current_resource.name).to eql(resource_source)
57
+ expect(provider.current_resource.name).to eql(resource_name)
47
58
  end
48
59
 
49
60
  it "sets the current version if the package is installed" do
@@ -76,19 +87,6 @@ describe Chef::Provider::Package::Windows, :windows_only do
76
87
  end
77
88
  it_behaves_like "a local file"
78
89
  end
79
-
80
- context "when remote_file_attributes are provided" do
81
- let (:remote_file_attributes) { {:path => 'C:\\foobar.msi'} }
82
- before(:each) do
83
- new_resource.remote_file_attributes(remote_file_attributes)
84
- end
85
-
86
- it 'should override the attributes of the remote file resource used' do
87
- expect(::File).to receive(:exists?).with(remote_file_attributes[:path])
88
- provider.load_current_resource
89
- end
90
-
91
- end
92
90
  end
93
91
 
94
92
  context "when source is a local file" do
@@ -98,6 +96,7 @@ describe Chef::Provider::Package::Windows, :windows_only do
98
96
 
99
97
  describe "package_provider" do
100
98
  shared_examples "a local file" do
99
+
101
100
  it "checks that the source path is valid" do
102
101
  expect(Chef::Util::PathHelper).to receive(:validate_path)
103
102
  provider.package_provider
@@ -108,9 +107,29 @@ describe Chef::Provider::Package::Windows, :windows_only do
108
107
  expect(provider.package_provider).to be_a(Chef::Provider::Package::Windows::MSI)
109
108
  end
110
109
 
111
- it "raises an error if the installer_type is unknown" do
112
- allow(provider).to receive(:installer_type).and_return(:apt_for_windows)
113
- expect { provider.package_provider }.to raise_error
110
+ it "sets the package provider to Exe if the the installer type is :inno" do
111
+ allow(provider).to receive(:installer_type).and_return(:inno)
112
+ expect(provider.package_provider).to be_a(Chef::Provider::Package::Windows::Exe)
113
+ end
114
+
115
+ it "sets the package provider to Exe if the the installer type is :nsis" do
116
+ allow(provider).to receive(:installer_type).and_return(:nsis)
117
+ expect(provider.package_provider).to be_a(Chef::Provider::Package::Windows::Exe)
118
+ end
119
+
120
+ it "sets the package provider to Exe if the the installer type is :wise" do
121
+ allow(provider).to receive(:installer_type).and_return(:wise)
122
+ expect(provider.package_provider).to be_a(Chef::Provider::Package::Windows::Exe)
123
+ end
124
+
125
+ it "sets the package provider to Exe if the the installer type is :installshield" do
126
+ allow(provider).to receive(:installer_type).and_return(:installshield)
127
+ expect(provider.package_provider).to be_a(Chef::Provider::Package::Windows::Exe)
128
+ end
129
+
130
+ it "defaults to exe if the installer_type is unknown" do
131
+ allow(provider).to receive(:installer_type).and_return(nil)
132
+ expect(provider.package_provider).to be_a(Chef::Provider::Package::Windows::Exe)
114
133
  end
115
134
  end
116
135
 
@@ -146,20 +165,202 @@ describe Chef::Provider::Package::Windows, :windows_only do
146
165
  end
147
166
 
148
167
  describe "installer_type" do
149
- it "it returns @installer_type if it is set" do
168
+ let(:resource_source) { "microsoft_installer.exe" }
169
+
170
+ context "there is no source" do
171
+ let(:uninstall_hash) do
172
+ [{
173
+ 'DisplayVersion' => 'outdated',
174
+ 'UninstallString' => "blah blah"
175
+ }]
176
+ end
177
+ let(:uninstall_key) { "blah" }
178
+ let(:uninstall_entry) do
179
+ entries = []
180
+ uninstall_hash.each do |entry|
181
+ entries.push(Chef::Provider::Package::Windows::RegistryUninstallEntry.new('hive', uninstall_key, entry))
182
+ end
183
+ entries
184
+ end
185
+
186
+ before do
187
+ allow(Chef::Provider::Package::Windows::RegistryUninstallEntry).to receive(:find_entries).and_return(uninstall_entry)
188
+ allow(::File).to receive(:exist?).with(Chef::Util::PathHelper.canonical_path(resource_source, false)).and_return(false)
189
+ end
190
+
191
+ context "uninstall string contains MsiExec.exe" do
192
+ let(:uninstall_hash) do
193
+ [{
194
+ 'DisplayVersion' => 'outdated',
195
+ 'UninstallString' => "MsiExec.exe /X{guid}"
196
+ }]
197
+ end
198
+
199
+ it "sets installer_type to MSI" do
200
+ expect(provider.installer_type).to eql(:msi)
201
+ end
202
+ end
203
+
204
+ context "uninstall string ends with uninst.exe" do
205
+ let(:uninstall_hash) do
206
+ [{
207
+ 'DisplayVersion' => 'outdated',
208
+ 'UninstallString' => %q{"c:/hfhfheru/uninst.exe"}
209
+ }]
210
+ end
211
+
212
+ it "sets installer_type to NSIS" do
213
+ expect(provider.installer_type).to eql(:nsis)
214
+ end
215
+ end
216
+
217
+ context "uninstall key ends in _is1" do
218
+ let(:uninstall_key) { "blah_is1" }
219
+
220
+ it "sets installer_type to inno" do
221
+ expect(provider.installer_type).to eql(:inno)
222
+ end
223
+ end
224
+
225
+ context "eninstall entries is empty" do
226
+ before { allow(Chef::Provider::Package::Windows::RegistryUninstallEntry).to receive(:find_entries).and_return([]) }
227
+
228
+ it "returns nil" do
229
+ expect(provider.installer_type).to eql(nil)
230
+ end
231
+ end
232
+ end
233
+
234
+ it "returns @installer_type if it is set" do
150
235
  provider.new_resource.installer_type(:downeaster)
151
236
  expect(provider.installer_type).to eql(:downeaster)
152
237
  end
153
238
 
154
- it "sets installer_type to msi if the source ends in .msi" do
155
- provider.new_resource.source("microsoft_installer.msi")
156
- expect(provider.installer_type).to eql(:msi)
239
+ it "sets installer_type to inno if the source contains inno" do
240
+ allow(::Kernel).to receive(:open).and_yield(StringIO.new('blah blah inno blah'))
241
+ expect(provider.installer_type).to eql(:inno)
157
242
  end
158
243
 
159
- it "raises an error if it cannot determine the installer type" do
160
- provider.new_resource.installer_type(nil)
161
- provider.new_resource.source("tomfoolery.now")
162
- expect { provider.installer_type }.to raise_error(ArgumentError)
244
+ it "sets installer_type to wise if the source contains wise" do
245
+ allow(::Kernel).to receive(:open).and_yield(StringIO.new('blah blah wise blah'))
246
+ expect(provider.installer_type).to eql(:wise)
247
+ end
248
+
249
+ it "sets installer_type to nsis if the source contains nsis" do
250
+ allow(::Kernel).to receive(:open).and_yield(StringIO.new('blah blah nullsoft blah'))
251
+ expect(provider.installer_type).to eql(:nsis)
252
+ end
253
+
254
+ context "source ends in .msi" do
255
+ let(:resource_source) { "microsoft_installer.msi" }
256
+
257
+ it "sets installer_type to msi" do
258
+ expect(provider.installer_type).to eql(:msi)
259
+ end
260
+ end
261
+
262
+ context "the source is setup.exe" do
263
+ let(:resource_source) { "setup.exe" }
264
+
265
+ it "sets installer_type to installshield" do
266
+ allow(::Kernel).to receive(:open).and_yield(StringIO.new(''))
267
+ expect(provider.installer_type).to eql(:installshield)
268
+ end
269
+ end
270
+
271
+ context "cannot determine the installer type" do
272
+ let(:resource_source) { "tomfoolery.now" }
273
+
274
+ it "raises an error" do
275
+ allow(::Kernel).to receive(:open).and_yield(StringIO.new(''))
276
+ provider.new_resource.installer_type(nil)
277
+ expect { provider.installer_type }.to raise_error(Chef::Exceptions::CannotDetermineWindowsInstallerType)
278
+ end
279
+ end
280
+ end
281
+
282
+ describe "action_install" do
283
+ let(:new_resource) { Chef::Resource::WindowsPackage.new("blah.exe") }
284
+ before do
285
+ new_resource.installer_type(:inno)
286
+ allow_any_instance_of(Chef::Provider::Package::Windows::Exe).to receive(:package_version).and_return(new_resource.version)
287
+ end
288
+
289
+ context "no version given, discovered or installed" do
290
+ it "installs latest" do
291
+ expect(provider).to receive(:install_package).with("blah.exe", "latest")
292
+ provider.run_action(:install)
293
+ end
294
+ end
295
+
296
+ context "no version given or discovered but package is installed" do
297
+ before { allow(provider).to receive(:current_version_array).and_return(["5.5.5"]) }
298
+
299
+ it "does not install" do
300
+ expect(provider).not_to receive(:install_package)
301
+ provider.run_action(:install)
302
+ end
303
+ end
304
+
305
+ context "a version is given and none is installed" do
306
+ before { new_resource.version('5.5.5') }
307
+
308
+ it "installs given version" do
309
+ expect(provider).to receive(:install_package).with("blah.exe", "5.5.5")
310
+ provider.run_action(:install)
311
+ end
312
+ end
313
+
314
+ context "a version is given and several are installed" do
315
+ context "given version matches an installed version" do
316
+ before do
317
+ new_resource.version('5.5.5')
318
+ allow(provider).to receive(:current_version_array).and_return([ ["5.5.5", "4.3.0", "1.1.1"] ])
319
+ end
320
+
321
+ it "does not install" do
322
+ expect(provider).not_to receive(:install_package)
323
+ provider.run_action(:install)
324
+ end
325
+ end
326
+
327
+ context "given version does not match an installed version" do
328
+ before do
329
+ new_resource.version('5.5.5')
330
+ allow(provider).to receive(:current_version_array).and_return([ ["5.5.0", "4.3.0", "1.1.1"] ])
331
+ end
332
+
333
+ it "installs given version" do
334
+ expect(provider).to receive(:install_package).with("blah.exe", "5.5.5")
335
+ provider.run_action(:install)
336
+ end
337
+ end
338
+ end
339
+
340
+ context "a version is given and one is installed" do
341
+ context "given version matches installed version" do
342
+ before do
343
+ new_resource.version('5.5.5')
344
+ allow(provider).to receive(:current_version_array).and_return(["5.5.5"])
345
+ end
346
+
347
+ it "does not install" do
348
+ expect(provider).not_to receive(:install_package)
349
+ provider.run_action(:install)
350
+ end
351
+ end
352
+
353
+ context "given version does not match installed version" do
354
+ before do
355
+ new_resource.version('5.5.5')
356
+ allow(provider).to receive(:current_version_array).and_return(["5.5.0"])
357
+ end
358
+
359
+ it "installs given version" do
360
+ expect(provider).to receive(:install_package).with("blah.exe", "5.5.5")
361
+ provider.run_action(:install)
362
+ end
363
+ end
163
364
  end
164
365
  end
165
366
  end