cheffish 1.5.0 → 1.6.0

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/Gemfile +10 -0
  3. data/LICENSE +201 -201
  4. data/README.md +120 -120
  5. data/Rakefile +23 -23
  6. data/cheffish.gemspec +26 -0
  7. data/lib/chef/provider/chef_acl.rb +446 -439
  8. data/lib/chef/provider/chef_client.rb +53 -53
  9. data/lib/chef/provider/chef_container.rb +55 -55
  10. data/lib/chef/provider/chef_data_bag.rb +55 -55
  11. data/lib/chef/provider/chef_data_bag_item.rb +278 -278
  12. data/lib/chef/provider/chef_environment.rb +83 -83
  13. data/lib/chef/provider/chef_group.rb +83 -83
  14. data/lib/chef/provider/chef_mirror.rb +169 -169
  15. data/lib/chef/provider/chef_node.rb +87 -87
  16. data/lib/chef/provider/chef_organization.rb +155 -155
  17. data/lib/chef/provider/chef_resolved_cookbooks.rb +46 -46
  18. data/lib/chef/provider/chef_role.rb +84 -84
  19. data/lib/chef/provider/chef_user.rb +59 -59
  20. data/lib/chef/provider/private_key.rb +225 -225
  21. data/lib/chef/provider/public_key.rb +88 -88
  22. data/lib/chef/resource/chef_acl.rb +69 -69
  23. data/lib/chef/resource/chef_client.rb +48 -48
  24. data/lib/chef/resource/chef_container.rb +22 -22
  25. data/lib/chef/resource/chef_data_bag.rb +22 -22
  26. data/lib/chef/resource/chef_data_bag_item.rb +121 -121
  27. data/lib/chef/resource/chef_environment.rb +77 -77
  28. data/lib/chef/resource/chef_group.rb +53 -53
  29. data/lib/chef/resource/chef_mirror.rb +52 -52
  30. data/lib/chef/resource/chef_node.rb +22 -22
  31. data/lib/chef/resource/chef_organization.rb +69 -69
  32. data/lib/chef/resource/chef_resolved_cookbooks.rb +35 -35
  33. data/lib/chef/resource/chef_role.rb +110 -110
  34. data/lib/chef/resource/chef_user.rb +56 -56
  35. data/lib/chef/resource/private_key.rb +48 -48
  36. data/lib/chef/resource/public_key.rb +25 -25
  37. data/lib/cheffish.rb +235 -235
  38. data/lib/cheffish/actor_provider_base.rb +131 -131
  39. data/lib/cheffish/basic_chef_client.rb +184 -184
  40. data/lib/cheffish/chef_provider_base.rb +246 -246
  41. data/lib/cheffish/chef_run.rb +162 -162
  42. data/lib/cheffish/chef_run_data.rb +19 -19
  43. data/lib/cheffish/chef_run_listener.rb +30 -30
  44. data/lib/cheffish/key_formatter.rb +113 -113
  45. data/lib/cheffish/merged_config.rb +98 -94
  46. data/lib/cheffish/recipe_dsl.rb +157 -157
  47. data/lib/cheffish/rspec.rb +8 -8
  48. data/lib/cheffish/rspec/chef_run_support.rb +83 -83
  49. data/lib/cheffish/rspec/matchers.rb +4 -4
  50. data/lib/cheffish/rspec/matchers/be_idempotent.rb +16 -16
  51. data/lib/cheffish/rspec/matchers/emit_no_warnings_or_errors.rb +15 -15
  52. data/lib/cheffish/rspec/matchers/have_updated.rb +37 -37
  53. data/lib/cheffish/rspec/matchers/partially_match.rb +63 -63
  54. data/lib/cheffish/rspec/recipe_run_wrapper.rb +78 -78
  55. data/lib/cheffish/rspec/repository_support.rb +108 -108
  56. data/lib/cheffish/server_api.rb +52 -52
  57. data/lib/cheffish/version.rb +3 -3
  58. data/lib/cheffish/with_pattern.rb +21 -21
  59. data/spec/functional/fingerprint_spec.rb +64 -64
  60. data/spec/functional/merged_config_spec.rb +19 -19
  61. data/spec/functional/server_api_spec.rb +13 -13
  62. data/spec/integration/chef_acl_spec.rb +892 -879
  63. data/spec/integration/chef_client_spec.rb +105 -105
  64. data/spec/integration/chef_container_spec.rb +33 -33
  65. data/spec/integration/chef_group_spec.rb +309 -309
  66. data/spec/integration/chef_mirror_spec.rb +491 -491
  67. data/spec/integration/chef_node_spec.rb +786 -786
  68. data/spec/integration/chef_organization_spec.rb +226 -226
  69. data/spec/integration/chef_role_spec.rb +78 -78
  70. data/spec/integration/chef_user_spec.rb +85 -85
  71. data/spec/integration/private_key_spec.rb +399 -399
  72. data/spec/integration/recipe_dsl_spec.rb +28 -28
  73. data/spec/integration/rspec/converge_spec.rb +183 -183
  74. data/spec/support/key_support.rb +29 -29
  75. data/spec/support/spec_support.rb +15 -15
  76. data/spec/unit/get_private_key_spec.rb +131 -131
  77. data/spec/unit/recipe_run_wrapper_spec.rb +37 -37
  78. metadata +7 -5
