chef 12.14.89 → 12.15.19

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/CONTRIBUTING.md +76 -51
  3. data/Gemfile +1 -1
  4. data/README.md +9 -7
  5. data/Rakefile +1 -1
  6. data/VERSION +1 -1
  7. data/acceptance/Gemfile +3 -0
  8. data/acceptance/Gemfile.lock +19 -18
  9. data/acceptance/fips/.kitchen.yml +1 -1
  10. data/lib/chef/application/exit_code.rb +9 -0
  11. data/lib/chef/cookbook/file_system_file_vendor.rb +7 -8
  12. data/lib/chef/cookbook/metadata.rb +8 -0
  13. data/lib/chef/exceptions.rb +5 -0
  14. data/lib/chef/knife.rb +14 -15
  15. data/lib/chef/knife/ssh.rb +1 -0
  16. data/lib/chef/node/attribute.rb +1 -3
  17. data/lib/chef/node/attribute_collections.rb +20 -0
  18. data/lib/chef/provider/apt_repository.rb +1 -1
  19. data/lib/chef/provider/apt_update.rb +1 -1
  20. data/lib/chef/provider/group/groupadd.rb +2 -1
  21. data/lib/chef/provider/package/cab.rb +150 -0
  22. data/lib/chef/provider/package/rubygems.rb +0 -1
  23. data/lib/chef/provider/registry_key.rb +26 -2
  24. data/lib/chef/provider/remote_file/content.rb +1 -1
  25. data/lib/chef/provider/user.rb +10 -0
  26. data/lib/chef/provider/user/dscl.rb +2 -2
  27. data/lib/chef/provider/user/linux.rb +4 -14
  28. data/lib/chef/provider/user/pw.rb +2 -2
  29. data/lib/chef/provider/user/solaris.rb +15 -0
  30. data/lib/chef/provider/user/useradd.rb +1 -5
  31. data/lib/chef/providers.rb +1 -0
  32. data/lib/chef/resource/cab_package.rb +44 -0
  33. data/lib/chef/resource/registry_key.rb +3 -3
  34. data/lib/chef/resource/yum_repository.rb +1 -1
  35. data/lib/chef/resources.rb +1 -0
  36. data/lib/chef/server_api.rb +1 -1
  37. data/lib/chef/util/dsc/local_configuration_manager.rb +1 -1
  38. data/lib/chef/version.rb +1 -1
  39. data/spec/data/templates/chef-seattle20160930-4388-1crv7ef.txt +1 -0
  40. data/spec/data/templates/chef-seattle20160930-4388-jjfoae.txt +1 -0
  41. data/spec/data/templates/chef-seattle20160930-4388-umeq2c.txt +1 -0
  42. data/spec/functional/knife/cookbook_delete_spec.rb +48 -59
  43. data/spec/functional/resource/ifconfig_spec.rb +6 -0
  44. data/spec/functional/resource/registry_spec.rb +110 -4
  45. data/spec/unit/application/exit_code_spec.rb +10 -0
  46. data/spec/unit/cookbook/file_vendor_spec.rb +15 -0
  47. data/spec/unit/cookbook/metadata_spec.rb +19 -0
  48. data/spec/unit/exceptions_spec.rb +2 -0
  49. data/spec/unit/node/attribute_spec.rb +23 -1
  50. data/spec/unit/node/vivid_mash_spec.rb +27 -0
  51. data/spec/unit/provider/group/groupadd_spec.rb +118 -99
  52. data/spec/unit/provider/package/cab_spec.rb +218 -0
  53. data/spec/unit/provider/package/rubygems_spec.rb +2 -4
  54. data/spec/unit/provider/registry_key_spec.rb +94 -0
  55. data/spec/unit/provider/remote_file/content_spec.rb +1 -0
  56. data/spec/unit/provider/user/solaris_spec.rb +52 -40
  57. data/spec/unit/resource/apt_update_spec.rb +25 -17
  58. data/spec/unit/resource/cab_package_spec.rb +38 -0
  59. data/spec/unit/resource/registry_key_spec.rb +26 -10
  60. data/spec/unit/server_api_spec.rb +50 -0
  61. data/spec/unit/util/dsc/local_configuration_manager_spec.rb +10 -4
  62. metadata +13 -5
