chef 12.4.3 → 12.5.0.alpha.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Rakefile +1 -2
- data/lib/chef.rb +1 -1
- data/lib/chef/application/solo.rb +1 -1
- data/lib/chef/application/windows_service_manager.rb +17 -12
- data/lib/chef/chef_class.rb +7 -0
- data/lib/chef/chef_fs/config.rb +22 -24
- data/lib/chef/chef_fs/file_pattern.rb +4 -15
- data/lib/chef/chef_fs/file_system/cookbook_dir.rb +1 -0
- data/lib/chef/chef_fs/knife.rb +35 -7
- data/lib/chef/chef_fs/path_utils.rb +65 -34
- data/lib/chef/constants.rb +27 -0
- data/lib/chef/delayed_evaluator.rb +21 -0
- data/lib/chef/dsl/recipe.rb +20 -2
- data/lib/chef/event_dispatch/base.rb +40 -16
- data/lib/chef/event_dispatch/dsl.rb +64 -0
- data/lib/chef/exceptions.rb +6 -1
- data/lib/chef/formatters/doc.rb +3 -1
- data/lib/chef/guard_interpreter/resource_guard_interpreter.rb +3 -1
- data/lib/chef/http/http_request.rb +1 -1
- data/lib/chef/knife/bootstrap/templates/chef-full.erb +1 -1
- data/lib/chef/knife/ssl_check.rb +3 -2
- data/lib/chef/knife/user_edit.rb +1 -2
- data/lib/chef/mixin/params_validate.rb +362 -135
- data/lib/chef/node.rb +19 -0
- data/lib/chef/platform/handler_map.rb +0 -5
- data/lib/chef/platform/rebooter.rb +1 -1
- data/lib/chef/property.rb +539 -0
- data/lib/chef/provider.rb +129 -12
- data/lib/chef/provider/deploy.rb +3 -5
- data/lib/chef/provider/lwrp_base.rb +1 -75
- data/lib/chef/provider/package.rb +1 -1
- data/lib/chef/provider/powershell_script.rb +32 -19
- data/lib/chef/provider/registry_key.rb +5 -5
- data/lib/chef/provider/service/macosx.rb +5 -1
- data/lib/chef/recipe.rb +1 -8
- data/lib/chef/resource.rb +499 -84
- data/lib/chef/resource/file/verification.rb +7 -1
- data/lib/chef/resource/lwrp_base.rb +1 -7
- data/lib/chef/run_context.rb +404 -83
- data/lib/chef/version.rb +1 -1
- data/lib/chef/win32/registry.rb +10 -2
- data/lib/chef/workstation_config_loader.rb +3 -158
- data/spec/data/run_context/cookbooks/include/recipes/default.rb +24 -0
- data/spec/data/run_context/cookbooks/include/recipes/includee.rb +3 -0
- data/spec/functional/rebooter_spec.rb +1 -1
- data/spec/functional/resource/{powershell_spec.rb → powershell_script_spec.rb} +3 -3
- data/spec/functional/win32/registry_helper_spec.rb +12 -0
- data/spec/functional/win32/service_manager_spec.rb +2 -2
- data/spec/integration/knife/chef_repo_path_spec.rb +13 -11
- data/spec/integration/recipes/recipe_dsl_spec.rb +0 -15
- data/spec/integration/recipes/resource_action_spec.rb +343 -0
- data/spec/spec_helper.rb +1 -0
- data/spec/support/shared/functional/win32_service.rb +2 -1
- data/spec/unit/application/solo_spec.rb +4 -3
- data/spec/unit/chef_class_spec.rb +23 -0
- data/spec/unit/chef_fs/path_util_spec.rb +108 -0
- data/spec/unit/event_dispatch/dsl_spec.rb +87 -0
- data/spec/unit/json_compat_spec.rb +4 -3
- data/spec/unit/knife/ssl_check_spec.rb +4 -0
- data/spec/unit/mixin/params_validate_spec.rb +4 -2
- data/spec/unit/node_spec.rb +7 -0
- data/spec/unit/property/state_spec.rb +506 -0
- data/spec/unit/property/validation_spec.rb +658 -0
- data/spec/unit/property_spec.rb +968 -0
- data/spec/unit/provider/{powershell_spec.rb → powershell_script_spec.rb} +0 -0
- data/spec/unit/provider/registry_key_spec.rb +12 -0
- data/spec/unit/provider/service/macosx_spec.rb +4 -4
- data/spec/unit/provider_spec.rb +1 -3
- data/spec/unit/recipe_spec.rb +0 -4
- data/spec/unit/registry_helper_spec.rb +15 -1
- data/spec/unit/resource/file/verification_spec.rb +33 -5
- data/spec/unit/resource/{powershell_spec.rb → powershell_script_spec.rb} +0 -0
- data/spec/unit/resource_spec.rb +2 -2
- data/spec/unit/run_context/child_run_context_spec.rb +133 -0
- data/spec/unit/run_context_spec.rb +7 -0
- metadata +25 -25
- data/spec/unit/workstation_config_loader_spec.rb +0 -283
@@ -0,0 +1,343 @@
|
|
1
|
+
require 'support/shared/integration/integration_helper'
|
2
|
+
|
3
|
+
describe "Resource.action" do
|
4
|
+
include IntegrationSupport
|
5
|
+
|
6
|
+
def converge(str=nil, file=nil, line=nil, &block)
|
7
|
+
if block
|
8
|
+
super(&block)
|
9
|
+
else
|
10
|
+
super() do
|
11
|
+
eval(str, nil, file, line)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
shared_context "ActionJackson" do
|
17
|
+
it "The default action is the first declared action" do
|
18
|
+
converge <<-EOM, __FILE__, __LINE__+1
|
19
|
+
#{resource_dsl} 'hi' do
|
20
|
+
foo 'foo!'
|
21
|
+
end
|
22
|
+
EOM
|
23
|
+
expect(ActionJackson.ran_action).to eq :access_recipe_dsl
|
24
|
+
expect(ActionJackson.succeeded).to eq true
|
25
|
+
end
|
26
|
+
|
27
|
+
it "The action can access recipe DSL" do
|
28
|
+
converge <<-EOM, __FILE__, __LINE__+1
|
29
|
+
#{resource_dsl} 'hi' do
|
30
|
+
foo 'foo!'
|
31
|
+
action :access_recipe_dsl
|
32
|
+
end
|
33
|
+
EOM
|
34
|
+
expect(ActionJackson.ran_action).to eq :access_recipe_dsl
|
35
|
+
expect(ActionJackson.succeeded).to eq true
|
36
|
+
end
|
37
|
+
|
38
|
+
it "The action can access attributes" do
|
39
|
+
converge <<-EOM, __FILE__, __LINE__+1
|
40
|
+
#{resource_dsl} 'hi' do
|
41
|
+
foo 'foo!'
|
42
|
+
action :access_attribute
|
43
|
+
end
|
44
|
+
EOM
|
45
|
+
expect(ActionJackson.ran_action).to eq :access_attribute
|
46
|
+
expect(ActionJackson.succeeded).to eq 'foo!'
|
47
|
+
end
|
48
|
+
|
49
|
+
it "The action can access public methods" do
|
50
|
+
converge <<-EOM, __FILE__, __LINE__+1
|
51
|
+
#{resource_dsl} 'hi' do
|
52
|
+
foo 'foo!'
|
53
|
+
action :access_method
|
54
|
+
end
|
55
|
+
EOM
|
56
|
+
expect(ActionJackson.ran_action).to eq :access_method
|
57
|
+
expect(ActionJackson.succeeded).to eq 'foo_public!'
|
58
|
+
end
|
59
|
+
|
60
|
+
it "The action can access protected methods" do
|
61
|
+
converge <<-EOM, __FILE__, __LINE__+1
|
62
|
+
#{resource_dsl} 'hi' do
|
63
|
+
foo 'foo!'
|
64
|
+
action :access_protected_method
|
65
|
+
end
|
66
|
+
EOM
|
67
|
+
expect(ActionJackson.ran_action).to eq :access_protected_method
|
68
|
+
expect(ActionJackson.succeeded).to eq 'foo_protected!'
|
69
|
+
end
|
70
|
+
|
71
|
+
it "The action cannot access private methods" do
|
72
|
+
expect {
|
73
|
+
converge(<<-EOM, __FILE__, __LINE__+1)
|
74
|
+
#{resource_dsl} 'hi' do
|
75
|
+
foo 'foo!'
|
76
|
+
action :access_private_method
|
77
|
+
end
|
78
|
+
EOM
|
79
|
+
}.to raise_error(NameError)
|
80
|
+
expect(ActionJackson.ran_action).to eq :access_private_method
|
81
|
+
end
|
82
|
+
|
83
|
+
it "The action cannot access resource instance variables" do
|
84
|
+
converge <<-EOM, __FILE__, __LINE__+1
|
85
|
+
#{resource_dsl} 'hi' do
|
86
|
+
foo 'foo!'
|
87
|
+
action :access_instance_variable
|
88
|
+
end
|
89
|
+
EOM
|
90
|
+
expect(ActionJackson.ran_action).to eq :access_instance_variable
|
91
|
+
expect(ActionJackson.succeeded).to be_nil
|
92
|
+
end
|
93
|
+
|
94
|
+
it "The action does not compile until the prior resource has converged" do
|
95
|
+
converge <<-EOM, __FILE__, __LINE__+1
|
96
|
+
ruby_block 'wow' do
|
97
|
+
block do
|
98
|
+
ActionJackson.ruby_block_converged = 'ruby_block_converged!'
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
#{resource_dsl} 'hi' do
|
103
|
+
foo 'foo!'
|
104
|
+
action :access_class_method
|
105
|
+
end
|
106
|
+
EOM
|
107
|
+
expect(ActionJackson.ran_action).to eq :access_class_method
|
108
|
+
expect(ActionJackson.succeeded).to eq 'ruby_block_converged!'
|
109
|
+
end
|
110
|
+
|
111
|
+
it "The action's resources converge before the next resource converges" do
|
112
|
+
converge <<-EOM, __FILE__, __LINE__+1
|
113
|
+
#{resource_dsl} 'hi' do
|
114
|
+
foo 'foo!'
|
115
|
+
action :access_attribute
|
116
|
+
end
|
117
|
+
|
118
|
+
ruby_block 'wow' do
|
119
|
+
block do
|
120
|
+
ActionJackson.ruby_block_converged = ActionJackson.succeeded
|
121
|
+
end
|
122
|
+
end
|
123
|
+
EOM
|
124
|
+
expect(ActionJackson.ran_action).to eq :access_attribute
|
125
|
+
expect(ActionJackson.succeeded).to eq 'foo!'
|
126
|
+
expect(ActionJackson.ruby_block_converged).to eq 'foo!'
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
context "With resource 'action_jackson'" do
|
131
|
+
before(:context) {
|
132
|
+
class ActionJackson < Chef::Resource
|
133
|
+
use_automatic_resource_name
|
134
|
+
def foo(value=nil)
|
135
|
+
@foo = value if value
|
136
|
+
@foo
|
137
|
+
end
|
138
|
+
def blarghle(value=nil)
|
139
|
+
@blarghle = value if value
|
140
|
+
@blarghle
|
141
|
+
end
|
142
|
+
|
143
|
+
class <<self
|
144
|
+
attr_accessor :ran_action
|
145
|
+
attr_accessor :succeeded
|
146
|
+
attr_accessor :ruby_block_converged
|
147
|
+
end
|
148
|
+
|
149
|
+
public
|
150
|
+
def foo_public
|
151
|
+
'foo_public!'
|
152
|
+
end
|
153
|
+
protected
|
154
|
+
def foo_protected
|
155
|
+
'foo_protected!'
|
156
|
+
end
|
157
|
+
private
|
158
|
+
def foo_private
|
159
|
+
'foo_private!'
|
160
|
+
end
|
161
|
+
|
162
|
+
public
|
163
|
+
action :access_recipe_dsl do
|
164
|
+
ActionJackson.ran_action = :access_recipe_dsl
|
165
|
+
ruby_block 'hi there' do
|
166
|
+
block do
|
167
|
+
ActionJackson.succeeded = true
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
action :access_attribute do
|
172
|
+
ActionJackson.ran_action = :access_attribute
|
173
|
+
ActionJackson.succeeded = foo
|
174
|
+
ActionJackson.succeeded += " #{blarghle}" if blarghle
|
175
|
+
ActionJackson.succeeded += " #{bar}" if respond_to?(:bar)
|
176
|
+
end
|
177
|
+
action :access_attribute2 do
|
178
|
+
ActionJackson.ran_action = :access_attribute2
|
179
|
+
ActionJackson.succeeded = foo
|
180
|
+
ActionJackson.succeeded += " #{blarghle}" if blarghle
|
181
|
+
ActionJackson.succeeded += " #{bar}" if respond_to?(:bar)
|
182
|
+
end
|
183
|
+
action :access_method do
|
184
|
+
ActionJackson.ran_action = :access_method
|
185
|
+
ActionJackson.succeeded = foo_public
|
186
|
+
end
|
187
|
+
action :access_protected_method do
|
188
|
+
ActionJackson.ran_action = :access_protected_method
|
189
|
+
ActionJackson.succeeded = foo_protected
|
190
|
+
end
|
191
|
+
action :access_private_method do
|
192
|
+
ActionJackson.ran_action = :access_private_method
|
193
|
+
ActionJackson.succeeded = foo_private
|
194
|
+
end
|
195
|
+
action :access_instance_variable do
|
196
|
+
ActionJackson.ran_action = :access_instance_variable
|
197
|
+
ActionJackson.succeeded = @foo
|
198
|
+
end
|
199
|
+
action :access_class_method do
|
200
|
+
ActionJackson.ran_action = :access_class_method
|
201
|
+
ActionJackson.succeeded = ActionJackson.ruby_block_converged
|
202
|
+
end
|
203
|
+
end
|
204
|
+
}
|
205
|
+
before(:each) {
|
206
|
+
ActionJackson.ran_action = :error
|
207
|
+
ActionJackson.succeeded = :error
|
208
|
+
ActionJackson.ruby_block_converged = :error
|
209
|
+
}
|
210
|
+
|
211
|
+
it_behaves_like "ActionJackson" do
|
212
|
+
let(:resource_dsl) { :action_jackson }
|
213
|
+
end
|
214
|
+
|
215
|
+
context "And 'action_jackgrandson' inheriting from ActionJackson and changing nothing" do
|
216
|
+
before(:context) {
|
217
|
+
class ActionJackgrandson < ActionJackson
|
218
|
+
use_automatic_resource_name
|
219
|
+
end
|
220
|
+
}
|
221
|
+
|
222
|
+
it_behaves_like "ActionJackson" do
|
223
|
+
let(:resource_dsl) { :action_jackgrandson }
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
context "And 'action_jackalope' inheriting from ActionJackson with an extra attribute and action" do
|
228
|
+
before(:context) {
|
229
|
+
class ActionJackalope < ActionJackson
|
230
|
+
use_automatic_resource_name
|
231
|
+
|
232
|
+
def foo(value=nil)
|
233
|
+
@foo = "#{value}alope" if value
|
234
|
+
@foo
|
235
|
+
end
|
236
|
+
def bar(value=nil)
|
237
|
+
@bar = "#{value}alope" if value
|
238
|
+
@bar
|
239
|
+
end
|
240
|
+
class <<self
|
241
|
+
attr_accessor :jackalope_ran
|
242
|
+
end
|
243
|
+
action :access_jackalope do
|
244
|
+
ActionJackalope.jackalope_ran = :access_jackalope
|
245
|
+
ActionJackalope.succeeded = "#{foo} #{blarghle} #{bar}"
|
246
|
+
end
|
247
|
+
action :access_attribute do
|
248
|
+
super()
|
249
|
+
ActionJackalope.jackalope_ran = :access_attribute
|
250
|
+
ActionJackalope.succeeded = ActionJackson.succeeded
|
251
|
+
end
|
252
|
+
end
|
253
|
+
}
|
254
|
+
before do
|
255
|
+
ActionJackalope.jackalope_ran = nil
|
256
|
+
end
|
257
|
+
|
258
|
+
context "action_jackson still behaves the same" do
|
259
|
+
it_behaves_like "ActionJackson" do
|
260
|
+
let(:resource_dsl) { :action_jackson }
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
it "The default action remains the same even though new actions were specified first" do
|
265
|
+
converge {
|
266
|
+
action_jackalope 'hi' do
|
267
|
+
foo 'foo!'
|
268
|
+
bar 'bar!'
|
269
|
+
end
|
270
|
+
}
|
271
|
+
expect(ActionJackson.ran_action).to eq :access_recipe_dsl
|
272
|
+
expect(ActionJackson.succeeded).to eq true
|
273
|
+
end
|
274
|
+
|
275
|
+
it "new actions run, and can access overridden, new, and overridden attributes" do
|
276
|
+
converge {
|
277
|
+
action_jackalope 'hi' do
|
278
|
+
foo 'foo!'
|
279
|
+
bar 'bar!'
|
280
|
+
blarghle 'blarghle!'
|
281
|
+
action :access_jackalope
|
282
|
+
end
|
283
|
+
}
|
284
|
+
expect(ActionJackalope.jackalope_ran).to eq :access_jackalope
|
285
|
+
expect(ActionJackalope.succeeded).to eq "foo!alope blarghle! bar!alope"
|
286
|
+
end
|
287
|
+
|
288
|
+
it "overridden actions run, call super, and can access overridden, new, and overridden attributes" do
|
289
|
+
converge {
|
290
|
+
action_jackalope 'hi' do
|
291
|
+
foo 'foo!'
|
292
|
+
bar 'bar!'
|
293
|
+
blarghle 'blarghle!'
|
294
|
+
action :access_attribute
|
295
|
+
end
|
296
|
+
}
|
297
|
+
expect(ActionJackson.ran_action).to eq :access_attribute
|
298
|
+
expect(ActionJackson.succeeded).to eq "foo!alope blarghle! bar!alope"
|
299
|
+
expect(ActionJackalope.jackalope_ran).to eq :access_attribute
|
300
|
+
expect(ActionJackalope.succeeded).to eq "foo!alope blarghle! bar!alope"
|
301
|
+
end
|
302
|
+
|
303
|
+
it "non-overridden actions run and can access overridden and non-overridden variables (but not necessarily new ones)" do
|
304
|
+
converge {
|
305
|
+
action_jackalope 'hi' do
|
306
|
+
foo 'foo!'
|
307
|
+
bar 'bar!'
|
308
|
+
blarghle 'blarghle!'
|
309
|
+
action :access_attribute2
|
310
|
+
end
|
311
|
+
}
|
312
|
+
expect(ActionJackson.ran_action).to eq :access_attribute2
|
313
|
+
expect(ActionJackson.succeeded).to eq("foo!alope blarghle! bar!alope").or(eq("foo!alope blarghle!"))
|
314
|
+
end
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
318
|
+
context "With a resource with no actions" do
|
319
|
+
before(:context) {
|
320
|
+
class NoActionJackson < Chef::Resource
|
321
|
+
use_automatic_resource_name
|
322
|
+
|
323
|
+
def foo(value=nil)
|
324
|
+
@foo = value if value
|
325
|
+
@foo
|
326
|
+
end
|
327
|
+
|
328
|
+
class <<self
|
329
|
+
attr_accessor :action_was
|
330
|
+
end
|
331
|
+
end
|
332
|
+
}
|
333
|
+
it "The default action is :nothing" do
|
334
|
+
converge {
|
335
|
+
no_action_jackson 'hi' do
|
336
|
+
foo 'foo!'
|
337
|
+
NoActionJackson.action_was = action
|
338
|
+
end
|
339
|
+
}
|
340
|
+
expect(NoActionJackson.action_was).to eq [:nothing]
|
341
|
+
end
|
342
|
+
end
|
343
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -118,6 +118,7 @@ RSpec.configure do |config|
|
|
118
118
|
config.filter_run_excluding :volatile_from_verify => false
|
119
119
|
|
120
120
|
config.filter_run_excluding :skip_appveyor => true if ENV["APPVEYOR"]
|
121
|
+
config.filter_run_excluding :appveyor_only => true unless ENV["APPVEYOR"]
|
121
122
|
|
122
123
|
config.filter_run_excluding :windows_only => true unless windows?
|
123
124
|
config.filter_run_excluding :not_supported_on_mac_osx_106 => true if mac_osx_106?
|
@@ -46,7 +46,8 @@ shared_context "using Win32::Service" do
|
|
46
46
|
:service_name => "spec-service",
|
47
47
|
:service_display_name => "Spec Test Service",
|
48
48
|
:service_description => "Service for testing Chef::Application::WindowsServiceManager.",
|
49
|
-
:service_file_path => File.expand_path(File.join(File.dirname(__FILE__), '../../platforms/win32/spec_service.rb'))
|
49
|
+
:service_file_path => File.expand_path(File.join(File.dirname(__FILE__), '../../platforms/win32/spec_service.rb')),
|
50
|
+
:delayed_start => true
|
50
51
|
}
|
51
52
|
}
|
52
53
|
|
@@ -106,7 +106,8 @@ Enable chef-client interval runs by setting `:client_fork = true` in your config
|
|
106
106
|
describe "when the recipe_url configuration option is specified" do
|
107
107
|
let(:tarfile) { StringIO.new("remote_tarball_content") }
|
108
108
|
let(:target_file) { StringIO.new }
|
109
|
-
|
109
|
+
let(:shellout) { double(run_command: nil, error!: nil, stdout: '') }
|
110
|
+
|
110
111
|
before do
|
111
112
|
Chef::Config[:cookbook_path] = "#{Dir.tmpdir}/chef-solo/cookbooks"
|
112
113
|
Chef::Config[:recipe_url] = "http://junglist.gen.nz/recipes.tgz"
|
@@ -117,7 +118,7 @@ Enable chef-client interval runs by setting `:client_fork = true` in your config
|
|
117
118
|
allow(app).to receive(:open).with("http://junglist.gen.nz/recipes.tgz").and_yield(tarfile)
|
118
119
|
allow(File).to receive(:open).with("#{Dir.tmpdir}/chef-solo/recipes.tgz", "wb").and_yield(target_file)
|
119
120
|
|
120
|
-
allow(
|
121
|
+
allow(Mixlib::ShellOut).to receive(:new).and_return(shellout)
|
121
122
|
end
|
122
123
|
|
123
124
|
it "should create the recipes path based on the parent of the cookbook path" do
|
@@ -136,7 +137,7 @@ Enable chef-client interval runs by setting `:client_fork = true` in your config
|
|
136
137
|
end
|
137
138
|
|
138
139
|
it "should untar the target file to the parent of the cookbook path" do
|
139
|
-
expect(
|
140
|
+
expect(Mixlib::ShellOut).to receive(:new).with("tar zxvf #{Dir.tmpdir}/chef-solo/recipes.tgz -C #{Dir.tmpdir}/chef-solo")
|
140
141
|
app.reconfigure
|
141
142
|
end
|
142
143
|
end
|
@@ -88,4 +88,27 @@ describe "Chef class" do
|
|
88
88
|
expect(Chef.node).to eql(node)
|
89
89
|
end
|
90
90
|
end
|
91
|
+
|
92
|
+
context '#event_handler' do
|
93
|
+
it 'adds a new handler' do
|
94
|
+
x = 1
|
95
|
+
Chef.event_handler do
|
96
|
+
on :converge_start do
|
97
|
+
x = 2
|
98
|
+
end
|
99
|
+
end
|
100
|
+
expect(Chef::Config[:event_handlers]).to_not be_empty
|
101
|
+
Chef::Config[:event_handlers].first.send(:converge_start)
|
102
|
+
expect(x).to eq(2)
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'raise error if unknown event type is passed' do
|
106
|
+
expect do
|
107
|
+
Chef.event_handler do
|
108
|
+
on :yolo do
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end.to raise_error(Chef::Exceptions::InvalidEventType)
|
112
|
+
end
|
113
|
+
end
|
91
114
|
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Kartik Null Cating-Subramanian (<ksubramanian@chef.io>)
|
3
|
+
# Copyright:: Copyright (c) 2015 Opscode, Inc.
|
4
|
+
# License:: Apache License, Version 2.0
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
#
|
18
|
+
|
19
|
+
require 'spec_helper'
|
20
|
+
require 'chef/chef_fs/path_utils'
|
21
|
+
|
22
|
+
describe Chef::ChefFS::PathUtils do
|
23
|
+
context 'invoking join' do
|
24
|
+
it 'joins well-behaved distinct path elements' do
|
25
|
+
expect(Chef::ChefFS::PathUtils.join('a', 'b', 'c')).to eq('a/b/c')
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'strips extraneous slashes in the middle of paths' do
|
29
|
+
expect(Chef::ChefFS::PathUtils.join('a/', '/b', '/c/')).to eq('a/b/c')
|
30
|
+
expect(Chef::ChefFS::PathUtils.join('a/', '/b', '///c/')).to eq('a/b/c')
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'preserves the whether the first element was absolute or not' do
|
34
|
+
expect(Chef::ChefFS::PathUtils.join('/a/', '/b', 'c/')).to eq('/a/b/c')
|
35
|
+
expect(Chef::ChefFS::PathUtils.join('///a/', '/b', 'c/')).to eq('/a/b/c')
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'invoking is_absolute?' do
|
40
|
+
it 'confirms that paths starting with / are absolute' do
|
41
|
+
expect(Chef::ChefFS::PathUtils.is_absolute?('/foo/bar/baz')).to be true
|
42
|
+
expect(Chef::ChefFS::PathUtils.is_absolute?('/foo')).to be true
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'confirms that paths starting with // are absolute even though that looks like some windows network path' do
|
46
|
+
expect(Chef::ChefFS::PathUtils.is_absolute?('//foo/bar/baz')).to be true
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'confirms that root is indeed absolute' do
|
50
|
+
expect(Chef::ChefFS::PathUtils.is_absolute?('/')).to be true
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'confirms that paths starting without / are relative' do
|
54
|
+
expect(Chef::ChefFS::PathUtils.is_absolute?('foo/bar/baz')).to be false
|
55
|
+
expect(Chef::ChefFS::PathUtils.is_absolute?('a')).to be false
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'returns false for an empty path.' do
|
59
|
+
expect(Chef::ChefFS::PathUtils.is_absolute?('')).to be false
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context 'invoking realest_path' do
|
64
|
+
let(:good_path) { File.dirname(__FILE__) }
|
65
|
+
let(:parent_path) { File.dirname(good_path) }
|
66
|
+
|
67
|
+
it 'handles paths with no wildcards or globs' do
|
68
|
+
expect(Chef::ChefFS::PathUtils.realest_path(good_path)).to eq(File.expand_path(good_path))
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'handles paths with .. and .' do
|
72
|
+
expect(Chef::ChefFS::PathUtils.realest_path(good_path+'/../.')).to eq(File.expand_path(parent_path))
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'handles paths with *' do
|
76
|
+
expect(Chef::ChefFS::PathUtils.realest_path(good_path + '/*/foo')).to eq(File.expand_path(good_path + '/*/foo'))
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'handles directories that do not exist' do
|
80
|
+
expect(Chef::ChefFS::PathUtils.realest_path(good_path + '/something/or/other')).to eq(File.expand_path(good_path + '/something/or/other'))
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'handles root correctly' do
|
84
|
+
if Chef::Platform.windows?
|
85
|
+
expect(Chef::ChefFS::PathUtils.realest_path('C:/')).to eq('C:/')
|
86
|
+
else
|
87
|
+
expect(Chef::ChefFS::PathUtils.realest_path('/')).to eq('/')
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
context 'invoking descendant_path' do
|
93
|
+
it 'handles paths with various casing on windows' do
|
94
|
+
allow(Chef::ChefFS).to receive(:windows?) { true }
|
95
|
+
expect(Chef::ChefFS::PathUtils.descendant_path('C:/ab/b/c', 'C:/AB/B')).to eq('c')
|
96
|
+
expect(Chef::ChefFS::PathUtils.descendant_path('C:/ab/b/c', 'c:/ab/B')).to eq('c')
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'returns nil if the path does not have the given ancestor' do
|
100
|
+
expect(Chef::ChefFS::PathUtils.descendant_path('/D/E/F', '/A/B/C')).to be_nil
|
101
|
+
expect(Chef::ChefFS::PathUtils.descendant_path('/A/B/D', '/A/B/C')).to be_nil
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'returns blank if the ancestor equals the path' do
|
105
|
+
expect(Chef::ChefFS::PathUtils.descendant_path('/A/B/D', '/A/B/D')).to eq('')
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|