chef-apply 0.1.17 → 0.1.18

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 (38) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +0 -7
  3. data/Gemfile.lock +176 -84
  4. data/chef-apply.gemspec +2 -2
  5. data/lib/chef_apply/version.rb +1 -1
  6. data/spec/fixtures/custom_config.toml +2 -0
  7. data/spec/integration/chef-run_spec.rb +41 -0
  8. data/spec/integration/fixtures/chef_help.out +69 -0
  9. data/spec/integration/fixtures/chef_version.out +1 -0
  10. data/spec/integration/spec_helper.rb +55 -0
  11. data/spec/spec_helper.rb +114 -0
  12. data/spec/support/matchers/output_to_terminal.rb +36 -0
  13. data/spec/unit/action/base_spec.rb +89 -0
  14. data/spec/unit/action/converge_target_spec.rb +292 -0
  15. data/spec/unit/action/generate_local_policy_spec.rb +114 -0
  16. data/spec/unit/action/generate_temp_cookbook_spec.rb +75 -0
  17. data/spec/unit/action/install_chef/base_spec.rb +234 -0
  18. data/spec/unit/action/install_chef_spec.rb +69 -0
  19. data/spec/unit/cli/options_spec.rb +75 -0
  20. data/spec/unit/cli/validation_spec.rb +78 -0
  21. data/spec/unit/cli_spec.rb +440 -0
  22. data/spec/unit/config_spec.rb +70 -0
  23. data/spec/unit/errors/ccr_failure_mapper_spec.rb +103 -0
  24. data/spec/unit/file_fetcher_spec.rb +40 -0
  25. data/spec/unit/fixtures/multi-error.out +2 -0
  26. data/spec/unit/log_spec.rb +37 -0
  27. data/spec/unit/recipe_lookup_spec.rb +122 -0
  28. data/spec/unit/startup_spec.rb +283 -0
  29. data/spec/unit/target_host_spec.rb +231 -0
  30. data/spec/unit/target_resolver_spec.rb +380 -0
  31. data/spec/unit/telemeter/sender_spec.rb +140 -0
  32. data/spec/unit/telemeter_spec.rb +191 -0
  33. data/spec/unit/temp_cookbook_spec.rb +199 -0
  34. data/spec/unit/ui/error_printer_spec.rb +173 -0
  35. data/spec/unit/ui/terminal_spec.rb +109 -0
  36. data/spec/unit/version_spec.rb +31 -0
  37. data/warning.txt +3 -0
  38. metadata +34 -2