@@ -64,6 +64,10 @@ describe Chef::Application::ExitCode do
64
64
  it "validates a REBOOT_FAILED return code of 41" do
65
65
  expect(valid_rfc_exit_codes.include?(41)).to eq(true)
66
66
  end
67
+
68
+ it "validates a CLIENT_UPGRADED return code of 213" do
69
+ expect(valid_rfc_exit_codes.include?(213)).to eq(true)
70
+ end
67
71
  end
68
72
 
69
73
  context "when Chef::Config :exit_status is not configured" do
@@ -215,6 +219,12 @@ describe Chef::Application::ExitCode do
215
219
  expect(exit_codes.normalize_exit_code(runtime_error)).to eq(37)
216
220
  end
217
221
 
222
+ it "returns CLIENT_UPGRADED when the client was upgraded during converge" do
223
+ client_upgraded_error = Chef::Exceptions::ClientUpgraded.new("BOOM")
224
+ runtime_error = Chef::Exceptions::RunFailedWrappingError.new(client_upgraded_error)
225
+ expect(exit_codes.normalize_exit_code(runtime_error)).to eq(213)
226
+ end
227
+
218
228
  it "returns SIGINT_RECEIVED when a SIGINT is received." do
219
229
  sigint_error = Chef::Exceptions::SigInt.new("BOOM")
220
230
  runtime_error = Chef::Exceptions::RunFailedWrappingError.new(sigint_error)
@@ -94,4 +94,19 @@ describe Chef::Cookbook::FileVendor do
94
94
 
95
95
  end
96
96
 
97
+ context "when vendoring a cookbook with a name mismatch" do
98
+ let(:cookbook_path) { File.join(CHEF_SPEC_DATA, "cookbooks") }
99
+
100
+ # A manifest is a Hash of the format defined by Chef::CookbookVersion#manifest
101
+ let(:manifest) { { :cookbook_name => "name-mismatch" } }
102
+
103
+ before do
104
+ file_vendor_class.fetch_from_disk(cookbook_path)
105
+ end
106
+
107
+ it "retrieves the file from the correct location based on path to the cookbook that conatins the correct name metadata" do
108
+ file_vendor = file_vendor_class.create_from_manifest(manifest)
109
+ file_vendor.get_filename("metadata.rb")
110
+ end
111
+ end
97
112
  end
@@ -948,5 +948,24 @@ describe Chef::Cookbook::Metadata do
948
948
  end
949
949
  end
950
950
 
951
+ describe "from_file" do
952
+ it "ignores unknown metadata fields in metadata.rb files" do
953
+ expect(Chef::Log).to receive(:debug).with(/ignoring method some_spiffy_new_metadata_field/)
954
+ Tempfile.open("metadata.rb") do |f|
955
+ f.write <<-EOF
956
+ some_spiffy_new_metadata_field "stuff its set to"
957
+ EOF
958
+ f.close
959
+ metadata.from_file(f.path)
960
+ end
961
+ end
962
+ end
963
+
964
+ describe "from_json" do
965
+ it "ignores unknown metadata fields in metdata.json files" do
966
+ json = %q{{ "some_spiffy_new_metadata_field": "stuff its set to" }}
967
+ metadata.from_json(json)
968
+ end
969
+ end
951
970
  end
952
971
  end
@@ -68,6 +68,8 @@ describe Chef::Exceptions do
68
68
  Chef::Exceptions::EnvironmentNotFound => RuntimeError,
69
69
  Chef::Exceptions::InvalidVersionConstraint => ArgumentError,
70
70
  Chef::Exceptions::IllegalVersionConstraint => NotImplementedError,
71
+ Chef::Exceptions::RegKeyValuesTypeMissing => ArgumentError,
72
+ Chef::Exceptions::RegKeyValuesDataMissing => ArgumentError,
71
73
  }
72
74
 
73
75
  exception_to_super_class.each do |exception, expected_super_class|
@@ -1171,7 +1171,29 @@ describe Chef::Node::Attribute do
1171
1171
  Chef::Config[:treat_deprecation_warnings_as_errors] = false
