chef 12.0.1 → 12.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/chef/chef_fs/file_system/chef_repository_file_system_entry.rb +1 -1
- data/lib/chef/digester.rb +1 -0
- data/lib/chef/dsl/recipe.rb +2 -1
- data/lib/chef/exceptions.rb +5 -0
- data/lib/chef/knife.rb +7 -0
- data/lib/chef/knife/cookbook_site_install.rb +34 -10
- data/lib/chef/provider/link.rb +1 -1
- data/lib/chef/provider/package/apt.rb +2 -2
- data/lib/chef/provider/package/homebrew.rb +11 -2
- data/lib/chef/provider/package/windows/msi.rb +2 -0
- data/lib/chef/provider/subversion.rb +3 -3
- data/lib/chef/resource.rb +23 -91
- data/lib/chef/resource/homebrew_package.rb +2 -1
- data/lib/chef/resource/resource_notification.rb +109 -0
- data/lib/chef/resource_collection/resource_set.rb +8 -8
- data/lib/chef/run_context.rb +4 -4
- data/lib/chef/version.rb +1 -1
- data/lib/chef/whitelist.rb +3 -1
- data/lib/chef/win32/api/file.rb +17 -3
- data/spec/functional/notifications_spec.rb +169 -0
- data/spec/functional/resource/link_spec.rb +31 -32
- data/spec/support/platform_helpers.rb +5 -2
- data/spec/unit/knife/cookbook_site_install_spec.rb +157 -116
- data/spec/unit/knife_spec.rb +108 -78
- data/spec/unit/mixin/shell_out_spec.rb +39 -40
- data/spec/unit/node_spec.rb +34 -0
- data/spec/unit/provider/link_spec.rb +5 -5
- data/spec/unit/provider/package/apt_spec.rb +264 -257
- data/spec/unit/provider/package/homebrew_spec.rb +26 -0
- data/spec/unit/provider/package/windows/msi_spec.rb +18 -3
- data/spec/unit/provider/subversion_spec.rb +5 -5
- data/spec/unit/provider_resolver_spec.rb +2 -2
- data/spec/unit/recipe_spec.rb +1 -0
- data/spec/unit/resource/apt_package_spec.rb +3 -5
- data/spec/unit/resource/resource_notification_spec.rb +170 -0
- data/spec/unit/resource_spec.rb +0 -151
- data/spec/unit/run_context_spec.rb +94 -55
- metadata +5 -2
@@ -1,7 +1,10 @@
|
|
1
1
|
require 'fcntl'
|
2
2
|
require 'chef/mixin/shell_out'
|
3
3
|
|
4
|
-
|
4
|
+
|
5
|
+
class ShellHelpers
|
6
|
+
extend Chef::Mixin::ShellOut
|
7
|
+
end
|
5
8
|
|
6
9
|
def ruby_gte_20?
|
7
10
|
RUBY_VERSION.to_f >= 2.0
|
@@ -78,7 +81,7 @@ end
|
|
78
81
|
|
79
82
|
def mac_osx_106?
|
80
83
|
if File.exists? "/usr/bin/sw_vers"
|
81
|
-
result = shell_out("/usr/bin/sw_vers")
|
84
|
+
result = ShellHelpers.shell_out("/usr/bin/sw_vers")
|
82
85
|
result.stdout.each_line do |line|
|
83
86
|
if line =~ /^ProductVersion:\s10.6.*$/
|
84
87
|
return true
|
@@ -19,132 +19,173 @@
|
|
19
19
|
require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "spec_helper"))
|
20
20
|
|
21
21
|
describe Chef::Knife::CookbookSiteInstall do
|
22
|
+
let(:knife) { Chef::Knife::CookbookSiteInstall.new }
|
23
|
+
let(:stdout) { StringIO.new }
|
24
|
+
let(:stderr) { StringIO.new }
|
25
|
+
let(:downloader) { Hash.new }
|
26
|
+
let(:repo) { double(:sanity_check => true, :reset_to_default_state => true,
|
27
|
+
:prepare_to_import => true, :finalize_updates_to => true,
|
28
|
+
:merge_updates_from => true) }
|
29
|
+
let(:install_path) { if Chef::Platform.windows?
|
30
|
+
'C:/tmp/chef'
|
31
|
+
else
|
32
|
+
'/var/tmp/chef'
|
33
|
+
end }
|
34
|
+
|
22
35
|
before(:each) do
|
23
36
|
require 'chef/knife/core/cookbook_scm_repo'
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
File.stub(:rmtree)
|
43
|
-
@knife.stub(:shell_out!).and_return(true)
|
44
|
-
|
45
|
-
#CookbookSiteDownload Stup
|
46
|
-
@downloader = {}
|
47
|
-
@knife.stub(:download_cookbook_to).and_return(@downloader)
|
48
|
-
@downloader.stub(:version).and_return do
|
49
|
-
if @knife.name_args.size == 2
|
50
|
-
@knife.name_args[1]
|
37
|
+
|
38
|
+
allow(knife.ui).to receive(:stdout).and_return(stdout)
|
39
|
+
knife.config = {}
|
40
|
+
knife.config[:cookbook_path] = [ install_path ]
|
41
|
+
|
42
|
+
allow(knife).to receive(:stderr).and_return(stderr)
|
43
|
+
allow(knife).to receive(:stdout).and_return(stdout)
|
44
|
+
|
45
|
+
# Assume all external commands would have succeed. :(
|
46
|
+
allow(File).to receive(:unlink)
|
47
|
+
allow(File).to receive(:rmtree)
|
48
|
+
allow(knife).to receive(:shell_out!).and_return(true)
|
49
|
+
|
50
|
+
# CookbookSiteDownload Stup
|
51
|
+
allow(knife).to receive(:download_cookbook_to).and_return(downloader)
|
52
|
+
allow(downloader).to receive(:version) do
|
53
|
+
if knife.name_args.size == 2
|
54
|
+
knife.name_args[1]
|
51
55
|
else
|
52
56
|
"0.3.0"
|
53
57
|
end
|
54
58
|
end
|
55
59
|
|
56
|
-
#Stubs for CookbookSCMRepo
|
57
|
-
|
58
|
-
:prepare_to_import => true, :finalize_updates_to => true,
|
59
|
-
:merge_updates_from => true)
|
60
|
-
Chef::Knife::CookbookSCMRepo.stub(:new).and_return(@repo)
|
60
|
+
# Stubs for CookbookSCMRepo
|
61
|
+
allow(Chef::Knife::CookbookSCMRepo).to receive(:new).and_return(repo)
|
61
62
|
end
|
62
63
|
|
63
|
-
|
64
64
|
describe "run" do
|
65
|
-
it "
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
end
|
70
|
-
|
71
|
-
it "
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
end
|
76
|
-
|
77
|
-
it "
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
end
|
82
|
-
|
83
|
-
it "
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
end
|
88
|
-
|
89
|
-
it "
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
end
|
94
|
-
|
95
|
-
it "
|
96
|
-
|
97
|
-
|
98
|
-
upstream_file = File.join(
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
end
|
105
|
-
|
106
|
-
it "
|
107
|
-
|
108
|
-
|
109
|
-
upstream_file = File.join(
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
end
|
116
|
-
|
117
|
-
it "
|
118
|
-
|
119
|
-
|
120
|
-
upstream_file = File.join(
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
end
|
127
|
-
|
128
|
-
it "
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
upstream_file = File.join(
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
end
|
137
|
-
|
138
|
-
it "should not raise an error if cookbook_path is a string" do
|
139
|
-
@knife.config[:cookbook_path] = @install_path
|
140
|
-
@knife.config[:no_deps] = true
|
141
|
-
@knife.name_args = ["getting-started"]
|
142
|
-
upstream_file = File.join(@install_path, "getting-started.tar.gz")
|
143
|
-
@knife.should_receive(:download_cookbook_to).with(upstream_file)
|
144
|
-
@knife.should_receive(:extract_cookbook).with(upstream_file, "0.3.0")
|
145
|
-
@knife.should_receive(:clear_existing_files).with(File.join(@install_path, "getting-started"))
|
146
|
-
@repo.should_receive(:merge_updates_from).with("getting-started", "0.3.0")
|
147
|
-
lambda { @knife.run }.should_not raise_error
|
65
|
+
it "raises an error if a cookbook name is not provided" do
|
66
|
+
knife.name_args = []
|
67
|
+
expect(knife.ui).to receive(:error).with("Please specify a cookbook to download and install.")
|
68
|
+
expect { knife.run }.to raise_error(SystemExit)
|
69
|
+
end
|
70
|
+
|
71
|
+
it "raises an error if more than two arguments are given" do
|
72
|
+
knife.name_args = ["foo", "bar", "baz"]
|
73
|
+
expect(knife.ui).to receive(:error).with("Installing multiple cookbooks at once is not supported.")
|
74
|
+
expect { knife.run }.to raise_error(SystemExit)
|
75
|
+
end
|
76
|
+
|
77
|
+
it "raises an error if the second argument is not a version" do
|
78
|
+
knife.name_args = ["getting-started", "1pass"]
|
79
|
+
expect(knife.ui).to receive(:error).with("Installing multiple cookbooks at once is not supported.")
|
80
|
+
expect { knife.run }.to raise_error(SystemExit)
|
81
|
+
end
|
82
|
+
|
83
|
+
it "raises an error if the second argument is a four-digit version" do
|
84
|
+
knife.name_args = ["getting-started", "0.0.0.1"]
|
85
|
+
expect(knife.ui).to receive(:error).with("Installing multiple cookbooks at once is not supported.")
|
86
|
+
expect { knife.run }.to raise_error(SystemExit)
|
87
|
+
end
|
88
|
+
|
89
|
+
it "raises an error if the second argument is a one-digit version" do
|
90
|
+
knife.name_args = ["getting-started", "1"]
|
91
|
+
expect(knife.ui).to receive(:error).with("Installing multiple cookbooks at once is not supported.")
|
92
|
+
expect { knife.run }.to raise_error(SystemExit)
|
93
|
+
end
|
94
|
+
|
95
|
+
it "installs the specified version if second argument is a three-digit version" do
|
96
|
+
knife.name_args = ["getting-started", "0.1.0"]
|
97
|
+
knife.config[:no_deps] = true
|
98
|
+
upstream_file = File.join(install_path, "getting-started.tar.gz")
|
99
|
+
expect(knife).to receive(:download_cookbook_to).with(upstream_file)
|
100
|
+
expect(knife).to receive(:extract_cookbook).with(upstream_file, "0.1.0")
|
101
|
+
expect(knife).to receive(:clear_existing_files).with(File.join(install_path, "getting-started"))
|
102
|
+
expect(repo).to receive(:merge_updates_from).with("getting-started", "0.1.0")
|
103
|
+
knife.run
|
104
|
+
end
|
105
|
+
|
106
|
+
it "installs the specified version if second argument is a two-digit version" do
|
107
|
+
knife.name_args = ["getting-started", "0.1"]
|
108
|
+
knife.config[:no_deps] = true
|
109
|
+
upstream_file = File.join(install_path, "getting-started.tar.gz")
|
110
|
+
expect(knife).to receive(:download_cookbook_to).with(upstream_file)
|
111
|
+
expect(knife).to receive(:extract_cookbook).with(upstream_file, "0.1")
|
112
|
+
expect(knife).to receive(:clear_existing_files).with(File.join(install_path, "getting-started"))
|
113
|
+
expect(repo).to receive(:merge_updates_from).with("getting-started", "0.1")
|
114
|
+
knife.run
|
115
|
+
end
|
116
|
+
|
117
|
+
it "installs the latest version if only a cookbook name is given" do
|
118
|
+
knife.name_args = ["getting-started"]
|
119
|
+
knife.config[:no_deps] = true
|
120
|
+
upstream_file = File.join(install_path, "getting-started.tar.gz")
|
121
|
+
expect(knife).to receive(:download_cookbook_to).with(upstream_file)
|
122
|
+
expect(knife).to receive(:extract_cookbook).with(upstream_file, "0.3.0")
|
123
|
+
expect(knife).to receive(:clear_existing_files).with(File.join(install_path, "getting-started"))
|
124
|
+
expect(repo).to receive(:merge_updates_from).with("getting-started", "0.3.0")
|
125
|
+
knife.run
|
126
|
+
end
|
127
|
+
|
128
|
+
it "does not create/reset git branches if use_current_branch is set" do
|
129
|
+
knife.name_args = ["getting-started"]
|
130
|
+
knife.config[:use_current_branch] = true
|
131
|
+
knife.config[:no_deps] = true
|
132
|
+
upstream_file = File.join(install_path, "getting-started.tar.gz")
|
133
|
+
expect(repo).not_to receive(:prepare_to_import)
|
134
|
+
expect(repo).not_to receive(:reset_to_default_state)
|
135
|
+
knife.run
|
148
136
|
end
|
137
|
+
|
138
|
+
it "does not raise an error if cookbook_path is a string" do
|
139
|
+
knife.config[:cookbook_path] = install_path
|
140
|
+
knife.config[:no_deps] = true
|
141
|
+
knife.name_args = ["getting-started"]
|
142
|
+
upstream_file = File.join(install_path, "getting-started.tar.gz")
|
143
|
+
expect(knife).to receive(:download_cookbook_to).with(upstream_file)
|
144
|
+
expect(knife).to receive(:extract_cookbook).with(upstream_file, "0.3.0")
|
145
|
+
expect(knife).to receive(:clear_existing_files).with(File.join(install_path, "getting-started"))
|
146
|
+
expect(repo).to receive(:merge_updates_from).with("getting-started", "0.3.0")
|
147
|
+
expect { knife.run }.not_to raise_error
|
148
|
+
end
|
149
|
+
end # end of run
|
150
|
+
|
151
|
+
let(:metadata) { Chef::Cookbook::Metadata.new }
|
152
|
+
let(:rb_metadata_path) { File.join(install_path, "post-punk-kitchen", "metadata.rb") }
|
153
|
+
let(:json_metadata_path) { File.join(install_path, "post-punk-kitchen", "metadata.json") }
|
154
|
+
|
155
|
+
describe "preferred_metadata" do
|
156
|
+
before do
|
157
|
+
allow(Chef::Cookbook::Metadata).to receive(:new).and_return(metadata)
|
158
|
+
allow(File).to receive(:exist?).and_return(false)
|
159
|
+
knife.instance_variable_set(:@cookbook_name, "post-punk-kitchen")
|
160
|
+
knife.instance_variable_set(:@install_path, install_path)
|
161
|
+
end
|
162
|
+
|
163
|
+
it "returns a populated Metadata object if metadata.rb exists" do
|
164
|
+
allow(File).to receive(:exist?).with(rb_metadata_path).and_return(true)
|
165
|
+
expect(metadata).to receive(:from_file).with(rb_metadata_path)
|
166
|
+
knife.preferred_metadata
|
167
|
+
end
|
168
|
+
|
169
|
+
it "returns a populated Metadata object if metadata.json exists" do
|
170
|
+
allow(File).to receive(:exist?).with(json_metadata_path).and_return(true)
|
171
|
+
#expect(IO).to receive(:read).with(json_metadata_path)
|
172
|
+
allow(IO).to receive(:read)
|
173
|
+
expect(metadata).to receive(:from_json)
|
174
|
+
knife.preferred_metadata
|
175
|
+
end
|
176
|
+
|
177
|
+
it "prefers metadata.rb over metadata.json" do
|
178
|
+
allow(File).to receive(:exist?).with(rb_metadata_path).and_return(true)
|
179
|
+
allow(File).to receive(:exist?).with(json_metadata_path).and_return(true)
|
180
|
+
allow(IO).to receive(:read)
|
181
|
+
expect(metadata).to receive(:from_file).with(rb_metadata_path)
|
182
|
+
expect(metadata).not_to receive(:from_json)
|
183
|
+
knife.preferred_metadata
|
184
|
+
end
|
185
|
+
|
186
|
+
it "rasies an error if it finds no metadata file" do
|
187
|
+
expect { knife.preferred_metadata }.to raise_error(Chef::Exceptions::MetadataNotFound)
|
188
|
+
end
|
189
|
+
|
149
190
|
end
|
150
191
|
end
|
data/spec/unit/knife_spec.rb
CHANGED
@@ -25,23 +25,26 @@ require 'spec_helper'
|
|
25
25
|
require 'uri'
|
26
26
|
|
27
27
|
describe Chef::Knife do
|
28
|
+
|
29
|
+
let(:stderr) { StringIO.new }
|
30
|
+
|
31
|
+
let(:knife) { Chef::Knife.new }
|
32
|
+
|
28
33
|
before(:each) do
|
29
34
|
Chef::Log.logger = Logger.new(StringIO.new)
|
30
35
|
|
31
36
|
Chef::Config[:node_name] = "webmonkey.example.com"
|
32
37
|
|
33
38
|
# Prevent gratuitous code reloading:
|
34
|
-
Chef::Knife.
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
Chef::Log.
|
39
|
-
Chef::Log.stub(:level)
|
39
|
+
allow(Chef::Knife).to receive(:load_commands)
|
40
|
+
allow(knife.ui).to receive(:puts)
|
41
|
+
allow(knife.ui).to receive(:print)
|
42
|
+
allow(Chef::Log).to receive(:init)
|
43
|
+
allow(Chef::Log).to receive(:level)
|
40
44
|
[:debug, :info, :warn, :error, :crit].each do |level_sym|
|
41
45
|
Chef::Log.stub(level_sym)
|
42
46
|
end
|
43
|
-
Chef::Knife.
|
44
|
-
@stderr = StringIO.new
|
47
|
+
allow(Chef::Knife).to receive(:puts)
|
45
48
|
end
|
46
49
|
|
47
50
|
after(:each) do
|
@@ -217,9 +220,12 @@ describe Chef::Knife do
|
|
217
220
|
end
|
218
221
|
|
219
222
|
it "exits if no subcommand matches the CLI args" do
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
+
stdout = StringIO.new
|
224
|
+
|
225
|
+
allow(Chef::Knife.ui).to receive(:stderr).and_return(stderr)
|
226
|
+
allow(Chef::Knife.ui).to receive(:stdout).and_return(stdout)
|
227
|
+
expect(Chef::Knife.ui).to receive(:fatal)
|
228
|
+
expect {Chef::Knife.run(%w{fuuu uuuu fuuuu})}.to raise_error(SystemExit) { |e| expect(e.status).not_to eq(0) }
|
223
229
|
end
|
224
230
|
|
225
231
|
it "loads lazy dependencies" do
|
@@ -269,157 +275,181 @@ describe Chef::Knife do
|
|
269
275
|
let(:fake_config) { "/does/not/exist/knife.rb" }
|
270
276
|
|
271
277
|
before do
|
272
|
-
|
273
|
-
|
278
|
+
knife.config[:verbosity] = 1
|
279
|
+
knife.config[:config_file] = fake_config
|
274
280
|
config_loader = double("Chef::WorkstationConfigLoader", :load => true, :no_config_found? => false, :chef_config_dir => "/etc/chef", :config_location => fake_config)
|
275
281
|
allow(config_loader).to receive(:explicit_config_file=).with(fake_config).and_return(fake_config)
|
276
282
|
allow(Chef::WorkstationConfigLoader).to receive(:new).and_return(config_loader)
|
277
283
|
end
|
278
284
|
|
279
285
|
it "prints the path to the configuration file used" do
|
280
|
-
|
281
|
-
|
286
|
+
stdout, stderr, stdin = StringIO.new, StringIO.new, StringIO.new
|
287
|
+
knife.ui = Chef::Knife::UI.new(stdout, stderr, stdin, {})
|
282
288
|
expect(Chef::Log).to receive(:info).with("Using configuration from #{fake_config}")
|
283
|
-
|
289
|
+
knife.configure_chef
|
284
290
|
end
|
285
291
|
end
|
286
292
|
end
|
287
293
|
end
|
288
294
|
|
289
295
|
describe "when first created" do
|
296
|
+
|
297
|
+
let(:knife) { KnifeSpecs::TestYourself.new(%w{with some args -s scrogramming}) }
|
298
|
+
|
290
299
|
before do
|
291
300
|
unless KnifeSpecs.const_defined?(:TestYourself)
|
292
301
|
Kernel.load(File.join(CHEF_SPEC_DATA, 'knife_subcommand', 'test_yourself.rb'))
|
293
302
|
end
|
294
|
-
@knife = KnifeSpecs::TestYourself.new(%w{with some args -s scrogramming})
|
295
303
|
end
|
296
304
|
|
297
305
|
it "it parses the options passed to it" do
|
298
|
-
|
306
|
+
expect(knife.config[:scro]).to eq('scrogramming')
|
299
307
|
end
|
300
308
|
|
301
309
|
it "extracts its command specific args from the full arg list" do
|
302
|
-
|
310
|
+
expect(knife.name_args).to eq(%w{with some args})
|
303
311
|
end
|
304
312
|
|
305
313
|
it "does not have lazy dependencies loaded" do
|
306
|
-
|
314
|
+
expect(knife.class.test_deps_loaded).to be(nil)
|
307
315
|
end
|
308
316
|
end
|
309
317
|
|
310
318
|
describe "when formatting exceptions" do
|
319
|
+
|
320
|
+
let(:stdout) { StringIO.new }
|
321
|
+
let(:stderr) { StringIO.new }
|
322
|
+
let(:stdin) { StringIO.new }
|
323
|
+
|
324
|
+
let(:ui) { Chef::Knife::UI.new(stdout, stderr, stdin, {}) }
|
325
|
+
|
311
326
|
before do
|
312
|
-
|
313
|
-
|
314
|
-
@knife.should_receive(:exit).with(100)
|
327
|
+
knife.ui = ui
|
328
|
+
expect(knife).to receive(:exit).with(100)
|
315
329
|
end
|
316
330
|
|
317
331
|
it "formats 401s nicely" do
|
318
332
|
response = Net::HTTPUnauthorized.new("1.1", "401", "Unauthorized")
|
319
333
|
response.instance_variable_set(:@read, true) # I hate you, net/http.
|
320
|
-
response.
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
334
|
+
allow(response).to receive(:body).and_return(Chef::JSONCompat.to_json(:error => "y u no syncronize your clock?"))
|
335
|
+
allow(knife).to receive(:run).and_raise(Net::HTTPServerException.new("401 Unauthorized", response))
|
336
|
+
knife.run_with_pretty_exceptions
|
337
|
+
expect(stderr.string).to match(/ERROR: Failed to authenticate to/)
|
338
|
+
expect(stderr.string).to match(/Response: y u no syncronize your clock\?/)
|
325
339
|
end
|
326
340
|
|
327
341
|
it "formats 403s nicely" do
|
328
342
|
response = Net::HTTPForbidden.new("1.1", "403", "Forbidden")
|
329
343
|
response.instance_variable_set(:@read, true) # I hate you, net/http.
|
330
|
-
response.
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
344
|
+
allow(response).to receive(:body).and_return(Chef::JSONCompat.to_json(:error => "y u no administrator"))
|
345
|
+
allow(knife).to receive(:run).and_raise(Net::HTTPServerException.new("403 Forbidden", response))
|
346
|
+
allow(knife).to receive(:username).and_return("sadpanda")
|
347
|
+
knife.run_with_pretty_exceptions
|
348
|
+
expect(stderr.string).to match(%r[ERROR: You authenticated successfully to http.+ as sadpanda but you are not authorized for this action])
|
349
|
+
expect(stderr.string).to match(%r[Response: y u no administrator])
|
336
350
|
end
|
337
351
|
|
338
352
|
it "formats 400s nicely" do
|
339
353
|
response = Net::HTTPBadRequest.new("1.1", "400", "Bad Request")
|
340
354
|
response.instance_variable_set(:@read, true) # I hate you, net/http.
|
341
|
-
response.
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
355
|
+
allow(response).to receive(:body).and_return(Chef::JSONCompat.to_json(:error => "y u search wrong"))
|
356
|
+
allow(knife).to receive(:run).and_raise(Net::HTTPServerException.new("400 Bad Request", response))
|
357
|
+
knife.run_with_pretty_exceptions
|
358
|
+
expect(stderr.string).to match(%r[ERROR: The data in your request was invalid])
|
359
|
+
expect(stderr.string).to match(%r[Response: y u search wrong])
|
346
360
|
end
|
347
361
|
|
348
362
|
it "formats 404s nicely" do
|
349
363
|
response = Net::HTTPNotFound.new("1.1", "404", "Not Found")
|
350
364
|
response.instance_variable_set(:@read, true) # I hate you, net/http.
|
351
|
-
response.
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
365
|
+
allow(response).to receive(:body).and_return(Chef::JSONCompat.to_json(:error => "nothing to see here"))
|
366
|
+
allow(knife).to receive(:run).and_raise(Net::HTTPServerException.new("404 Not Found", response))
|
367
|
+
knife.run_with_pretty_exceptions
|
368
|
+
expect(stderr.string).to match(%r[ERROR: The object you are looking for could not be found])
|
369
|
+
expect(stderr.string).to match(%r[Response: nothing to see here])
|
356
370
|
end
|
357
371
|
|
358
372
|
it "formats 500s nicely" do
|
359
373
|
response = Net::HTTPInternalServerError.new("1.1", "500", "Internal Server Error")
|
360
374
|
response.instance_variable_set(:@read, true) # I hate you, net/http.
|
361
|
-
response.
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
375
|
+
allow(response).to receive(:body).and_return(Chef::JSONCompat.to_json(:error => "sad trombone"))
|
376
|
+
allow(knife).to receive(:run).and_raise(Net::HTTPFatalError.new("500 Internal Server Error", response))
|
377
|
+
knife.run_with_pretty_exceptions
|
378
|
+
expect(stderr.string).to match(%r[ERROR: internal server error])
|
379
|
+
expect(stderr.string).to match(%r[Response: sad trombone])
|
366
380
|
end
|
367
381
|
|
368
382
|
it "formats 502s nicely" do
|
369
383
|
response = Net::HTTPBadGateway.new("1.1", "502", "Bad Gateway")
|
370
384
|
response.instance_variable_set(:@read, true) # I hate you, net/http.
|
371
|
-
response.
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
385
|
+
allow(response).to receive(:body).and_return(Chef::JSONCompat.to_json(:error => "sadder trombone"))
|
386
|
+
allow(knife).to receive(:run).and_raise(Net::HTTPFatalError.new("502 Bad Gateway", response))
|
387
|
+
knife.run_with_pretty_exceptions
|
388
|
+
expect(stderr.string).to match(%r[ERROR: bad gateway])
|
389
|
+
expect(stderr.string).to match(%r[Response: sadder trombone])
|
376
390
|
end
|
377
391
|
|
378
392
|
it "formats 503s nicely" do
|
379
393
|
response = Net::HTTPServiceUnavailable.new("1.1", "503", "Service Unavailable")
|
380
394
|
response.instance_variable_set(:@read, true) # I hate you, net/http.
|
381
|
-
response.
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
395
|
+
allow(response).to receive(:body).and_return(Chef::JSONCompat.to_json(:error => "saddest trombone"))
|
396
|
+
allow(knife).to receive(:run).and_raise(Net::HTTPFatalError.new("503 Service Unavailable", response))
|
397
|
+
knife.run_with_pretty_exceptions
|
398
|
+
expect(stderr.string).to match(%r[ERROR: Service temporarily unavailable])
|
399
|
+
expect(stderr.string).to match(%r[Response: saddest trombone])
|
386
400
|
end
|
387
401
|
|
388
402
|
it "formats other HTTP errors nicely" do
|
389
403
|
response = Net::HTTPPaymentRequired.new("1.1", "402", "Payment Required")
|
390
404
|
response.instance_variable_set(:@read, true) # I hate you, net/http.
|
391
|
-
response.
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
405
|
+
allow(response).to receive(:body).and_return(Chef::JSONCompat.to_json(:error => "nobugfixtillyoubuy"))
|
406
|
+
allow(knife).to receive(:run).and_raise(Net::HTTPServerException.new("402 Payment Required", response))
|
407
|
+
knife.run_with_pretty_exceptions
|
408
|
+
expect(stderr.string).to match(%r[ERROR: Payment Required])
|
409
|
+
expect(stderr.string).to match(%r[Response: nobugfixtillyoubuy])
|
396
410
|
end
|
397
411
|
|
398
412
|
it "formats NameError and NoMethodError nicely" do
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
413
|
+
allow(knife).to receive(:run).and_raise(NameError.new("Undefined constant FUUU"))
|
414
|
+
knife.run_with_pretty_exceptions
|
415
|
+
expect(stderr.string).to match(%r[ERROR: knife encountered an unexpected error])
|
416
|
+
expect(stderr.string).to match(%r[This may be a bug in the 'knife' knife command or plugin])
|
417
|
+
expect(stderr.string).to match(%r[Exception: NameError: Undefined constant FUUU])
|
404
418
|
end
|
405
419
|
|
406
420
|
it "formats missing private key errors nicely" do
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
421
|
+
allow(knife).to receive(:run).and_raise(Chef::Exceptions::PrivateKeyMissing.new('key not there'))
|
422
|
+
allow(knife).to receive(:api_key).and_return("/home/root/.chef/no-key-here.pem")
|
423
|
+
knife.run_with_pretty_exceptions
|
424
|
+
expect(stderr.string).to match(%r[ERROR: Your private key could not be loaded from /home/root/.chef/no-key-here.pem])
|
425
|
+
expect(stderr.string).to match(%r[Check your configuration file and ensure that your private key is readable])
|
412
426
|
end
|
413
427
|
|
414
428
|
it "formats connection refused errors nicely" do
|
415
|
-
|
416
|
-
|
429
|
+
allow(knife).to receive(:run).and_raise(Errno::ECONNREFUSED.new('y u no shut up'))
|
430
|
+
knife.run_with_pretty_exceptions
|
417
431
|
# Errno::ECONNREFUSED message differs by platform
|
418
432
|
# *nix = Errno::ECONNREFUSED: Connection refused
|
419
433
|
# win32: Errno::ECONNREFUSED: No connection could be made because the target machine actively refused it.
|
420
|
-
|
421
|
-
|
434
|
+
expect(stderr.string).to match(%r[ERROR: Network Error: .* - y u no shut up])
|
435
|
+
expect(stderr.string).to match(%r[Check your knife configuration and network settings])
|
422
436
|
end
|
437
|
+
|
438
|
+
it "formats SSL errors nicely and suggests to use `knife ssl check` and `knife ssl fetch`" do
|
439
|
+
error = OpenSSL::SSL::SSLError.new("SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed")
|
440
|
+
allow(knife).to receive(:run).and_raise(error)
|
441
|
+
|
442
|
+
knife.run_with_pretty_exceptions
|
443
|
+
|
444
|
+
expected_message=<<-MSG
|
445
|
+
ERROR: Could not establish a secure connection to the server.
|
446
|
+
Use `knife ssl check` to troubleshoot your SSL configuration.
|
447
|
+
If your Chef Server uses a self-signed certificate, you can use
|
448
|
+
`knife ssl fetch` to make knife trust the server's certificates.
|
449
|
+
MSG
|
450
|
+
expect(stderr.string).to include(expected_message)
|
451
|
+
end
|
452
|
+
|
423
453
|
end
|
424
454
|
|
425
455
|
end
|