test-kitchen 1.2.1 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (114) hide show
  1. checksums.yaml +4 -4
  2. data/.cane +1 -1
  3. data/.rubocop.yml +3 -0
  4. data/.travis.yml +20 -9
  5. data/CHANGELOG.md +219 -108
  6. data/Gemfile +10 -6
  7. data/Guardfile +38 -9
  8. data/README.md +11 -1
  9. data/Rakefile +21 -37
  10. data/bin/kitchen +4 -4
  11. data/features/kitchen_action_commands.feature +161 -0
  12. data/features/kitchen_console_command.feature +34 -0
  13. data/features/kitchen_diagnose_command.feature +64 -0
  14. data/features/kitchen_init_command.feature +29 -17
  15. data/features/kitchen_list_command.feature +2 -2
  16. data/features/kitchen_login_command.feature +56 -0
  17. data/features/{sink_command.feature → kitchen_sink_command.feature} +0 -0
  18. data/features/kitchen_test_command.feature +88 -0
  19. data/features/step_definitions/gem_steps.rb +8 -6
  20. data/features/step_definitions/git_steps.rb +4 -2
  21. data/features/step_definitions/output_steps.rb +5 -0
  22. data/features/support/env.rb +12 -9
  23. data/lib/kitchen.rb +60 -38
  24. data/lib/kitchen/base64_stream.rb +55 -0
  25. data/lib/kitchen/busser.rb +124 -58
  26. data/lib/kitchen/cli.rb +121 -38
  27. data/lib/kitchen/collection.rb +3 -3
  28. data/lib/kitchen/color.rb +4 -4
  29. data/lib/kitchen/command.rb +78 -11
  30. data/lib/kitchen/command/action.rb +3 -2
  31. data/lib/kitchen/command/console.rb +12 -5
  32. data/lib/kitchen/command/diagnose.rb +17 -3
  33. data/lib/kitchen/command/driver_discover.rb +26 -7
  34. data/lib/kitchen/command/exec.rb +41 -0
  35. data/lib/kitchen/command/list.rb +44 -14
  36. data/lib/kitchen/command/login.rb +2 -1
  37. data/lib/kitchen/command/sink.rb +2 -1
  38. data/lib/kitchen/command/test.rb +5 -4
  39. data/lib/kitchen/config.rb +146 -14
  40. data/lib/kitchen/configurable.rb +314 -0
  41. data/lib/kitchen/data_munger.rb +522 -18
  42. data/lib/kitchen/diagnostic.rb +43 -4
  43. data/lib/kitchen/driver.rb +4 -4
  44. data/lib/kitchen/driver/base.rb +80 -115
  45. data/lib/kitchen/driver/dummy.rb +34 -6
  46. data/lib/kitchen/driver/proxy.rb +14 -3
  47. data/lib/kitchen/driver/ssh_base.rb +61 -7
  48. data/lib/kitchen/errors.rb +109 -9
  49. data/lib/kitchen/generator/driver_create.rb +39 -5
  50. data/lib/kitchen/generator/init.rb +130 -45
  51. data/lib/kitchen/instance.rb +162 -28
  52. data/lib/kitchen/lazy_hash.rb +79 -7
  53. data/lib/kitchen/loader/yaml.rb +159 -27
  54. data/lib/kitchen/logger.rb +267 -21
  55. data/lib/kitchen/logging.rb +30 -3
  56. data/lib/kitchen/login_command.rb +11 -2
  57. data/lib/kitchen/metadata_chopper.rb +2 -2
  58. data/lib/kitchen/provisioner.rb +4 -4
  59. data/lib/kitchen/provisioner/base.rb +107 -103
  60. data/lib/kitchen/provisioner/chef/berkshelf.rb +36 -8
  61. data/lib/kitchen/provisioner/chef/librarian.rb +40 -11
  62. data/lib/kitchen/provisioner/chef_base.rb +206 -167
  63. data/lib/kitchen/provisioner/chef_solo.rb +25 -7
  64. data/lib/kitchen/provisioner/chef_zero.rb +105 -29
  65. data/lib/kitchen/provisioner/dummy.rb +1 -1
  66. data/lib/kitchen/provisioner/shell.rb +21 -6
  67. data/lib/kitchen/rake_tasks.rb +8 -3
  68. data/lib/kitchen/shell_out.rb +15 -18
  69. data/lib/kitchen/ssh.rb +122 -27
  70. data/lib/kitchen/state_file.rb +24 -7
  71. data/lib/kitchen/thor_tasks.rb +9 -4
  72. data/lib/kitchen/util.rb +43 -118
  73. data/lib/kitchen/version.rb +1 -1
  74. data/lib/vendor/hash_recursive_merge.rb +10 -2
  75. data/spec/kitchen/base64_stream_spec.rb +77 -0
  76. data/spec/kitchen/busser_spec.rb +490 -0
  77. data/spec/kitchen/collection_spec.rb +10 -10
  78. data/spec/kitchen/color_spec.rb +2 -2
  79. data/spec/kitchen/config_spec.rb +234 -62
  80. data/spec/kitchen/configurable_spec.rb +490 -0
  81. data/spec/kitchen/data_munger_spec.rb +1070 -862
  82. data/spec/kitchen/diagnostic_spec.rb +79 -0
  83. data/spec/kitchen/driver/base_spec.rb +80 -85
  84. data/spec/kitchen/driver/dummy_spec.rb +43 -14
  85. data/spec/kitchen/driver/proxy_spec.rb +134 -0
  86. data/spec/kitchen/driver/ssh_base_spec.rb +644 -0
  87. data/spec/kitchen/driver_spec.rb +15 -15
  88. data/spec/kitchen/errors_spec.rb +309 -0
  89. data/spec/kitchen/instance_spec.rb +143 -46
  90. data/spec/kitchen/lazy_hash_spec.rb +36 -9
  91. data/spec/kitchen/loader/yaml_spec.rb +237 -226
  92. data/spec/kitchen/logger_spec.rb +419 -0
  93. data/spec/kitchen/logging_spec.rb +59 -0
  94. data/spec/kitchen/login_command_spec.rb +49 -0
  95. data/spec/kitchen/metadata_chopper_spec.rb +82 -0
  96. data/spec/kitchen/platform_spec.rb +4 -4
  97. data/spec/kitchen/provisioner/base_spec.rb +65 -125
  98. data/spec/kitchen/provisioner/chef_base_spec.rb +798 -0
  99. data/spec/kitchen/provisioner/chef_solo_spec.rb +316 -0
  100. data/spec/kitchen/provisioner/chef_zero_spec.rb +624 -0
  101. data/spec/kitchen/provisioner/shell_spec.rb +269 -0
  102. data/spec/kitchen/provisioner_spec.rb +6 -6
  103. data/spec/kitchen/shell_out_spec.rb +143 -0
  104. data/spec/kitchen/ssh_spec.rb +683 -0
  105. data/spec/kitchen/state_file_spec.rb +28 -21
  106. data/spec/kitchen/suite_spec.rb +7 -7
  107. data/spec/kitchen/util_spec.rb +68 -10
  108. data/spec/kitchen_spec.rb +107 -0
  109. data/spec/spec_helper.rb +18 -13
  110. data/support/chef-client-zero.rb +10 -9
  111. data/support/chef_helpers.sh +16 -0
  112. data/support/download_helpers.sh +109 -0
  113. data/test-kitchen.gemspec +42 -33
  114. metadata +107 -33
