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.
- 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
|