1172
1172
  expect { @attributes.new_key = "new value" }.to raise_error(Chef::Exceptions::ImmutableAttributeModification)
1173
1173
  end
1174
-
1175
1174
  end
1176
1175
 
1176
+ describe "deeply converting values" do
1177
+ it "converts values through an array" do
1178
+ @attributes.default[:foo] = [ { bar: true } ]
1179
+ expect(@attributes["foo"].class).to eql(Chef::Node::ImmutableArray)
1180
+ expect(@attributes["foo"][0].class).to eql(Chef::Node::ImmutableMash)
1181
+ expect(@attributes["foo"][0]["bar"]).to be true
1182
+ end
1183
+
1184
+ it "converts values through nested arrays" do
1185
+ @attributes.default[:foo] = [ [ { bar: true } ] ]
1186
+ expect(@attributes["foo"].class).to eql(Chef::Node::ImmutableArray)
1187
+ expect(@attributes["foo"][0].class).to eql(Chef::Node::ImmutableArray)
1188
+ expect(@attributes["foo"][0][0].class).to eql(Chef::Node::ImmutableMash)
1189
+ expect(@attributes["foo"][0][0]["bar"]).to be true
1190
+ end
1191
+
1192
+ it "converts values through nested hashes" do
1193
+ @attributes.default[:foo] = { baz: { bar: true } }
1194
+ expect(@attributes["foo"].class).to eql(Chef::Node::ImmutableMash)
1195
+ expect(@attributes["foo"]["baz"].class).to eql(Chef::Node::ImmutableMash)
1196
+ expect(@attributes["foo"]["baz"]["bar"]).to be true
1197
+ end
1198
+ end
1177
1199
  end
@@ -37,6 +37,33 @@ describe Chef::Node::VividMash do
37
37
  expect(root).to receive(:top_level_breadcrumb=).with(key).at_least(:once).and_call_original
38
38
  end
39
39
 
40
+ context "#[]=" do
41
+ it "deep converts values through arrays" do
42
+ allow(root).to receive(:reset_cache)
43
+ vivid[:foo] = [ { :bar => true } ]
44
+ expect(vivid["foo"].class).to eql(Chef::Node::AttrArray)
45
+ expect(vivid["foo"][0].class).to eql(Chef::Node::VividMash)
46
+ expect(vivid["foo"][0]["bar"]).to be true
47
+ end
48
+
49
+ it "deep converts values through nested arrays" do
50
+ allow(root).to receive(:reset_cache)
51
+ vivid[:foo] = [ [ { :bar => true } ] ]
52
+ expect(vivid["foo"].class).to eql(Chef::Node::AttrArray)
53
+ expect(vivid["foo"][0].class).to eql(Chef::Node::AttrArray)
54
+ expect(vivid["foo"][0][0].class).to eql(Chef::Node::VividMash)
55
+ expect(vivid["foo"][0][0]["bar"]).to be true
56
+ end
57
+
58
+ it "deep converts values through hashes" do
59
+ allow(root).to receive(:reset_cache)
60
+ vivid[:foo] = { baz: { :bar => true } }
61
+ expect(vivid["foo"]).to be_an_instance_of(Chef::Node::VividMash)
62
+ expect(vivid["foo"]["baz"]).to be_an_instance_of(Chef::Node::VividMash)
63
+ expect(vivid["foo"]["baz"]["bar"]).to be true
64
+ end
65
+ end
66
+
40
67
  context "#read" do
41
68
  before do
42
69
  # vivify the vividmash, then we're read-only so the cache should never be cleared afterwards
@@ -18,156 +18,175 @@
18
18
 
19
19
  require "spec_helper"
20
20
 