@@ -16,7 +16,7 @@
16
16
  # See the License for the specific language governing permissions and
17
17
  # limitations under the License.
18
18
 
19
- require 'vendor/hash_recursive_merge'
19
+ require "vendor/hash_recursive_merge"
20
20
 
21
21
  module Kitchen
22
22
 
@@ -26,9 +26,18 @@ module Kitchen
26
26
  # This object will mutate the data Hash passed into its constructor and so
27
27
  # should not be reused or shared across threads.
28
28
  #
29
+ # If you are squeamish or faint of heart, then you might want to skip this
30
+ # class. Just remember, you were warned. And if you made it this far, be
31
+ # sure to tweet at @fnichol and let him know your fear factor level.
32
+ #
29
33
  # @author Fletcher Nichol <fnichol@nichol.ca>
30
34
  class DataMunger
31
35
 
36
+ # Constructs a new DataMunger object.
37
+ #
38
+ # @param data [Hash] the incoming user data hash
39
+ # @param kitchen_config [Hash] the incoming Test Kitchen-provided
40
+ # configuration hash
32
41
  def initialize(data, kitchen_config = {})
33
42
  @data = data
34
43
  @kitchen_config = kitchen_config
@@ -38,6 +47,13 @@ module Kitchen
38
47
  move_chef_data_to_provisioner!
