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.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +1 -2
  3. data/lib/chef.rb +1 -1
  4. data/lib/chef/application/solo.rb +1 -1
  5. data/lib/chef/application/windows_service_manager.rb +17 -12
  6. data/lib/chef/chef_class.rb +7 -0
  7. data/lib/chef/chef_fs/config.rb +22 -24
  8. data/lib/chef/chef_fs/file_pattern.rb +4 -15
  9. data/lib/chef/chef_fs/file_system/cookbook_dir.rb +1 -0
  10. data/lib/chef/chef_fs/knife.rb +35 -7
  11. data/lib/chef/chef_fs/path_utils.rb +65 -34
  12. data/lib/chef/constants.rb +27 -0
  13. data/lib/chef/delayed_evaluator.rb +21 -0
  14. data/lib/chef/dsl/recipe.rb +20 -2
  15. data/lib/chef/event_dispatch/base.rb +40 -16
  16. data/lib/chef/event_dispatch/dsl.rb +64 -0
  17. data/lib/chef/exceptions.rb +6 -1
  18. data/lib/chef/formatters/doc.rb +3 -1
  19. data/lib/chef/guard_interpreter/resource_guard_interpreter.rb +3 -1
  20. data/lib/chef/http/http_request.rb +1 -1
  21. data/lib/chef/knife/bootstrap/templates/chef-full.erb +1 -1
  22. data/lib/chef/knife/ssl_check.rb +3 -2
  23. data/lib/chef/knife/user_edit.rb +1 -2
  24. data/lib/chef/mixin/params_validate.rb +362 -135
  25. data/lib/chef/node.rb +19 -0
  26. data/lib/chef/platform/handler_map.rb +0 -5
  27. data/lib/chef/platform/rebooter.rb +1 -1
  28. data/lib/chef/property.rb +539 -0
  29. data/lib/chef/provider.rb +129 -12
  30. data/lib/chef/provider/deploy.rb +3 -5
  31. data/lib/chef/provider/lwrp_base.rb +1 -75
  32. data/lib/chef/provider/package.rb +1 -1
  33. data/lib/chef/provider/powershell_script.rb +32 -19
  34. data/lib/chef/provider/registry_key.rb +5 -5
  35. data/lib/chef/provider/service/macosx.rb +5 -1
  36. data/lib/chef/recipe.rb +1 -8
  37. data/lib/chef/resource.rb +499 -84
  38. data/lib/chef/resource/file/verification.rb +7 -1
  39. data/lib/chef/resource/lwrp_base.rb +1 -7
  40. data/lib/chef/run_context.rb +404 -83
  41. data/lib/chef/version.rb +1 -1
  42. data/lib/chef/win32/registry.rb +10 -2
  43. data/lib/chef/workstation_config_loader.rb +3 -158
  44. data/spec/data/run_context/cookbooks/include/recipes/default.rb +24 -0
  45. data/spec/data/run_context/cookbooks/include/recipes/includee.rb +3 -0
  46. data/spec/functional/rebooter_spec.rb +1 -1
  47. data/spec/functional/resource/{powershell_spec.rb → powershell_script_spec.rb} +3 -3
  48. data/spec/functional/win32/registry_helper_spec.rb +12 -0
  49. data/spec/functional/win32/service_manager_spec.rb +2 -2
  50. data/spec/integration/knife/chef_repo_path_spec.rb +13 -11
  51. data/spec/integration/recipes/recipe_dsl_spec.rb +0 -15
  52. data/spec/integration/recipes/resource_action_spec.rb +343 -0
  53. data/spec/spec_helper.rb +1 -0
  54. data/spec/support/shared/functional/win32_service.rb +2 -1
  55. data/spec/unit/application/solo_spec.rb +4 -3
  56. data/spec/unit/chef_class_spec.rb +23 -0
  57. data/spec/unit/chef_fs/path_util_spec.rb +108 -0
  58. data/spec/unit/event_dispatch/dsl_spec.rb +87 -0
  59. data/spec/unit/json_compat_spec.rb +4 -3
  60. data/spec/unit/knife/ssl_check_spec.rb +4 -0
  61. data/spec/unit/mixin/params_validate_spec.rb +4 -2
  62. data/spec/unit/node_spec.rb +7 -0
  63. data/spec/unit/property/state_spec.rb +506 -0
  64. data/spec/unit/property/validation_spec.rb +658 -0
  65. data/spec/unit/property_spec.rb +968 -0
  66. data/spec/unit/provider/{powershell_spec.rb → powershell_script_spec.rb} +0 -0
  67. data/spec/unit/provider/registry_key_spec.rb +12 -0
  68. data/spec/unit/provider/service/macosx_spec.rb +4 -4
  69. data/spec/unit/provider_spec.rb +1 -3
  70. data/spec/unit/recipe_spec.rb +0 -4
  71. data/spec/unit/registry_helper_spec.rb +15 -1
  72. data/spec/unit/resource/file/verification_spec.rb +33 -5
  73. data/spec/unit/resource/{powershell_spec.rb → powershell_script_spec.rb} +0 -0
  74. data/spec/unit/resource_spec.rb +2 -2
  75. data/spec/unit/run_context/child_run_context_spec.rb +133 -0
  76. data/spec/unit/run_context_spec.rb +7 -0
  77. metadata +25 -25
  78. data/spec/unit/workstation_config_loader_spec.rb +0 -283
