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