39
48
  end
40
49
 
50
+ # Generate a new Hash of configuration data that can be used to construct
51
+ # a new Busser object.
52
+ #
53
+ # @param suite [String] a suite name
54
+ # @param platform [String] a platform name
55
+ # @return [Hash] a new configuration Hash that can be used to construct a
56
+ # new Busser
41
57
  def busser_data_for(suite, platform)
42
58
  merged_data_for(:busser, suite, platform, :version).tap do |bdata|
43
59
  set_kitchen_config_at!(bdata, :kitchen_root)
@@ -46,6 +62,13 @@ module Kitchen
46
62
  end
47
63
  end
48
64
 
65
+ # Generate a new Hash of configuration data that can be used to construct
66
+ # a new Driver object.
67
+ #
68
+ # @param suite [String] a suite name
69
+ # @param platform [String] a platform name
70
+ # @return [Hash] a new configuration Hash that can be used to construct a
71
+ # new Driver
49
72
  def driver_data_for(suite, platform)
50
73
  merged_data_for(:driver, suite, platform).tap do |ddata|
51
74
  set_kitchen_config_at!(ddata, :kitchen_root)
@@ -54,10 +77,20 @@ module Kitchen
54
77
  end
55
78
  end
56
79
 
80
+ # Returns an Array of platform Hashes.
81
+ #
82
+ # @return [Array<Hash>] an Array of Hashes
57
83
  def platform_data
58
84
  data.fetch(:platforms, [])
59
85
  end
60
86
 
87
+ # Generate a new Hash of configuration data that can be used to construct
88
+ # a new Provisioner object.
89
+ #
90
+ # @param suite [String] a suite name
91
+ # @param platform [String] a platform name
92
+ # @return [Hash] a new configuration Hash that can be used to construct a
93
+ # new Provisioner
61
94
  def provisioner_data_for(suite, platform)
62
95
  merged_data_for(:provisioner, suite, platform).tap do |pdata|
63
96
  set_kitchen_config_at!(pdata, :kitchen_root)
@@ -67,31 +100,145 @@ module Kitchen
67
100
  end
68
101
  end
69
102
 
103
+ # Returns an Array of suite Hashes.
104
+ #
105
+ # @return [Array<Hash>] an Array of Hashes
70
106
  def suite_data
71
107
  data.fetch(:suites, [])
72
108
  end
73
109
 
74
110
  private
75
111
 
76
- attr_reader :data, :kitchen_config
112
+ # @return [Hash] the user data hash
113
+ # @api private
114
+ attr_reader :data
115
+
116
+ # @return [Hash] the Test Kitchen-provided configuration hash
117
+ # @api private
118
+ attr_reader :kitchen_config
77
119
 
78
120
  def combine_arrays!(root, key, *namespaces)
79
- if root.has_key?(key)
121
+ if root.key?(key)
80
122
  root[key] = namespaces.
81
123
  map { |namespace| root.fetch(key).fetch(namespace, []) }.flatten.
82
124
  compact
83
125
  end
84
126
  end
85
127
 
128
+ # Destructively moves Chef-related paths out of a suite hash and into the
129
+ # suite's provisioner sub-hash.
130
+ #
131
+ # This method converts the following:
132
+ #
133
+ # {
134
+ # :suites => [
135
+ # {
136
+ # :name => "alpha",
137
+ # :nodes_path => "/a/b/c"
138
+ # },
139
+ # {
140
+ # :name => "beta",
141
+ # :roles_path => "/tmp/roles",
142
+ # :data_bags_path => "/bags"
143
+ # },
144
+ # ]
145
+ # }
146
+ #
147
+ # into the following:
148
+ #
149
+ # {
150
+ # :suites => [
151
+ # {
152
+ # :name => "alpha",
153
+ # :provisioner => {
154
+ # :nodes_path => "/a/b/c"
155
+ # }
156
+ # },
157
+ # {
158
+ # :name => "beta",
159
+ # :provisioner => {
160
+ # :roles_path => "/tmp/roles",
161
+ # :data_bags_path => "/bags"
162
+ # }
163
+ # },
164
+ # ]
165
+ # }
166
+ #
167
+ # @deprecated The following Chef paths should no longer be created directly
168
+ # under a suite hash: [`data_path`, `data_bags_path`,
169
+ # `encrypted_data_bag_secret_key_path`, `environments_path`, `nodes_path`,
170
+ # `roles_path`]. Instead put these key/value pairs directly inside a
171
+ # `provisioner` hash.
172
+ # @api private
86
173
  def convert_legacy_chef_paths_format!