21
- describe Chef::Provider::Group::Groupadd, "set_options" do
22
- before do
23
- @node = Chef::Node.new
24
- @events = Chef::EventDispatch::Dispatcher.new
25
- @run_context = Chef::RunContext.new(@node, {}, @events)
26
- @new_resource = Chef::Resource::Group.new("aj")
27
- @new_resource.gid(50)
28
- @new_resource.members(%w{root aj})
29
- @new_resource.system false
30
- @new_resource.non_unique false
31
- @current_resource = Chef::Resource::Group.new("aj")
32
- @current_resource.gid(50)
33
- @current_resource.members(%w{root aj})
34
- @current_resource.system false
35
- @current_resource.non_unique false
36
- @provider = Chef::Provider::Group::Groupadd.new(@new_resource, @run_context)
37
- @provider.current_resource = @current_resource
38
- end
39
-
40
- field_list = {
41
- :gid => "-g",
42
- }
43
-
44
- field_list.each do |attribute, option|
45
- it "should check for differences in #{attribute} between the current and new resources" do
46
- expect(@new_resource).to receive(attribute)
47
- expect(@current_resource).to receive(attribute)
48
- @provider.set_options
21
+ describe Chef::Provider::Group::Groupadd do
22
+ let(:node) { Chef::Node.new }
23
+ let(:events) { Chef::EventDispatch::Dispatcher.new }
24
+ let(:run_context) { Chef::RunContext.new(node, {}, events) }
25
+ let(:new_resource) do
26
+ Chef::Resource::Group.new("aj").tap do |r|
27
+ r.gid 50
28
+ r.members %w{root aj}
29
+ r.system false
30
+ r.non_unique false
49
31
  end
50
- it "should set the option for #{attribute} if the new resources #{attribute} is not null" do
51
- allow(@new_resource).to receive(attribute).and_return("wowaweea")
52
- expect(@provider.set_options).to eql(" #{option} '#{@new_resource.send(attribute)}' #{@new_resource.group_name}")
32
+ end
33
+ let(:current_resource) do
34
+ Chef::Resource::Group.new("aj").tap do |r|
35
+ r.gid 50
36
+ r.members %w{root aj}
37
+ r.system false
38
+ r.non_unique false
53
39
  end
54
40
  end
55
-
56
- it "should combine all the possible options" do
57
- match_string = ""
58
- field_list.sort { |a, b| a[0] <=> b[0] }.each do |attribute, option|
59
- allow(@new_resource).to receive(attribute).and_return("hola")
60
- match_string << " #{option} 'hola'"
41
+ let(:provider) do
42
+ described_class.new(new_resource, run_context).tap do |p|
43
+ p.current_resource = current_resource
61
44
  end
62
- match_string << " aj"
63
- expect(@provider.set_options).to eql(match_string)
64
45
  end
65
46
 
66
- describe "when we want to create a system group" do
67
- it "should not set groupadd_options '-r' when system is false" do
68
- @new_resource.system(false)
69
- expect(@provider.groupadd_options).not_to match(/-r/)
47
+ describe "#set_options" do
48
+ field_list = {
49
+ :gid => "-g",
50
+ }
51
+
52
+ field_list.each do |attribute, option|
53
+ it "should check for differences in #{attribute} between the current and new resources" do
54
+ expect(new_resource).to receive(attribute)
55
+ expect(current_resource).to receive(attribute)
56
+ provider.set_options
57
+ end
58
+
59
+ it "should set the option for #{attribute} if the new resources #{attribute} is not null" do
60
+ allow(new_resource).to receive(attribute).and_return("wowaweea")
61
+ expect(provider.set_options).to eql(" #{option} '#{new_resource.send(attribute)}' #{new_resource.group_name}")
62
+ end
70
63
  end
71
64
 
72
- it "should set groupadd -r if system is true" do
73
- @new_resource.system(true)
74
- expect(@provider.groupadd_options).to eq(" -r")
65
+ it "should combine all the possible options" do
66
+ match_string = ""
67
+ field_list.sort { |a, b| a[0] <=> b[0] }.each do |attribute, option|
68
+ allow(new_resource).to receive(attribute).and_return("hola")
69
+ match_string << " #{option} 'hola'"
70
+ end
71
+ match_string << " aj"
72
+ expect(provider.set_options).to eql(match_string)
75
73
  end
76
- end
77
74
 
