chef 12.4.3 → 12.5.0.alpha.1
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/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
|