chef-dk 0.2.1 → 0.3.0
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/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
|