78
- describe "when we want to create a non_unique gid group" do
79
- it "should not set groupadd_options '-o' when non_unique is false" do
80
- @new_resource.non_unique(false)
81
- expect(@provider.groupadd_options).not_to match(/-o/)
75
+ describe "when we want to create a system group" do
76
+ it "should not set groupadd_options '-r' when system is false" do
77
+ new_resource.system(false)
78
+ expect(provider.groupadd_options).not_to match(/-r/)
79
+ end
80
+
81
+ it "should set groupadd -r if system is true" do
82
+ new_resource.system(true)
83
+ expect(provider.groupadd_options).to eq(" -r")
84
+ end
85
+
86
+ context "on Solaris" do
87
+ before { node.automatic["platform"] = "solaris2" }
88
+ it "should not set groupadd -r if system is true" do
89
+ new_resource.system(true)
90
+ expect(provider.groupadd_options).not_to match(/-r/)
91
+ end
92
+ end
82
93
  end
83
94
 
84
- it "should set groupadd -o if non_unique is true" do
85
- @new_resource.non_unique(true)
86
- expect(@provider.groupadd_options).to eq(" -o")
87
- end
88
- end
89
- end
95
+ describe "when we want to create a non_unique gid group" do
96
+ it "should not set groupadd_options '-o' when non_unique is false" do
97
+ new_resource.non_unique(false)
98
+ expect(provider.groupadd_options).not_to match(/-o/)
99
+ end
90
100
 
91
- describe Chef::Provider::Group::Groupadd, "create_group" do
92
- before do
93
- @node = Chef::Node.new
94
- @new_resource = Chef::Resource::Group.new("aj")
95
- @provider = Chef::Provider::Group::Groupadd.new(@node, @new_resource)
96
- allow(@provider).to receive(:run_command).and_return(true)
97
- allow(@provider).to receive(:set_options).and_return(" monkey")
98
- allow(@provider).to receive(:groupadd_options).and_return("")
99
- allow(@provider).to receive(:modify_group_members).and_return(true)
101
+ it "should set groupadd -o if non_unique is true" do
102
+ new_resource.non_unique(true)
103
+ expect(provider.groupadd_options).to eq(" -o")
104
+ end
105
+ end
100
106
  end
101
107
 
102
- it "should run groupadd with the return of set_options" do
103
- expect(@provider).to receive(:run_command).with({ :command => "groupadd monkey" }).and_return(true)
104
- @provider.create_group
105
- end
108
+ describe "#create_group" do
109
+ before do
110
+ allow(provider).to receive(:run_command).and_return(true)
111
+ allow(provider).to receive(:set_options).and_return(" monkey")
112
+ allow(provider).to receive(:groupadd_options).and_return("")
113
+ allow(provider).to receive(:modify_group_members).and_return(true)
114
+ end
106
115
 
107
- it "should modify the group members" do
108
- expect(@provider).to receive(:modify_group_members).and_return(true)
109
- @provider.create_group
110
- end
111
- end
116
+ it "should run groupadd with the return of set_options" do
117
+ expect(provider).to receive(:run_command).with({ :command => "groupadd monkey" }).and_return(true)
118
+ provider.create_group
119
+ end
112
120
 
113
- describe Chef::Provider::Group::Groupadd do
114
- before do
115
- @node = Chef::Node.new
116
- @events = Chef::EventDispatch::Dispatcher.new
117
- @run_context = Chef::RunContext.new(@node, {}, @events)
118
- @new_resource = Chef::Resource::Group.new("aj")
119
- @provider = Chef::Provider::Group::Groupadd.new(@new_resource, @run_context)
120
- allow(@provider).to receive(:run_command).and_return(true)
121
- allow(@provider).to receive(:set_options).and_return(" monkey")
121
+ it "should modify the group members" do
122
+ expect(provider).to receive(:modify_group_members).and_return(true)
123
+ provider.create_group
124
+ end
122
125
  end
123
126
 
124
- describe "manage group" do
127
+ describe "#manage_group" do
128
+ before do
129
+ allow(provider).to receive(:run_command).and_return(true)
130
+ allow(provider).to receive(:set_options).and_return(" monkey")
131
+ end
125
132
 
126
133
  it "should run groupmod with the return of set_options" do
127
- allow(@provider).to receive(:modify_group_members).and_return(true)
128
- expect(@provider).to receive(:run_command).with({ :command => "groupmod monkey" }).and_return(true)
129
- @provider.manage_group
134
+ allow(provider).to receive(:modify_group_members).and_return(true)
135
+ expect(provider).to receive(:run_command).with({ :command => "groupmod monkey" }).and_return(true)
136
+ provider.manage_group
130
137
  end
