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,644 @@
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::Driver::SSHBase do
24
+
25
+ let(:logged_output) { StringIO.new }
26
+ let(:logger) { Logger.new(logged_output) }
27
+ let(:config) { Hash.new }
28
+ let(:state) { Hash.new }
29
+
30
+ let(:busser) do
31
+ stub(
32
+ :setup_cmd => "setup",
33
+ :sync_cmd => "sync",
34
+ :run_cmd => "run"
35
+ )
36
+ end
37
+
38
+ let(:provisioner) do
39
+ stub(
40
+ :install_command => "install",
41
+ :init_command => "init",
42
+ :prepare_command => "prepare",
43
+ :run_command => "run",
44
+ :create_sandbox => true,
45
+ :cleanup_sandbox => true,
46
+ :sandbox_path => "/tmp/sandbox"
47
+ )
48
+ end
49
+
50
+ let(:instance) do
51
+ stub(
52
+ :name => "coolbeans",
53
+ :logger => logger,
54
+ :busser => busser,
55
+ :provisioner => provisioner,
56
+ :to_str => "instance"
57
+ )
58
+ end
59
+
60
+ let(:driver) do
61
+ Kitchen::Driver::SSHBase.new(config).finalize_config!(instance)
62
+ end
63
+
64
+ describe "configuration" do
65
+
66
+ it ":sudo defaults to true" do
67
+ driver[:sudo].must_equal true
68
+ end
69
+
70
+ it ":port defaults to 22" do
71
+ driver[:port].must_equal 22
72
+ end
73
+ end
74
+
75
+ it "#create raises a ClientError" do
76
+ proc { driver.create(state) }.must_raise Kitchen::ClientError
77
+ end
78
+
79
+ it "#destroy raises a ClientError" do
80
+ proc { driver.destroy(state) }.must_raise Kitchen::ClientError
81
+ end
82
+
83
+ # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
84
+ def self.constructs_an_ssh_object
85
+ describe "constructs an SSH object" do
86
+
87
+ it "with hostname set from state" do
88
+ Kitchen::SSH.expects(:new).with { |hostname, _username, _opts|
89
+ hostname.must_equal "fizzy"
90
+ }.returns(stub(:login_command => stub))
91
+
92
+ cmd
93
+ end
94
+
95
+ it "with username set from state" do
96
+ Kitchen::SSH.expects(:new).with { |_hostname, username, _opts|
97
+ username.must_equal "bork"
98
+ }.returns(stub(:login_command => stub))
99
+
100
+ cmd
101
+ end
102
+
103
+ it "with :user_known_hosts_file option set to /dev/null" do
104
+ Kitchen::SSH.expects(:new).with { |_hostname, _username, opts|
105
+ opts[:user_known_hosts_file].must_equal "/dev/null"
106
+ }.returns(stub(:login_command => stub))
107
+
108
+ cmd
109
+ end
110
+
111
+ it "with :paranoid option set to false" do
112
+ Kitchen::SSH.expects(:new).with { |_hostname, _username, opts|
113
+ opts[:paranoid].must_equal false
114
+ }.returns(stub(:login_command => stub))
115
+
116
+ cmd
117
+ end
118
+
119
+ it "with :keys_only option set to falsey by default" do
120
+ Kitchen::SSH.expects(:new).with { |_hostname, _username, opts|
121
+ opts[:keys_only].nil?
122
+ }.returns(stub(:login_command => stub))
123
+
124
+ cmd
125
+ end
126
+
127
+ it "with :keys_only option set to true if :ssh_key is set in config" do
128
+ config[:ssh_key] = "wicked"
129
+
130
+ Kitchen::SSH.expects(:new).with { |_hostname, _username, opts|
131
+ opts[:keys_only].must_equal true
132
+ }.returns(stub(:login_command => stub))
133
+
134
+ cmd
135
+ end
136
+
137
+ it "with :keys_only option set to true if :ssh_key is set in state" do
138
+ state[:ssh_key] = "wicked"
139
+
140
+ Kitchen::SSH.expects(:new).with { |_hostname, _username, opts|
141
+ opts[:keys_only].must_equal true
142
+ }.returns(stub(:login_command => stub))
143
+
144
+ cmd
145
+ end
146
+
147
+ it "with :keys option set to falsey by default" do
148
+ Kitchen::SSH.expects(:new).with { |_hostname, _username, opts|
149
+ opts[:keys].nil?
150
+ }.returns(stub(:login_command => stub))
151
+
152
+ cmd
153
+ end
154
+
155
+ it "with :keys option set to an array if :ssh_key is set in config" do
156
+ config[:ssh_key] = "wicked"
157
+
158
+ Kitchen::SSH.expects(:new).with { |_hostname, _username, opts|
159
+ opts[:keys].must_equal ["wicked"]
160
+ }.returns(stub(:login_command => stub))
161
+
162
+ cmd
163
+ end
164
+
165
+ it "with :keys option set to an array if :ssh_key is set in state" do
166
+ state[:ssh_key] = "wicked"
167
+
168
+ Kitchen::SSH.expects(:new).with { |_hostname, _username, opts|
169
+ opts[:keys].must_equal ["wicked"]
170
+ }.returns(stub(:login_command => stub))
171
+
172
+ cmd
173
+ end
174
+
175
+ it "with :password option set to falsey by default" do
176
+ Kitchen::SSH.expects(:new).with { |_hostname, _username, opts|
177
+ opts[:password].nil?
178
+ }.returns(stub(:login_command => stub))
179
+
180
+ cmd
181
+ end
182
+
183
+ it "with :password option set if given in config" do
184
+ config[:password] = "psst"
185
+
186
+ Kitchen::SSH.expects(:new).with { |_hostname, _username, opts|
187
+ opts[:password].must_equal "psst"
188
+ }.returns(stub(:login_command => stub))
189
+
190
+ cmd
191
+ end
192
+
193
+ it "with :password option set if given in state" do
194
+ state[:password] = "psst"
195
+
196
+ Kitchen::SSH.expects(:new).with { |_hostname, _username, opts|
197
+ opts[:password].must_equal "psst"
198
+ }.returns(stub(:login_command => stub))
199
+
200
+ cmd
201
+ end
202
+
203
+ it "with :forward_agent option set to falsey by default" do
204
+ Kitchen::SSH.expects(:new).with { |_hostname, _username, opts|
205
+ opts[:forward_agent].nil?
206
+ }.returns(stub(:login_command => stub))
207
+
208
+ cmd
209
+ end
210
+
211
+ it "with :forward_agent option set if given in config" do
212
+ config[:forward_agent] = "yeah?"
213
+
214
+ Kitchen::SSH.expects(:new).with { |_hostname, _username, opts|
215
+ opts[:forward_agent].must_equal "yeah?"
216
+ }.returns(stub(:login_command => stub))
217
+
218
+ cmd
219
+ end
220
+
221
+ it "with :forward_agent option set if given in state" do
222
+ state[:forward_agent] = "yeah?"
223
+
224
+ Kitchen::SSH.expects(:new).with { |_hostname, _username, opts|
225
+ opts[:forward_agent].must_equal "yeah?"
226
+ }.returns(stub(:login_command => stub))
227
+
228
+ cmd
229
+ end
230
+
231
+ it "with :port option set to 22 by default" do
232
+ Kitchen::SSH.expects(:new).with { |_hostname, _username, opts|
233
+ opts[:port].must_equal 22
234
+ }.returns(stub(:login_command => stub))
235
+
236
+ cmd
237
+ end
238
+
239
+ it "with :port option set if customized in config" do
240
+ config[:port] = 1234
241
+
242
+ Kitchen::SSH.expects(:new).with { |_hostname, _username, opts|
243
+ opts[:port].must_equal 1234
244
+ }.returns(stub(:login_command => stub))
245
+
246
+ cmd
247
+ end
248
+
249
+ it "with :port option set if customized in state" do
250
+ state[:port] = 9999
251
+
252
+ Kitchen::SSH.expects(:new).with { |_hostname, _username, opts|
253
+ opts[:port].must_equal 9999
254
+ }.returns(stub(:login_command => stub))
255
+
256
+ cmd
257
+ end
258
+
259
+ it "with :logger option set to driver's logger" do
260
+ Kitchen::SSH.expects(:new).with { |_hostname, _username, opts|
261
+ opts[:logger].must_equal logger
262
+ }.returns(stub(:login_command => stub))
263
+
264
+ cmd
265
+ end
266
+ end
267
+ end
268
+ # rubocop:enable Metrics/MethodLength, Metrics/AbcSize
269
+
270
+ describe "#login_command" do
271
+
272
+ let(:cmd) { driver.login_command(state) }
273
+
274
+ before do
275
+ state[:hostname] = "fizzy"
276
+ state[:username] = "bork"
277
+ end
278
+
279
+ it "returns a LoginCommand" do
280
+ cmd.must_be_instance_of Kitchen::LoginCommand
281
+ end
282
+
283
+ constructs_an_ssh_object
284
+ end
285
+
286
+ describe "#converge" do
287
+
288
+ let(:cmd) { driver.converge(state) }
289
+ let(:connection) { stub(:exec => true) }
290
+
291
+ before do
292
+ state[:hostname] = "fizzy"
293
+ state[:username] = "bork"
294
+ provisioner.stubs(:[]).with(:root_path).returns("/rooty")
295
+ FakeFS.activate!
296
+ FileUtils.mkdir_p("/tmp")
297
+ end
298
+
299
+ after do
300
+ FakeFS.deactivate!
301
+ FakeFS::FileSystem.clear
302
+ end
303
+
304
+ constructs_an_ssh_object
305
+
306
+ it "creates the sandbox" do
307
+ Kitchen::SSH.stubs(:new).yields(connection)
308
+ provisioner.expects(:create_sandbox)
309
+
310
+ cmd
311
+ end
312
+
313
+ it "ensures that the sandbox is cleaned up" do
314
+ Kitchen::SSH.stubs(:new).raises
315
+ provisioner.expects(:cleanup_sandbox)
316
+
317
+ begin
318
+ cmd
319
+ rescue # rubocop:disable Lint/HandleExceptions
320
+ end
321
+ end
322
+
323
+ it "invokes the provisioner commands over ssh" do
324
+ Kitchen::SSH.stubs(:new).yields(connection)
325
+ order = sequence("order")
326
+ connection.expects(:exec).with("install").in_sequence(order)
327
+ connection.expects(:exec).with("init").in_sequence(order)
328
+ connection.expects(:exec).with("prepare").in_sequence(order)
329
+ connection.expects(:exec).with("run").in_sequence(order)
330
+
331
+ cmd
332
+ end
333
+
334
+ it "invokes the #install_command with :http_proxy set in config" do
335
+ config[:http_proxy] = "http://proxy"
336
+ Kitchen::SSH.stubs(:new).yields(connection)
337
+ connection.expects(:exec).with("env http_proxy=http://proxy install")
338
+
339
+ cmd
340
+ end
341
+
342
+ it "invokes the #install_command with :https_proxy set in config" do
343
+ config[:https_proxy] = "https://proxy"
344
+ Kitchen::SSH.stubs(:new).yields(connection)
345
+ connection.expects(:exec).with("env https_proxy=https://proxy install")
346
+
347
+ cmd
348
+ end
349
+
350
+ it "invokes the #install_command with :http_proxy & :https_proxy set" do
351
+ config[:http_proxy] = "http://proxy"
352
+ config[:https_proxy] = "https://proxy"
353
+ Kitchen::SSH.stubs(:new).yields(connection)
354
+ connection.expects(:exec).with(
355
+ "env http_proxy=http://proxy https_proxy=https://proxy install")
356
+
357
+ cmd
358
+ end
359
+
360
+ describe "transferring files" do
361
+
362
+ before do
363
+ Kitchen::SSH.stubs(:new).yields(connection)
364
+ connection.stubs(:upload_path!)
365
+ FileUtils.mkdir_p "/tmp/sandbox/stuff"
366
+ end
367
+
368
+ it "uploads files" do
369
+ connection.expects(:upload_path!).with("/tmp/sandbox/stuff", "/rooty")
370
+
371
+ cmd
372
+ end
373
+
374
+ it "logs to info" do
375
+ cmd
376
+
377
+ logged_output.string.
378
+ must_match(/INFO -- : Transferring files to instance$/)
379
+ end
380
+
381
+ it "logs to debug" do
382
+ cmd
383
+
384
+ logged_output.string.must_match(/DEBUG -- : Transfer complete$/)
385
+ end
386
+
387
+ it "raises an ActionFailed on transfer when SSHFailed is raised" do
388
+ connection.stubs(:upload_path!).raises(Kitchen::SSHFailed.new("dang"))
389
+
390
+ proc { cmd }.must_raise Kitchen::ActionFailed
391
+ end
392
+
393
+ it "raises an ActionFailed on exec when Net::SSH:Exception is raised" do
394
+ connection.stubs(:upload_path!).raises(Net::SSH::Exception.new("dang"))
395
+
396
+ proc { cmd }.must_raise Kitchen::ActionFailed
397
+ end
398
+ end
399
+
400
+ it "raises an ActionFailed on exec when SSHFailed is raised" do
401
+ Kitchen::SSH.stubs(:new).yields(connection)
402
+ connection.stubs(:exec).raises(Kitchen::SSHFailed.new("dang"))
403
+
404
+ proc { cmd }.must_raise Kitchen::ActionFailed
405
+ end
406
+
407
+ it "raises an ActionFailed on exec when Net::SSH:Exception is raised" do
408
+ Kitchen::SSH.stubs(:new).yields(connection)
409
+ connection.stubs(:exec).raises(Net::SSH::Exception.new("dang"))
410
+
411
+ proc { cmd }.must_raise Kitchen::ActionFailed
412
+ end
413
+ end
414
+
415
+ describe "#setup" do
416
+
417
+ let(:cmd) { driver.setup(state) }
418
+ let(:connection) { mock }
419
+
420
+ before do
421
+ state[:hostname] = "fizzy"
422
+ state[:username] = "bork"
423
+ end
424
+
425
+ constructs_an_ssh_object
426
+
427
+ it "doesn't invoke an ssh command if busser#setup_cmd is nil" do
428
+ busser.stubs(:setup_cmd).returns(nil)
429
+ Kitchen::SSH.stubs(:new).yields(connection)
430
+
431
+ cmd
432
+ end
433
+
434
+ it "invokes the busser#setup_cmd over ssh" do
435
+ Kitchen::SSH.stubs(:new).yields(connection)
436
+ connection.expects(:exec).with("setup")
437
+
438
+ cmd
439
+ end
440
+
441
+ it "invokes the busser#setup_cmd with :http_proxy set in config" do
442
+ config[:http_proxy] = "http://proxy"
443
+ Kitchen::SSH.stubs(:new).yields(connection)
444
+ connection.expects(:exec).with("env http_proxy=http://proxy setup")
445
+
446
+ cmd
447
+ end
448
+
449
+ it "invokes the busser#setup_cmd with :https_proxy set in config" do
450
+ config[:https_proxy] = "https://proxy"
451
+ Kitchen::SSH.stubs(:new).yields(connection)
452
+ connection.expects(:exec).with("env https_proxy=https://proxy setup")
453
+
454
+ cmd
455
+ end
456
+
457
+ it "invokes the busser#setup_cmd with :http_proxy & :https_proxy set" do
458
+ config[:http_proxy] = "http://proxy"
459
+ config[:https_proxy] = "https://proxy"
460
+ Kitchen::SSH.stubs(:new).yields(connection)
461
+ connection.expects(:exec).with(
462
+ "env http_proxy=http://proxy https_proxy=https://proxy setup")
463
+
464
+ cmd
465
+ end
466
+
467
+ it "raises an ActionFailed when SSHFailed is raised" do
468
+ Kitchen::SSH.stubs(:new).yields(connection)
469
+ connection.stubs(:exec).raises(Kitchen::SSHFailed.new("dang"))
470
+
471
+ proc { cmd }.must_raise Kitchen::ActionFailed
472
+ end
473
+
474
+ it "raises an ActionFailed when Net::SSH:Exception is raised" do
475
+ Kitchen::SSH.stubs(:new).yields(connection)
476
+ connection.stubs(:exec).raises(Net::SSH::Exception.new("dang"))
477
+
478
+ proc { cmd }.must_raise Kitchen::ActionFailed
479
+ end
480
+ end
481
+
482
+ describe "#verify" do
483
+
484
+ let(:cmd) { driver.verify(state) }
485
+ let(:connection) { mock }
486
+
487
+ before do
488
+ state[:hostname] = "fizzy"
489
+ state[:username] = "bork"
490
+ end
491
+
492
+ constructs_an_ssh_object
493
+
494
+ it "doesn't invoke an ssh command if busser#sync_cmd & #run_cmd are nil" do
495
+ busser.stubs(:sync_cmd).returns(nil)
496
+ busser.stubs(:run_cmd).returns(nil)
497
+ Kitchen::SSH.stubs(:new).yields(connection)
498
+
499
+ cmd
500
+ end
501
+
502
+ it "doesn't invoke an ssh command for busser#sync_cmd if nil" do
503
+ busser.stubs(:sync_cmd).returns(nil)
504
+ Kitchen::SSH.stubs(:new).yields(connection)
505
+ connection.expects(:exec).with("run")
506
+
507
+ cmd
508
+ end
509
+
510
+ it "doesn't invoke an ssh command for busser#run_cmd if nil" do
511
+ busser.stubs(:run_cmd).returns(nil)
512
+ Kitchen::SSH.stubs(:new).yields(connection)
513
+ connection.expects(:exec).with("sync")
514
+
515
+ cmd
516
+ end
517
+
518
+ it "invokes the busser#sync_cmd & #run_cmd over ssh" do
519
+ Kitchen::SSH.stubs(:new).yields(connection)
520
+ connection.expects(:exec).with("sync")
521
+ connection.expects(:exec).with("run")
522
+
523
+ cmd
524
+ end
525
+
526
+ it "invokes the busser#setup_cmd with :http_proxy set in config" do
527
+ busser.stubs(:run_cmd).returns(nil)
528
+ config[:http_proxy] = "http://proxy"
529
+ Kitchen::SSH.stubs(:new).yields(connection)
530
+ connection.expects(:exec).with("env http_proxy=http://proxy sync")
531
+
532
+ cmd
533
+ end
534
+
535
+ it "invokes the busser#setup_cmd with :https_proxy set in config" do
536
+ busser.stubs(:run_cmd).returns(nil)
537
+ config[:https_proxy] = "https://proxy"
538
+ Kitchen::SSH.stubs(:new).yields(connection)
539
+ connection.expects(:exec).with("env https_proxy=https://proxy sync")
540
+
541
+ cmd
542
+ end
543
+
544
+ it "invokes the busser#setup_cmd with :http_proxy & :https_proxy set" do
545
+ busser.stubs(:run_cmd).returns(nil)
546
+ config[:http_proxy] = "http://proxy"
547
+ config[:https_proxy] = "https://proxy"
548
+ Kitchen::SSH.stubs(:new).yields(connection)
549
+ connection.expects(:exec).with(
550
+ "env http_proxy=http://proxy https_proxy=https://proxy sync")
551
+
552
+ cmd
553
+ end
554
+
555
+ it "raises an ActionFailed when SSHFailed is raised" do
556
+ Kitchen::SSH.stubs(:new).yields(connection)
557
+ connection.stubs(:exec).raises(Kitchen::SSHFailed.new("dang"))
558
+
559
+ proc { cmd }.must_raise Kitchen::ActionFailed
560
+ end
561
+
562
+ it "raises an ActionFailed when Net::SSH:Exception is raised" do
563
+ Kitchen::SSH.stubs(:new).yields(connection)
564
+ connection.stubs(:exec).raises(Net::SSH::Exception.new("dang"))
565
+
566
+ proc { cmd }.must_raise Kitchen::ActionFailed
567
+ end
568
+ end
569
+
570
+ describe "#ssh" do
571
+
572
+ let(:cmd) { driver.ssh(["host", "user", { :one => "two" }], "go") }
573
+ let(:connection) { mock }
574
+
575
+ it "creates an SSH object" do
576
+ Kitchen::SSH.expects(:new).with { |hostname, username, opts|
577
+ hostname.must_equal "host"
578
+ username.must_equal "user"
579
+ opts.must_equal(:one => "two")
580
+ }
581
+
582
+ cmd
583
+ end
584
+
585
+ it "invokes the command over ssh" do
586
+ Kitchen::SSH.stubs(:new).yields(connection)
587
+ connection.expects(:exec).with("go")
588
+
589
+ cmd
590
+ end
591
+ end
592
+
593
+ describe "#remote_command" do
594
+
595
+ let(:cmd) { driver.remote_command(state, "shipit") }
596
+ let(:connection) { mock }
597
+
598
+ before do
599
+ state[:hostname] = "fizzy"
600
+ state[:username] = "bork"
601
+ end
602
+
603
+ it "creates an SSH object" do
604
+ Kitchen::SSH.expects(:new).with { |hostname, username, _opts|
605
+ hostname.must_equal "fizzy"
606
+ username.must_equal "bork"
607
+ }
608
+
609
+ cmd
610
+ end
611
+
612
+ it "invokes the command over ssh" do
613
+ Kitchen::SSH.stubs(:new).yields(connection)
614
+ connection.expects(:exec).with("shipit")
615
+
616
+ cmd
617
+ end
618
+ end
619
+
620
+ describe "#wait_for_sshd" do
621
+
622
+ let(:cmd) do
623
+ driver.send(:wait_for_sshd, "host", "user", :one => "two")
624
+ end
625
+
626
+ it "creates an SSH object with merged options" do
627
+ Kitchen::SSH.expects(:new).with { |hostname, username, opts|
628
+ hostname.must_equal "host"
629
+ username.must_equal "user"
630
+ opts.must_equal(:one => "two", :logger => logger)
631
+ }.returns(stub(:wait => true))
632
+
633
+ cmd
634
+ end
635
+
636
+ it "calls wait on the SSH object" do
637
+ ssh = mock
638
+ Kitchen::SSH.stubs(:new).returns(ssh)
639
+ ssh.expects(:wait)
640
+
641
+ cmd
642
+ end
643
+ end
644
+ end