87
174
  data.fetch(:suites, []).each do |suite|
88
- %w{data data_bags encrypted_data_bag_secret_key
89
- environments nodes roles}.each do |key|
90
- move_chef_data_to_provisioner_at!(suite, "#{key}_path".to_sym)
175
+ %w[
176
+ data data_bags encrypted_data_bag_secret_key
177
+ environments nodes roles
178
+ ].each do |key|
179
+ move_chef_data_to_provisioner_at!(suite, "#{key}_path".to_sym)
91
180
  end
92
181
  end
93
182
  end
94
183
 
184
+ # Destructively moves old-style `:driver_plugin` and `:driver_config`
185
+ # configuration hashes into the correct `:driver` hash.
186
+ #
187
+ # This method converts the following:
188
+ #
189
+ # {
190
+ # :driver_plugin => "foo",
191
+ # :driver_config => { :one => "two" },
192
+ #
193
+ # :platforms => [
194
+ # {
195
+ # :name => "ubuntu-12.04",
196
+ # :driver_plugin => "bar"
197
+ # }
198
+ # ],
199
+ #
200
+ # :suites => [
201
+ # {
202
+ # :name => "alpha",
203
+ # :driver_plugin => "baz"
204
+ # :driver_config => { :three => "four" }
205
+ # }
206
+ # ]
207
+ # }
208
+ #
209
+ # into the following:
210
+ #
211
+ # {
212
+ # :driver => {
213
+ # :name => "foo",
214
+ # :one => "two"
215
+ # }
216
+ #
217
+ # :platforms => [
218
+ # {
219
+ # :name => "ubuntu-12.04",
220
+ # :driver => {
221
+ # :name => "bar"
222
+ # }
223
+ # }
224
+ # ],
225
+ #
226
+ # :suites => [
227
+ # {
228
+ # :name => "alpha",
229
+ # :driver => {
230
+ # :name => "baz",
231
+ # :three => "four"
232
+ # }
233
+ # }
234
+ # ]
235
+ # }
236
+ #
237
+ # @deprecated The following configuration hashes should no longer be
238
+ # created in a `:platform`, `:suite`, or common location:
239
+ # [`:driver_plugin`, `:driver_config`]. Use a `:driver` hash block in
240
+ # their place.
241
+ # @api private
95
242
  def convert_legacy_driver_format!
96
243
  convert_legacy_driver_format_at!(data)
97
244
  data.fetch(:platforms, []).each do |platform|
@@ -102,20 +249,89 @@ module Kitchen
102
249
  end
103
250
  end
104
251
 
252
+ # Destructively moves old-style `:driver_plugin` and `:driver_config`
253
+ # configuration hashes into the correct `:driver` in the first level depth
254
+ # of a hash. This method has no knowledge of suites, platforms, or the
255
+ # like, just a vanilla hash.
256
+ #
257
+ # @param root [Hash] a hash to use as the root of the conversion
258
+ # @deprecated The following configuration hashes should no longer be
259
+ # created in a Test Kitche hash: [`:driver_plugin`, `:driver_config`].
260
+ # Use a `:driver` hash block in their place.
261
+ # @api private
105
262
  def convert_legacy_driver_format_at!(root)
106
- if root.has_key?(:driver_config)
263
+ if root.key?(:driver_config)
107
264
  ddata = root.fetch(:driver, Hash.new)
108
265
  ddata = { :name => ddata } if ddata.is_a?(String)
109
266
  root[:driver] = root.delete(:driver_config).rmerge(ddata)
110
267
  end
111
268
 
112
- if root.has_key?(:driver_plugin)
269
+ if root.key?(:driver_plugin)
113
270
  ddata = root.fetch(:driver, Hash.new)
114
271
  ddata = { :name => ddata } if ddata.is_a?(String)
115
272
  root[:driver] = { :name => root.delete(:driver_plugin) }.rmerge(ddata)
116
273
  end
117
274
  end
118
275
 
