chef-apply 0.1.17 → 0.1.18
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +0 -7
- data/Gemfile.lock +176 -84
- data/chef-apply.gemspec +2 -2
- data/lib/chef_apply/version.rb +1 -1
- data/spec/fixtures/custom_config.toml +2 -0
- data/spec/integration/chef-run_spec.rb +41 -0
- data/spec/integration/fixtures/chef_help.out +69 -0
- data/spec/integration/fixtures/chef_version.out +1 -0
- data/spec/integration/spec_helper.rb +55 -0
- data/spec/spec_helper.rb +114 -0
- data/spec/support/matchers/output_to_terminal.rb +36 -0
- data/spec/unit/action/base_spec.rb +89 -0
- data/spec/unit/action/converge_target_spec.rb +292 -0
- data/spec/unit/action/generate_local_policy_spec.rb +114 -0
- data/spec/unit/action/generate_temp_cookbook_spec.rb +75 -0
- data/spec/unit/action/install_chef/base_spec.rb +234 -0
- data/spec/unit/action/install_chef_spec.rb +69 -0
- data/spec/unit/cli/options_spec.rb +75 -0
- data/spec/unit/cli/validation_spec.rb +78 -0
- data/spec/unit/cli_spec.rb +440 -0
- data/spec/unit/config_spec.rb +70 -0
- data/spec/unit/errors/ccr_failure_mapper_spec.rb +103 -0
- data/spec/unit/file_fetcher_spec.rb +40 -0
- data/spec/unit/fixtures/multi-error.out +2 -0
- data/spec/unit/log_spec.rb +37 -0
- data/spec/unit/recipe_lookup_spec.rb +122 -0
- data/spec/unit/startup_spec.rb +283 -0
- data/spec/unit/target_host_spec.rb +231 -0
- data/spec/unit/target_resolver_spec.rb +380 -0
- data/spec/unit/telemeter/sender_spec.rb +140 -0
- data/spec/unit/telemeter_spec.rb +191 -0
- data/spec/unit/temp_cookbook_spec.rb +199 -0
- data/spec/unit/ui/error_printer_spec.rb +173 -0
- data/spec/unit/ui/terminal_spec.rb +109 -0
- data/spec/unit/version_spec.rb +31 -0
- data/warning.txt +3 -0
- 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
|