131
138
 
132
139
  it "should modify the group members" do
133
- expect(@provider).to receive(:modify_group_members).and_return(true)
134
- @provider.manage_group
140
+ expect(provider).to receive(:modify_group_members).and_return(true)
141
+ provider.manage_group
135
142
  end
136
143
  end
137
144
 
138
- describe "remove_group" do
145
+ describe "#remove_group" do
146
+ before do
147
+ allow(provider).to receive(:run_command).and_return(true)
148
+ allow(provider).to receive(:set_options).and_return(" monkey")
149
+ end
139
150
 
140
151
  it "should run groupdel with the new resources group name" do
141
- expect(@provider).to receive(:run_command).with({ :command => "groupdel aj" }).and_return(true)
142
- @provider.remove_group
152
+ expect(provider).to receive(:run_command).with({ :command => "groupdel aj" }).and_return(true)
153
+ provider.remove_group
143
154
  end
144
155
  end
145
156
 
146
157
  [:add_member, :remove_member, :set_members].each do |m|
147
158
  it "should raise an error when calling #{m}" do
148
- expect { @provider.send(m, [ ]) }.to raise_error(Chef::Exceptions::Group, "you must override #{m} in #{@provider}")
159
+ expect { provider.send(m, [ ]) }.to raise_error(Chef::Exceptions::Group, "you must override #{m} in #{provider}")
149
160
  end
150
161
  end
151
162
 
152
- describe "load_current_resource" do
163
+ describe "#load_current_resource" do
164
+ before do
165
+ allow(provider).to receive(:run_command).and_return(true)
166
+ allow(provider).to receive(:set_options).and_return(" monkey")
167
+ end
168
+
153
169
  before do
154
170
  allow(File).to receive(:exists?).and_return(false)
155
- @provider.define_resource_requirements
171
+ provider.define_resource_requirements
156
172
  end
173
+
157
174
  it "should raise an error if the required binary /usr/sbin/groupadd doesn't exist" do
158
175
  expect(File).to receive(:exists?).with("/usr/sbin/groupadd").and_return(false)
159
- expect { @provider.process_resource_requirements }.to raise_error(Chef::Exceptions::Group)
176
+ expect { provider.process_resource_requirements }.to raise_error(Chef::Exceptions::Group)
160
177
  end
178
+
161
179
  it "should raise an error if the required binary /usr/sbin/groupmod doesn't exist" do
162
180
  expect(File).to receive(:exists?).with("/usr/sbin/groupadd").and_return(true)
163
181
  expect(File).to receive(:exists?).with("/usr/sbin/groupmod").and_return(false)
164
- expect { @provider.process_resource_requirements }.to raise_error(Chef::Exceptions::Group)
182
+ expect { provider.process_resource_requirements }.to raise_error(Chef::Exceptions::Group)
165
183
  end
184
+
166
185
  it "should raise an error if the required binary /usr/sbin/groupdel doesn't exist" do
167
186
  expect(File).to receive(:exists?).with("/usr/sbin/groupadd").and_return(true)
168
187
  expect(File).to receive(:exists?).with("/usr/sbin/groupmod").and_return(true)
169
188
  expect(File).to receive(:exists?).with("/usr/sbin/groupdel").and_return(false)
170
- expect { @provider.process_resource_requirements }.to raise_error(Chef::Exceptions::Group)
189
+ expect { provider.process_resource_requirements }.to raise_error(Chef::Exceptions::Group)
171
190
  end
172
191
 
173
192
  end
