test-kitchen 1.2.1 → 1.3.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 (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
@@ -0,0 +1,419 @@
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ # Author:: Fletcher Nichol (<fnichol@nichol.ca>)
4
+ #
5
+ # Copyright (C) 2014, Fletcher Nichol
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+
19
+ require_relative "../spec_helper"
20
+
21
+ require "kitchen"
22
+
23
+ describe Kitchen::Logger do
24
+
25
+ before do
26
+ Kitchen.stubs(:tty?).returns(true)
27
+ @orig_stdout = $stdout
28
+ $stdout = StringIO.new
29
+ end
30
+
31
+ after do
32
+ $stdout = @orig_stdout
33
+ end
34
+
35
+ def colorize(*args)
36
+ Kitchen::Color.colorize(*args)
37
+ end
38
+
39
+ let(:opts) do
40
+ { :color => :red }
41
+ end
42
+
43
+ let(:logger) do
44
+ Kitchen::Logger.new(opts)
45
+ end
46
+
47
+ it "sets the log level to :info by default" do
48
+ logger.level.must_equal Kitchen::Util.to_logger_level(:info)
49
+ logger.debug?.must_equal false
50
+ logger.info?.must_equal true
51
+ logger.error?.must_equal true
52
+ logger.warn?.must_equal true
53
+ logger.fatal?.must_equal true
54
+ end
55
+
56
+ it "sets a level at creation" do
57
+ opts[:level] = Kitchen::Util.to_logger_level(:warn)
58
+
59
+ logger.level.must_equal Kitchen::Util.to_logger_level(:warn)
60
+ logger.info?.must_equal false
61
+ logger.warn?.must_equal true
62
+ logger.fatal?.must_equal true
63
+ end
64
+
65
+ it "sets a level after creation" do
66
+ logger.level = Kitchen::Util.to_logger_level(:fatal)
67
+
68
+ logger.level.must_equal Kitchen::Util.to_logger_level(:fatal)
69
+ logger.warn?.must_equal false
70
+ logger.fatal?.must_equal true
71
+ end
72
+
73
+ it "datetime_format is nil by default" do
74
+ logger.datetime_format.must_equal nil
75
+ end
76
+
77
+ it "sets datetime_format after creation" do
78
+ logger.datetime_format = "smart?"
79
+
80
+ logger.datetime_format.must_equal "smart?"
81
+ end
82
+
83
+ it "sets progname to Kitchen by default" do
84
+ logger.progname.must_equal "Kitchen"
85
+ end
86
+
87
+ it "sets progname at creation" do
88
+ opts[:progname] = "Dream Theater"
89
+
90
+ logger.progname.must_equal "Dream Theater"
91
+ end
92
+
93
+ it "sets progname after creation" do
94
+ logger.progname = "MASTA"
95
+
96
+ logger.progname.must_equal "MASTA"
97
+ end
98
+
99
+ describe "stdout-based logger" do
100
+
101
+ let(:stdout) { StringIO.new }
102
+
103
+ before { opts[:stdout] = stdout }
104
+
105
+ it "sets up a simple STDOUT logger by default" do
106
+ opts.delete(:stdout)
107
+ logger.info("hello")
108
+
109
+ $stdout.string.must_equal colorize(" hello", opts[:color]) + "\n"
110
+ end
111
+
112
+ it "sets up a simple STDOUT logger by default with no color" do
113
+ Kitchen.stubs(:tty?).returns(false)
114
+ opts.delete(:stdout)
115
+ logger.info("hello")
116
+
117
+ $stdout.string.must_equal " hello\n"
118
+ end
119
+
120
+ it "accepts a :stdout option to redirect output" do
121
+ logger.info("hello")
122
+
123
+ stdout.string.must_equal colorize(" hello", opts[:color]) + "\n"
124
+ end
125
+
126
+ it "accepts a :stdout option to redirect output with no color" do
127
+ Kitchen.stubs(:tty?).returns(false)
128
+ logger.info("hello")
129
+
130
+ stdout.string.must_equal " hello\n"
131
+ end
132
+
133
+ describe "for severity" do
134
+
135
+ before { opts[:level] = Kitchen::Util.to_logger_level(:debug) }
136
+
137
+ it "logs to banner" do
138
+ logger.banner("yo")
139
+
140
+ stdout.string.must_equal colorize("-----> yo", opts[:color]) + "\n"
141
+ end
142
+
143
+ it "logs to banner with no color" do
144
+ Kitchen.stubs(:tty?).returns(false)
145
+ logger.banner("yo")
146
+
147
+ stdout.string.must_equal "-----> yo\n"
148
+ end
149
+
150
+ it "logs to debug" do
151
+ logger.debug("yo")
152
+
153
+ stdout.string.must_equal colorize("D yo", opts[:color]) + "\n"
154
+ end
155
+
156
+ it "logs to debug with no color" do
157
+ Kitchen.stubs(:tty?).returns(false)
158
+ logger.debug("yo")
159
+
160
+ stdout.string.must_equal "D yo\n"
161
+ end
162
+
163
+ it "logs to info" do
164
+ logger.info("yo")
165
+
166
+ stdout.string.must_equal colorize(" yo", opts[:color]) + "\n"
167
+ end
168
+
169
+ it "logs to info with no color" do
170
+ Kitchen.stubs(:tty?).returns(false)
171
+ logger.info("yo")
172
+
173
+ stdout.string.must_equal " yo\n"
174
+ end
175
+
176
+ it "logs to error" do
177
+ logger.error("yo")
178
+
179
+ stdout.string.must_equal colorize(">>>>>> yo", opts[:color]) + "\n"
180
+ end
181
+
182
+ it "logs to error with no color" do
183
+ Kitchen.stubs(:tty?).returns(false)
184
+ logger.error("yo")
185
+
186
+ stdout.string.must_equal ">>>>>> yo\n"
187
+ end
188
+
189
+ it "logs to warn" do
190
+ logger.warn("yo")
191
+
192
+ stdout.string.must_equal colorize("$$$$$$ yo", opts[:color]) + "\n"
193
+ end
194
+
195
+ it "logs to warn with no color" do
196
+ Kitchen.stubs(:tty?).returns(false)
197
+ logger.warn("yo")
198
+
199
+ stdout.string.must_equal "$$$$$$ yo\n"
200
+ end
201
+
202
+ it "logs to fatal" do
203
+ logger.fatal("yo")
204
+
205
+ stdout.string.must_equal colorize("!!!!!! yo", opts[:color]) + "\n"
206
+ end
207
+
208
+ it "logs to fatal with no color" do
209
+ Kitchen.stubs(:tty?).returns(false)
210
+ logger.fatal("yo")
211
+
212
+ stdout.string.must_equal "!!!!!! yo\n"
213
+ end
214
+
215
+ it "logs to unknown" do
216
+ logger.unknown("yo")
217
+
218
+ stdout.string.must_equal colorize("?????? yo", opts[:color]) + "\n"
219
+ end
220
+
221
+ it "logs to unknown with no color" do
222
+ Kitchen.stubs(:tty?).returns(false)
223
+ logger.unknown("yo")
224
+
225
+ stdout.string.must_equal "?????? yo\n"
226
+ end
227
+ end
228
+
229
+ describe "#<<" do
230
+
231
+ it "message with a newline are logged on info" do
232
+ logger << "yo\n"
233
+
234
+ stdout.string.must_equal colorize(" yo", opts[:color]) + "\n"
235
+ end
236
+
237
+ it "message with multiple newlines are separately logged on info" do
238
+ logger << "yo\nheya\n"
239
+
240
+ stdout.string.must_equal(
241
+ colorize(" yo", opts[:color]) + "\n" +
242
+ colorize(" heya", opts[:color]) + "\n"
243
+ )
244
+ end
245
+
246
+ it "message with info, error, and banner lines will be preserved" do
247
+ logger << [
248
+ "-----> banner",
249
+ " info",
250
+ ">>>>>> error",
251
+ "vanilla"
252
+ ].join("\n").concat("\n")
253
+
254
+ stdout.string.must_equal(
255
+ colorize("-----> banner", opts[:color]) + "\n" +
256
+ colorize(" info", opts[:color]) + "\n" +
257
+ colorize(">>>>>> error", opts[:color]) + "\n" +
258
+ colorize(" vanilla", opts[:color]) + "\n"
259
+ )
260
+ end
261
+
262
+ it "message with line that is not newline terminated will be buffered" do
263
+ logger << [
264
+ "-----> banner",
265
+ " info",
266
+ "partial"
267
+ ].join("\n")
268
+
269
+ stdout.string.must_equal(
270
+ colorize("-----> banner", opts[:color]) + "\n" +
271
+ colorize(" info", opts[:color]) + "\n"
272
+ )
273
+ end
274
+
275
+ it "logger with buffered data will flush on next message with newline" do
276
+ logger << "partial"
277
+ logger << "ly\nokay\n"
278
+
279
+ stdout.string.must_equal(
280
+ colorize(" partially", opts[:color]) + "\n" +
281
+ colorize(" okay", opts[:color]) + "\n"
282
+ )
283
+ end
284
+
285
+ it "logger chomps carriage return characters" do
286
+ logger << [
287
+ "-----> banner\r",
288
+ "vanilla\r"
289
+ ].join("\n").concat("\n")
290
+
291
+ stdout.string.must_equal(
292
+ colorize("-----> banner", opts[:color]) + "\n" +
293
+ colorize(" vanilla", opts[:color]) + "\n"
294
+ )
295
+ end
296
+ end
297
+ end
298
+
299
+ describe "opened IO logdev-based logger" do
300
+
301
+ let(:logdev) { StringIO.new }
302
+
303
+ before { opts[:logdev] = logdev }
304
+
305
+ describe "for severity" do
306
+
307
+ before { opts[:level] = Kitchen::Util.to_logger_level(:debug) }
308
+
309
+ let(:ts) { "\\[[^\\]]+\\]" }
310
+
311
+ it "logs to banner" do
312
+ logger.banner("yo")
313
+
314
+ logdev.string.must_match(/^I, #{ts} INFO -- Kitchen: -----> yo$/)
315
+ end
316
+
317
+ it "logs to debug" do
318
+ logger.debug("yo")
319
+
320
+ logdev.string.must_match(/^D, #{ts} DEBUG -- Kitchen: yo$/)
321
+ end
322
+
323
+ it "logs to info" do
324
+ logger.info("yo")
325
+
326
+ logdev.string.must_match(/^I, #{ts} INFO -- Kitchen: yo$/)
327
+ end
328
+
329
+ it "logs to error" do
330
+ logger.error("yo")
331
+
332
+ logdev.string.must_match(/^E, #{ts} ERROR -- Kitchen: yo$/)
333
+ end
334
+
335
+ it "logs to warn" do
336
+ logger.warn("yo")
337
+
338
+ logdev.string.must_match(/^W, #{ts} WARN -- Kitchen: yo$/)
339
+ end
340
+
341
+ it "logs to fatal" do
342
+ logger.fatal("yo")
343
+
344
+ logdev.string.must_match(/^F, #{ts} FATAL -- Kitchen: yo$/)
345
+ end
346
+
347
+ it "logs to unknown" do
348
+ logger.unknown("yo")
349
+
350
+ logdev.string.must_match(/^A, #{ts} ANY -- Kitchen: yo$/)
351
+ end
352
+ end
353
+ end
354
+
355
+ describe "file IO logdev-based logger" do
356
+
357
+ let(:logfile) { Dir::Tmpname.make_tmpname(%w[kitchen .log], nil) }
358
+
359
+ before do
360
+ opts[:logdev] = logfile
361
+ FakeFS.activate!
362
+ FileUtils.mkdir_p("/tmp")
363
+ end
364
+
365
+ after do
366
+ FakeFS.deactivate!
367
+ FakeFS::FileSystem.clear
368
+ end
369
+
370
+ describe "for severity" do
371
+
372
+ before { opts[:level] = Kitchen::Util.to_logger_level(:debug) }
373
+
374
+ let(:ts) { "\\[[^\\]]+\\]" }
375
+
376
+ it "logs to banner" do
377
+ logger.banner("yo")
378
+
379
+ IO.read(logfile).must_match(/^I, #{ts} INFO -- Kitchen: -----> yo$/)
380
+ end
381
+
382
+ it "logs to debug" do
383
+ logger.debug("yo")
384
+
385
+ IO.read(logfile).must_match(/^D, #{ts} DEBUG -- Kitchen: yo$/)
386
+ end
387
+
388
+ it "logs to info" do
389
+ logger.info("yo")
390
+
391
+ IO.read(logfile).must_match(/^I, #{ts} INFO -- Kitchen: yo$/)
392
+ end
393
+
394
+ it "logs to error" do
395
+ logger.error("yo")
396
+
397
+ IO.read(logfile).must_match(/^E, #{ts} ERROR -- Kitchen: yo$/)
398
+ end
399
+
400
+ it "logs to warn" do
401
+ logger.warn("yo")
402
+
403
+ IO.read(logfile).must_match(/^W, #{ts} WARN -- Kitchen: yo$/)
404
+ end
405
+
406
+ it "logs to fatal" do
407
+ logger.fatal("yo")
408
+
409
+ IO.read(logfile).must_match(/^F, #{ts} FATAL -- Kitchen: yo$/)
410
+ end
411
+
412
+ it "logs to unknown" do
413
+ logger.unknown("yo")
414
+
415
+ IO.read(logfile).must_match(/^A, #{ts} ANY -- Kitchen: yo$/)
416
+ end
417
+ end
418
+ end
419
+ end
@@ -0,0 +1,59 @@
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ # Author:: Fletcher Nichol (<fnichol@nichol.ca>)
4
+ #
5
+ # Copyright (C) 2014, Fletcher Nichol
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+
19
+ require_relative "../spec_helper"
20
+
21
+ require "kitchen/logging"
22
+
23
+ class LoggingDummy
24
+
25
+ include Kitchen::Logging
26
+
27
+ attr_reader :logger
28
+
29
+ def initialize(logger)
30
+ @logger = logger
31
+ end
32
+
33
+ class Logger
34
+
35
+ METHODS = [:banner, :debug, :info, :warn, :error, :fatal]
36
+
37
+ attr_reader(*(METHODS.map { |m| "#{m}_msg".to_sym }))
38
+
39
+ METHODS.each do |meth|
40
+ define_method(meth) do |*args|
41
+ instance_variable_set("@#{meth}_msg", args.first)
42
+ end
43
+ end
44
+ end
45
+ end
46
+
47
+ describe Kitchen::Logging do
48
+
49
+ let(:logger) { LoggingDummy::Logger.new }
50
+ let(:subject) { LoggingDummy.new(logger) }
51
+
52
+ LoggingDummy::Logger::METHODS.each do |meth|
53
+ it "##{meth} calls method on logger" do
54
+ subject.public_send(meth, "ping")
55
+
56
+ logger.public_send("#{meth}_msg").must_equal "ping"
57
+ end
58
+ end
59
+ end