@@ -1,786 +1,786 @@
1
- require 'support/spec_support'
2
- require 'cheffish/rspec/chef_run_support'
3
- require 'chef/resource/chef_node'
4
- require 'chef/provider/chef_node'
5
-
6
- describe Chef::Resource::ChefNode do
7
- extend Cheffish::RSpec::ChefRunSupport
8
-
9
- when_the_chef_12_server 'is in multi-org mode' do
10
- organization 'foo'
11
-
12
- before :each do
13
- Chef::Config.chef_server_url = URI.join(Chef::Config.chef_server_url, '/organizations/foo').to_s
14
- end
15
-
16
- context 'and is empty' do
17
- context 'and we run a recipe that creates node "blah"' do
18
- it 'the node gets created' do
19
- expect_recipe {
20
- chef_node 'blah'
21
- }.to have_updated 'chef_node[blah]', :create
22
- expect(get('nodes/blah')['name']).to eq('blah')
23
- end
24
- end
25
-
26
- # TODO why-run mode
27
-
28
- context 'and another chef server is running on port 8899' do
29
- before :each do
30
- @server = ChefZero::Server.new(:port => 8899)
31
- @server.start_background
32
- end
33
-
34
- after :each do
35
- @server.stop
36
- end
37
-
38
- context 'and a recipe is run that creates node "blah" on the second chef server using with_chef_server' do
39
-
40
- it 'the node is created on the second chef server but not the first' do
41
- expect_recipe {
42
- with_chef_server 'http://127.0.0.1:8899'
43
- chef_node 'blah'
44
- }.to have_updated 'chef_node[blah]', :create
45
- expect { get('nodes/blah') }.to raise_error(Net::HTTPServerException)
46
- expect(get('http://127.0.0.1:8899/nodes/blah')['name']).to eq('blah')
47
- end
48
- end
49
-
50
- context 'and a recipe is run that creates node "blah" on the second chef server using chef_server' do
51
-
52
- it 'the node is created on the second chef server but not the first' do
53
- expect_recipe {
54
- chef_node 'blah' do
55
- chef_server({ :chef_server_url => 'http://127.0.0.1:8899' })
56
- end
57
- }.to have_updated 'chef_node[blah]', :create
58
- expect { get('nodes/blah') }.to raise_error(Net::HTTPServerException)
59
- expect(get('http://127.0.0.1:8899/nodes/blah')['name']).to eq('blah')
60
- end
61
- end
62
- end
63
- end
64
-
65
- context 'and has a node named "blah"' do
66
- node 'blah', {}
67
-
68
- it 'chef_node "blah" does not get created or updated' do
69
- expect_recipe {
70
- chef_node 'blah'
71
- }.not_to have_updated 'chef_node[blah]', :create
72
- end
73
- end
74
-
75
- context 'and has a node named "blah" with tags' do
76
- node 'blah', {
77
- 'normal' => { 'tags' => [ 'a', 'b' ] }
78
- }
79
-
80
- context 'with chef_node "blah" that sets attributes' do
81
- with_converge do
82
- chef_node 'blah' do
83
- attributes({})
84
- end
85
- end
86
-
87
- it 'the tags in attributes are used' do
88
- expect(get('nodes/blah')['normal']['tags']).to eq([ 'a', 'b' ])
89
- end
90
- end
91
-
92
- context 'with chef_node "blah" that sets attributes with tags in them' do
93
- with_converge do
94
- chef_node 'blah' do
95
- attributes 'tags' => [ 'c', 'd' ]
96
- end
97
- end
98
-
99
- it 'the tags in attributes are used' do
100
- expect(get('nodes/blah')['normal']['tags']).to eq([ 'c', 'd' ])
101
- end
102
- end
103
- end
104
-
105
- describe '#complete' do
106
- context 'when the Chef server has a node named "blah" with everything in it' do
107
- node 'blah', {
108
- 'chef_environment' => 'blah',
109
- 'run_list' => [ 'recipe[bjork]' ],
110
- 'normal' => { 'foo' => 'bar', 'tags' => [ 'a', 'b' ] },
111
- 'default' => { 'foo2' => 'bar2' },
112
- 'automatic' => { 'foo3' => 'bar3' },
113
- 'override' => { 'foo4' => 'bar4' }
114
- }
115
-
116
- it 'chef_node with no attributes modifies nothing' do
117
- expect_recipe {
118
- chef_node 'blah'
119
- }.to be_up_to_date
120
- expect(get('nodes/blah')).to include(
121
- 'name' => 'blah',
122
- 'chef_environment' => 'blah',
123
- 'run_list' => [ 'recipe[bjork]' ],
124
- 'normal' => { 'foo' => 'bar', 'tags' => [ 'a', 'b' ] },
125
- 'default' => { 'foo2' => 'bar2' },
126
- 'automatic' => { 'foo3' => 'bar3' },
127
- 'override' => { 'foo4' => 'bar4' }
128
- )
129
- end
130
-
131
- it 'chef_node with complete true removes everything except default, automatic and override' do
132
- expect_recipe {
133
- chef_node 'blah' do
134
- complete true
135
- end
136
- }.to be_updated
137
- expect(get('nodes/blah')).to include(
138
- 'name' => 'blah',
139
- 'chef_environment' => '_default',
140
- 'run_list' => [ ],
141
- 'normal' => { 'tags' => [ 'a', 'b' ] },
142
- 'default' => { 'foo2' => 'bar2' },
143
- 'automatic' => { 'foo3' => 'bar3' },
144
- 'override' => { 'foo4' => 'bar4' }
145
- )
146
- end
147
-
148
- it 'chef_node with complete true sets the given attributes' do
149
- expect_recipe {
150
- chef_node 'blah' do
151
- chef_environment 'x'
152
- run_list [ 'recipe[y]' ]
153
- attributes 'a' => 'b'
154
- tags 'c', 'd'
155
- complete true
156
- end
157
- }.to be_updated
158
- expect(get('nodes/blah')).to include(
159
- 'name' => 'blah',
160
- 'chef_environment' => 'x',
161
- 'run_list' => [ 'recipe[y]' ],
162
- 'normal' => { 'a' => 'b', 'tags' => [ 'c', 'd' ] },
163
- 'default' => { 'foo2' => 'bar2' },
164
- 'automatic' => { 'foo3' => 'bar3' },
165
- 'override' => { 'foo4' => 'bar4' }
166
- )
167
- end
168
-
169
- it 'chef_node with complete true and partial attributes sets the given attributes' do
170
- expect_recipe {
171
- chef_node 'blah' do
172
- chef_environment 'x'
173
- recipe 'y'
174
- attribute 'a', 'b'
175
- tags 'c', 'd'
176
- complete true
177
- end
178
- }.to be_updated
179
- expect(get('nodes/blah')).to include(
180
- 'name' => 'blah',
181
- 'chef_environment' => 'x',
182
- 'run_list' => [ 'recipe[y]' ],
183
- 'normal' => { 'a' => 'b', 'tags' => [ 'c', 'd' ] },
184
- 'default' => { 'foo2' => 'bar2' },
185
- 'automatic' => { 'foo3' => 'bar3' },
186
- 'override' => { 'foo4' => 'bar4' }
187
- )
188
- end
189
- end
190
- end
191
-
192
- describe '#attributes' do
193
- context 'with a node with normal attributes a => b and c => { d => e }' do
194
- node 'blah', {
195
- 'normal' => {
196
- 'a' => 'b',
197
- 'c' => { 'd' => 'e' },
198
- 'tags' => [ 'a', 'b' ]
199
- },
200
- 'automatic' => {
201
- 'x' => 'y'
202
- },
203
- 'chef_environment' => 'desert'
204
- }
205
-
206
- it 'chef_node with attributes {} removes all normal attributes but leaves tags, automatic and environment alone' do
207
- expect_recipe {
208
- chef_node 'blah' do
209
- attributes({})
210
- end
211
- }.to have_updated('chef_node[blah]', :create)
212
- expect(get('nodes/blah')).to include(
213
- 'normal' => { 'tags' => [ 'a', 'b' ] },
214
- 'automatic' => { 'x' => 'y' },
215
- 'chef_environment' => 'desert'
216
- )
217
- end
218
-
219
- it 'chef_node with attributes { c => d } replaces normal but not tags/automatic/environment' do
220
- expect_recipe {
221
- chef_node 'blah' do
222
- attributes 'c' => 'd'
223
- end
224
- }.to have_updated('chef_node[blah]', :create)
225
- expect(get('nodes/blah')).to include(
226
- 'normal' => { 'c' => 'd', 'tags' => [ 'a', 'b' ] },
227
- 'automatic' => { 'x' => 'y' },
228
- 'chef_environment' => 'desert'
229
- )
230
- end
231
-
232
- it 'chef_node with attributes { c => f => g, y => z } replaces normal but not tags/automatic/environment' do
233
- expect_recipe {
234
- chef_node 'blah' do
235
- attributes 'c' => { 'f' => 'g' }, 'y' => 'z'
236
- end
237
- }.to have_updated('chef_node[blah]', :create)
238
- expect(get('nodes/blah')).to include(
239
- 'normal' => { 'c' => { 'f' => 'g' }, 'y' => 'z', 'tags' => [ 'a', 'b' ] },
240
- 'automatic' => { 'x' => 'y' },
241
- 'chef_environment' => 'desert'
242
- )
243
- end
244
-
245
- it 'chef_node with attributes { tags => [ "x" ] } replaces normal and tags but not automatic/environment' do
246
- expect_recipe {
247
- chef_node 'blah' do
248
- attributes 'tags' => [ 'x' ]
249
- end
250
- }.to have_updated('chef_node[blah]', :create)
251
- expect(get('nodes/blah')).to include(
252
- 'normal' => { 'tags' => [ 'x' ] },
253
- 'automatic' => { 'x' => 'y' },
254
- 'chef_environment' => 'desert'
255
- )
256
- end
257
-
258
- it 'chef_node with tags "x" and attributes { "tags" => [ "y" ] } sets tags to "x"' do
259
- expect_recipe {
260
- chef_node 'blah' do
261
- tags 'x'
262
- attributes 'tags' => [ 'y' ]
263
- end
264
- }.to have_updated('chef_node[blah]', :create)
265
- expect(get('nodes/blah')).to include(
266
- 'normal' => {
267
- 'tags' => [ 'x' ]
268
- },
269
- 'automatic' => { 'x' => 'y' },
270
- 'chef_environment' => 'desert'
271
- )
272
- end
273
- end
274
- end
275
-
276
- describe '#attribute' do
277
- context 'with a node with normal attributes a => b and c => { d => e }' do
278
- node 'blah', {
279
- 'normal' => {
280
- 'a' => 'b',
281
- 'c' => { 'd' => 'e' },
282
- 'tags' => [ 'a', 'b' ]
283
- },
284
- 'automatic' => {
285
- 'x' => 'y'
286
- },
287
- 'chef_environment' => 'desert'
288
- }
289
-
290
- context 'basic scenarios' do
291
- it 'chef_node with no attributes, leaves it alone' do
292
- expect_recipe {
293
- chef_node 'blah'
294
- }.not_to have_updated('chef_node[blah]', :create)
295
- expect(get('nodes/blah')).to include(
296
- 'normal' => {
297
- 'a' => 'b',
298
- 'c' => { 'd' => 'e' },
299
- 'tags' => [ 'a', 'b' ]
300
- },
301
- 'automatic' => { 'x' => 'y' },
302
- 'chef_environment' => 'desert'
303
- )
304
- end
305
-
306
- it 'chef_node with attribute d, e adds the attribute' do
307
- expect_recipe {
308
- chef_node 'blah' do
309
- attribute 'd', 'e'
310
- end
311
- }.to have_updated('chef_node[blah]', :create)
312
- expect(get('nodes/blah')).to include(
313
- 'normal' => {
314
- 'a' => 'b',
315
- 'c' => { 'd' => 'e' },
316
- 'd' => 'e',
317
- 'tags' => [ 'a', 'b' ]
318
- },
319
- 'automatic' => { 'x' => 'y' },
320
- 'chef_environment' => 'desert'
321
- )
322
- end
323
-
324
- it 'chef_node with attribute tags, [ "x" ] replaces tags' do
325
- expect_recipe {
326
- chef_node 'blah' do
327
- attribute 'tags', [ 'x' ]
328
- end
329
- }.to have_updated('chef_node[blah]', :create)
330
- expect(get('nodes/blah')).to include(
331
- 'normal' => {
332
- 'a' => 'b',
333
- 'c' => { 'd' => 'e' },
334
- 'tags' => [ 'x' ]
335
- },
336
- 'automatic' => { 'x' => 'y' },
337
- 'chef_environment' => 'desert'
338
- )
339
- end
340
-
341
- it 'chef_node with attribute c, x replaces the attribute' do
342
- expect_recipe {
343
- chef_node 'blah' do
344
- attribute 'c', 'x'
345
- end
346
- }.to have_updated('chef_node[blah]', :create)
347
- expect(get('nodes/blah')).to include(
348
- 'normal' => {
349
- 'a' => 'b',
350
- 'c' => 'x',
351
- 'tags' => [ 'a', 'b' ]
352
- },
353
- 'automatic' => { 'x' => 'y' },
354
- 'chef_environment' => 'desert'
355
- )
356
- end
357
-
358
- it 'chef_node with attribute c, { d => x } replaces the attribute' do
359
- expect_recipe {
360
- chef_node 'blah' do
361
- attribute 'c', { 'd' => 'x' }
362
- end
363
- }.to have_updated('chef_node[blah]', :create)
364
- expect(get('nodes/blah')).to include(
365
- 'normal' => {
366
- 'a' => 'b',
367
- 'c' => { 'd' => 'x' },
368
- 'tags' => [ 'a', 'b' ]
369
- },
370
- 'automatic' => { 'x' => 'y' },
371
- 'chef_environment' => 'desert'
372
- )
373
- end
374
-
375
- it 'chef_node with attribute [ c, d ], x replaces the attribute' do
376
- expect_recipe {
377
- chef_node 'blah' do
378
- attribute [ 'c', 'd' ], 'x'
379
- end
380
- }.to have_updated('chef_node[blah]', :create)
381
- expect(get('nodes/blah')).to include(
382
- 'normal' => {
383
- 'a' => 'b',
384
- 'c' => { 'd' => 'x' },
385
- 'tags' => [ 'a', 'b' ]
386
- },
387
- 'automatic' => { 'x' => 'y' },
388
- 'chef_environment' => 'desert'
389
- )
390
- end
391
-
392
- it 'chef_node with attribute [ a, b ], x raises an error' do
393
- expect {
394
- converge {
395
- chef_node 'blah' do
396
- attribute [ 'a', 'b' ], 'x'
397
- end
398
- }
399
- }.to raise_error /Attempt to set \["a", "b"\] to x when \["a"\] is not a hash/
400
- end
401
-
402
- it 'chef_node with attribute [ a, b, c ], x raises an error' do
403
- expect {
404
- converge {
405
- chef_node 'blah' do
406
- attribute [ 'a', 'b', 'c' ], 'x'
407
- end
408
- }
409
- }.to raise_error /Attempt to set \["a", "b", "c"\] to x when \["a"\] is not a hash/
410
- end
411
-
412
- it 'chef_node with attribute [ x, y ], z adds a new attribute' do
413
- expect_recipe {
414
- chef_node 'blah' do
415
- attribute [ 'x', 'y' ], 'z'
416
- end
417
- }.to have_updated('chef_node[blah]', :create)
418
- expect(get('nodes/blah')).to include(
419
- 'normal' => {
420
- 'a' => 'b',
421
- 'c' => { 'd' => 'e' },
422
- 'x' => { 'y' => 'z' },
423
- 'tags' => [ 'a', 'b' ]
424
- },
425
- 'automatic' => { 'x' => 'y' },
426
- 'chef_environment' => 'desert'
427
- )
428
- end
429
-
430
- it 'chef_node with attribute [], {} clears all attributes' do
431
- expect_recipe {
432
- chef_node 'blah' do
433
- attribute([], {})
434
- end
435
- }.to have_updated('chef_node[blah]', :create)
436
- expect(get('nodes/blah')).to include(
437
- 'normal' => { },
438
- 'automatic' => { 'x' => 'y' },
439
- 'chef_environment' => 'desert'
440
- )
441
- end
442
- end
443
-
444
- context 'delete' do
445
- it 'chef_node with attribute a, :delete deletes the attribute' do
446
- expect_recipe {
447
- chef_node 'blah' do
448
- attribute 'a', :delete
449
- end
450
- }.to have_updated('chef_node[blah]', :create)
451
- expect(get('nodes/blah')).to include(
452
- 'normal' => {
453
- 'c' => { 'd' => 'e' },
454
- 'tags' => [ 'a', 'b' ]
455
- },
456
- 'automatic' => { 'x' => 'y' },
457
- 'chef_environment' => 'desert'
458
- )
459
- end
460
-
461
- it 'chef_node with attribute c, :delete deletes the attribute' do
462
- expect_recipe {
463
- chef_node 'blah' do
464
- attribute 'c', :delete
465
- end
466
- }.to have_updated('chef_node[blah]', :create)
467
- expect(get('nodes/blah')).to include(
468
- 'normal' => {
469
- 'a' => 'b',
470
- 'tags' => [ 'a', 'b' ]
471
- },
472
- 'automatic' => { 'x' => 'y' },
473
- 'chef_environment' => 'desert'
474
- )
475
- end
476
-
477
- it 'chef_node with attribute [ c, d ], :delete deletes the attribute' do
478
- expect_recipe {
479
- chef_node 'blah' do
480
- attribute [ 'c', 'd' ], :delete
481
- end
482
- }.to have_updated('chef_node[blah]', :create)
483
- expect(get('nodes/blah')).to include(
484
- 'normal' => {
485
- 'a' => 'b',
486
- 'c' => {},
487
- 'tags' => [ 'a', 'b' ]
488
- },
489
- 'automatic' => { 'x' => 'y' },
490
- 'chef_environment' => 'desert'
491
- )
492
- end
493
-
494
- it 'chef_node with attribute xyz, :delete does nothing' do
495
- expect_recipe {
496
- chef_node 'blah' do
497
- attribute 'xyz', :delete
498
- end
499
- }.not_to have_updated('chef_node[blah]', :create)
500
- expect(get('nodes/blah')).to include(
501
- 'normal' => {
502
- 'a' => 'b',
503
- 'c' => { 'd' => 'e' },
504
- 'tags' => [ 'a', 'b' ]
505
- },
506
- 'automatic' => { 'x' => 'y' },
507
- 'chef_environment' => 'desert'
508
- )
509
- end
510
-
511
- it 'chef_node with attribute [ c, x ], :delete does nothing' do
512
- expect_recipe {
513
- chef_node 'blah' do
514
- attribute [ 'c', 'x' ], :delete
515
- end
516
- }.not_to have_updated('chef_node[blah]', :create)
517
- expect(get('nodes/blah')).to include(
518
- 'normal' => {
519
- 'a' => 'b',
520
- 'c' => { 'd' => 'e' },
521
- 'tags' => [ 'a', 'b' ]
522
- },
523
- 'automatic' => { 'x' => 'y' },
524
- 'chef_environment' => 'desert'
525
- )
526
- end
527
- end
528
-
529
- context 'types' do
530
- it 'chef_node with attribute a, true sets a to true' do
531
- expect_recipe {
532
- chef_node 'blah' do
533
- attribute 'a', true
534
- end
535
- }.to be_updated
536
- expect(get('nodes/blah')).to include(
537
- 'normal' => {
538
- 'a' => true,
539
- 'c' => { 'd' => 'e' },
540
- 'tags' => [ 'a', 'b' ]
541
- },
542
- 'automatic' => { 'x' => 'y' },
543
- 'chef_environment' => 'desert'
544
- )
545
- end
546
-
547
- it 'chef_node with attribute a, 1 sets a to 1' do
548
- expect_recipe {
549
- chef_node 'blah' do
550
- attribute 'a', 1
551
- end
552
- }.to be_updated
553
- expect(get('nodes/blah')).to include(
554
- 'normal' => {
555
- 'a' => 1,
556
- 'c' => { 'd' => 'e' },
557
- 'tags' => [ 'a', 'b' ]
558
- },
559
- 'automatic' => { 'x' => 'y' },
560
- 'chef_environment' => 'desert'
561
- )
562
- end
563
-
564
- it 'chef_node with attribute a, "1" sets a to "1"' do
565
- expect_recipe {
566
- chef_node 'blah' do
567
- attribute 'a', "1"
568
- end
569
- }.to be_updated
570
- expect(get('nodes/blah')).to include(
571
- 'normal' => {
572
- 'a' => "1",
573
- 'c' => { 'd' => 'e' },
574
- 'tags' => [ 'a', 'b' ]
575
- },
576
- 'automatic' => { 'x' => 'y' },
577
- 'chef_environment' => 'desert'
578
- )
579
- end
580
-
581
- it 'chef_node with attribute a, "" sets a to ""' do
582
- expect_recipe {
583
- chef_node 'blah' do
584
- attribute 'a', ""
585
- end
586
- }.to be_updated
587
- expect(get('nodes/blah')).to include(
588
- 'normal' => {
589
- 'a' => "",
590
- 'c' => { 'd' => 'e' },
591
- 'tags' => [ 'a', 'b' ]
592
- },
593
- 'automatic' => { 'x' => 'y' },
594
- 'chef_environment' => 'desert'
595
- )
596
- end
597
-
598
- it 'chef_node with attribute a, nil sets a to nil' do
599
- expect_recipe {
600
- chef_node 'blah' do
601
- attribute 'a', nil
602
- end
603
- }.to be_updated
604
- expect(get('nodes/blah')).to include(
605
- 'normal' => {
606
- 'a' => nil,
607
- 'c' => { 'd' => 'e' },
608
- 'tags' => [ 'a', 'b' ]
609
- },
610
- 'automatic' => { 'x' => 'y' },
611
- 'chef_environment' => 'desert'
612
- )
613
- end
614
- end
615
-
616
- context 'multiple attribute definitions' do
617
- it 'chef_node with attribute a, x and c, y replaces both attributes' do
618
- expect_recipe {
619
- chef_node 'blah' do
620
- attribute 'a', 'x'
621
- attribute 'c', 'y'
622
- end
623
- }.to be_updated
624
- expect(get('nodes/blah')).to include(
625
- 'normal' => {
626
- 'a' => 'x',
627
- 'c' => 'y',
628
- 'tags' => [ 'a', 'b' ]
629
- },
630
- 'automatic' => { 'x' => 'y' },
631
- 'chef_environment' => 'desert'
632
- )
633
- end
634
-
635
- it 'chef_node with attribute m, x and n, y adds both attributes' do
636
- expect_recipe {
637
- chef_node 'blah' do
638
- attribute 'm', 'x'
639
- attribute 'n', 'y'
640
- end
641
- }.to be_updated
642
- expect(get('nodes/blah')).to include(
643
- 'normal' => {
644
- 'a' => 'b',
645
- 'c' => { 'd' => 'e' },
646
- 'm' => 'x',
647
- 'n' => 'y',
648
- 'tags' => [ 'a', 'b' ]
649
- },
650
- 'automatic' => { 'x' => 'y' },
651
- 'chef_environment' => 'desert'
652
- )
653
- end
654
-
655
- it 'chef_node with attribute [x, y], z and [x, yy], zz adds both attributes' do
656
- expect_recipe {
657
- chef_node 'blah' do
658
- attribute [ 'x', 'y' ], 'z'
659
- attribute [ 'x', 'yy' ], 'zz'
660
- end
661
- }.to be_updated
662
- expect(get('nodes/blah')).to include(
663
- 'normal' => {
664
- 'a' => 'b',
665
- 'c' => { 'd' => 'e' },
666
- 'x' => {
667
- 'y' => 'z',
668
- 'yy' => 'zz'
669
- },
670
- 'tags' => [ 'a', 'b' ]
671
- },
672
- 'automatic' => { 'x' => 'y' },
673
- 'chef_environment' => 'desert'
674
- )
675
- end
676
-
677
- describe 'precedence' do
678
- it 'chef_node with attribute a, 1 and a, 2 sets a to 2' do
679
- expect_recipe {
680
- chef_node 'blah' do
681
- attribute 'a', 1
682
- attribute 'a', 2
683
- end
684
- }.to be_updated
685
- expect(get('nodes/blah')).to include(
686
- 'normal' => {
687
- 'a' => 2,
688
- 'c' => { 'd' => 'e' },
689
- 'tags' => [ 'a', 'b' ]
690
- },
691
- 'automatic' => { 'x' => 'y' },
692
- 'chef_environment' => 'desert'
693
- )
694
- end
695
-
696
- it 'chef_node with attribute [ x, y ], 1 and [ x, y ], 2 sets [ x, y ], 2' do
697
- expect_recipe {
698
- chef_node 'blah' do
699
- attribute [ 'x', 'y' ], 1
700
- attribute [ 'x', 'y' ], 2
701
- end
702
- }.to be_updated
703
- expect(get('nodes/blah')).to include(
704
- 'normal' => {
705
- 'a' => 'b',
706
- 'c' => { 'd' => 'e' },
707
- 'x' => { 'y' => 2 },
708
- 'tags' => [ 'a', 'b' ]
709
- },
710
- 'automatic' => { 'x' => 'y' },
711
- 'chef_environment' => 'desert'
712
- )
713
- end
714
-
715
- it 'chef_node with attribute [ c, e ], { a => 1 }, [ c, e ], { b => 2 } sets b only' do
716
- expect_recipe {
717
- chef_node 'blah' do
718
- attribute [ 'c', 'e' ], { 'a' => 1 }
719
- attribute [ 'c', 'e' ], { 'b' => 2 }
720
- end
721
- }.to be_updated
722
- expect(get('nodes/blah')).to include(
723
- 'normal' => {
724
- 'a' => 'b',
725
- 'c' => { 'd' => 'e', 'e' => { 'b' => 2 } },
726
- 'tags' => [ 'a', 'b' ]
727
- },
728
- 'automatic' => { 'x' => 'y' },
729
- 'chef_environment' => 'desert'
730
- )
731
- end
732
-
733
- it 'chef_node with attribute [ c, e ], { a => 1 }, [ c, e, b ], 2 sets both' do
734
- expect_recipe {
735
- chef_node 'blah' do
736
- attribute [ 'c', 'e' ], { 'a' => 1 }
737
- attribute [ 'c', 'e', 'b' ], 2
738
- end
739
- }.to be_updated
740
- expect(get('nodes/blah')).to include(
741
- 'normal' => {
742
- 'a' => 'b',
743
- 'c' => { 'd' => 'e', 'e' => { 'a' => 1, 'b' => 2 } },
744
- 'tags' => [ 'a', 'b' ]
745
- },
746
- 'automatic' => { 'x' => 'y' },
747
- 'chef_environment' => 'desert'
748
- )
749
- end
750
-
751
- it 'chef_node with attribute [ c, e, b ], 2, [ c, e ], { a => 1 } sets a only' do
752
- expect_recipe {
753
- chef_node 'blah' do
754
- attribute [ 'c', 'e', 'b' ], 2
755
- attribute [ 'c', 'e' ], { 'a' => 1 }
756
- end
757
- }.to be_updated
758
- expect(get('nodes/blah')).to include(
759
- 'normal' => {
760
- 'a' => 'b',
761
- 'c' => { 'd' => 'e', 'e' => { 'a' => 1 } },
762
- 'tags' => [ 'a', 'b' ]
763
- },
764
- 'automatic' => { 'x' => 'y' },
765
- 'chef_environment' => 'desert'
766
- )
767
- end
768
- end
769
- end
770
- end
771
- end
772
- end
773
-
774
- when_the_chef_server 'is in OSC mode' do
775
- context 'and is empty' do
776
- context 'and we run a recipe that creates node "blah"' do
777
- it 'the node gets created' do
778
- expect_recipe {
779
- chef_node 'blah'
780
- }.to have_updated 'chef_node[blah]', :create
781
- expect(get('nodes/blah')['name']).to eq('blah')
782
- end
783
- end
784
- end
785
- end
786
- end
1
+ require 'support/spec_support'
2
+ require 'cheffish/rspec/chef_run_support'
3
+ require 'chef/resource/chef_node'
4
+ require 'chef/provider/chef_node'
5
+
6
+ describe Chef::Resource::ChefNode do
7
+ extend Cheffish::RSpec::ChefRunSupport
8
+
9
+ when_the_chef_12_server 'is in multi-org mode' do
10
+ organization 'foo'
11
+
12
+ before :each do
13
+ Chef::Config.chef_server_url = URI.join(Chef::Config.chef_server_url, '/organizations/foo').to_s
14
+ end
15
+
16
+ context 'and is empty' do
17
+ context 'and we run a recipe that creates node "blah"' do
18
+ it 'the node gets created' do
19
+ expect_recipe {
20
+ chef_node 'blah'
21
+ }.to have_updated 'chef_node[blah]', :create
22
+ expect(get('nodes/blah')['name']).to eq('blah')
23
+ end
24
+ end
25
+
26
+ # TODO why-run mode
27
+
28
+ context 'and another chef server is running on port 8899' do
29
+ before :each do
30
+ @server = ChefZero::Server.new(:port => 8899)
31
+ @server.start_background
32
+ end
33
+
34
+ after :each do
35
+ @server.stop
36
+ end
37
+
38
+ context 'and a recipe is run that creates node "blah" on the second chef server using with_chef_server' do
39
+
40
+ it 'the node is created on the second chef server but not the first' do
41
+ expect_recipe {
42
+ with_chef_server 'http://127.0.0.1:8899'
43
+ chef_node 'blah'
44
+ }.to have_updated 'chef_node[blah]', :create
45
+ expect { get('nodes/blah') }.to raise_error(Net::HTTPServerException)
46
+ expect(get('http://127.0.0.1:8899/nodes/blah')['name']).to eq('blah')
47
+ end
48
+ end
49
+
50
+ context 'and a recipe is run that creates node "blah" on the second chef server using chef_server' do
51
+
52
+ it 'the node is created on the second chef server but not the first' do
53
+ expect_recipe {
54
+ chef_node 'blah' do
55
+ chef_server({ :chef_server_url => 'http://127.0.0.1:8899' })
56
+ end
57
+ }.to have_updated 'chef_node[blah]', :create
58
+ expect { get('nodes/blah') }.to raise_error(Net::HTTPServerException)
59
+ expect(get('http://127.0.0.1:8899/nodes/blah')['name']).to eq('blah')
60
+ end
61
+ end
62
+ end
63
+ end
64
+
65
+ context 'and has a node named "blah"' do
66
+ node 'blah', {}
67
+
68
+ it 'chef_node "blah" does not get created or updated' do
69
+ expect_recipe {
70
+ chef_node 'blah'
71
+ }.not_to have_updated 'chef_node[blah]', :create
72
+ end
73
+ end
74
+
75
+ context 'and has a node named "blah" with tags' do
76
+ node 'blah', {
77
+ 'normal' => { 'tags' => [ 'a', 'b' ] }
78
+ }
79
+
80
+ context 'with chef_node "blah" that sets attributes' do
81
+ with_converge do
82
+ chef_node 'blah' do
83
+ attributes({})
84
+ end
85
+ end
86
+
87
+ it 'the tags in attributes are used' do
88
+ expect(get('nodes/blah')['normal']['tags']).to eq([ 'a', 'b' ])
89
+ end
90
+ end
91
+
92
+ context 'with chef_node "blah" that sets attributes with tags in them' do
93
+ with_converge do
94
+ chef_node 'blah' do
95
+ attributes 'tags' => [ 'c', 'd' ]
96
+ end
97
+ end
98
+
99
+ it 'the tags in attributes are used' do
100
+ expect(get('nodes/blah')['normal']['tags']).to eq([ 'c', 'd' ])
101
+ end
102
+ end
103
+ end
104
+
105
+ describe '#complete' do
106
+ context 'when the Chef server has a node named "blah" with everything in it' do
107
+ node 'blah', {
108
+ 'chef_environment' => 'blah',
109
+ 'run_list' => [ 'recipe[bjork]' ],
110
+ 'normal' => { 'foo' => 'bar', 'tags' => [ 'a', 'b' ] },
111
+ 'default' => { 'foo2' => 'bar2' },
112
+ 'automatic' => { 'foo3' => 'bar3' },
113
+ 'override' => { 'foo4' => 'bar4' }
114
+ }
115
+
116
+ it 'chef_node with no attributes modifies nothing' do
117
+ expect_recipe {
118
+ chef_node 'blah'
119
+ }.to be_up_to_date
120
+ expect(get('nodes/blah')).to include(
121
+ 'name' => 'blah',
122
+ 'chef_environment' => 'blah',
123
+ 'run_list' => [ 'recipe[bjork]' ],
124
+ 'normal' => { 'foo' => 'bar', 'tags' => [ 'a', 'b' ] },
125
+ 'default' => { 'foo2' => 'bar2' },
126
+ 'automatic' => { 'foo3' => 'bar3' },
127
+ 'override' => { 'foo4' => 'bar4' }
128
+ )
129
+ end
130
+
131
+ it 'chef_node with complete true removes everything except default, automatic and override' do
132
+ expect_recipe {
133
+ chef_node 'blah' do
134
+ complete true
135
+ end
136
+ }.to be_updated
137
+ expect(get('nodes/blah')).to include(
138
+ 'name' => 'blah',
139
+ 'chef_environment' => '_default',
140
+ 'run_list' => [ ],
141
+ 'normal' => { 'tags' => [ 'a', 'b' ] },
142
+ 'default' => { 'foo2' => 'bar2' },
143
+ 'automatic' => { 'foo3' => 'bar3' },
144
+ 'override' => { 'foo4' => 'bar4' }
145
+ )
146
+ end
147
+
148
+ it 'chef_node with complete true sets the given attributes' do
149
+ expect_recipe {
150
+ chef_node 'blah' do
151
+ chef_environment 'x'
152
+ run_list [ 'recipe[y]' ]
153
+ attributes 'a' => 'b'
154
+ tags 'c', 'd'
155
+ complete true
156
+ end
157
+ }.to be_updated
158
+ expect(get('nodes/blah')).to include(
159
+ 'name' => 'blah',
160
+ 'chef_environment' => 'x',
161
+ 'run_list' => [ 'recipe[y]' ],
162
+ 'normal' => { 'a' => 'b', 'tags' => [ 'c', 'd' ] },
163
+ 'default' => { 'foo2' => 'bar2' },
164
+ 'automatic' => { 'foo3' => 'bar3' },
165
+ 'override' => { 'foo4' => 'bar4' }
166
+ )
167
+ end
168
+
169
+ it 'chef_node with complete true and partial attributes sets the given attributes' do
170
+ expect_recipe {
171
+ chef_node 'blah' do
172
+ chef_environment 'x'
173
+ recipe 'y'
174
+ attribute 'a', 'b'
175
+ tags 'c', 'd'
176
+ complete true
177
+ end
178
+ }.to be_updated
179
+ expect(get('nodes/blah')).to include(
180
+ 'name' => 'blah',
181
+ 'chef_environment' => 'x',
182
+ 'run_list' => [ 'recipe[y]' ],
183
+ 'normal' => { 'a' => 'b', 'tags' => [ 'c', 'd' ] },
184
+ 'default' => { 'foo2' => 'bar2' },
185
+ 'automatic' => { 'foo3' => 'bar3' },
186
+ 'override' => { 'foo4' => 'bar4' }
187
+ )
188
+ end
189
+ end
190
+ end
191
+
192
+ describe '#attributes' do
193
+ context 'with a node with normal attributes a => b and c => { d => e }' do
194
+ node 'blah', {
195
+ 'normal' => {
196
+ 'a' => 'b',
197
+ 'c' => { 'd' => 'e' },
198
+ 'tags' => [ 'a', 'b' ]
199
+ },
200
+ 'automatic' => {
201
+ 'x' => 'y'
202
+ },
203
+ 'chef_environment' => 'desert'
204
+ }
205
+
206
+ it 'chef_node with attributes {} removes all normal attributes but leaves tags, automatic and environment alone' do
207
+ expect_recipe {
208
+ chef_node 'blah' do
209
+ attributes({})
210
+ end
211
+ }.to have_updated('chef_node[blah]', :create)
212
+ expect(get('nodes/blah')).to include(
213
+ 'normal' => { 'tags' => [ 'a', 'b' ] },
214
+ 'automatic' => { 'x' => 'y' },
215
+ 'chef_environment' => 'desert'
216
+ )
217
+ end
218
+
219
+ it 'chef_node with attributes { c => d } replaces normal but not tags/automatic/environment' do
220
+ expect_recipe {
221
+ chef_node 'blah' do
222
+ attributes 'c' => 'd'
223
+ end
224
+ }.to have_updated('chef_node[blah]', :create)
225
+ expect(get('nodes/blah')).to include(
226
+ 'normal' => { 'c' => 'd', 'tags' => [ 'a', 'b' ] },
227
+ 'automatic' => { 'x' => 'y' },
228
+ 'chef_environment' => 'desert'
229
+ )
230
+ end
231
+
232
+ it 'chef_node with attributes { c => f => g, y => z } replaces normal but not tags/automatic/environment' do
233
+ expect_recipe {
234
+ chef_node 'blah' do
235
+ attributes 'c' => { 'f' => 'g' }, 'y' => 'z'
236
+ end
237
+ }.to have_updated('chef_node[blah]', :create)
238
+ expect(get('nodes/blah')).to include(
239
+ 'normal' => { 'c' => { 'f' => 'g' }, 'y' => 'z', 'tags' => [ 'a', 'b' ] },
240
+ 'automatic' => { 'x' => 'y' },
241
+ 'chef_environment' => 'desert'
242
+ )
243
+ end
244
+
245
+ it 'chef_node with attributes { tags => [ "x" ] } replaces normal and tags but not automatic/environment' do
246
+ expect_recipe {
247
+ chef_node 'blah' do
248
+ attributes 'tags' => [ 'x' ]
249
+ end
250
+ }.to have_updated('chef_node[blah]', :create)
251
+ expect(get('nodes/blah')).to include(
252
+ 'normal' => { 'tags' => [ 'x' ] },
253
+ 'automatic' => { 'x' => 'y' },
254
+ 'chef_environment' => 'desert'
255
+ )
256
+ end
257
+
258
+ it 'chef_node with tags "x" and attributes { "tags" => [ "y" ] } sets tags to "x"' do
259
+ expect_recipe {
260
+ chef_node 'blah' do
261
+ tags 'x'
262
+ attributes 'tags' => [ 'y' ]
263
+ end
264
+ }.to have_updated('chef_node[blah]', :create)
265
+ expect(get('nodes/blah')).to include(
266
+ 'normal' => {
267
+ 'tags' => [ 'x' ]
268
+ },
269
+ 'automatic' => { 'x' => 'y' },
270
+ 'chef_environment' => 'desert'
271
+ )
272
+ end
273
+ end
274
+ end
275
+
276
+ describe '#attribute' do
277
+ context 'with a node with normal attributes a => b and c => { d => e }' do
278
+ node 'blah', {
279
+ 'normal' => {
280
+ 'a' => 'b',
281
+ 'c' => { 'd' => 'e' },
282
+ 'tags' => [ 'a', 'b' ]
283
+ },
284
+ 'automatic' => {
285
+ 'x' => 'y'
286
+ },
287
+ 'chef_environment' => 'desert'
288
+ }
289
+
290
+ context 'basic scenarios' do
291
+ it 'chef_node with no attributes, leaves it alone' do
292
+ expect_recipe {
293
+ chef_node 'blah'
294
+ }.not_to have_updated('chef_node[blah]', :create)
295
+ expect(get('nodes/blah')).to include(
296
+ 'normal' => {
297
+ 'a' => 'b',
298
+ 'c' => { 'd' => 'e' },
299
+ 'tags' => [ 'a', 'b' ]
300
+ },
301
+ 'automatic' => { 'x' => 'y' },
302
+ 'chef_environment' => 'desert'
303
+ )
304
+ end
305
+
306
+ it 'chef_node with attribute d, e adds the attribute' do
307
+ expect_recipe {
308
+ chef_node 'blah' do
309
+ attribute 'd', 'e'
310
+ end
311
+ }.to have_updated('chef_node[blah]', :create)
312
+ expect(get('nodes/blah')).to include(
313
+ 'normal' => {
314
+ 'a' => 'b',
315
+ 'c' => { 'd' => 'e' },
316
+ 'd' => 'e',
317
+ 'tags' => [ 'a', 'b' ]
318
+ },
319
+ 'automatic' => { 'x' => 'y' },
320
+ 'chef_environment' => 'desert'
321
+ )
322
+ end
323
+
324
+ it 'chef_node with attribute tags, [ "x" ] replaces tags' do
325
+ expect_recipe {
326
+ chef_node 'blah' do
327
+ attribute 'tags', [ 'x' ]
328
+ end
329
+ }.to have_updated('chef_node[blah]', :create)
330
+ expect(get('nodes/blah')).to include(
331
+ 'normal' => {
332
+ 'a' => 'b',
333
+ 'c' => { 'd' => 'e' },
334
+ 'tags' => [ 'x' ]
335
+ },
336
+ 'automatic' => { 'x' => 'y' },
337
+ 'chef_environment' => 'desert'
338
+ )
339
+ end
340
+
341
+ it 'chef_node with attribute c, x replaces the attribute' do
342
+ expect_recipe {
343
+ chef_node 'blah' do
344
+ attribute 'c', 'x'
345
+ end
346
+ }.to have_updated('chef_node[blah]', :create)
347
+ expect(get('nodes/blah')).to include(
348
+ 'normal' => {
349
+ 'a' => 'b',
350
+ 'c' => 'x',
351
+ 'tags' => [ 'a', 'b' ]
352
+ },
353
+ 'automatic' => { 'x' => 'y' },
354
+ 'chef_environment' => 'desert'
355
+ )
356
+ end
357
+
358
+ it 'chef_node with attribute c, { d => x } replaces the attribute' do
359
+ expect_recipe {
360
+ chef_node 'blah' do
361
+ attribute 'c', { 'd' => 'x' }
362
+ end
363
+ }.to have_updated('chef_node[blah]', :create)
364
+ expect(get('nodes/blah')).to include(
365
+ 'normal' => {
366
+ 'a' => 'b',
367
+ 'c' => { 'd' => 'x' },
368
+ 'tags' => [ 'a', 'b' ]
369
+ },
370
+ 'automatic' => { 'x' => 'y' },
371
+ 'chef_environment' => 'desert'
372
+ )
373
+ end
374
+
375
+ it 'chef_node with attribute [ c, d ], x replaces the attribute' do
376
+ expect_recipe {
377
+ chef_node 'blah' do
378
+ attribute [ 'c', 'd' ], 'x'
379
+ end
380
+ }.to have_updated('chef_node[blah]', :create)
381
+ expect(get('nodes/blah')).to include(
382
+ 'normal' => {
383
+ 'a' => 'b',
384
+ 'c' => { 'd' => 'x' },
385
+ 'tags' => [ 'a', 'b' ]
386
+ },
387
+ 'automatic' => { 'x' => 'y' },
388
+ 'chef_environment' => 'desert'
389
+ )
390
+ end
391
+
392
+ it 'chef_node with attribute [ a, b ], x raises an error' do
393
+ expect {
394
+ converge {
395
+ chef_node 'blah' do
396
+ attribute [ 'a', 'b' ], 'x'
397
+ end
398
+ }
399
+ }.to raise_error /Attempt to set \["a", "b"\] to x when \["a"\] is not a hash/
400
+ end
401
+
402
+ it 'chef_node with attribute [ a, b, c ], x raises an error' do
403
+ expect {
404
+ converge {
405
+ chef_node 'blah' do
406
+ attribute [ 'a', 'b', 'c' ], 'x'
407
+ end
408
+ }
409
+ }.to raise_error /Attempt to set \["a", "b", "c"\] to x when \["a"\] is not a hash/
410
+ end
411
+
412
+ it 'chef_node with attribute [ x, y ], z adds a new attribute' do
413
+ expect_recipe {
414
+ chef_node 'blah' do
415
+ attribute [ 'x', 'y' ], 'z'
416
+ end
417
+ }.to have_updated('chef_node[blah]', :create)
418
+ expect(get('nodes/blah')).to include(
419
+ 'normal' => {
420
+ 'a' => 'b',
421
+ 'c' => { 'd' => 'e' },
422
+ 'x' => { 'y' => 'z' },
423
+ 'tags' => [ 'a', 'b' ]
424
+ },
425
+ 'automatic' => { 'x' => 'y' },
426
+ 'chef_environment' => 'desert'
427
+ )
428
+ end
429
+
430
+ it 'chef_node with attribute [], {} clears all attributes' do
431
+ expect_recipe {
432
+ chef_node 'blah' do
433
+ attribute([], {})
434
+ end
435
+ }.to have_updated('chef_node[blah]', :create)
436
+ expect(get('nodes/blah')).to include(
437
+ 'normal' => { },
438
+ 'automatic' => { 'x' => 'y' },
439
+ 'chef_environment' => 'desert'
440
+ )
441
+ end
442
+ end
443
+
444
+ context 'delete' do
445
+ it 'chef_node with attribute a, :delete deletes the attribute' do
446
+ expect_recipe {
447
+ chef_node 'blah' do
448
+ attribute 'a', :delete
449
+ end
450
+ }.to have_updated('chef_node[blah]', :create)
451
+ expect(get('nodes/blah')).to include(
452
+ 'normal' => {
453
+ 'c' => { 'd' => 'e' },
454
+ 'tags' => [ 'a', 'b' ]
455
+ },
456
+ 'automatic' => { 'x' => 'y' },
457
+ 'chef_environment' => 'desert'
458
+ )
459
+ end
460
+
461
+ it 'chef_node with attribute c, :delete deletes the attribute' do
462
+ expect_recipe {
463
+ chef_node 'blah' do
464
+ attribute 'c', :delete
465
+ end
466
+ }.to have_updated('chef_node[blah]', :create)
467
+ expect(get('nodes/blah')).to include(
468
+ 'normal' => {
469
+ 'a' => 'b',
470
+ 'tags' => [ 'a', 'b' ]
471
+ },
472
+ 'automatic' => { 'x' => 'y' },
473
+ 'chef_environment' => 'desert'
474
+ )
475
+ end
476
+
477
+ it 'chef_node with attribute [ c, d ], :delete deletes the attribute' do
478
+ expect_recipe {
479
+ chef_node 'blah' do
480
+ attribute [ 'c', 'd' ], :delete
481
+ end
482
+ }.to have_updated('chef_node[blah]', :create)
483
+ expect(get('nodes/blah')).to include(
484
+ 'normal' => {
485
+ 'a' => 'b',
486
+ 'c' => {},
487
+ 'tags' => [ 'a', 'b' ]
488
+ },
489
+ 'automatic' => { 'x' => 'y' },
490
+ 'chef_environment' => 'desert'
491
+ )
492
+ end
493
+
494
+ it 'chef_node with attribute xyz, :delete does nothing' do
495
+ expect_recipe {
496
+ chef_node 'blah' do
497
+ attribute 'xyz', :delete
498
+ end
499
+ }.not_to have_updated('chef_node[blah]', :create)
500
+ expect(get('nodes/blah')).to include(
501
+ 'normal' => {
502
+ 'a' => 'b',
503
+ 'c' => { 'd' => 'e' },
504
+ 'tags' => [ 'a', 'b' ]
505
+ },
506
+ 'automatic' => { 'x' => 'y' },
507
+ 'chef_environment' => 'desert'
508
+ )
509
+ end
510
+
511
+ it 'chef_node with attribute [ c, x ], :delete does nothing' do
512
+ expect_recipe {
513
+ chef_node 'blah' do
514
+ attribute [ 'c', 'x' ], :delete
515
+ end
516
+ }.not_to have_updated('chef_node[blah]', :create)
517
+ expect(get('nodes/blah')).to include(
518
+ 'normal' => {
519
+ 'a' => 'b',
520
+ 'c' => { 'd' => 'e' },
521
+ 'tags' => [ 'a', 'b' ]
522
+ },
523
+ 'automatic' => { 'x' => 'y' },
524
+ 'chef_environment' => 'desert'
525
+ )
526
+ end
527
+ end
528
+
529
+ context 'types' do
530
+ it 'chef_node with attribute a, true sets a to true' do
531
+ expect_recipe {
532
+ chef_node 'blah' do
533
+ attribute 'a', true
534
+ end
535
+ }.to be_updated
536
+ expect(get('nodes/blah')).to include(
537
+ 'normal' => {
538
+ 'a' => true,
539
+ 'c' => { 'd' => 'e' },
540
+ 'tags' => [ 'a', 'b' ]
541
+ },
542
+ 'automatic' => { 'x' => 'y' },
543
+ 'chef_environment' => 'desert'
544
+ )
545
+ end
546
+
547
+ it 'chef_node with attribute a, 1 sets a to 1' do
548
+ expect_recipe {
549
+ chef_node 'blah' do
550
+ attribute 'a', 1
551
+ end
552
+ }.to be_updated
553
+ expect(get('nodes/blah')).to include(
554
+ 'normal' => {
555
+ 'a' => 1,
556
+ 'c' => { 'd' => 'e' },
557
+ 'tags' => [ 'a', 'b' ]
558
+ },
559
+ 'automatic' => { 'x' => 'y' },
560
+ 'chef_environment' => 'desert'
561
+ )
562
+ end
563
+
564
+ it 'chef_node with attribute a, "1" sets a to "1"' do
565
+ expect_recipe {
566
+ chef_node 'blah' do
567
+ attribute 'a', "1"
568
+ end
569
+ }.to be_updated
570
+ expect(get('nodes/blah')).to include(
571
+ 'normal' => {
572
+ 'a' => "1",
573
+ 'c' => { 'd' => 'e' },
574
+ 'tags' => [ 'a', 'b' ]
575
+ },
576
+ 'automatic' => { 'x' => 'y' },
577
+ 'chef_environment' => 'desert'
578
+ )
579
+ end
580
+
581
+ it 'chef_node with attribute a, "" sets a to ""' do
582
+ expect_recipe {
583
+ chef_node 'blah' do
584
+ attribute 'a', ""
585
+ end
586
+ }.to be_updated
587
+ expect(get('nodes/blah')).to include(
588
+ 'normal' => {
589
+ 'a' => "",
590
+ 'c' => { 'd' => 'e' },
591
+ 'tags' => [ 'a', 'b' ]
592
+ },
593
+ 'automatic' => { 'x' => 'y' },
594
+ 'chef_environment' => 'desert'
595
+ )
596
+ end
597
+
598
+ it 'chef_node with attribute a, nil sets a to nil' do
599
+ expect_recipe {
600
+ chef_node 'blah' do
601
+ attribute 'a', nil
602
+ end
603
+ }.to be_updated
604
+ expect(get('nodes/blah')).to include(
605
+ 'normal' => {
606
+ 'a' => nil,
607
+ 'c' => { 'd' => 'e' },
608
+ 'tags' => [ 'a', 'b' ]
609
+ },
610
+ 'automatic' => { 'x' => 'y' },
611
+ 'chef_environment' => 'desert'
612
+ )
613
+ end
614
+ end
615
+
616
+ context 'multiple attribute definitions' do
617
+ it 'chef_node with attribute a, x and c, y replaces both attributes' do
618
+ expect_recipe {
619
+ chef_node 'blah' do
620
+ attribute 'a', 'x'
621
+ attribute 'c', 'y'
622
+ end
623
+ }.to be_updated
624
+ expect(get('nodes/blah')).to include(
625
+ 'normal' => {
626
+ 'a' => 'x',
627
+ 'c' => 'y',
628
+ 'tags' => [ 'a', 'b' ]
629
+ },
630
+ 'automatic' => { 'x' => 'y' },
631
+ 'chef_environment' => 'desert'
632
+ )
633
+ end
634
+
635
+ it 'chef_node with attribute m, x and n, y adds both attributes' do
636
+ expect_recipe {
637
+ chef_node 'blah' do
638
+ attribute 'm', 'x'
639
+ attribute 'n', 'y'
640
+ end
641
+ }.to be_updated
642
+ expect(get('nodes/blah')).to include(
643
+ 'normal' => {
644
+ 'a' => 'b',
645
+ 'c' => { 'd' => 'e' },
646
+ 'm' => 'x',
647
+ 'n' => 'y',
648
+ 'tags' => [ 'a', 'b' ]
649
+ },
650
+ 'automatic' => { 'x' => 'y' },
651
+ 'chef_environment' => 'desert'
652
+ )
653
+ end
654
+
655
+ it 'chef_node with attribute [x, y], z and [x, yy], zz adds both attributes' do
656
+ expect_recipe {
657
+ chef_node 'blah' do
658
+ attribute [ 'x', 'y' ], 'z'
659
+ attribute [ 'x', 'yy' ], 'zz'
660
+ end
661
+ }.to be_updated
662
+ expect(get('nodes/blah')).to include(
663
+ 'normal' => {
664
+ 'a' => 'b',
665
+ 'c' => { 'd' => 'e' },
666
+ 'x' => {
667
+ 'y' => 'z',
668
+ 'yy' => 'zz'
669
+ },
670
+ 'tags' => [ 'a', 'b' ]
671
+ },
672
+ 'automatic' => { 'x' => 'y' },
673
+ 'chef_environment' => 'desert'
674
+ )
675
+ end
676
+
677
+ describe 'precedence' do
678
+ it 'chef_node with attribute a, 1 and a, 2 sets a to 2' do
679
+ expect_recipe {
680
+ chef_node 'blah' do
681
+ attribute 'a', 1
682
+ attribute 'a', 2
683
+ end
684
+ }.to be_updated
685
+ expect(get('nodes/blah')).to include(
686
+ 'normal' => {
687
+ 'a' => 2,
688
+ 'c' => { 'd' => 'e' },
689
+ 'tags' => [ 'a', 'b' ]
690
+ },
691
+ 'automatic' => { 'x' => 'y' },
692
+ 'chef_environment' => 'desert'
693
+ )
694
+ end
695
+
696
+ it 'chef_node with attribute [ x, y ], 1 and [ x, y ], 2 sets [ x, y ], 2' do
697
+ expect_recipe {
698
+ chef_node 'blah' do
699
+ attribute [ 'x', 'y' ], 1
700
+ attribute [ 'x', 'y' ], 2
701
+ end
702
+ }.to be_updated
703
+ expect(get('nodes/blah')).to include(
704
+ 'normal' => {
705
+ 'a' => 'b',
706
+ 'c' => { 'd' => 'e' },
707
+ 'x' => { 'y' => 2 },
708
+ 'tags' => [ 'a', 'b' ]
709
+ },
710
+ 'automatic' => { 'x' => 'y' },
711
+ 'chef_environment' => 'desert'
712
+ )
713
+ end
714
+
715
+ it 'chef_node with attribute [ c, e ], { a => 1 }, [ c, e ], { b => 2 } sets b only' do
716
+ expect_recipe {
717
+ chef_node 'blah' do
718
+ attribute [ 'c', 'e' ], { 'a' => 1 }
719
+ attribute [ 'c', 'e' ], { 'b' => 2 }
720
+ end
721
+ }.to be_updated
722
+ expect(get('nodes/blah')).to include(
723
+ 'normal' => {
724
+ 'a' => 'b',
725
+ 'c' => { 'd' => 'e', 'e' => { 'b' => 2 } },
726
+ 'tags' => [ 'a', 'b' ]
727
+ },
728
+ 'automatic' => { 'x' => 'y' },
729
+ 'chef_environment' => 'desert'
730
+ )
731
+ end
732
+
733
+ it 'chef_node with attribute [ c, e ], { a => 1 }, [ c, e, b ], 2 sets both' do
734
+ expect_recipe {
735
+ chef_node 'blah' do
736
+ attribute [ 'c', 'e' ], { 'a' => 1 }
737
+ attribute [ 'c', 'e', 'b' ], 2
738
+ end
739
+ }.to be_updated
740
+ expect(get('nodes/blah')).to include(
741
+ 'normal' => {
742
+ 'a' => 'b',
743
+ 'c' => { 'd' => 'e', 'e' => { 'a' => 1, 'b' => 2 } },
744
+ 'tags' => [ 'a', 'b' ]
745
+ },
746
+ 'automatic' => { 'x' => 'y' },
747
+ 'chef_environment' => 'desert'
748
+ )
749
+ end
750
+
751
+ it 'chef_node with attribute [ c, e, b ], 2, [ c, e ], { a => 1 } sets a only' do
752
+ expect_recipe {
753
+ chef_node 'blah' do
754
+ attribute [ 'c', 'e', 'b' ], 2
755
+ attribute [ 'c', 'e' ], { 'a' => 1 }
756
+ end
757
+ }.to be_updated
758
+ expect(get('nodes/blah')).to include(
759
+ 'normal' => {
760
+ 'a' => 'b',
761
+ 'c' => { 'd' => 'e', 'e' => { 'a' => 1 } },
762
+ 'tags' => [ 'a', 'b' ]
763
+ },
764
+ 'automatic' => { 'x' => 'y' },
765
+ 'chef_environment' => 'desert'
766
+ )
767
+ end
768
+ end
769
+ end
770
+ end
771
+ end
772
+ end
773
+
774
+ when_the_chef_server 'is in OSC mode' do
775
+ context 'and is empty' do
776
+ context 'and we run a recipe that creates node "blah"' do
777
+ it 'the node gets created' do
778
+ expect_recipe {
779
+ chef_node 'blah'
780
+ }.to have_updated 'chef_node[blah]', :create
781
+ expect(get('nodes/blah')['name']).to eq('blah')
782
+ end
783
+ end
784
+ end
785
+ end
786
+ end