276
+ # Destructively moves a `:require_chef_omnibus` key/value pair from a
277
+ # `:driver` hash block to a `:provisioner` hash block.
278
+ #
279
+ # This method converts the following:
280
+ #
281
+ # {
282
+ # :driver => {
283
+ # :require_chef_omnibus => true
284
+ # }
285
+ #
286
+ # :platforms => [
287
+ # {
288
+ # :name => "ubuntu-12.04",
289
+ # :driver => {
290
+ # :require_chef_omnibus => "10.8.2"
291
+ # }
292
+ # }
293
+ # ],
294
+ #
295
+ # :suites => [
296
+ # {
297
+ # :name => "alpha",
298
+ # :driver => {
299
+ # :require_chef_omnibus => "11"
300
+ # }
301
+ # }
302
+ # ]
303
+ # }
304
+ #
305
+ # into the following:
306
+ #
307
+ # {
308
+ # :provisioner => {
309
+ # :require_chef_omnibus => true
310
+ # }
311
+ #
312
+ # :platforms => [
313
+ # {
314
+ # :name => "ubuntu-12.04",
315
+ # :provisioner => {
316
+ # :require_chef_omnibus => "10.8.2"
317
+ # }
318
+ # }
319
+ # ],
320
+ #
321
+ # :suites => [
322
+ # {
323
+ # :name => "alpha",
324
+ # :provisioner => {
325
+ # :require_chef_omnibus => "11"
326
+ # }
327
+ # }
328
+ # ]
329
+ # }
330
+ #
331
+ # @deprecated The `:require_chef_omnibus` key/value pair should no longer
332
+ # be created inside a `:driver` hash block. Put it in a `:provisioner`
333
+ # hash block instead.
334
+ # @api private
119
335
  def convert_legacy_require_chef_omnibus_format!
120
336
  convert_legacy_require_chef_omnibus_format_at!(data)
121
337
  data.fetch(:platforms, []).each do |platform|
@@ -126,11 +342,21 @@ module Kitchen
126
342
  end
127
343
  end
128
344
 
345
+ # Destructively moves a `:require_chef_omnibus` key/value pair from a
346
+ # `:driver` hash block to a `:provisioner` hash block in the first leve
347
+ # depth of a hash. This method has no knowledge of suites, platforms, or
348
+ # the like, just a vanilla haash.
349
+ #
350
+ # @param root [Hash] a hash to use as the root of the conversion
351
+ # @deprecated The `:require_chef_omnibus` key/value pair should no longer
352
+ # be created inside a `:driver` hash block. Put it in a `:provisioner`
353
+ # hash block instead.
354
+ # @api private
129
355
  def convert_legacy_require_chef_omnibus_format_at!(root)
130
356
  key = :require_chef_omnibus
131
357
  ddata = root.fetch(:driver, Hash.new)
132
358
 
133
- if ddata.is_a?(Hash) && ddata.has_key?(key)
359
+ if ddata.is_a?(Hash) && ddata.key?(key)
134
360
  pdata = root.fetch(:provisioner, Hash.new)
135
361
  pdata = { :name => pdata } if pdata.is_a?(String)
136
362
  root[:provisioner] =
@@ -138,6 +364,27 @@ module Kitchen
138
364
  end
139
365
  end
140
366
 
367
+ # Performs a prioritized recursive merge of several source Hashes and
368
+ # returns a new merged Hash. For these data sub-hash structures, there are
369
+ # 4 sources for configuration data:
370
+ #
371
+ # 1. defaults, provided by Test Kitchen code
372
+ # 2. user-provided in the common root-level of the incoming data hash
373
+ # 3. user-provided in a platform sub-hash
374
+ # 4. user-provided in a suite sub-hash
375
+ #
376
+ # The merge order is 4 -> 3 -> 2 -> 1, meaning that the highest number in
377
+ # the above list has merge precedence over any lower numbered source. Put
378
+ # another way, a key/value pair in a suite sub-hash will be used over the
379
+ # key/value pair in a platform sub-hash.
380
+ #
381
+ # @param key [Symbol] the data sub-hash(es) to merge
382
+ # @param suite [String] a suite name
383
+ # @param platform [String] a platform name
384
+ # @param default_key [Symbol] the default key to use when normalizing the
385
+ # data sub-hashes (default: `:name`)
386
+ # @return [Hash] a new merged Hash
387
+ # @api private
141
388
  def merged_data_for(key, suite, platform, default_key = :name)
142
389
  ddata = normalized_default_data(key, default_key)
143
390
  cdata = normalized_common_data(key, default_key)