@@ -0,0 +1,218 @@
1
+ #
2
+ # Author:: Vasundhara Jagdale (<vasundhara.jagdale@msystechnologies.com>)
3
+ # Copyright:: Copyright 2008-2016, 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
+
21
+ describe Chef::Provider::Package::Cab do
22
+ let(:timeout) {}
23
+
24
+ let(:new_resource) { Chef::Resource::CabPackage.new("windows_test_pkg") }
25
+
26
+ let(:provider) do
27
+ node = Chef::Node.new
28
+ events = Chef::EventDispatch::Dispatcher.new
29
+ run_context = Chef::RunContext.new(node, {}, events)
30
+ Chef::Provider::Package::Cab.new(new_resource, run_context)
31
+ end
32
+
33
+ let(:installed_package_list_stdout) do
34
+ <<-EOF
35
+ Packages listing:
36
+ Package Identity : Package_for_KB2999486~31bf3856ad364e35~amd64~~6.1.9768.0
37
+ Package Identity : Package_for_KB2994825~31bf3856ad364e35~amd64~~6.1.7601.0
38
+ EOF
39
+ end
40
+
41
+ let(:package_version_stdout) do
42
+ <<-EOF
43
+ Package information:
44
+ Package Identity : Package_for_KB2664825~31bf3856ad364e35~amd64~~6.1.3.0
45
+ State : Installed
46
+ Dependency : Language Pack
47
+ The operation completed successfully
48
+ EOF
49
+ end
50
+
51
+ before do
52
+ new_resource.source = "C:\\Temp\\Test6.1-KB2664825-v3-x64.cab"
53
+ installed_package_list_obj = double(stdout: installed_package_list_stdout)
54
+ allow(provider).to receive(:dism_command).with("/Get-Packages").and_return(installed_package_list_obj)
55
+ package_version_obj = double(stdout: package_version_stdout)
56
+ allow(provider).to receive(:dism_command).with("/Get-PackageInfo /PackagePath:\"#{new_resource.source}\"").and_return(package_version_obj)
57
+ end
58
+
59
+ def allow_package_info(package_path = nil, package_name = nil)
60
+ get_package_info_stdout = <<-EOF
61
+ Deployment Image Servicing and Management tool
62
+ Version: 6.1.7600.16385
63
+
64
+ Image Version: 6.1.7600.16385
65
+
66
+ Package information:
67
+ Package Identity : Package_for_KB2664825~31bf3856ad364e35~amd64~~6.1.3.0
68
+ Applicable : Yes
69
+ Copyright : Microsoft Corporation
70
+ Company : Microsoft Corporation
71
+ State : Installed
72
+ Dependency : Language Pack
73
+ The operation completed successfully
74
+ EOF
75
+ get_package_info_obj = double(stdout: get_package_info_stdout)
76
+ if package_path
77
+ allow(provider).to receive(:dism_command).with("/Get-PackageInfo /PackagePath:\"#{package_path}\"").and_return(get_package_info_obj)
78
+ else
79
+ allow(provider).to receive(:dism_command).with("/Get-PackageInfo /PackageName:\"#{package_name}\"").and_return(get_package_info_obj)
80
+ end
81
+ end
82
+
83
+ def allow_get_packages
84
+ get_packages_stdout = <<-EOF
85
+ Deployment Image Servicing and Management tool
86
+ Version: 6.1.7600.16385
87
+
88
+ Image Version: 6.1.7600.16385
89
+
90
+ Packages listing:
91
+
92
+ Package Identity : Package_for_KB2999486~31bf3856ad364e35~amd64~~6.1.9768.0
93
+ State : Installed
94
+ Release Type : Language Pack
95
+ Install Time : 2/11/2015 11:33 PM
96
+
97
+ Package Identity : Package_for_KB2994825~31bf3856ad364e35~amd64~~6.1.7601.0
98
+ State : Installed
99
+ Release Type : Language Pack
100
+ Install Time : 2/11/2015 11:33 PM
101
+
102
+ Package Identity : Package_for_KB2664825~31bf3856ad364e35~amd64~~6.1.3.0
103
+ State : Installed
104
+ Release Type : Feature Pack
105
+ Install Time : 11/21/2010 3:40 AM
106
+
107
+ The operation completed successfully.
108
+ EOF
109
+ get_packages_obj = double(stdout: get_packages_stdout)
110
+ allow(provider).to receive(:dism_command).with("/Get-Packages").and_return(get_packages_obj)
111
+ end
112
+
113
+ describe "#load_current_resource" do
114
+ it "returns a current_resource" do
115
+ expect(provider.load_current_resource).to be_kind_of(Chef::Resource::CabPackage)
116
+ end
117
+
118
+ it "sets the current_resource.version to nil when the package is not installed" do
119
+ provider.load_current_resource
120
+ expect(provider.current_resource.version).to eql(nil)
121
+ end
122
+
123
+ it "sets the new resource package version" do
124
+ provider.load_current_resource
125
+ expect(provider.new_resource.version).to eql("6.1.3.0")
126
+ end
127
+ end
128
+
129
+ describe "#initialize" do
130
+ it "returns the correct class" do
131
+ expect(provider).to be_kind_of(Chef::Provider::Package::Cab)
132
+ end
133
+ end
134
+
135
+ describe "#package_version" do
136
+ it "returns the new package version" do
137
+ allow_package_info(new_resource.source, nil)
138
+ expect(provider.package_version).to eql("6.1.3.0")
139
+ end
140
+ end
141
+
142
+ describe "#installed_version" do
143
+ it "returns the current installed version of package" do
144
+ allow_package_info(new_resource.source, nil)
145
+ allow_get_packages
146
+ allow_package_info(nil, "Package_for_KB2664825~31bf3856ad364e35~amd64~~6.1.3.0")
147
+ expect(provider.installed_version).to eql("6.1.3.0")
148
+ end
149
+ end
150
+
151
+ describe "#action_remove" do
152
+ it "does nothing when the package is already removed" do
153
+ provider.load_current_resource
154
+ expect(provider).not_to receive(:remove_package)
155
+ provider.run_action(:remove)
156
+ expect(new_resource).not_to be_updated_by_last_action
157
+ end
158
+
159
+ it "removes packages if package is installed" do
160
+ allow_package_info(new_resource.source, nil)
161
+ allow_get_packages
162
+ allow_package_info(nil, "Package_for_KB2664825~31bf3856ad364e35~amd64~~6.1.3.0")
163
+ provider.load_current_resource
164
+ expect(provider.installed_version).not_to eql(nil)
165
+ expect(provider).to receive(:remove_package)
166
+ provider.run_action(:remove)
167
+ expect(new_resource).to be_updated_by_last_action
168
+ end
169
+ end
170
+
171
+ describe "#action_install" do
172
+ it "installs package if already not installed" do
173
+ provider.load_current_resource
174
+ expect(provider.installed_version).to eql(nil)
175
+ expect(provider).to receive(:install_package)
176
+ provider.run_action(:install)
177
+ expect(new_resource).to be_updated_by_last_action
178
+ end
179
+
180
+ it "does not install package if already installed" do
181
+ allow_package_info(new_resource.source, nil)
182
+ allow_get_packages
183
+ allow_package_info(nil, "Package_for_KB2664825~31bf3856ad364e35~amd64~~6.1.3.0")
184
+ provider.load_current_resource
185
+ expect(provider.installed_version).not_to eql(nil)
186
+ expect(provider).not_to receive(:install_package)
187
+ provider.run_action(:install)
188
+ expect(new_resource).not_to be_updated_by_last_action
189
+ end
190
+ end
191
+
192
+ context "Invalid package source" do
193
+ def package_version_stdout
194
+ package_version_stdout = <<-EOF
195
+
196
+ Deployment Image Servicing and Management tool
197
+ Version: 6.1.7600.16385
198
+
199
+ Image Version: 6.1.7600.16385
200
+
201
+ An error occurred trying to open - c:\\temp\\test6.1-KB2664825-v3-x64.cab Error: 0x80070003
202
+ Error: 3
203
+ The system cannot find the path specified.
204
+ The DISM log file can be found at C:\\Windows\\Logs\\DISM\\dism.log.
205
+ EOF
206
+ end
207
+
208
+ before do
209
+ new_resource.source = "C:\\Temp\\Test6.1-KB2664825-v3-x64.cab"
210
+ installed_package_list_obj = double(stdout: installed_package_list_stdout)
211
+ allow(provider).to receive(:dism_command).with("/Get-Packages").and_return(installed_package_list_obj)
212
+ end
213
+
214
+ it "raises error for invalid source path or file" do
215
+ expect { provider.load_current_resource }.to raise_error(Chef::Exceptions::Package, "DISM: The system cannot find the path or file specified.")
216
+ end
217
+ end
218
+ end