@@ -0,0 +1,75 @@
1
+ #
2
+ # Copyright:: Copyright (c) 2018 Chef Software Inc.
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
17
+
18
+ require "spec_helper"
19
+ require "mixlib/cli"
20
+ require "chef_apply/cli/options"
21
+ require "chef-config/config"
22
+
23
+ ChefApply::Config.load
24
+
25
+ module ChefApply
26
+ module CLIOptions
27
+ class TestClass
28
+ include Mixlib::CLI
29
+ include ChefApply::CLI::Options
30
+ end
31
+
32
+ def parse(argv)
33
+ parse_options(argv)
34
+ end
35
+ end
36
+ end
37
+
38
+ RSpec.describe ChefApply::CLIOptions do
39
+ let(:klass) { ChefApply::CLIOptions::TestClass.new }
40
+
41
+ it "contains the specified options" do
42
+ expect(klass.options.keys).to eq([
43
+ :version,
44
+ :help,
45
+ :config_path,
46
+ :identity_file,
47
+ :ssl,
48
+ :ssl_verify,
49
+ :protocol,
50
+ :user,
51
+ :password,
52
+ :cookbook_repo_paths,
53
+ :install,
54
+ :sudo,
55
+ :sudo_command,
56
+ :sudo_password,
57
+ :sudo_options
58
+ ])
59
+ end
60
+
61
+ it "persists certain CLI options back to the ChefApply::Config" do
62
+ # First we check the default value beforehand
63
+ expect(ChefApply::Config.connection.winrm.ssl).to eq(false)
64
+ expect(ChefApply::Config.connection.winrm.ssl_verify).to eq(true)
65
+ expect(ChefApply::Config.connection.default_protocol).to eq("ssh")
66
+ expect(ChefApply::Config.chef.cookbook_repo_paths).to_not be_empty
67
+ # Then we set the values and check they are changed
68
+ klass.parse_options(["--ssl", "--no-ssl-verify", "--protocol", "winrm", "--cookbook-repo-paths", "a,b"])
69
+ expect(ChefApply::Config.connection.winrm.ssl).to eq(true)
70
+ expect(ChefApply::Config.connection.winrm.ssl_verify).to eq(false)
71
+ expect(ChefApply::Config.connection.default_protocol).to eq("winrm")
72
+ expect(ChefApply::Config.chef.cookbook_repo_paths).to eq(%w{a b})
73
+ end
74
+
75
+ end
@@ -0,0 +1,78 @@
1
+ require "spec_helper"
2
+ require "chef_apply/error"
3
+ require "chef_apply/cli/validation"
4
+
5
+ RSpec.describe ChefApply::CLI::Validation do
6
+ class Validator
7
+ include ChefApply::CLI::Validation
8
+ end
9
+ subject { Validator.new }
10
+
11
+ context "#validate_params" do
12
+ OptionValidationError = ChefApply::CLI::OptionValidationError
13
+ it "raises an error if not enough params are specified" do
14
+ params = [
15
+ [],
16
+ %w{one}
17
+ ]
18
+ params.each do |p|
19
+ expect { subject.validate_params(p) }.to raise_error(OptionValidationError) do |e|
20
+ e.id == "CHEFVAL002"
21
+ end
22
+ end
23
+ end
24
+
25
+ it "succeeds if the second command is a valid file path" do
26
+ params = %w{target /some/path}
27
+ expect(File).to receive(:exist?).with("/some/path").and_return true
28
+ expect { subject.validate_params(params) }.to_not raise_error
29
+ end
30
+
31
+ it "succeeds if the second argument looks like a cookbook name" do
32
+ params = [
33
+ %w{target cb},
34
+ %w{target cb::recipe}
35
+ ]
36
+ params.each do |p|
37
+ expect { subject.validate_params(p) }.to_not raise_error
38
+ end
39
+ end
40
+
41
+ it "raises an error if the second argument is neither a valid path or a valid cookbook name" do
42
+ params = %w{target weird%name}
43
+ expect { subject.validate_params(params) }.to raise_error(OptionValidationError) do |e|
44
+ e.id == "CHEFVAL004"
45
+ end
46
+ end
47
+
48
+ it "raises an error if properties are not specified as key value pairs" do
49
+ params = [
50
+ %w{one two three four},
51
+ %w{one two three four=value five six=value},
52
+ %w{one two three non.word=value},
53
+ ]
54
+ params.each do |p|
55
+ expect { subject.validate_params(p) }.to raise_error(OptionValidationError) do |e|
56
+ e.id == "CHEFVAL003"
57
+ end
58
+ end
59
+ end
60
+ end
61
+ describe "#properties_from_string" do
62
+ it "parses properties into a hash" do
63
+ provided = %w{key1=value key2=1 key3=true key4=FaLsE key5=0777 key6=https://some.website key7=num1and2digit key_8=underscore}
64
+ expected = {
65
+ "key1" => "value",
66
+ "key2" => 1,
67
+ "key3" => true,
68
+ "key4" => false,
69
+ "key5" => "0777",
70
+ "key6" => "https://some.website",
71
+ "key7" => "num1and2digit",
72
+ "key_8" => "underscore"
73
+ }
74
+ expect(subject.properties_from_string(provided)).to eq(expected)
75
+ end
76
+ end
77
+
78
+ end
@@ -0,0 +1,440 @@
1
+ #
2
+ # Copyright:: Copyright (c) 2018 Chef Software Inc.
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
17
+
18
+ require "spec_helper"
19
+ require "chef_apply/cli"
20
+ require "chef_apply/error"
21
+ require "chef_apply/telemeter"
22
+ require "chef_apply/telemeter/sender"
23
+ require "chef_apply/ui/terminal"
24
+ require "chef_apply/action/generate_temp_cookbook"
25
+
26
+ require "chef-dk/ui"
27
+ require "chef-dk/policyfile_services/export_repo"
28
+ require "chef-dk/policyfile_services/install"
29
+
30
+ RSpec.describe ChefApply::CLI do
31
+ subject { ChefApply::CLI.new(argv) }
32
+ let(:argv) { [] }
33
+ # TODO why isn't this mocked?
34
+ let(:telemetry) { ChefApply::Telemeter.instance }
35
+
36
+ before do
37
+ # Avoid messy object dumps in failures because subject is an object instance
38
+ allow(subject).to receive(:inspect).and_return("The subject instance")
39
+ end
40
+
41
+ describe "run" do
42
+ before do
43
+ # Catch all of the calls by default, to prevent the various
44
+ # startup actions from actually occuring on the workstatoin.
45
+ allow(telemetry).to receive(:timed_run_capture).and_yield
46
+ allow(subject).to receive(:perform_run)
47
+ allow(telemetry).to receive(:commit)
48
+ end
49
+
50
+ it "captures and commits the run to telemetry" do
51
+ expect(telemetry).to receive(:timed_run_capture)
52
+ expect(telemetry).to receive(:commit)
53
+ expect { subject.run }.to exit_with_code(0)
54
+ end
55
+
56
+ it "calls perform_run" do
57
+ expect(subject).to receive(:perform_run)
58
+ expect { subject.run }.to exit_with_code(0)
59
+ end
60
+
61
+ context "perform_run raises WrappedError" do
62
+ let(:e) { ChefApply::WrappedError.new(RuntimeError.new("Test"), "host") }
63
+
64
+ it "prints the error and exits" do
65
+ expect(subject).to receive(:perform_run).and_raise(e)
66
+ expect(ChefApply::UI::ErrorPrinter).to receive(:show_error).with(e)
67
+ expect { subject.run }.to exit_with_code(1)
68
+ end
69
+ end
70
+
71
+ context "perform_run raises SystemExit" do
72
+ it "exits with same exit code" do
73
+ expect(subject).to receive(:perform_run).and_raise(SystemExit.new(99))
74
+ expect { subject.run }.to exit_with_code(99)
75
+ end
76
+ end
77
+
78
+ context "perform_run raises any other exception" do
79
+ let(:e) { Exception.new("test") }
80
+
81
+ it "exits with code 64" do
82
+ expect(subject).to receive(:perform_run).and_raise(e)
83
+ expect(ChefApply::UI::ErrorPrinter).to receive(:dump_unexpected_error).with(e)
84
+ expect { subject.run }.to exit_with_code(64)
85
+ end
86
+ end
87
+ end
88
+
89
+ describe "#perform_run" do
90
+ it "parses options" do
91
+ expect(subject).to receive(:parse_options).with(argv)
92
+ subject.perform_run
93
+ end
94
+
95
+ context "when any error is raised" do
96
+ let(:e) { RuntimeError.new("Test") }
97
+ before do
98
+ allow(subject).to receive(:parse_options).and_raise(e)
99
+ end
100
+
101
+ it "calls handle_perform_error" do
102
+ expect(subject).to receive(:handle_perform_error).with(e)
103
+ subject.perform_run
104
+ end
105
+ end
106
+
107
+ context "when argv is empty" do
108
+ let(:argv) { [] }
109
+ it "shows the help text" do
110
+ expect(subject).to receive(:show_help)
111
+ subject.perform_run
112
+ end
113
+ end
114
+
115
+ context "when help flags are passed" do
116
+ %w{-h --help}.each do |flag|
117
+ context flag do
118
+ let(:argv) { [flag] }
119
+ it "shows the help text" do
120
+ expect(subject).to receive(:show_help)
121
+ subject.perform_run
122
+ end
123
+ end
124
+ end
125
+
126
+ %w{-v --version}.each do |flag|
127
+ context flag do
128
+ let(:argv) { [flag] }
129
+ it "shows the help text" do
130
+ expect(subject).to receive(:show_version)
131
+ subject.perform_run
132
+ end
133
+ end
134
+ end
135
+ end
136
+
137
+ context "when arguments are provided" do
138
+ let(:argv) { ["hostname", "resourcetype", "resourcename", "someproperty=true"] }
139
+ let(:target_hosts) { [double("TargetHost")] }
140
+ before do
141
+ # parse_options sets `cli_argument` - because we stub out parse_options,
142
+ # later calls that rely on cli_arguments will fail without this.
143
+ allow(subject).to receive(:cli_arguments).and_return argv
144
+ end
145
+
146
+ context "and they are valid" do
147
+ it "creates the cookbook locally and converges it" do
148
+ expect(subject).to receive(:parse_options)
149
+ expect(subject).to receive(:validate_params)
150
+ expect(subject).to receive(:resolve_targets).and_return target_hosts
151
+ expect(subject).to receive(:render_cookbook_setup)
152
+ expect(subject).to receive(:render_converge).with(target_hosts)
153
+ subject.perform_run
154
+ end
155
+ end
156
+ end
157
+ end
158
+
159
+ describe "#connect_target" do
160
+ let(:host) { double("TargetHost", config: {}, user: "root" ) }
161
+ let(:reporter) { double("reporter", update: :ok, success: :ok) }
162
+ it "invokes do_connect with correct options" do
163
+ expect(subject).to receive(:do_connect).
164
+ with(host, reporter)
165
+ subject.connect_target(host, reporter)
166
+ end
167
+ end
168
+
169
+ describe "#generate_temp_cookbook" do
170
+ before do
171
+ allow(subject).to receive(:parsed_options).and_return({ cookbook_repo_paths: "/tmp" })
172
+ end
173
+ let(:temp_cookbook) { double("TempCookbook") }
174
+ let(:action) { double("generator", generated_cookbook: temp_cookbook) }
175
+
176
+ context "when a resource is provided" do
177
+ it "gets an action via GenerateTemporaryCookbook.from_options and executes it " do
178
+ expect(ChefApply::Action::GenerateTempCookbook)
179
+ .to receive(:from_options)
180
+ .with(resource_type: "user",
181
+ resource_name: "test", resource_properties: {})
182
+ .and_return(action)
183
+ expect(action).to receive(:run)
184
+ expect(subject.generate_temp_cookbook(%w{user test}, nil)).to eq temp_cookbook
185
+ end
186
+ end
187
+
188
+ context "when a recipe specifier is provided" do
189
+
190
+ it "gets an action via GenerateTemporaryCookbook.from_options and executes it" do
191
+ expect(ChefApply::Action::GenerateTempCookbook)
192
+ .to receive(:from_options)
193
+ .with(recipe_spec: "mycookbook::default", cookbook_repo_paths: "/tmp")
194
+ .and_return(action)
195
+ expect(action).to receive(:run)
196
+ subject.generate_temp_cookbook(["mycookbook::default"], nil)
197
+ end
198
+ end
199
+
200
+ context "when generator posts event:" do
201
+ let(:reporter) { double("reporter") }
202
+ before do
203
+ expect(ChefApply::Action::GenerateTempCookbook)
204
+ .to receive(:from_options)
205
+ .and_return(action)
206
+ allow(action).to receive(:run) { |&block| block.call(event, event_args) }
207
+ end
208
+
209
+ context ":generating" do
210
+ let(:event) { :generating }
211
+ let(:event_args) { nil }
212
+ it "updates message text via reporter" do
213
+ expected_text = ChefApply::CLI::TS.generate_temp_cookbook.generating
214
+ expect(reporter).to receive(:update).with(expected_text)
215
+ subject.generate_temp_cookbook(%w{user jimbo}, reporter)
216
+ end
217
+ end
218
+
219
+ context ":success" do
220
+ let(:event) { :success }
221
+ let(:event_args) { [ temp_cookbook ] }
222
+ it "indicates success via reporter and returns the cookbook" do
223
+ expected_text = ChefApply::CLI::TS.generate_temp_cookbook.success
224
+ expect(reporter).to receive(:success).with(expected_text)
225
+ expect(subject.generate_temp_cookbook(%w{user jimbo}, reporter))
226
+ .to eq temp_cookbook
227
+ end
228
+ end
229
+ end
230
+ end
231
+
232
+ describe "#generate_local_policy" do
233
+ let(:reporter) { double("reporter") }
234
+ let(:action) { double("GenerateLocalPolicy") }
235
+ let(:temp_cookbook) { instance_double("TempCookbook") }
236
+ let(:archive_file_location) { "/temp/archive.gz" }
237
+
238
+ before do
239
+ allow(subject).to receive(:temp_cookbook).and_return temp_cookbook
240
+ allow(action).to receive(:archive_file_location).and_return archive_file_location
241
+ end
242
+ it "creates a GenerateLocalPolicy action and executes it" do
243
+ expect(ChefApply::Action::GenerateLocalPolicy).to receive(:new)
244
+ .with(cookbook: temp_cookbook)
245
+ .and_return(action)
246
+ expect(action).to receive(:run)
247
+ subject.generate_local_policy(reporter)
248
+ end
249
+
250
+ context "when generator posts an event:" do
251
+ before do
252
+ expect(ChefApply::Action::GenerateLocalPolicy).to receive(:new)
253
+ .with(cookbook: temp_cookbook)
254
+ .and_return(action)
255
+ allow(action).to receive(:run) { |&block| block.call(event, event_args) }
256
+ end
257
+
258
+ context ":generating" do
259
+ let(:event) { :generating }
260
+ let(:event_args) { nil }
261
+ let(:expected_msg) { ChefApply::CLI::TS.generate_local_policy.generating }
262
+ it "updates message text correctly via reporter" do
263
+ expect(reporter).to receive(:update).with(expected_msg)
264
+ subject.generate_local_policy(reporter)
265
+ end
266
+
267
+ end
268
+
269
+ context ":exporting" do
270
+ let(:event) { :exporting }
271
+ let(:event_args) { nil }
272
+ let(:expected_msg) { ChefApply::CLI::TS.generate_local_policy.exporting }
273
+ it "updates message text correctly via reporter" do
274
+ expect(reporter).to receive(:update).with(expected_msg)
275
+ subject.generate_local_policy(reporter)
276
+ end
277
+ end
278
+
279
+ context ":success" do
280
+ let(:event) { :success }
281
+ let(:expected_msg) { ChefApply::CLI::TS.generate_local_policy.success }
282
+ let(:event_args) { [archive_file_location] }
283
+ it "indicates success via reporter and returns the archive file location" do
284
+ expect(reporter).to receive(:success).with(expected_msg)
285
+ expect(subject.generate_local_policy(reporter)).to eq archive_file_location
286
+ end
287
+ end
288
+ end
289
+ end
290
+
291
+ describe "#render_cookbook_setup" do
292
+ let(:reporter) { instance_double(ChefApply::StatusReporter) }
293
+ let(:temp_cookbook) { double(ChefApply::TempCookbook) }
294
+ let(:archive_file_location) { "/path/to/archive" }
295
+ let(:args) { [] }
296
+ before do
297
+ allow(ChefApply::UI::Terminal).to receive(:render_job).and_yield(reporter)
298
+ end
299
+
300
+ it "generates the cookbook and local policy" do
301
+ expect(subject).to receive(:generate_temp_cookbook)
302
+ .with(args, reporter).and_return temp_cookbook
303
+ expect(subject).to receive(:generate_local_policy)
304
+ .with(reporter).and_return archive_file_location
305
+ subject.render_cookbook_setup(args)
306
+ end
307
+ end
308
+
309
+ describe "#render_converge" do
310
+
311
+ let(:reporter) { instance_double(ChefApply::StatusReporter) }
312
+ let(:host1) { ChefApply::TargetHost.new("ssh://host1") }
313
+ let(:host2) { ChefApply::TargetHost.new("ssh://host2") }
314
+ let(:cookbook_type) { :resource } # || :recipe
315
+ let(:temp_cookbook) do
316
+ instance_double(ChefApply::TempCookbook,
317
+ descriptor: "resource[name]",
318
+ from: "resource") end
319
+ let(:archive_file_location) { "/path/to/archive" }
320
+
321
+ before do
322
+ allow(subject).to receive(:temp_cookbook).and_return temp_cookbook
323
+ allow(subject).to receive(:archive_file_location).and_return archive_file_location
324
+ expected_header = ChefApply::CLI::TS.converge.header(2, temp_cookbook.descriptor, temp_cookbook.from)
325
+ allow(ChefApply::UI::Terminal).to receive(:render_parallel_jobs) do |header, jobs|
326
+ expect(header).to eq expected_header
327
+ jobs.each { |j| j.run(reporter) }
328
+ end
329
+ end
330
+
331
+ let(:target_hosts) { [host1, host2] }
332
+ it "connects, installs chef, and converges for each target" do
333
+ target_hosts.each do |host|
334
+ expect(subject).to receive(:connect_target).with(host, reporter)
335
+ expect(subject).to receive(:install).with(host, reporter)
336
+ expect(subject).to receive(:converge).with(reporter, archive_file_location, host)
337
+ end
338
+ subject.render_converge(target_hosts)
339
+ end
340
+ end
341
+
342
+ describe "#install" do
343
+ let(:upgrading) { false }
344
+ let(:target_host) { double("targethost", installed_chef_version: "14.0") }
345
+ let(:reporter) { double("reporter") }
346
+ let(:action) do
347
+ double("ChefApply::Actions::InstallChef",
348
+ upgrading?: upgrading,
349
+ version_to_install: "14.0") end
350
+
351
+ it "updates status, gets an InstallChef via instance_for_target and executes it" do
352
+ expect(reporter)
353
+ .to receive(:update)
354
+ .with(ChefApply::CLI::TS.install_chef.verifying)
355
+ expect(ChefApply::Action::InstallChef).to receive(:instance_for_target)
356
+ .with(target_host, check_only: false)
357
+ .and_return action
358
+ expect(action).to receive(:run)
359
+ subject.install(target_host, reporter)
360
+ end
361
+
362
+ context "when generator posts event:" do
363
+ let(:event_args) { nil }
364
+ let(:text_context) { ChefApply::Text.status.install_chef }
365
+
366
+ before do
367
+ allow(ChefApply::Action::InstallChef)
368
+ .to receive(:instance_for_target).and_return action
369
+ allow(action)
370
+ .to receive(:run) { |&block| block.call(event, event_args) }
371
+ allow(reporter)
372
+ .to receive(:update).with(ChefApply::CLI::TS.install_chef.verifying)
373
+ end
374
+
375
+ context ":installing" do
376
+ let(:event) { :installing }
377
+
378
+ context "when installer is upgrading" do
379
+ let(:upgrading) { true }
380
+ it "reports the update correctly" do
381
+ expect(reporter).to receive(:update).with(text_context.upgrading(target_host.installed_chef_version, action.version_to_install))
382
+ subject.install(target_host, reporter)
383
+ end
384
+ end
385
+
386
+ context "when installer is installing clean" do
387
+ let(:upgrading) { false }
388
+ it "reports the update correctly" do
389
+ expect(reporter).to receive(:update).with(text_context.installing(action.version_to_install))
390
+ subject.install(target_host, reporter)
391
+ end
392
+ end
393
+ end
394
+
395
+ context ":uploading" do
396
+ let(:event) { :uploading }
397
+ it "reports the update correctly" do
398
+ expect(reporter).to receive(:update).with(text_context.uploading)
399
+ subject.install(target_host, reporter)
400
+ end
401
+ end
402
+
403
+ context ":downloading" do
404
+ let(:event) { :downloading }
405
+ it "reports the update correctly" do
406
+ expect(reporter).to receive(:update).with(text_context.downloading)
407
+ subject.install(target_host, reporter)
408
+ end
409
+ end
410
+
411
+ context ":already_installed" do
412
+ let(:event) { :already_installed }
413
+ it "reports the update correctly" do
414
+ expect(reporter).to receive(:update).with(text_context.already_present(target_host.installed_chef_version))
415
+ subject.install(target_host, reporter)
416
+ end
417
+ end
418
+
419
+ context ":install_complete" do
420
+ let(:event) { :install_complete }
421
+ context "when installer is upgrading" do
422
+ let(:upgrading) { true }
423
+ it "reports the update correctly" do
424
+ expect(reporter).to receive(:update).with(text_context.upgrade_success(target_host.installed_chef_version,
425
+ action.version_to_install))
426
+ subject.install(target_host, reporter)
427
+ end
428
+ end
429
+
430
+ context "when installer installing clean" do
431
+ let(:upgrading) { false }
432
+ it "reports the update correctly" do
433
+ expect(reporter).to receive(:update).with(text_context.install_success(target_host.installed_chef_version))
434
+ subject.install(target_host, reporter)
435
+ end
436
+ end
437
+ end
438
+ end
439
+ end
440
+ end