@@ -147,6 +394,59 @@ module Kitchen
147
394
  ddata.rmerge(cdata.rmerge(pdata.rmerge(sdata)))
148
395
  end
149
396
 
397
+ # Destructively moves key Chef configuration key/value pairs from being
398
+ # directly under a suite or platform into a `:provisioner` sub-hash.
399
+ #
400
+ # There are two key Chef configuration key/value pairs:
401
+ #
402
+ # 1. `:attributes`
403
+ # 2. `:run_list`
404
+ #
405
+ # This method converts the following:
406
+ #
407
+ # {
408
+ # :platforms => [
409
+ # {
410
+ # :name => "ubuntu-12.04",
411
+ # :attributes => { :one => "two" },
412
+ # :run_list => ["alpha", "bravo"]
413
+ # }
414
+ # ],
415
+ #
416
+ # :suites => [
417
+ # {
418
+ # :name => "alpha",
419
+ # :attributes => { :three => "four" },
420
+ # :run_list => ["charlie", "delta"]
421
+ # }
422
+ # ]
423
+ # }
424
+ #
425
+ # into the following:
426
+ #
427
+ # {
428
+ # :platforms => [
429
+ # {
430
+ # :name => "ubuntu-12.04",
431
+ # :provisioner => {
432
+ # :attributes => { :one => "two" },
433
+ # :run_list => ["alpha", "bravo"]
434
+ # }
435
+ # }
436
+ # ],
437
+ #
438
+ # :suites => [
439
+ # {
440
+ # :name => "alpha",
441
+ # :provisioner => {
442
+ # :attributes => { :three => "four" },
443
+ # :run_list => ["charlie", "delta"]
444
+ # }
445
+ # }
446
+ # ]
447
+ # }
448
+ #
449
+ # @api private
150
450
  def move_chef_data_to_provisioner!
151
451
  data.fetch(:suites, []).each do |suite|
152
452
  move_chef_data_to_provisioner_at!(suite, :attributes)
@@ -159,20 +459,71 @@ module Kitchen
159
459
  end
160
460
  end
161
461
 
462
+ # Destructively moves key Chef configuration key/value pairs from being
463
+ # directly under a hash into a `:provisioner` sub-hash block. This method
464
+ # has no knowledge of suites, platforms, or the like, just a vanilla hash.
465
+ #
466
+ # @param root [Hash] a hash to use as the root of the conversion
467
+ # @param key [Symbol] a key in the root hash to move into a `:provisioner`
468
+ # sub-hash block
469
+ # @api private
162
470
  def move_chef_data_to_provisioner_at!(root, key)
163
- if root.has_key?(key)
471
+ if root.key?(key)
164
472
  pdata = root.fetch(:provisioner, Hash.new)
165
473
  pdata = { :name => pdata } if pdata.is_a?(String)
166
- if ! root.fetch(key, nil).nil?
167
- root[:provisioner] = pdata.rmerge({ key => root.delete(key) })
474
+ if !root.fetch(key, nil).nil?
475
+ root[:provisioner] = pdata.rmerge(key => root.delete(key))
168
476
  end
169
477
  end
170
478
  end
171
479
 
480
+ # Vicious hack to allow for Array-appending merge semantics. This method
481
+ # takes an array value and transforms it into a hash with a bucket name
482
+ # containing the original Array. This way semantic Hash merging will do
483
+ # its thing and another process can collapse the hash into a flat array
484
+ # afterwards, given a strategy (like use the array segmenet from one
485
+ # bucket first, then another one second). To anyone who made it this far,
486
+ # Fletcher appologizes.
487
+ #
488
+ # @param root [Hash] a hash to use as the root of the conversion
489
+ # @param key [Symbol] a key in the root hash that, if exists, has its
490
+ # value transformed into a sub-hash
491
+ # @param bucket [Symbol] a key to use for the sub-hash
492
+ # @api private
172
493
  def namespace_array!(root, key, bucket)
173
- root[key] = { bucket => root.fetch(key) } if root.has_key?(key)
494
+ root[key] = { bucket => root.fetch(key) } if root.key?(key)
174
495
  end
175
496
 