@@ -0,0 +1,968 @@
1
+ require 'support/shared/integration/integration_helper'
2
+
3
+ describe "Chef::Resource.property" do
4
+ include IntegrationSupport
5
+
6
+ module Namer
7
+ @i = 0
8
+ def self.next_resource_name
9
+ "chef_resource_property_spec_#{@i += 1}"
10
+ end
11
+ def self.reset_index
12
+ @current_index = 0
13
+ end
14
+ def self.current_index
15
+ @current_index
16
+ end
17
+ def self.next_index
18
+ @current_index += 1
19
+ end
20
+ end
21
+
22
+ def lazy(&block)
23
+ Chef::DelayedEvaluator.new(&block)
24
+ end
25
+
26
+ before do
27
+ Namer.reset_index
28
+ end
29
+
30
+ def self.new_resource_name
31
+ Namer.next_resource_name
32
+ end
33
+
34
+ let(:resource_class) do
35
+ new_resource_name = self.class.new_resource_name
36
+ Class.new(Chef::Resource) do
37
+ resource_name new_resource_name
38
+ def next_index
39
+ Namer.next_index
40
+ end
41
+ end
42
+ end
43
+
44
+ let(:resource) do
45
+ resource_class.new("blah")
46
+ end
47
+
48
+ def self.english_join(values)
49
+ return '<nothing>' if values.size == 0
50
+ return values[0].inspect if values.size == 1
51
+ "#{values[0..-2].map { |v| v.inspect }.join(", ")} and #{values[-1].inspect}"
52
+ end
53
+
54
+ def self.with_property(*properties, &block)
55
+ tags_index = properties.find_index { |p| !p.is_a?(String)}
56
+ if tags_index
57
+ properties, tags = properties[0..tags_index-1], properties[tags_index..-1]
58
+ else
59
+ tags = []
60
+ end
61
+ if properties.size == 1
62
+ description = "With property #{properties.first}"
63
+ else
64
+ description = "With properties #{english_join(properties.map { |property| "#{property.inspect}" })}"
65
+ end
66
+ context description, *tags do
67
+ before do
68
+ properties.each do |property_str|
69
+ resource_class.class_eval("property #{property_str}", __FILE__, __LINE__)
70
+ end
71
+ end
72
+ instance_eval(&block)
73
+ end
74
+ end
75
+
76
+ # Basic properties
77
+ with_property ':bare_property' do
78
+ it "can be set" do
79
+ expect(resource.bare_property 10).to eq 10
80
+ expect(resource.bare_property).to eq 10
81
+ end
82
+ it "emits a deprecation warning and does a get, if set to nil" do
83
+ expect(resource.bare_property 10).to eq 10
84
+ expect { resource.bare_property nil }.to raise_error Chef::Exceptions::DeprecatedFeatureError
85
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
86
+ expect(resource.bare_property nil).to eq 10
87
+ expect(resource.bare_property).to eq 10
88
+ end
89
+ it "can be updated" do
90
+ expect(resource.bare_property 10).to eq 10
91
+ expect(resource.bare_property 20).to eq 20
92
+ expect(resource.bare_property).to eq 20
93
+ end
94
+ it "can be set with =" do
95
+ expect(resource.bare_property 10).to eq 10
96
+ expect(resource.bare_property).to eq 10
97
+ end
98
+ it "can be set to nil with =" do
99
+ expect(resource.bare_property 10).to eq 10
100
+ expect(resource.bare_property = nil).to be_nil
101
+ expect(resource.bare_property).to be_nil
102
+ end
103
+ it "can be updated with =" do
104
+ expect(resource.bare_property 10).to eq 10
105
+ expect(resource.bare_property = 20).to eq 20
106
+ expect(resource.bare_property).to eq 20
107
+ end
108
+ end
109
+
110
+ with_property ":x, Integer" do
111
+ context "and subclass" do
112
+ let(:subresource_class) do
113
+ new_resource_name = self.class.new_resource_name
114
+ Class.new(resource_class) do
115
+ resource_name new_resource_name
116
+ end
117
+ end
118
+ let(:subresource) do
119
+ subresource_class.new('blah')
120
+ end
121
+
122
+ it "x is inherited" do
123
+ expect(subresource.x 10).to eq 10
124
+ expect(subresource.x).to eq 10
125
+ expect(subresource.x = 20).to eq 20
126
+ expect(subresource.x).to eq 20
127
+ expect(subresource_class.properties[:x]).not_to be_nil
128
+ end
129
+
130
+ it "x's validation is inherited" do
131
+ expect { subresource.x 'ohno' }.to raise_error Chef::Exceptions::ValidationFailed
132
+ end
133
+
134
+ context "with property :y on the subclass" do
135
+ before do
136
+ subresource_class.class_eval do
137
+ property :y
138
+ end
139
+ end
140
+
141
+ it "x is still there" do
142
+ expect(subresource.x 10).to eq 10
143
+ expect(subresource.x).to eq 10
144
+ expect(subresource.x = 20).to eq 20
145
+ expect(subresource.x).to eq 20
146
+ expect(subresource_class.properties[:x]).not_to be_nil
147
+ end
148
+ it "y is there" do
149
+ expect(subresource.y 10).to eq 10
150
+ expect(subresource.y).to eq 10
151
+ expect(subresource.y = 20).to eq 20
152
+ expect(subresource.y).to eq 20
153
+ expect(subresource_class.properties[:y]).not_to be_nil
154
+ end
155
+ it "y is not on the superclass" do
156
+ expect { resource_class.y 10 }.to raise_error
157
+ expect(resource_class.properties[:y]).to be_nil
158
+ end
159
+ end
160
+
161
+ context "with property :x on the subclass" do
162
+ before do
163
+ subresource_class.class_eval do
164
+ property :x
165
+ end
166
+ end
167
+
168
+ it "x is still there" do
169
+ expect(subresource.x 10).to eq 10
170
+ expect(subresource.x).to eq 10
171
+ expect(subresource.x = 20).to eq 20
172
+ expect(subresource.x).to eq 20
173
+ expect(subresource_class.properties[:x]).not_to be_nil
174
+ expect(subresource_class.properties[:x]).not_to eq resource_class.properties[:x]
175
+ end
176
+
177
+ it "x's validation is inherited" do
178
+ expect { subresource.x 'ohno' }.to raise_error Chef::Exceptions::ValidationFailed
179
+ end
180
+ end
181
+
182
+ context "with property :x, default: 80 on the subclass" do
183
+ before do
184
+ subresource_class.class_eval do
185
+ property :x, default: 80
186
+ end
187
+ end
188
+
189
+ it "x is still there" do
190
+ expect(subresource.x 10).to eq 10
191
+ expect(subresource.x).to eq 10
192
+ expect(subresource.x = 20).to eq 20
193
+ expect(subresource.x).to eq 20
194
+ expect(subresource_class.properties[:x]).not_to be_nil
195
+ expect(subresource_class.properties[:x]).not_to eq resource_class.properties[:x]
196
+ end
197
+
198
+ it "x defaults to 80" do
199
+ expect(subresource.x).to eq 80
200
+ end
201
+
202
+ it "x's validation is inherited" do
203
+ expect { subresource.x 'ohno' }.to raise_error Chef::Exceptions::ValidationFailed
204
+ end
205
+ end
206
+
207
+ context "with property :x, String on the subclass" do
208
+ before do
209
+ subresource_class.class_eval do
210
+ property :x, String
211
+ end
212
+ end
213
+
214
+ it "x is still there" do
215
+ expect(subresource.x "10").to eq "10"
216
+ expect(subresource.x).to eq "10"
217
+ expect(subresource.x = "20").to eq "20"
218
+ expect(subresource.x).to eq "20"
219
+ expect(subresource_class.properties[:x]).not_to be_nil
220
+ expect(subresource_class.properties[:x]).not_to eq resource_class.properties[:x]
221
+ end
222
+
223
+ it "x's validation is overwritten" do
224
+ expect { subresource.x 10 }.to raise_error Chef::Exceptions::ValidationFailed
225
+ expect(subresource.x 'ohno').to eq 'ohno'
226
+ expect(subresource.x).to eq 'ohno'
227
+ end
228
+
229
+ it "the superclass's validation for x is still there" do
230
+ expect { resource.x 'ohno' }.to raise_error Chef::Exceptions::ValidationFailed
231
+ expect(resource.x 10).to eq 10
232
+ expect(resource.x).to eq 10
233
+ end
234
+ end
235
+ end
236
+ end
237
+
238
+ context "Chef::Resource::Property#reset_property" do
239
+ it "when a resource is newly created, reset_property(:name) sets property to nil" do
240
+ expect(resource.property_is_set?(:name)).to be_truthy
241
+ resource.reset_property(:name)
242
+ expect(resource.property_is_set?(:name)).to be_falsey
243
+ expect(resource.name).to be_nil
244
+ end
245
+
246
+ it "when referencing an undefined property, reset_property(:x) raises an error" do
247
+ expect { resource.reset_property(:x) }.to raise_error(ArgumentError)
248
+ end
249
+
250
+ with_property ':x' do
251
+ it "when the resource is newly created, reset_property(:x) does nothing" do
252
+ expect(resource.property_is_set?(:x)).to be_falsey
253
+ resource.reset_property(:x)
254
+ expect(resource.property_is_set?(:x)).to be_falsey
255
+ expect(resource.x).to be_nil
256
+ end
257
+ it "when x is set, reset_property resets it" do
258
+ resource.x 10
259
+ expect(resource.property_is_set?(:x)).to be_truthy
260
+ resource.reset_property(:x)
261
+ expect(resource.property_is_set?(:x)).to be_falsey
262
+ expect(resource.x).to be_nil
263
+ end
264
+ end
265
+
266
+ with_property ':x, Integer' do
267
+ it "when the resource is newly created, reset_property(:x) does nothing" do
268
+ expect(resource.property_is_set?(:x)).to be_falsey
269
+ resource.reset_property(:x)
270
+ expect(resource.property_is_set?(:x)).to be_falsey
271
+ expect(resource.x).to be_nil
272
+ end
273
+ it "when x is set, reset_property resets it even though `nil` is technically invalid" do
274
+ resource.x 10
275
+ expect(resource.property_is_set?(:x)).to be_truthy
276
+ resource.reset_property(:x)
277
+ expect(resource.property_is_set?(:x)).to be_falsey
278
+ expect(resource.x).to be_nil
279
+ end
280
+ end
281
+
282
+ with_property ':x, default: 10' do
283
+ it "when the resource is newly created, reset_property(:x) does nothing" do
284
+ expect(resource.property_is_set?(:x)).to be_falsey
285
+ resource.reset_property(:x)
286
+ expect(resource.property_is_set?(:x)).to be_falsey
287
+ expect(resource.x).to eq 10
288
+ end
289
+ it "when x is set, reset_property resets it and it returns the default" do
290
+ resource.x 20
291
+ resource.reset_property(:x)
292
+ expect(resource.property_is_set?(:x)).to be_falsey
293
+ expect(resource.x).to eq 10
294
+ end
295
+ end
296
+
297
+ with_property ':x, default: lazy { 10 }' do
298
+ it "when the resource is newly created, reset_property(:x) does nothing" do
299
+ expect(resource.property_is_set?(:x)).to be_falsey
300
+ resource.reset_property(:x)
301
+ expect(resource.property_is_set?(:x)).to be_falsey
302
+ expect(resource.x).to eq 10
303
+ end
304
+ it "when x is set, reset_property resets it and it returns the default" do
305
+ resource.x 20
306
+ resource.reset_property(:x)
307
+ expect(resource.property_is_set?(:x)).to be_falsey
308
+ expect(resource.x).to eq 10
309
+ end
310
+ end
311
+ end
312
+
313
+ context "Chef::Resource::Property#property_is_set?" do
314
+ it "when a resource is newly created, property_is_set?(:name) is true" do
315
+ expect(resource.property_is_set?(:name)).to be_truthy
316
+ end
317
+
318
+ it "when referencing an undefined property, property_is_set?(:x) raises an error" do
319
+ expect { resource.property_is_set?(:x) }.to raise_error(ArgumentError)
320
+ end
321
+
322
+ with_property ':x' do
323
+ it "when the resource is newly created, property_is_set?(:x) is false" do
324
+ expect(resource.property_is_set?(:x)).to be_falsey
325
+ end
326
+ it "when x is set, property_is_set?(:x) is true" do
327
+ resource.x 10
328
+ expect(resource.property_is_set?(:x)).to be_truthy
329
+ end
330
+ it "when x is set with =, property_is_set?(:x) is true" do
331
+ resource.x = 10
332
+ expect(resource.property_is_set?(:x)).to be_truthy
333
+ end
334
+ it "when x is set to a lazy value, property_is_set?(:x) is true" do
335
+ resource.x lazy { 10 }
336
+ expect(resource.property_is_set?(:x)).to be_truthy
337
+ end
338
+ it "when x is retrieved, property_is_set?(:x) is false" do
339
+ resource.x
340
+ expect(resource.property_is_set?(:x)).to be_falsey
341
+ end
342
+ end
343
+
344
+ with_property ':x, default: 10' do
345
+ it "when the resource is newly created, property_is_set?(:x) is false" do
346
+ expect(resource.property_is_set?(:x)).to be_falsey
347
+ end
348
+ it "when x is set, property_is_set?(:x) is true" do
349
+ resource.x 10
350
+ expect(resource.property_is_set?(:x)).to be_truthy
351
+ end
352
+ it "when x is set with =, property_is_set?(:x) is true" do
353
+ resource.x = 10
354
+ expect(resource.property_is_set?(:x)).to be_truthy
355
+ end
356
+ it "when x is set to a lazy value, property_is_set?(:x) is true" do
357
+ resource.x lazy { 10 }
358
+ expect(resource.property_is_set?(:x)).to be_truthy
359
+ end
360
+ it "when x is retrieved, property_is_set?(:x) is false" do
361
+ resource.x
362
+ expect(resource.property_is_set?(:x)).to be_falsey
363
+ end
364
+ end
365
+
366
+ with_property ':x, default: nil' do
367
+ it "when the resource is newly created, property_is_set?(:x) is false" do
368
+ expect(resource.property_is_set?(:x)).to be_falsey
369
+ end
370
+ it "when x is set, property_is_set?(:x) is true" do
371
+ resource.x 10
372
+ expect(resource.property_is_set?(:x)).to be_truthy
373
+ end
374
+ it "when x is set with =, property_is_set?(:x) is true" do
375
+ resource.x = 10
376
+ expect(resource.property_is_set?(:x)).to be_truthy
377
+ end
378
+ it "when x is set to a lazy value, property_is_set?(:x) is true" do
379
+ resource.x lazy { 10 }
380
+ expect(resource.property_is_set?(:x)).to be_truthy
381
+ end
382
+ it "when x is retrieved, property_is_set?(:x) is false" do
383
+ resource.x
384
+ expect(resource.property_is_set?(:x)).to be_falsey
385
+ end
386
+ end
387
+
388
+ with_property ':x, default: lazy { 10 }' do
389
+ it "when the resource is newly created, property_is_set?(:x) is false" do
390
+ expect(resource.property_is_set?(:x)).to be_falsey
391
+ end
392
+ it "when x is set, property_is_set?(:x) is true" do
393
+ resource.x 10
394
+ expect(resource.property_is_set?(:x)).to be_truthy
395
+ end
396
+ it "when x is set with =, property_is_set?(:x) is true" do
397
+ resource.x = 10
398
+ expect(resource.property_is_set?(:x)).to be_truthy
399
+ end
400
+ it "when x is retrieved, property_is_set?(:x) is false" do
401
+ resource.x
402
+ expect(resource.property_is_set?(:x)).to be_falsey
403
+ end
404
+ end
405
+ end
406
+
407
+ context "Chef::Resource::Property#default" do
408
+ with_property ':x, default: 10' do
409
+ it "when x is set, it returns its value" do
410
+ expect(resource.x 20).to eq 20
411
+ expect(resource.property_is_set?(:x)).to be_truthy
412
+ expect(resource.x).to eq 20
413
+ end
414
+ it "when x is not set, it returns 10" do
415
+ expect(resource.x).to eq 10
416
+ end
417
+ it "when x is not set, it is not included in state" do
418
+ expect(resource.state_for_resource_reporter).to eq({})
419
+ end
420
+ it "when x is set to nil, it returns nil" do
421
+ resource.instance_eval { @x = nil }
422
+ expect(resource.x).to be_nil
423
+ end
424
+
425
+ context "With a subclass" do
426
+ let(:subresource_class) do
427
+ new_resource_name = self.class.new_resource_name
428
+ Class.new(resource_class) do
429
+ resource_name new_resource_name
430
+ end
431
+ end
432
+ let(:subresource) { subresource_class.new('blah') }
433
+ it "The default is inherited" do
434
+ expect(subresource.x).to eq 10
435
+ end
436
+ end
437
+ end
438
+
439
+ with_property ':x, default: 10, identity: true' do
440
+ it "when x is not set, it is included in identity" do
441
+ expect(resource.identity).to eq(10)
442
+ end
443
+ end
444
+
445
+ with_property ':x, default: 1, identity: true', ':y, default: 2, identity: true' do
446
+ it "when x is not set, it is still included in identity" do
447
+ resource.y 20
448
+ expect(resource.identity).to eq(x: 1, y: 20)
449
+ end
450
+ end
451
+
452
+ with_property ':x, default: nil' do
453
+ it "when x is not set, it returns nil" do
454
+ expect(resource.x).to be_nil
455
+ end
456
+ end
457
+
458
+ with_property ':x' do
459
+ it "when x is not set, it returns nil" do
460
+ expect(resource.x).to be_nil
461
+ end
462
+ end
463
+
464
+ context "hash default" do
465
+ with_property ':x, default: {}' do
466
+ it "when x is not set, it returns {}" do
467
+ expect(resource.x).to eq({})
468
+ end
469
+ it "The same exact value is returned multiple times in a row" do
470
+ value = resource.x
471
+ expect(value).to eq({})
472
+ expect(resource.x.object_id).to eq(value.object_id)
473
+ end
474
+ it "Multiple instances of x receive the exact same value" do
475
+ expect(resource.x.object_id).to eq(resource_class.new('blah2').x.object_id)
476
+ end
477
+ it "The default value is frozen" do
478
+ expect(resource.x).to be_frozen
479
+ end
480
+ it "The default value cannot be written to" do
481
+ expect { resource.x[:a] = 1 }.to raise_error RuntimeError, /frozen/
482
+ end
483
+ end
484
+
485
+ with_property ':x, default: lazy { {} }' do
486
+ it "when x is not set, it returns {}" do
487
+ expect(resource.x).to eq({})
488
+ end
489
+ # it "The value is different each time it is called" do
490
+ # value = resource.x
491
+ # expect(value).to eq({})
492
+ # expect(resource.x.object_id).not_to eq(value.object_id)
493
+ # end
494
+ it "Multiple instances of x receive different values" do
495
+ expect(resource.x.object_id).not_to eq(resource_class.new('blah2').x.object_id)
496
+ end
497
+ end
498
+ end
499
+
500
+ context "with a class with 'blah' as both class and instance methods" do
501
+ before do
502
+ resource_class.class_eval do
503
+ def self.blah
504
+ 'class'
505
+ end
506
+ def blah
507
+ "#{name}#{next_index}"
508
+ end
509
+ end
510
+ end
511
+
512
+ with_property ':x, default: lazy { blah }' do
513
+ it "x is run in context of the instance" do
514
+ expect(resource.x).to eq "blah1"
515
+ end
516
+ it "x is run in the context of each instance it is run in" do
517
+ expect(resource.x).to eq "blah1"
518
+ expect(resource_class.new('another').x).to eq "another2"
519
+ # expect(resource.x).to eq "blah3"
520
+ end
521
+ end
522
+
523
+ with_property ':x, default: lazy { |x| "#{blah}#{x.blah}" }' do
524
+ it "x is run in context of the class (where it was defined) and passed the instance" do
525
+ expect(resource.x).to eq "classblah1"
526
+ end
527
+ it "x is passed the value of each instance it is run in" do
528
+ expect(resource.x).to eq "classblah1"
529
+ expect(resource_class.new('another').x).to eq "classanother2"
530
+ # expect(resource.x).to eq "classblah3"
531
+ end
532
+ end
533
+ end
534
+
535
+ context "validation of defaults" do
536
+ with_property ':x, String, default: 10' do
537
+ it "when the resource is created, no error is raised" do
538
+ resource
539
+ end
540
+ it "when x is set, no error is raised" do
541
+ expect(resource.x 'hi').to eq 'hi'
542
+ expect(resource.x).to eq 'hi'
543
+ end
544
+ it "when x is retrieved, no validation error is raised" do
545
+ expect(resource.x).to eq 10
546
+ end
547
+ # it "when x is retrieved, a validation error is raised" do
548
+ # expect { resource.x }.to raise_error Chef::Exceptions::ValidationFailed
549
+ # end
550
+ end
551
+
552
+ with_property ":x, String, default: lazy { Namer.next_index }" do
553
+ it "when the resource is created, no error is raised" do
554
+ resource
555
+ end
556
+ it "when x is set, no error is raised" do
557
+ expect(resource.x 'hi').to eq 'hi'
558
+ expect(resource.x).to eq 'hi'
559
+ end
560
+ it "when x is retrieved, no validation error is raised" do
561
+ expect(resource.x).to eq 1
562
+ expect(Namer.current_index).to eq 1
563
+ end
564
+ # it "when x is retrieved, a validation error is raised" do
565
+ # expect { resource.x }.to raise_error Chef::Exceptions::ValidationFailed
566
+ # expect(Namer.current_index).to eq 1
567
+ # end
568
+ end
569
+
570
+ with_property ":x, default: lazy { Namer.next_index.to_s }, is: proc { |v| Namer.next_index; true }" do
571
+ it "validation is not run at all on the default value" do
572
+ expect(resource.x).to eq '1'
573
+ expect(Namer.current_index).to eq 1
574
+ end
575
+ # it "validation is run each time" do
576
+ # expect(resource.x).to eq '1'
577
+ # expect(Namer.current_index).to eq 2
578
+ # expect(resource.x).to eq '1'
579
+ # expect(Namer.current_index).to eq 2
580
+ # end
581
+ end
582
+
583
+ with_property ":x, default: lazy { Namer.next_index.to_s.freeze }, is: proc { |v| Namer.next_index; true }" do
584
+ it "validation is not run at all on the default value" do
585
+ expect(resource.x).to eq '1'
586
+ expect(Namer.current_index).to eq 1
587
+ end
588
+ # it "validation is only run the first time" do
589
+ # expect(resource.x).to eq '1'
590
+ # expect(Namer.current_index).to eq 2
591
+ # expect(resource.x).to eq '1'
592
+ # expect(Namer.current_index).to eq 2
593
+ # end
594
+ end
595
+ end
596
+
597
+ context "coercion of defaults" do
598
+ # Frozen default, non-frozen coerce
599
+ with_property ':x, coerce: proc { |v| "#{v}#{next_index}" }, default: 10' do
600
+ it "when the resource is created, the proc is not yet run" do
601
+ resource
602
+ expect(Namer.current_index).to eq 0
603
+ end
604
+ it "when x is set, coercion is run" do
605
+ expect(resource.x 'hi').to eq 'hi1'
606
+ expect(resource.x).to eq 'hi1'
607
+ expect(Namer.current_index).to eq 1
608
+ end
609
+ it "when x is retrieved, coercion is run exactly once" do
610
+ expect(resource.x).to eq '101'
611
+ expect(resource.x).to eq '101'
612
+ expect(Namer.current_index).to eq 1
613
+ end
614
+ end
615
+
616
+ # Frozen default, frozen coerce
617
+ with_property ':x, coerce: proc { |v| "#{v}#{next_index}".freeze }, default: 10' do
618
+ it "when the resource is created, the proc is not yet run" do
619
+ resource
620
+ expect(Namer.current_index).to eq 0
621
+ end
622
+ it "when x is set, coercion is run" do
623
+ expect(resource.x 'hi').to eq 'hi1'
624
+ expect(resource.x).to eq 'hi1'
625
+ expect(Namer.current_index).to eq 1
626
+ end
627
+ it "when x is retrieved, coercion is run each time" do
628
+ expect(resource.x).to eq '101'
629
+ expect(resource.x).to eq '102'
630
+ expect(Namer.current_index).to eq 2
631
+ end
632
+ end
633
+
634
+ # Frozen lazy default, non-frozen coerce
635
+ with_property ':x, coerce: proc { |v| "#{v}#{next_index}" }, default: lazy { 10 }' do
636
+ it "when the resource is created, the proc is not yet run" do
637
+ resource
638
+ expect(Namer.current_index).to eq 0
639
+ end
640
+ it "when x is set, coercion is run" do
641
+ expect(resource.x 'hi').to eq 'hi1'
642
+ expect(resource.x).to eq 'hi1'
643
+ expect(Namer.current_index).to eq 1
644
+ end
645
+ it "when x is retrieved, coercion is run exactly once" do
646
+ expect(resource.x).to eq '101'
647
+ expect(resource.x).to eq '101'
648
+ expect(Namer.current_index).to eq 1
649
+ end
650
+ end
651
+
652
+ # Non-frozen lazy default, frozen coerce
653
+ with_property ':x, coerce: proc { |v| "#{v}#{next_index}".freeze }, default: lazy { "10" }' do
654
+ it "when the resource is created, the proc is not yet run" do
655
+ resource
656
+ expect(Namer.current_index).to eq 0
657
+ end
658
+ it "when x is set, coercion is run" do
659
+ expect(resource.x 'hi').to eq 'hi1'
660
+ expect(resource.x).to eq 'hi1'
661
+ expect(Namer.current_index).to eq 1
662
+ end
663
+ it "when x is retrieved, coercion is run each time" do
664
+ expect(resource.x).to eq '101'
665
+ expect(resource.x).to eq '102'
666
+ expect(Namer.current_index).to eq 2
667
+ end
668
+ end
669
+
670
+ with_property ':x, proc { |v| Namer.next_index; true }, coerce: proc { |v| "#{v}#{next_index}" }, default: lazy { 10 }' do
671
+ it "coercion is only run the first time x is retrieved, and validation is not run" do
672
+ expect(Namer.current_index).to eq 0
673
+ expect(resource.x).to eq '101'
674
+ expect(Namer.current_index).to eq 1
675
+ expect(resource.x).to eq '101'
676
+ expect(Namer.current_index).to eq 1
677
+ end
678
+ end
679
+
680
+ context "validation and coercion of defaults" do
681
+ with_property ':x, String, coerce: proc { |v| "#{v}#{next_index}" }, default: 10' do
682
+ it "when x is retrieved, it is coerced before validating and passes" do
683
+ expect(resource.x).to eq '101'
684
+ end
685
+ end
686
+ with_property ':x, Integer, coerce: proc { |v| "#{v}#{next_index}" }, default: 10' do
687
+ it "when x is retrieved, it is coerced and not validated" do
688
+ expect(resource.x).to eq '101'
689
+ end
690
+ # it "when x is retrieved, it is coerced before validating and fails" do
691
+ # expect { resource.x }.to raise_error Chef::Exceptions::ValidationFailed
692
+ # end
693
+ end
694
+ with_property ':x, String, coerce: proc { |v| "#{v}#{next_index}" }, default: lazy { 10 }' do
695
+ it "when x is retrieved, it is coerced before validating and passes" do
696
+ expect(resource.x).to eq '101'
697
+ end
698
+ end
699
+ with_property ':x, Integer, coerce: proc { |v| "#{v}#{next_index}" }, default: lazy { 10 }' do
700
+ it "when x is retrieved, it is coerced and not validated" do
701
+ expect(resource.x).to eq '101'
702
+ end
703
+ # it "when x is retrieved, it is coerced before validating and fails" do
704
+ # expect { resource.x }.to raise_error Chef::Exceptions::ValidationFailed
705
+ # end
706
+ end
707
+ with_property ':x, proc { |v| Namer.next_index; true }, coerce: proc { |v| "#{v}#{next_index}" }, default: lazy { 10 }' do
708
+ it "coercion is only run the first time x is retrieved, and validation is not run" do
709
+ expect(Namer.current_index).to eq 0
710
+ expect(resource.x).to eq '101'
711
+ expect(Namer.current_index).to eq 1
712
+ expect(resource.x).to eq '101'
713
+ expect(Namer.current_index).to eq 1
714
+ end
715
+ end
716
+ end
717
+ end
718
+ end
719
+
720
+ context "Chef::Resource#lazy" do
721
+ with_property ':x' do
722
+ it "setting x to a lazy value does not run it immediately" do
723
+ resource.x lazy { Namer.next_index }
724
+ expect(Namer.current_index).to eq 0
725
+ end
726
+ it "you can set x to a lazy value in the instance" do
727
+ resource.instance_eval do
728
+ x lazy { Namer.next_index }
729
+ end
730
+ expect(resource.x).to eq 1
731
+ expect(Namer.current_index).to eq 1
732
+ end
733
+ it "retrieving a lazy value pops it open" do
734
+ resource.x lazy { Namer.next_index }
735
+ expect(resource.x).to eq 1
736
+ expect(Namer.current_index).to eq 1
737
+ end
738
+ it "retrieving a lazy value twice evaluates it twice" do
739
+ resource.x lazy { Namer.next_index }
740
+ expect(resource.x).to eq 1
741
+ expect(resource.x).to eq 2
742
+ expect(Namer.current_index).to eq 2
743
+ end
744
+ it "setting the same lazy value on two different instances runs it on each instancee" do
745
+ resource2 = resource_class.new("blah2")
746
+ l = lazy { Namer.next_index }
747
+ resource.x l
748
+ resource2.x l
749
+ expect(resource2.x).to eq 1
750
+ expect(resource.x).to eq 2
751
+ expect(resource2.x).to eq 3
752
+ end
753
+
754
+ context "when the class has a class and instance method named blah" do
755
+ before do
756
+ resource_class.class_eval do
757
+ def self.blah
758
+ "class"
759
+ end
760
+ def blah
761
+ "#{name}#{Namer.next_index}"
762
+ end
763
+ end
764
+ end
765
+ def blah
766
+ "example"
767
+ end
768
+ # it "retrieving lazy { blah } gets the instance variable" do
769
+ # resource.x lazy { blah }
770
+ # expect(resource.x).to eq "blah1"
771
+ # end
772
+ # it "retrieving lazy { blah } from two different instances gets two different instance variables" do
773
+ # resource2 = resource_class.new("another")
774
+ # l = lazy { blah }
775
+ # resource2.x l
776
+ # resource.x l
777
+ # expect(resource2.x).to eq "another1"
778
+ # expect(resource.x).to eq "blah2"
779
+ # expect(resource2.x).to eq "another3"
780
+ # end
781
+ it 'retrieving lazy { |x| "#{blah}#{x.blah}" } gets the example and instance variables' do
782
+ resource.x lazy { |x| "#{blah}#{x.blah}" }
783
+ expect(resource.x).to eq "exampleblah1"
784
+ end
785
+ it 'retrieving lazy { |x| "#{blah}#{x.blah}" } from two different instances gets two different instance variables' do
786
+ resource2 = resource_class.new("another")
787
+ l = lazy { |x| "#{blah}#{x.blah}" }
788
+ resource2.x l
789
+ resource.x l
790
+ expect(resource2.x).to eq "exampleanother1"
791
+ expect(resource.x).to eq "exampleblah2"
792
+ expect(resource2.x).to eq "exampleanother3"
793
+ end
794
+ end
795
+ end
796
+
797
+ with_property ':x, coerce: proc { |v| "#{v}#{Namer.next_index}" }' do
798
+ it "lazy values are not coerced on set" do
799
+ resource.x lazy { Namer.next_index }
800
+ expect(Namer.current_index).to eq 0
801
+ end
802
+ it "lazy values are coerced on get" do
803
+ resource.x lazy { Namer.next_index }
804
+ expect(resource.x).to eq "12"
805
+ expect(Namer.current_index).to eq 2
806
+ end
807
+ it "lazy values are coerced on each access" do
808
+ resource.x lazy { Namer.next_index }
809
+ expect(resource.x).to eq "12"
810
+ expect(Namer.current_index).to eq 2
811
+ expect(resource.x).to eq "34"
812
+ expect(Namer.current_index).to eq 4
813
+ end
814
+ end
815
+
816
+ with_property ':x, String' do
817
+ it "lazy values are not validated on set" do
818
+ resource.x lazy { Namer.next_index }
819
+ expect(Namer.current_index).to eq 0
820
+ end
821
+ it "lazy values are validated on get" do
822
+ resource.x lazy { Namer.next_index }
823
+ expect { resource.x }.to raise_error Chef::Exceptions::ValidationFailed
824
+ expect(Namer.current_index).to eq 1
825
+ end
826
+ end
827
+
828
+ with_property ':x, is: proc { |v| Namer.next_index; true }' do
829
+ it "lazy values are validated on each access" do
830
+ resource.x lazy { Namer.next_index }
831
+ expect(resource.x).to eq 1
832
+ expect(Namer.current_index).to eq 2
833
+ expect(resource.x).to eq 3
834
+ expect(Namer.current_index).to eq 4
835
+ end
836
+ end
837
+
838
+ with_property ':x, Integer, coerce: proc { |v| "#{v}#{Namer.next_index}" }' do
839
+ it "lazy values are not validated or coerced on set" do
840
+ resource.x lazy { Namer.next_index }
841
+ expect(Namer.current_index).to eq 0
842
+ end
843
+ it "lazy values are coerced before being validated, which fails" do
844
+ resource.x lazy { Namer.next_index }
845
+ expect(Namer.current_index).to eq 0
846
+ expect { resource.x }.to raise_error Chef::Exceptions::ValidationFailed
847
+ expect(Namer.current_index).to eq 2
848
+ end
849
+ end
850
+
851
+ with_property ':x, coerce: proc { |v| "#{v}#{Namer.next_index}" }, is: proc { |v| Namer.next_index; true }' do
852
+ it "lazy values are coerced and validated exactly once" do
853
+ resource.x lazy { Namer.next_index }
854
+ expect(resource.x).to eq "12"
855
+ expect(Namer.current_index).to eq 3
856
+ expect(resource.x).to eq "45"
857
+ expect(Namer.current_index).to eq 6
858
+ end
859
+ end
860
+
861
+ with_property ':x, String, coerce: proc { |v| "#{v}#{Namer.next_index}" }' do
862
+ it "lazy values are coerced before being validated, which succeeds" do
863
+ resource.x lazy { Namer.next_index }
864
+ expect(resource.x).to eq "12"
865
+ expect(Namer.current_index).to eq 2
866
+ end
867
+ end
868
+ end
869
+
870
+ context "Chef::Resource::Property#coerce" do
871
+ with_property ':x, coerce: proc { |v| "#{v}#{Namer.next_index}" }' do
872
+ it "coercion runs on set" do
873
+ expect(resource.x 10).to eq "101"
874
+ expect(Namer.current_index).to eq 1
875
+ end
876
+ it "coercion sets the value (and coercion does not run on get)" do
877
+ expect(resource.x 10).to eq "101"
878
+ expect(resource.x).to eq "101"
879
+ expect(Namer.current_index).to eq 1
880
+ end
881
+ it "coercion runs each time set happens" do
882
+ expect(resource.x 10).to eq "101"
883
+ expect(Namer.current_index).to eq 1
884
+ expect(resource.x 10).to eq "102"
885
+ expect(Namer.current_index).to eq 2
886
+ end
887
+ end
888
+ with_property ':x, coerce: proc { |x| Namer.next_index; raise "hi" if x == 10; x }, is: proc { |x| Namer.next_index; x != 10 }' do
889
+ it "failed coercion fails to set the value" do
890
+ resource.x 20
891
+ expect(resource.x).to eq 20
892
+ expect(Namer.current_index).to eq 2
893
+ expect { resource.x 10 }.to raise_error 'hi'
894
+ expect(resource.x).to eq 20
895
+ expect(Namer.current_index).to eq 3
896
+ end
897
+ it "validation does not run if coercion fails" do
898
+ expect { resource.x 10 }.to raise_error 'hi'
899
+ expect(Namer.current_index).to eq 1
900
+ end
901
+ end
902
+ end
903
+
904
+ context "Chef::Resource::Property validation" do
905
+ with_property ':x, is: proc { |v| Namer.next_index; v.is_a?(Integer) }' do
906
+ it "validation runs on set" do
907
+ expect(resource.x 10).to eq 10
908
+ expect(Namer.current_index).to eq 1
909
+ end
910
+ it "validation sets the value (and validation does not run on get)" do
911
+ expect(resource.x 10).to eq 10
912
+ expect(resource.x).to eq 10
913
+ expect(Namer.current_index).to eq 1
914
+ end
915
+ it "validation runs each time set happens" do
916
+ expect(resource.x 10).to eq 10
917
+ expect(Namer.current_index).to eq 1
918
+ expect(resource.x 10).to eq 10
919
+ expect(Namer.current_index).to eq 2
920
+ end
921
+ it "failed validation fails to set the value" do
922
+ expect(resource.x 10).to eq 10
923
+ expect(Namer.current_index).to eq 1
924
+ expect { resource.x 'blah' }.to raise_error Chef::Exceptions::ValidationFailed
925
+ expect(resource.x).to eq 10
926
+ expect(Namer.current_index).to eq 2
927
+ end
928
+ end
929
+ end
930
+
931
+ [ 'name_attribute', 'name_property' ].each do |name|
932
+ context "Chef::Resource::Property##{name}" do
933
+ with_property ":x, #{name}: true" do
934
+ it "defaults x to resource.name" do
935
+ expect(resource.x).to eq 'blah'
936
+ end
937
+ it "does not pick up resource.name if set" do
938
+ expect(resource.x 10).to eq 10
939
+ expect(resource.x).to eq 10
940
+ end
941
+ it "binds to the latest resource.name when run" do
942
+ resource.name 'foo'
943
+ expect(resource.x).to eq 'foo'
944
+ end
945
+ it "caches resource.name" do
946
+ expect(resource.x).to eq 'blah'
947
+ resource.name 'foo'
948
+ expect(resource.x).to eq 'blah'
949
+ end
950
+ end
951
+ with_property ":x, default: 10, #{name}: true" do
952
+ it "chooses default over #{name}" do
953
+ expect(resource.x).to eq 10
954
+ end
955
+ end
956
+ with_property ":x, #{name}: true, default: 10" do
957
+ it "chooses default over #{name}" do
958
+ expect(resource.x).to eq 10
959
+ end
960
+ end
961
+ with_property ":x, #{name}: true, required: true" do
962
+ it "defaults x to resource.name" do
963
+ expect(resource.x).to eq 'blah'
964
+ end
965
+ end
966
+ end
967
+ end
968
+ end