chef-dk 0.2.1 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CONTRIBUTING.md +2 -2
- data/README.md +25 -0
- data/lib/chef-dk/builtin_commands.rb +4 -0
- data/lib/chef-dk/cli.rb +46 -0
- data/lib/chef-dk/command/base.rb +4 -0
- data/lib/chef-dk/command/generator_commands/template.rb +2 -1
- data/lib/chef-dk/command/install.rb +105 -0
- data/lib/chef-dk/command/push.rb +123 -0
- data/lib/chef-dk/cookbook_profiler/identifiers.rb +5 -0
- data/lib/chef-dk/exceptions.rb +38 -0
- data/lib/chef-dk/generator.rb +16 -1
- data/lib/chef-dk/helpers.rb +1 -1
- data/lib/chef-dk/policyfile/cookbook_location_specification.rb +4 -0
- data/lib/chef-dk/policyfile/cookbook_locks.rb +73 -0
- data/lib/chef-dk/policyfile/reports/install.rb +70 -0
- data/lib/chef-dk/policyfile/reports/table_printer.rb +58 -0
- data/lib/chef-dk/policyfile/reports/upload.rb +70 -0
- data/lib/chef-dk/policyfile/solution_dependencies.rb +102 -8
- data/lib/chef-dk/policyfile/uploader.rb +37 -6
- data/lib/chef-dk/policyfile_compiler.rb +19 -5
- data/lib/chef-dk/policyfile_lock.rb +122 -9
- data/lib/chef-dk/policyfile_services/install.rb +131 -0
- data/lib/chef-dk/policyfile_services/push.rb +121 -0
- data/lib/chef-dk/skeletons/code_generator/recipes/cookbook.rb +6 -4
- data/lib/chef-dk/ui.rb +50 -0
- data/lib/chef-dk/version.rb +1 -1
- data/spec/shared/a_file_generator.rb +4 -1
- data/spec/test_helpers.rb +21 -0
- data/spec/unit/cli_spec.rb +100 -1
- data/spec/unit/command/base_spec.rb +23 -0
- data/spec/unit/command/exec_spec.rb +2 -2
- data/spec/unit/command/install_spec.rb +159 -0
- data/spec/unit/command/push_spec.rb +203 -0
- data/spec/unit/command/shell_init_spec.rb +1 -1
- data/spec/unit/policyfile/cookbook_location_specification_spec.rb +7 -0
- data/spec/unit/policyfile/cookbook_locks_spec.rb +13 -2
- data/spec/unit/policyfile/reports/install_spec.rb +115 -0
- data/spec/unit/policyfile/reports/upload_spec.rb +96 -0
- data/spec/unit/policyfile/solution_dependencies_spec.rb +1 -1
- data/spec/unit/policyfile/uploader_spec.rb +9 -12
- data/spec/unit/policyfile_lock_serialization_spec.rb +292 -0
- data/spec/unit/policyfile_services/install_spec.rb +170 -0
- data/spec/unit/policyfile_services/push_spec.rb +202 -0
- metadata +48 -6
@@ -0,0 +1,121 @@
|
|
1
|
+
#
|
2
|
+
# Copyright:: Copyright (c) 2014 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 'chef-dk/authenticated_http'
|
19
|
+
require 'chef-dk/policyfile_compiler'
|
20
|
+
require 'chef-dk/policyfile/uploader'
|
21
|
+
|
22
|
+
module ChefDK
|
23
|
+
module PolicyfileServices
|
24
|
+
class Push
|
25
|
+
|
26
|
+
attr_reader :root_dir
|
27
|
+
attr_reader :config
|
28
|
+
attr_reader :policy_group
|
29
|
+
attr_reader :ui
|
30
|
+
|
31
|
+
def initialize(policyfile: nil, ui: nil, policy_group: nil, config: nil, root_dir: nil)
|
32
|
+
@root_dir = root_dir
|
33
|
+
@policyfile_relative_path = policyfile
|
34
|
+
@ui = ui
|
35
|
+
@config = config
|
36
|
+
@policy_group = policy_group
|
37
|
+
|
38
|
+
@http_client = nil
|
39
|
+
@storage_config = nil
|
40
|
+
@policy_data = nil
|
41
|
+
end
|
42
|
+
|
43
|
+
def policyfile_relative_path
|
44
|
+
@policyfile_relative_path || "Policyfile.rb"
|
45
|
+
end
|
46
|
+
|
47
|
+
def policyfile_path
|
48
|
+
File.expand_path(policyfile_relative_path, root_dir)
|
49
|
+
end
|
50
|
+
|
51
|
+
def lockfile_relative_path
|
52
|
+
policyfile_relative_path.gsub(/\.rb\Z/, '') + ".lock.json"
|
53
|
+
end
|
54
|
+
|
55
|
+
def lockfile_path
|
56
|
+
File.expand_path(lockfile_relative_path, root_dir)
|
57
|
+
end
|
58
|
+
|
59
|
+
def http_client
|
60
|
+
@http_client ||= ChefDK::AuthenticatedHTTP.new(config.chef_server_url,
|
61
|
+
signing_key_filename: config.client_key,
|
62
|
+
client_name: config.node_name)
|
63
|
+
end
|
64
|
+
|
65
|
+
def policy_data
|
66
|
+
@policy_data ||= FFI_Yajl::Parser.parse(IO.read(lockfile_path))
|
67
|
+
rescue => error
|
68
|
+
raise PolicyfilePushError.new("Error reading lockfile #{lockfile_path}", error)
|
69
|
+
end
|
70
|
+
|
71
|
+
def storage_config
|
72
|
+
@storage_config ||= ChefDK::Policyfile::StorageConfig.new.use_policyfile_lock(lockfile_path)
|
73
|
+
end
|
74
|
+
|
75
|
+
def uploader
|
76
|
+
ChefDK::Policyfile::Uploader.new(policyfile_lock, policy_group, ui: ui, http_client: http_client)
|
77
|
+
end
|
78
|
+
|
79
|
+
def run
|
80
|
+
unless File.exist?(lockfile_path)
|
81
|
+
raise LockfileNotFound, "No lockfile at #{lockfile_path} - you need to run `install` before `push`"
|
82
|
+
end
|
83
|
+
|
84
|
+
validate_lockfile
|
85
|
+
write_updated_lockfile
|
86
|
+
upload_policy
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
def policyfile_lock
|
91
|
+
@policyfile_lock || validate_lockfile
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
def upload_policy
|
97
|
+
uploader.upload
|
98
|
+
rescue => error
|
99
|
+
raise PolicyfilePushError.new("Failed to upload policy to policy group #{policy_group}", error)
|
100
|
+
end
|
101
|
+
|
102
|
+
def write_updated_lockfile
|
103
|
+
File.open(lockfile_path, "w+") do |f|
|
104
|
+
f.print(FFI_Yajl::Encoder.encode(policyfile_lock.to_lock, pretty: true ))
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def validate_lockfile
|
109
|
+
return @policyfile_lock if @policyfile_lock
|
110
|
+
@policyfile_lock = ChefDK::PolicyfileLock.new(storage_config).build_from_lock_data(policy_data)
|
111
|
+
# TODO: enumerate any cookbook that have been updated
|
112
|
+
@policyfile_lock.validate_cookbooks!
|
113
|
+
@policyfile_lock
|
114
|
+
rescue => error
|
115
|
+
raise PolicyfilePushError.new("Invalid lockfile data", error)
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
@@ -43,11 +43,13 @@ template "#{cookbook_dir}/recipes/default.rb" do
|
|
43
43
|
end
|
44
44
|
|
45
45
|
# git
|
46
|
-
if context.have_git
|
46
|
+
if context.have_git
|
47
|
+
if !context.skip_git_init
|
47
48
|
|
48
|
-
|
49
|
-
|
50
|
-
|
49
|
+
execute("initialize-git") do
|
50
|
+
command("git init .")
|
51
|
+
cwd cookbook_dir
|
52
|
+
end
|
51
53
|
end
|
52
54
|
|
53
55
|
cookbook_file "#{cookbook_dir}/.gitignore" do
|
data/lib/chef-dk/ui.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
#
|
2
|
+
# Copyright:: Copyright (c) 2014 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
|
+
module ChefDK
|
19
|
+
class UI
|
20
|
+
|
21
|
+
class NullStream
|
22
|
+
|
23
|
+
def puts(*anything)
|
24
|
+
nil
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.null
|
30
|
+
new(out: NullStream.new, err: NullStream.new)
|
31
|
+
end
|
32
|
+
|
33
|
+
attr_reader :out_stream
|
34
|
+
attr_reader :err_stream
|
35
|
+
|
36
|
+
def initialize(out: nil, err: nil)
|
37
|
+
@out_stream = out || $stdout
|
38
|
+
@err_stream = err || $stderr
|
39
|
+
end
|
40
|
+
|
41
|
+
def err(message)
|
42
|
+
@err_stream.puts(message)
|
43
|
+
end
|
44
|
+
|
45
|
+
def msg(message)
|
46
|
+
@out_stream.puts(message)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
data/lib/chef-dk/version.rb
CHANGED
@@ -32,6 +32,10 @@ shared_examples_for "a file generator" do
|
|
32
32
|
reset_tempdir
|
33
33
|
end
|
34
34
|
|
35
|
+
after(:each) do
|
36
|
+
ChefDK::Generator::Context.reset
|
37
|
+
end
|
38
|
+
|
35
39
|
context "when argv is empty" do
|
36
40
|
let(:argv) { [] }
|
37
41
|
|
@@ -118,4 +122,3 @@ shared_examples_for "a file generator" do
|
|
118
122
|
end
|
119
123
|
|
120
124
|
end
|
121
|
-
|
data/spec/test_helpers.rb
CHANGED
@@ -56,4 +56,25 @@ module TestHelpers
|
|
56
56
|
@tmpdir ||= Dir.mktmpdir("chef-dk")
|
57
57
|
File.realpath(@tmpdir)
|
58
58
|
end
|
59
|
+
|
60
|
+
class TestUI
|
61
|
+
|
62
|
+
attr_reader :output_stream
|
63
|
+
|
64
|
+
def initialize
|
65
|
+
@output_stream = StringIO.new
|
66
|
+
end
|
67
|
+
|
68
|
+
def err(message)
|
69
|
+
@output_stream.puts(message)
|
70
|
+
end
|
71
|
+
|
72
|
+
def msg(message)
|
73
|
+
@output_stream.puts(message)
|
74
|
+
end
|
75
|
+
|
76
|
+
def output
|
77
|
+
@output_stream.string
|
78
|
+
end
|
79
|
+
end
|
59
80
|
end
|
data/spec/unit/cli_spec.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
#
|
2
1
|
# Copyright:: Copyright (c) 2014 Chef Software Inc.
|
3
2
|
# License:: Apache License, Version 2.0
|
4
3
|
#
|
@@ -58,6 +57,12 @@ E
|
|
58
57
|
let(:version_message) { "Chef Development Kit Version: #{ChefDK::VERSION}\n" }
|
59
58
|
|
60
59
|
def run_cli(expected_exit_code)
|
60
|
+
expect(cli).to receive(:exit).with(expected_exit_code)
|
61
|
+
expect(cli).to receive(:sanity_check!)
|
62
|
+
cli.run
|
63
|
+
end
|
64
|
+
|
65
|
+
def run_cli_with_sanity_check(expected_exit_code)
|
61
66
|
expect(cli).to receive(:exit).with(expected_exit_code)
|
62
67
|
cli.run
|
63
68
|
end
|
@@ -107,6 +112,18 @@ E
|
|
107
112
|
end
|
108
113
|
end
|
109
114
|
|
115
|
+
context "given an invalid option" do
|
116
|
+
|
117
|
+
let(:argv) { %w[-nope] }
|
118
|
+
|
119
|
+
it "prints an 'invalid option message and the help output, then exits non-zero" do
|
120
|
+
run_cli(1)
|
121
|
+
expect(stdout).to eq(base_help_message)
|
122
|
+
expect(stderr).to eq("invalid option: -nope\n")
|
123
|
+
end
|
124
|
+
|
125
|
+
end
|
126
|
+
|
110
127
|
context "given an invalid/unknown subcommand" do
|
111
128
|
let(:argv) { %w[ancient-aliens] }
|
112
129
|
|
@@ -148,4 +165,86 @@ E
|
|
148
165
|
end
|
149
166
|
end
|
150
167
|
|
168
|
+
context "sanity_check!" do
|
169
|
+
context "on unix" do
|
170
|
+
it "complains if embedded is first" do
|
171
|
+
expect(cli).to receive(:env).and_return({'PATH' => '/opt/chefdk/embedded/bin:/opt/chefdk/bin' })
|
172
|
+
allow(cli).to receive(:omnibus_embedded_bin_dir).and_return("/opt/chefdk/embedded/bin")
|
173
|
+
allow(cli).to receive(:omnibus_bin_dir).and_return("/opt/chefdk/bin")
|
174
|
+
run_cli_with_sanity_check(0)
|
175
|
+
expect(stdout).not_to eq(base_help_message)
|
176
|
+
expect(stdout).to include("please reverse that order")
|
177
|
+
expect(stdout).to include("chef shell-init")
|
178
|
+
end
|
179
|
+
|
180
|
+
it "complains if only embedded is present" do
|
181
|
+
expect(cli).to receive(:env).and_return({'PATH' => '/opt/chefdk/embedded/bin' })
|
182
|
+
allow(cli).to receive(:omnibus_embedded_bin_dir).and_return("/opt/chefdk/embedded/bin")
|
183
|
+
allow(cli).to receive(:omnibus_bin_dir).and_return("/opt/chefdk/bin")
|
184
|
+
run_cli_with_sanity_check(0)
|
185
|
+
expect(stdout).not_to eq(base_help_message)
|
186
|
+
expect(stdout).to include("you must add")
|
187
|
+
expect(stdout).to include("chef shell-init")
|
188
|
+
end
|
189
|
+
|
190
|
+
it "passes when both are present in the correct order" do
|
191
|
+
expect(cli).to receive(:env).and_return({'PATH' => '/opt/chefdk/bin:/opt/chefdk/embedded/bin' })
|
192
|
+
allow(cli).to receive(:omnibus_embedded_bin_dir).and_return("/opt/chefdk/embedded/bin")
|
193
|
+
allow(cli).to receive(:omnibus_bin_dir).and_return("/opt/chefdk/bin")
|
194
|
+
run_cli_with_sanity_check(0)
|
195
|
+
expect(stdout).to eq(base_help_message)
|
196
|
+
end
|
197
|
+
|
198
|
+
it "passes when only the omnibus bin dir is present" do
|
199
|
+
expect(cli).to receive(:env).and_return({'PATH' => '/opt/chefdk/bin' })
|
200
|
+
allow(cli).to receive(:omnibus_embedded_bin_dir).and_return("/opt/chefdk/embedded/bin")
|
201
|
+
allow(cli).to receive(:omnibus_bin_dir).and_return("/opt/chefdk/bin")
|
202
|
+
run_cli_with_sanity_check(0)
|
203
|
+
expect(stdout).to eq(base_help_message)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
context "on windows" do
|
208
|
+
before do
|
209
|
+
allow(Chef::Platform).to receive(:windows?).and_return(true)
|
210
|
+
stub_const("File::PATH_SEPARATOR", ';')
|
211
|
+
end
|
212
|
+
|
213
|
+
it "complains if embedded is first" do
|
214
|
+
expect(cli).to receive(:env).and_return({'PATH' => 'C:\opscode\chefdk\embedded\bin;C:\opscode\chefdk\bin' })
|
215
|
+
allow(cli).to receive(:omnibus_embedded_bin_dir).and_return("c:/opscode/chefdk/embedded/bin")
|
216
|
+
allow(cli).to receive(:omnibus_bin_dir).and_return("c:/opscode/chefdk/bin")
|
217
|
+
run_cli_with_sanity_check(0)
|
218
|
+
expect(stdout).not_to eq(base_help_message)
|
219
|
+
expect(stdout).to include("please reverse that order")
|
220
|
+
expect(stdout).to include("chef shell-init")
|
221
|
+
end
|
222
|
+
|
223
|
+
it "complains if only embedded is present" do
|
224
|
+
expect(cli).to receive(:env).and_return({'PATH' => 'C:\opscode\chefdk\embedded\bin' })
|
225
|
+
allow(cli).to receive(:omnibus_embedded_bin_dir).and_return("c:/opscode/chefdk/embedded/bin")
|
226
|
+
allow(cli).to receive(:omnibus_bin_dir).and_return("c:/opscode/chefdk/bin")
|
227
|
+
run_cli_with_sanity_check(0)
|
228
|
+
expect(stdout).not_to eq(base_help_message)
|
229
|
+
expect(stdout).to include("you must add")
|
230
|
+
expect(stdout).to include("chef shell-init")
|
231
|
+
end
|
232
|
+
|
233
|
+
it "passes when both are present in the correct order" do
|
234
|
+
expect(cli).to receive(:env).and_return({'PATH' => 'C:\opscode\chefdk\bin;C:\opscode\chefdk\embedded\bin' })
|
235
|
+
allow(cli).to receive(:omnibus_embedded_bin_dir).and_return("c:/opscode/chefdk/embedded/bin")
|
236
|
+
allow(cli).to receive(:omnibus_bin_dir).and_return("c:/opscode/chefdk/bin")
|
237
|
+
run_cli_with_sanity_check(0)
|
238
|
+
expect(stdout).to eq(base_help_message)
|
239
|
+
end
|
240
|
+
|
241
|
+
it "passes when only the omnibus bin dir is present" do
|
242
|
+
expect(cli).to receive(:env).and_return({'PATH' => 'C:\opscode\chefdk\bin' })
|
243
|
+
allow(cli).to receive(:omnibus_embedded_bin_dir).and_return("c:/opscode/chefdk/embedded/bin")
|
244
|
+
allow(cli).to receive(:omnibus_bin_dir).and_return("c:/opscode/chefdk/bin")
|
245
|
+
run_cli_with_sanity_check(0)
|
246
|
+
expect(stdout).to eq(base_help_message)
|
247
|
+
end
|
248
|
+
end
|
249
|
+
end
|
151
250
|
end
|
@@ -34,6 +34,7 @@ describe ChefDK::Command::Base do
|
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
37
|
+
let(:stderr_io) { StringIO.new }
|
37
38
|
let(:stdout_io) { StringIO.new }
|
38
39
|
let(:command_instance) { TestCommand.new() }
|
39
40
|
|
@@ -41,8 +42,13 @@ describe ChefDK::Command::Base do
|
|
41
42
|
stdout_io.string
|
42
43
|
end
|
43
44
|
|
45
|
+
def stderr
|
46
|
+
stderr_io.string
|
47
|
+
end
|
48
|
+
|
44
49
|
before do
|
45
50
|
allow(command_instance).to receive(:stdout).and_return(stdout_io)
|
51
|
+
allow(command_instance).to receive(:stderr).and_return(stderr_io)
|
46
52
|
end
|
47
53
|
|
48
54
|
|
@@ -85,4 +91,21 @@ describe ChefDK::Command::Base do
|
|
85
91
|
expect(stdout).to eq("thanks for passing me true\n")
|
86
92
|
end
|
87
93
|
|
94
|
+
describe "when given invalid options" do
|
95
|
+
|
96
|
+
it "prints the help banner and exits gracefully" do
|
97
|
+
expect(run_command(%w[-foo])).to eq(1)
|
98
|
+
|
99
|
+
expect(stderr).to eq("invalid option: -foo\n")
|
100
|
+
|
101
|
+
expected = <<-E
|
102
|
+
use me please
|
103
|
+
-u, --user If the user exists
|
104
|
+
|
105
|
+
E
|
106
|
+
expect(stdout).to eq(expected)
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
|
88
111
|
end
|
@@ -73,7 +73,7 @@ describe ChefDK::Command::Exec do
|
|
73
73
|
|
74
74
|
let(:expected_GEM_ROOT) { Gem.default_dir.inspect }
|
75
75
|
|
76
|
-
let(:expected_GEM_HOME) {
|
76
|
+
let(:expected_GEM_HOME) { Gem.user_dir }
|
77
77
|
|
78
78
|
let(:expected_GEM_PATH) { Gem.path.join(':') }
|
79
79
|
|
@@ -107,7 +107,7 @@ describe ChefDK::Command::Exec do
|
|
107
107
|
|
108
108
|
let(:expected_GEM_ROOT) { Gem.default_dir.inspect }
|
109
109
|
|
110
|
-
let(:expected_GEM_HOME) {
|
110
|
+
let(:expected_GEM_HOME) { Gem.user_dir }
|
111
111
|
|
112
112
|
let(:expected_GEM_PATH) { Gem.path.join(':') }
|
113
113
|
|
@@ -0,0 +1,159 @@
|
|
1
|
+
#
|
2
|
+
# Copyright:: Copyright (c) 2014 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-dk/command/install'
|
20
|
+
|
21
|
+
describe ChefDK::Command::Install do
|
22
|
+
|
23
|
+
let(:params) { [] }
|
24
|
+
|
25
|
+
let(:command) do
|
26
|
+
c = described_class.new
|
27
|
+
c.apply_params!(params)
|
28
|
+
c
|
29
|
+
end
|
30
|
+
|
31
|
+
let(:install_service) { instance_double(ChefDK::PolicyfileServices::Install) }
|
32
|
+
|
33
|
+
it "disables debug by default" do
|
34
|
+
expect(command.debug?).to be(false)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "configures a default UI component" do
|
38
|
+
ui = command.ui
|
39
|
+
expect(ui.out_stream).to eq($stdout)
|
40
|
+
expect(ui.err_stream).to eq($stderr)
|
41
|
+
end
|
42
|
+
|
43
|
+
context "when debug mode is set" do
|
44
|
+
|
45
|
+
let(:params) { [ "-D" ] }
|
46
|
+
|
47
|
+
it "enables debug" do
|
48
|
+
expect(command.debug?).to be(true)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context "with no arguments" do
|
53
|
+
|
54
|
+
it "does not specify a policyfile relative path" do
|
55
|
+
expect(command.policyfile_relative_path).to be(nil)
|
56
|
+
end
|
57
|
+
|
58
|
+
it "creates the installer service with a `nil` policyfile path" do
|
59
|
+
expect(ChefDK::PolicyfileServices::Install).to receive(:new).
|
60
|
+
with(policyfile: nil, ui: command.ui, root_dir: Dir.pwd).
|
61
|
+
and_return(install_service)
|
62
|
+
expect(command.installer).to eq(install_service)
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
context "with an explicit policyfile relative path" do
|
68
|
+
|
69
|
+
let(:params) { [ "MyPolicy.rb" ] }
|
70
|
+
|
71
|
+
it "respects the user-supplied path" do
|
72
|
+
expect(command.policyfile_relative_path).to eq("MyPolicy.rb")
|
73
|
+
end
|
74
|
+
|
75
|
+
it "creates the installer service with the specified policyfile path" do
|
76
|
+
expect(ChefDK::PolicyfileServices::Install).to receive(:new).
|
77
|
+
with(policyfile: "MyPolicy.rb", ui: command.ui, root_dir: Dir.pwd).
|
78
|
+
and_return(install_service)
|
79
|
+
expect(command.installer).to eq(install_service)
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
describe "running the install" do
|
85
|
+
|
86
|
+
let(:ui) { TestHelpers::TestUI.new }
|
87
|
+
|
88
|
+
before do
|
89
|
+
command.ui = ui
|
90
|
+
allow(command).to receive(:installer).and_return(install_service)
|
91
|
+
end
|
92
|
+
|
93
|
+
context "when the command is successful" do
|
94
|
+
before do
|
95
|
+
expect(install_service).to receive(:run)
|
96
|
+
end
|
97
|
+
|
98
|
+
it "returns 0" do
|
99
|
+
expect(command.run).to eq(0)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
context "when the command is unsuccessful" do
|
104
|
+
|
105
|
+
let(:backtrace) { caller[0...3] }
|
106
|
+
|
107
|
+
let(:cause) do
|
108
|
+
e = StandardError.new("some operation failed")
|
109
|
+
e.set_backtrace(backtrace)
|
110
|
+
e
|
111
|
+
end
|
112
|
+
|
113
|
+
let(:exception) do
|
114
|
+
ChefDK::PolicyfileInstallError.new("install failed", cause)
|
115
|
+
end
|
116
|
+
|
117
|
+
before do
|
118
|
+
expect(install_service).to receive(:run).and_raise(exception)
|
119
|
+
end
|
120
|
+
|
121
|
+
it "returns 1" do
|
122
|
+
expect(command.run).to eq(1)
|
123
|
+
end
|
124
|
+
|
125
|
+
it "displays the exception and cause" do
|
126
|
+
expected_error_text=<<-E
|
127
|
+
Error: install failed
|
128
|
+
Reason: StandardError
|
129
|
+
|
130
|
+
some operation failed
|
131
|
+
E
|
132
|
+
|
133
|
+
command.run
|
134
|
+
expect(ui.output).to eq(expected_error_text)
|
135
|
+
end
|
136
|
+
|
137
|
+
context "and debug is enabled" do
|
138
|
+
|
139
|
+
let(:params) { ["-D"] }
|
140
|
+
|
141
|
+
it "displays the exception and cause with backtrace" do
|
142
|
+
expected_error_text=<<-E
|
143
|
+
Error: install failed
|
144
|
+
Reason: StandardError
|
145
|
+
|
146
|
+
some operation failed
|
147
|
+
E
|
148
|
+
|
149
|
+
expected_error_text << backtrace.join("\n") << "\n"
|
150
|
+
|
151
|
+
command.run
|
152
|
+
expect(ui.output).to eq(expected_error_text)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
end
|
157
|
+
|
158
|
+
end
|
159
|
+
end
|