497
+ # Normalizes a specific key in the root of the data hash to be a proper
498
+ # sub-hash in all cases. Specifically handled are the following cases:
499
+ #
500
+ # * If the value for a key is set to `nil`, a new Hash will be put in
501
+ # its place.
502
+ # * If the value is a String, then convert the value to a new Hash with
503
+ # a default key pointing to the original String
504
+ #
505
+ # Given a hash:
506
+ #
507
+ # { :driver => nil }
508
+ #
509
+ # this method (`normalized_common_data(:driver, :name)`) would return:
510
+ #
511
+ # {}
512
+ #
513
+ # Given a hash:
514
+ #
515
+ # { :driver => "coolbeans" }
516
+ #
517
+ # this method (`normalized_common_data(:driver, :name)`) would return:
518
+ #
519
+ # { :name => "coolbeans" }
520
+ #
521
+ # @param key [Symbol] the value to normalize
522
+ # @param default_key [Symbol] the implicit default key if a String value
523
+ # is given
524
+ # @return [Hash] a shallow Hash copy of the original if not modified, or a
525
+ # new Hash otherwise
526
+ # @api private
176
527
  def normalized_common_data(key, default_key)
177
528
  cdata = data.fetch(key, Hash.new)
178
529
  cdata = cdata.nil? ? Hash.new : cdata.dup
@@ -180,12 +531,94 @@ module Kitchen
180
531
  cdata
181
532
  end
182
533
 
534
+ # Normalizes a specific key in the `:defaults` data sub-hash to be a proper
535
+ # sub-hash in all cases. Specifically handled are the following cases:
536
+ #
537
+ # * If the value for a key is not set, a new Hash will be put in its place
538
+ # * If the value is a String, then convert the value to a new Hash with
539
+ # a default key pointing to the original String
540
+ #
541
+ # Given a hash:
542
+ #
543
+ # {
544
+ # :defaults => {}
545
+ # }
546
+ #
547
+ # this method (`normalized_default_data(:driver, :name)`) would return:
548
+ #
549
+ # {}
550
+ #
551
+ # Given a hash:
552
+ #
553
+ # {
554
+ # :defaults => {
555
+ # :driver => "coolbeans"
556
+ # }
557
+ # }
558
+ #
559
+ # this method (`normalized_default_data(:driver, :name)`) would return:
560
+ #
561
+ # { :name => "coolbeans" }
562
+ #
563
+ # @param key [Symbol] the value to normalize
564
+ # @param default_key [Symbol] the implicit default key if a String value
565
+ # is given
566
+ # @return [Hash] a shallow Hash copy of the original if not modified, or a
567
+ # new Hash otherwise
568
+ # @api private
183
569
  def normalized_default_data(key, default_key)
184
570
  ddata = kitchen_config.fetch(:defaults, Hash.new).fetch(key, Hash.new).dup
185
571
  ddata = { default_key => ddata } if ddata.is_a?(String)
186
572
  ddata
187
573
  end
188
574
 
575
+ # Normalizes a specific key in a platform hash data sub-hash to be a proper
576
+ # sub-hash in all cases. Specifically handled are the following cases:
577
+ #
578
+ # * If the value for a key is set to `nil`, a new Hash will be put in
579
+ # its place.
580
+ # * If the value is a String, then convert the value to a new Hash with
581
+ # a default key pointing to the original String
582
+ #
583
+ # Given a hash:
584
+ #
585
+ # {
586
+ # :platforms => [
587
+ # {
588
+ # :name => "alpha",
589
+ # :driver => nil
590
+ # }
591
+ # ]
592
+ # }
593
+ #
594
+ # this method (`normalized_platform_data(:driver, :name, "alpha)`) would
595
+ # return:
596
+ #
597
+ # {}
598
+ #
599
+ # Given a hash:
600
+ #
601
+ # {
602
+ # :platforms => [
603
+ # {
604
+ # :name => "alpha",
605
+ # :driver => "coolbeans"
606
+ # }
607
+ # ]
608
+ # }
609
+ #
610
+ # this method (`normalized_common_data(:driver, :name, "alpha")`) would
611
+ # return:
612
+ #
613
+ # { :name => "coolbeans" }
614
+ #
615
+ # @param key [Symbol] the value to normalize
616
+ # @param default_key [Symbol] the implicit default key if a String value
617
+ # is given
618
+ # @param platform [String] name of a platform
619
+ # @return [Hash] a shallow Hash copy of the original if not modified, or a
620
+ # new Hash otherwise
621
+ # @api private
189
622
  def normalized_platform_data(key, default_key, platform)
190
623
  pdata = platform_data_for(platform).fetch(key, Hash.new)
