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.
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