191
624
  pdata = pdata.nil? ? Hash.new : pdata.dup
@@ -194,6 +627,53 @@ module Kitchen
194
627
  pdata
195
628
  end
196
629
 
630
+ # Normalizes a specific key in a suite hash data sub-hash to be a proper
631
+ # sub-hash in all cases. Specifically handled are the following cases:
632
+ #
633
+ # * If the value for a key is set to `nil`, a new Hash will be put in
634
+ # its place.
635
+ # * If the value is a String, then convert the value to a new Hash with
636
+ # a default key pointing to the original String
637
+ #
638
+ # Given a hash:
639
+ #
640
+ # {
641
+ # :suites => [
642
+ # {
643
+ # :name => "full",
644
+ # :driver => nil
645
+ # }
646
+ # ]
647
+ # }
648
+ #
649
+ # this method (`normalized_platform_data(:driver, :name, "full)`) would
650
+ # return:
651
+ #
652
+ # {}
653
+ #
654
+ # Given a hash:
655
+ #
656
+ # {
657
+ # :suites => [
658
+ # {
659
+ # :name => "full",
660
+ # :driver => "coolbeans"
661
+ # }
662
+ # ]
663
+ # }
664
+ #
665
+ # this method (`normalized_common_data(:driver, :name, "full")`) would
666
+ # return:
667
+ #
668
+ # { :name => "coolbeans" }
669
+ #
670
+ # @param key [Symbol] the value to normalize
671
+ # @param default_key [Symbol] the implicit default key if a String value
672
+ # is given
673
+ # @param suite [String] name of a suite
674
+ # @return [Hash] a shallow Hash copy of the original if not modified, or a
675
+ # new Hash otherwise
676
+ # @api private
197
677
  def normalized_suite_data(key, default_key, suite)
198
678
  sdata = suite_data_for(suite).fetch(key, Hash.new)
199
679
  sdata = sdata.nil? ? Hash.new : sdata.dup
@@ -202,22 +682,46 @@ module Kitchen
202
682
  sdata
203
683
  end
204
684
 
685
+ # Returns the hash for a platform by name, or an empty Hash if none
686
+ # could be found.
687
+ #
688
+ # @param name [String] name of a platform
689
+ # @return [Hash] the configuration hash for the platform, or an empty
690
+ # Hash if not found
691
+ # @api private
205
692
  def platform_data_for(name)
206
- data.fetch(:platforms, Hash.new).find(lambda { Hash.new }) do |platform|
693
+ data.fetch(:platforms, Hash.new).find(-> { Hash.new }) do |platform|
207
694
  platform.fetch(:name, nil) == name
208
695
  end
209
696
  end
210
697
 
698
+ # Destructively sets a base kitchen config key/value pair at the root of
699
+ # the given hash. If the key is present in the given Hash, it is deleted
700
+ # and will not be used. If the key is found in the `kitchen_config` hash
701
+ # (default values), then its value will be used and set. Finally, if
702
+ # the key is found in `:kitchen` data sub-hash, then its value will be used
703
+ # and set.
704
+ #
705
+ # @param root [Hash] a hash to use as the root of the conversion
706
+ # @param key [Symbol] the key to search for
707
+ # @api private
211
708
  def set_kitchen_config_at!(root, key)
212
709
  kdata = data.fetch(:kitchen, Hash.new)
213
710
 
214
- root.delete(key) if root.has_key?(key)
215
- root[key] = kitchen_config.fetch(key) if kitchen_config.has_key?(key)
216
- root[key] = kdata.fetch(key) if kdata.has_key?(key)
711
+ root.delete(key) if root.key?(key)
712
+ root[key] = kitchen_config.fetch(key) if kitchen_config.key?(key)
713
+ root[key] = kdata.fetch(key) if kdata.key?(key)
217
714
  end
218
715
 
716
+ # Returns the hash for a suite by name, or an empty Hash if none
717
+ # could be found.
718
+ #
719
+ # @param name [String] name of a suite
720
+ # @return [Hash] the configuration hash for the suite, or an empty
721
+ # Hash if not found
722
+ # @api private
219
723
  def suite_data_for(name)
220
- data.fetch(:suites, Hash.new).find(lambda { Hash.new }) do |suite|
724
+ data.fetch(:suites, Hash.new).find(-> { Hash.new }) do |suite|
221
725
  suite.fetch(:name, nil) == name
222
726
  end
223
727
  end