test-kitchen 1.6.0 → 1.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (180) hide show
  1. checksums.yaml +4 -4
  2. data/.cane +8 -7
  3. data/.github/ISSUE_TEMPLATE.md +56 -0
  4. data/.gitignore +28 -27
  5. data/.kitchen.ci.yml +23 -0
  6. data/.kitchen.proxy.yml +27 -0
  7. data/.rubocop.yml +3 -3
  8. data/.travis.yml +70 -53
  9. data/.yardopts +3 -3
  10. data/Berksfile +3 -0
  11. data/CHANGELOG.md +1083 -1051
  12. data/CONTRIBUTING.md +14 -14
  13. data/Gemfile +19 -14
  14. data/Gemfile.proxy_tests +4 -5
  15. data/Guardfile +42 -42
  16. data/LICENSE +15 -15
  17. data/MAINTAINERS.md +23 -24
  18. data/README.md +135 -135
  19. data/Rakefile +61 -76
  20. data/appveyor.yml +44 -34
  21. data/features/kitchen_action_commands.feature +164 -164
  22. data/features/kitchen_command.feature +16 -16
  23. data/features/kitchen_console_command.feature +34 -34
  24. data/features/kitchen_defaults.feature +38 -38
  25. data/features/kitchen_diagnose_command.feature +96 -96
  26. data/features/kitchen_driver_create_command.feature +64 -64
  27. data/features/kitchen_driver_discover_command.feature +25 -25
  28. data/features/kitchen_help_command.feature +16 -16
  29. data/features/kitchen_init_command.feature +274 -274
  30. data/features/kitchen_list_command.feature +104 -104
  31. data/features/kitchen_login_command.feature +62 -62
  32. data/features/kitchen_sink_command.feature +30 -30
  33. data/features/kitchen_test_command.feature +88 -88
  34. data/features/step_definitions/gem_steps.rb +36 -36
  35. data/features/step_definitions/git_steps.rb +5 -5
  36. data/features/step_definitions/output_steps.rb +5 -5
  37. data/features/support/env.rb +75 -75
  38. data/lib/kitchen.rb +150 -150
  39. data/lib/kitchen/base64_stream.rb +55 -55
  40. data/lib/kitchen/cli.rb +419 -419
  41. data/lib/kitchen/collection.rb +55 -55
  42. data/lib/kitchen/color.rb +65 -65
  43. data/lib/kitchen/command.rb +185 -185
  44. data/lib/kitchen/command/action.rb +45 -45
  45. data/lib/kitchen/command/console.rb +58 -58
  46. data/lib/kitchen/command/diagnose.rb +92 -92
  47. data/lib/kitchen/command/driver_discover.rb +105 -105
  48. data/lib/kitchen/command/exec.rb +41 -41
  49. data/lib/kitchen/command/list.rb +119 -119
  50. data/lib/kitchen/command/login.rb +43 -43
  51. data/lib/kitchen/command/sink.rb +54 -54
  52. data/lib/kitchen/command/test.rb +51 -51
  53. data/lib/kitchen/config.rb +322 -322
  54. data/lib/kitchen/configurable.rb +529 -529
  55. data/lib/kitchen/data_munger.rb +959 -960
  56. data/lib/kitchen/diagnostic.rb +141 -141
  57. data/lib/kitchen/driver.rb +56 -56
  58. data/lib/kitchen/driver/base.rb +134 -134
  59. data/lib/kitchen/driver/dummy.rb +108 -108
  60. data/lib/kitchen/driver/proxy.rb +72 -72
  61. data/lib/kitchen/driver/ssh_base.rb +357 -357
  62. data/lib/kitchen/errors.rb +229 -229
  63. data/lib/kitchen/generator/driver_create.rb +177 -177
  64. data/lib/kitchen/generator/init.rb +296 -296
  65. data/lib/kitchen/instance.rb +662 -662
  66. data/lib/kitchen/lazy_hash.rb +142 -142
  67. data/lib/kitchen/loader/yaml.rb +349 -349
  68. data/lib/kitchen/logger.rb +423 -423
  69. data/lib/kitchen/logging.rb +56 -56
  70. data/lib/kitchen/login_command.rb +52 -52
  71. data/lib/kitchen/metadata_chopper.rb +52 -52
  72. data/lib/kitchen/platform.rb +67 -67
  73. data/lib/kitchen/provisioner.rb +54 -54
  74. data/lib/kitchen/provisioner/base.rb +236 -236
  75. data/lib/kitchen/provisioner/chef/berkshelf.rb +114 -114
  76. data/lib/kitchen/provisioner/chef/common_sandbox.rb +322 -322
  77. data/lib/kitchen/provisioner/chef/librarian.rb +112 -112
  78. data/lib/kitchen/provisioner/chef_apply.rb +124 -125
  79. data/lib/kitchen/provisioner/chef_base.rb +341 -294
  80. data/lib/kitchen/provisioner/chef_solo.rb +88 -89
  81. data/lib/kitchen/provisioner/chef_zero.rb +245 -245
  82. data/lib/kitchen/provisioner/dummy.rb +79 -79
  83. data/lib/kitchen/provisioner/shell.rb +138 -138
  84. data/lib/kitchen/rake_tasks.rb +63 -63
  85. data/lib/kitchen/shell_out.rb +93 -93
  86. data/lib/kitchen/ssh.rb +276 -276
  87. data/lib/kitchen/state_file.rb +120 -120
  88. data/lib/kitchen/suite.rb +51 -51
  89. data/lib/kitchen/thor_tasks.rb +66 -66
  90. data/lib/kitchen/transport.rb +54 -54
  91. data/lib/kitchen/transport/base.rb +176 -176
  92. data/lib/kitchen/transport/dummy.rb +79 -79
  93. data/lib/kitchen/transport/ssh.rb +364 -364
  94. data/lib/kitchen/transport/winrm.rb +486 -486
  95. data/lib/kitchen/util.rb +147 -147
  96. data/lib/kitchen/verifier.rb +55 -55
  97. data/lib/kitchen/verifier/base.rb +235 -235
  98. data/lib/kitchen/verifier/busser.rb +277 -277
  99. data/lib/kitchen/verifier/dummy.rb +79 -79
  100. data/lib/kitchen/verifier/shell.rb +101 -101
  101. data/lib/kitchen/version.rb +21 -21
  102. data/lib/vendor/hash_recursive_merge.rb +82 -82
  103. data/spec/kitchen/base64_stream_spec.rb +77 -77
  104. data/spec/kitchen/cli_spec.rb +56 -56
  105. data/spec/kitchen/collection_spec.rb +80 -80
  106. data/spec/kitchen/color_spec.rb +54 -54
  107. data/spec/kitchen/config_spec.rb +408 -408
  108. data/spec/kitchen/configurable_spec.rb +1095 -1062
  109. data/spec/kitchen/data_munger_spec.rb +2694 -2383
  110. data/spec/kitchen/diagnostic_spec.rb +129 -129
  111. data/spec/kitchen/driver/base_spec.rb +121 -121
  112. data/spec/kitchen/driver/dummy_spec.rb +199 -199
  113. data/spec/kitchen/driver/proxy_spec.rb +138 -138
  114. data/spec/kitchen/driver/ssh_base_spec.rb +1115 -1115
  115. data/spec/kitchen/driver_spec.rb +112 -112
  116. data/spec/kitchen/errors_spec.rb +309 -309
  117. data/spec/kitchen/instance_spec.rb +1419 -1419
  118. data/spec/kitchen/lazy_hash_spec.rb +117 -117
  119. data/spec/kitchen/loader/yaml_spec.rb +774 -774
  120. data/spec/kitchen/logger_spec.rb +429 -429
  121. data/spec/kitchen/logging_spec.rb +59 -59
  122. data/spec/kitchen/login_command_spec.rb +68 -68
  123. data/spec/kitchen/metadata_chopper_spec.rb +82 -82
  124. data/spec/kitchen/platform_spec.rb +89 -89
  125. data/spec/kitchen/provisioner/base_spec.rb +386 -386
  126. data/spec/kitchen/provisioner/chef_apply_spec.rb +136 -136
  127. data/spec/kitchen/provisioner/chef_base_spec.rb +1161 -1067
  128. data/spec/kitchen/provisioner/chef_solo_spec.rb +557 -557
  129. data/spec/kitchen/provisioner/chef_zero_spec.rb +1001 -1001
  130. data/spec/kitchen/provisioner/dummy_spec.rb +99 -99
  131. data/spec/kitchen/provisioner/shell_spec.rb +566 -566
  132. data/spec/kitchen/provisioner_spec.rb +107 -107
  133. data/spec/kitchen/shell_out_spec.rb +150 -150
  134. data/spec/kitchen/ssh_spec.rb +693 -693
  135. data/spec/kitchen/state_file_spec.rb +129 -129
  136. data/spec/kitchen/suite_spec.rb +62 -62
  137. data/spec/kitchen/transport/base_spec.rb +89 -89
  138. data/spec/kitchen/transport/ssh_spec.rb +1255 -1255
  139. data/spec/kitchen/transport/winrm_spec.rb +1143 -1143
  140. data/spec/kitchen/transport_spec.rb +112 -112
  141. data/spec/kitchen/util_spec.rb +165 -165
  142. data/spec/kitchen/verifier/base_spec.rb +362 -362
  143. data/spec/kitchen/verifier/busser_spec.rb +610 -610
  144. data/spec/kitchen/verifier/dummy_spec.rb +99 -99
  145. data/spec/kitchen/verifier/shell_spec.rb +160 -158
  146. data/spec/kitchen/verifier_spec.rb +120 -120
  147. data/spec/kitchen_spec.rb +114 -114
  148. data/spec/spec_helper.rb +85 -85
  149. data/spec/support/powershell_max_size_spec.rb +40 -40
  150. data/support/busser_install_command.ps1 +14 -14
  151. data/support/busser_install_command.sh +14 -14
  152. data/support/chef-client-zero.rb +77 -77
  153. data/support/chef_base_init_command.ps1 +18 -18
  154. data/support/chef_base_init_command.sh +2 -2
  155. data/support/chef_base_install_command.ps1 +85 -85
  156. data/support/chef_base_install_command.sh +229 -229
  157. data/support/chef_zero_prepare_command_legacy.ps1 +9 -9
  158. data/support/chef_zero_prepare_command_legacy.sh +10 -10
  159. data/support/download_helpers.sh +109 -109
  160. data/support/dummy-validation.pem +27 -27
  161. data/templates/driver/CHANGELOG.md.erb +3 -3
  162. data/templates/driver/Gemfile.erb +3 -3
  163. data/templates/driver/README.md.erb +64 -64
  164. data/templates/driver/Rakefile.erb +21 -21
  165. data/templates/driver/driver.rb.erb +23 -23
  166. data/templates/driver/gemspec.erb +29 -29
  167. data/templates/driver/gitignore.erb +17 -17
  168. data/templates/driver/license_apachev2.erb +15 -15
  169. data/templates/driver/license_lgplv3.erb +16 -16
  170. data/templates/driver/license_mit.erb +22 -22
  171. data/templates/driver/license_reserved.erb +5 -5
  172. data/templates/driver/tailor.erb +4 -4
  173. data/templates/driver/travis.yml.erb +11 -11
  174. data/templates/driver/version.rb.erb +12 -12
  175. data/templates/init/chefignore.erb +1 -1
  176. data/templates/init/kitchen.yml.erb +18 -18
  177. data/test-kitchen.gemspec +62 -62
  178. data/test/integration/default/default_spec.rb +3 -0
  179. data/testing_windows.md +37 -37
  180. metadata +23 -11
@@ -1,1115 +1,1115 @@
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
- require "kitchen/transport/ssh"
23
- require "kitchen/verifier/busser"
24
-
25
- module Kitchen
26
-
27
- module Driver
28
-
29
- class BackCompat < Kitchen::Driver::SSHBase
30
-
31
- def use_run_remote(state, command)
32
- connection = Kitchen::SSH.new(*build_ssh_args(state))
33
- run_remote(command, connection)
34
- end
35
-
36
- def use_transfer_path(state, locals, remote)
37
- connection = Kitchen::SSH.new(*build_ssh_args(state))
38
- transfer_path(locals, remote, connection)
39
- end
40
- end
41
-
42
- class SpeedyCompat < Kitchen::Driver::SSHBase
43
- end
44
-
45
- class DodgyCompat < Kitchen::Driver::SSHBase
46
-
47
- no_parallel_for :converge
48
- end
49
-
50
- class SlowCompat < Kitchen::Driver::SSHBase
51
-
52
- no_parallel_for :create, :destroy
53
- no_parallel_for :verify
54
- end
55
- end
56
- end
57
-
58
- describe Kitchen::Driver::SSHBase do
59
-
60
- let(:logged_output) { StringIO.new }
61
- let(:logger) { Logger.new(logged_output) }
62
- let(:config) { Hash.new }
63
- let(:state) { Hash.new }
64
-
65
- let(:verifier) do
66
- v = mock("busser")
67
- v.responds_like_instance_of(Kitchen::Verifier::Busser)
68
- v.stubs(:install_command).returns("install")
69
- v.stubs(:init_command).returns("init")
70
- v.stubs(:prepare_command).returns("prepare")
71
- v.stubs(:run_command).returns("run")
72
- v.stubs(:create_sandbox).returns(true)
73
- v.stubs(:cleanup_sandbox).returns(true)
74
- v.stubs(:sandbox_path).returns("/tmp/sandbox")
75
- v.stubs(:[]).with(:root_path).returns("/tmp/verifier")
76
- v
77
- end
78
-
79
- let(:provisioner) do
80
- stub(
81
- :install_command => "install",
82
- :init_command => "init",
83
- :prepare_command => "prepare",
84
- :run_command => "run",
85
- :create_sandbox => true,
86
- :cleanup_sandbox => true,
87
- :sandbox_path => "/tmp/sandbox"
88
- )
89
- end
90
-
91
- let(:transport) do
92
- t = mock("transport")
93
- t.responds_like_instance_of(Kitchen::Transport::Base)
94
- t
95
- end
96
-
97
- let(:instance) do
98
- stub(
99
- :name => "coolbeans",
100
- :logger => logger,
101
- :verifier => verifier,
102
- :provisioner => provisioner,
103
- :transport => transport,
104
- :to_str => "instance"
105
- )
106
- end
107
-
108
- let(:driver) do
109
- Kitchen::Driver::SSHBase.new(config).finalize_config!(instance)
110
- end
111
-
112
- it "plugin_version is not set" do
113
- driver.diagnose_plugin[:version].must_equal nil
114
- end
115
-
116
- describe "configuration" do
117
-
118
- it ":sudo defaults to true" do
119
- driver[:sudo].must_equal true
120
- end
121
-
122
- it ":port defaults to 22" do
123
- driver[:port].must_equal 22
124
- end
125
- end
126
-
127
- it "#create raises a ClientError" do
128
- proc { driver.create(state) }.must_raise Kitchen::ClientError
129
- end
130
-
131
- it "#destroy raises a ClientError" do
132
- proc { driver.destroy(state) }.must_raise Kitchen::ClientError
133
- end
134
-
135
- # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
136
- def self.constructs_an_ssh_connection
137
- describe "constructs an SSH connection" do
138
-
139
- it "with hostname set from state" do
140
- transport.expects(:connection).with { |state|
141
- state[:hostname].must_equal "fizzy"
142
- }.returns(stub(:login_command => stub))
143
-
144
- cmd
145
- end
146
-
147
- it "with username set from state" do
148
- transport.expects(:connection).with { |state|
149
- state[:username].must_equal "bork"
150
- }.returns(stub(:login_command => stub))
151
-
152
- cmd
153
- end
154
-
155
- it "with :ssh_key option set from config" do
156
- config[:ssh_key] = "wicked"
157
-
158
- transport.expects(:connection).with { |state|
159
- state[:ssh_key].must_equal "wicked"
160
- }.returns(stub(:login_command => stub))
161
-
162
- cmd
163
- end
164
-
165
- it "with :ssh_key option set from state" do
166
- state[:ssh_key] = "wicked"
167
-
168
- transport.expects(:connection).with { |state|
169
- state[:ssh_key].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
- transport.expects(:connection).with { |state|
177
- state[: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
- transport.expects(:connection).with { |state|
187
- state[: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
- transport.expects(:connection).with { |state|
197
- state[: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
- transport.expects(:connection).with { |state|
205
- state[: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
- transport.expects(:connection).with { |state|
215
- state[: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
- transport.expects(:connection).with { |state|
225
- state[: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
- transport.expects(:connection).with { |state|
233
- state[: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
- transport.expects(:connection).with { |state|
243
- state[: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
- transport.expects(:connection).with { |state|
253
- state[:port].must_equal 9999
254
- }.returns(stub(:login_command => stub))
255
-
256
- cmd
257
- end
258
- end
259
- end
260
- # rubocop:enable Metrics/MethodLength, Metrics/AbcSize
261
-
262
- describe "#login_command" do
263
-
264
- let(:cmd) { driver.login_command(state) }
265
-
266
- before do
267
- state[:hostname] = "fizzy"
268
- state[:username] = "bork"
269
- end
270
-
271
- it "returns a LoginCommand" do
272
- transport.stubs(:connection).returns(stub(:login_command => "command"))
273
-
274
- cmd.must_equal "command"
275
- end
276
-
277
- constructs_an_ssh_connection
278
- end
279
-
280
- describe "#converge" do
281
-
282
- let(:cmd) { driver.converge(state) }
283
- let(:connection) { stub(:execute => true, :upload => true) }
284
-
285
- before do
286
- state[:hostname] = "fizzy"
287
- state[:username] = "bork"
288
- provisioner.stubs(:[]).with(:root_path).returns("/rooty")
289
- FakeFS.activate!
290
- FileUtils.mkdir_p("/tmp")
291
- @original_env = ENV.to_hash
292
- ENV.replace("http_proxy" => nil, "HTTP_PROXY" => nil,
293
- "https_proxy" => nil, "HTTPS_PROXY" => nil,
294
- "ftp_proxy" => nil, "FTP_PROXY" => nil,
295
- "no_proxy" => nil, "NO_PROXY" => nil)
296
- end
297
-
298
- after do
299
- FakeFS.deactivate!
300
- FakeFS::FileSystem.clear
301
- ENV.clear
302
- ENV.replace(@original_env)
303
- end
304
-
305
- constructs_an_ssh_connection
306
-
307
- it "creates the sandbox" do
308
- transport.stubs(:connection).yields(connection)
309
- provisioner.expects(:create_sandbox)
310
-
311
- cmd
312
- end
313
-
314
- it "ensures that the sandbox is cleaned up" do
315
- transport.stubs(:connection).raises
316
- provisioner.expects(:cleanup_sandbox)
317
-
318
- begin
319
- cmd
320
- rescue # rubocop:disable Lint/HandleExceptions
321
- end
322
- end
323
-
324
- it "invokes the provisioner commands over ssh" do
325
- transport.stubs(:connection).yields(connection)
326
- order = sequence("order")
327
- connection.expects(:execute).with("install").in_sequence(order)
328
- connection.expects(:execute).with("init").in_sequence(order)
329
- connection.expects(:execute).with("prepare").in_sequence(order)
330
- connection.expects(:execute).with("run").in_sequence(order)
331
-
332
- cmd
333
- end
334
-
335
- it "invokes the #install_command with :http_proxy set in config" do
336
- config[:http_proxy] = "http://proxy"
337
- transport.stubs(:connection).yields(connection)
338
- connection.expects(:execute).with("env http_proxy=http://proxy install")
339
-
340
- cmd
341
- end
342
-
343
- it "invokes the #install_command with ENV[\"http_proxy\"] set" do
344
- ENV["http_proxy"] = "http://proxy"
345
- transport.stubs(:connection).yields(connection)
346
- if running_tests_on_windows?
347
- connection.expects(:execute).
348
- with("env http_proxy=http://proxy HTTP_PROXY=http://proxy install")
349
- else
350
- connection.expects(:execute).with("env http_proxy=http://proxy install")
351
- end
352
- cmd
353
- end
354
-
355
- it "invokes the #install_command with ENV[\"http_proxy\"] and ENV[\"no_proxy\"] set" do
356
- ENV["http_proxy"] = "http://proxy"
357
- ENV["no_proxy"] = "http://no"
358
- transport.stubs(:connection).yields(connection)
359
- if running_tests_on_windows?
360
- connection.expects(:execute).
361
- with("env http_proxy=http://proxy HTTP_PROXY=http://proxy " \
362
- "no_proxy=http://no NO_PROXY=http://no install")
363
- else
364
- connection.expects(:execute).with("env http_proxy=http://proxy " \
365
- "no_proxy=http://no install")
366
- end
367
- cmd
368
- end
369
-
370
- it "invokes the #install_command with :https_proxy set in config" do
371
- config[:https_proxy] = "https://proxy"
372
- transport.stubs(:connection).yields(connection)
373
- connection.expects(:execute).with("env https_proxy=https://proxy install")
374
-
375
- cmd
376
- end
377
-
378
- it "invokes the #install_command with ENV[\"https_proxy\"] set" do
379
- ENV["https_proxy"] = "https://proxy"
380
- transport.stubs(:connection).yields(connection)
381
- if running_tests_on_windows?
382
- connection.expects(:execute).
383
- with("env https_proxy=https://proxy HTTPS_PROXY=https://proxy install")
384
- else
385
- connection.expects(:execute).with("env https_proxy=https://proxy install")
386
- end
387
- cmd
388
- end
389
-
390
- it "invokes the #install_command with ENV[\"https_proxy\"] and ENV[\"no_proxy\"] set" do
391
- ENV["https_proxy"] = "https://proxy"
392
- ENV["no_proxy"] = "https://no"
393
- transport.stubs(:connection).yields(connection)
394
- if running_tests_on_windows?
395
- connection.expects(:execute).
396
- with("env https_proxy=https://proxy HTTPS_PROXY=https://proxy " \
397
- "no_proxy=https://no NO_PROXY=https://no install")
398
- else
399
- connection.expects(:execute).with("env https_proxy=https://proxy " \
400
- "no_proxy=https://no install")
401
- end
402
- cmd
403
- end
404
-
405
- it "invokes the #install_command with :ftp_proxy set in config" do
406
- config[:ftp_proxy] = "ftp://proxy"
407
- transport.stubs(:connection).yields(connection)
408
- connection.expects(:execute).with("env ftp_proxy=ftp://proxy install")
409
-
410
- cmd
411
- end
412
-
413
- it "invokes the #install_command with ENV[\"ftp_proxy\"] set" do
414
- ENV["ftp_proxy"] = "ftp://proxy"
415
- transport.stubs(:connection).yields(connection)
416
- if running_tests_on_windows?
417
- connection.expects(:execute).
418
- with("env ftp_proxy=ftp://proxy FTP_PROXY=ftp://proxy install")
419
- else
420
- connection.expects(:execute).with("env ftp_proxy=ftp://proxy install")
421
- end
422
- cmd
423
- end
424
-
425
- it "invokes the #install_command with ENV[\"ftp_proxy\"] and ENV[\"no_proxy\"] set" do
426
- ENV["ftp_proxy"] = "ftp://proxy"
427
- ENV["no_proxy"] = "http://no"
428
- transport.stubs(:connection).yields(connection)
429
- if running_tests_on_windows?
430
- connection.expects(:execute).
431
- with("env ftp_proxy=ftp://proxy FTP_PROXY=http://proxy " \
432
- "no_proxy=http://no NO_PROXY=http://no install")
433
- else
434
- connection.expects(:execute).with("env ftp_proxy=ftp://proxy " \
435
- "no_proxy=http://no install")
436
- end
437
- cmd
438
- end
439
-
440
- it "invokes the #install_command with :http_proxy & :https_proxy & :ftp_proxy set" do
441
- config[:http_proxy] = "http://proxy"
442
- config[:https_proxy] = "https://proxy"
443
- config[:ftp_proxy] = "ftp://proxy"
444
- transport.stubs(:connection).yields(connection)
445
- connection.expects(:execute).with(
446
- "env http_proxy=http://proxy https_proxy=https://proxy ftp_proxy=ftp://proxy install")
447
-
448
- cmd
449
- end
450
-
451
- describe "transferring files" do
452
-
453
- before do
454
- transport.stubs(:connection).yields(connection)
455
- connection.stubs(:upload)
456
- FileUtils.mkdir_p "/tmp/sandbox/stuff"
457
- end
458
-
459
- it "uploads files" do
460
- connection.expects(:upload).with(["/tmp/sandbox/stuff"], "/rooty")
461
-
462
- cmd
463
- end
464
-
465
- it "logs to info" do
466
- cmd
467
-
468
- logged_output.string.
469
- must_match(/INFO -- : Transferring files to instance$/)
470
- end
471
-
472
- it "logs to debug" do
473
- cmd
474
-
475
- logged_output.string.must_match(/DEBUG -- : Transfer complete$/)
476
- end
477
-
478
- it "raises an ActionFailed on transfer when SshFailed is raised" do
479
- connection.stubs(:upload).raises(Kitchen::Transport::SshFailed.new("dang"))
480
-
481
- proc { cmd }.must_raise Kitchen::ActionFailed
482
- end
483
- end
484
-
485
- it "raises an ActionFailed on execute when SshFailed is raised" do
486
- transport.stubs(:connection).yields(connection)
487
- connection.stubs(:execute).raises(Kitchen::Transport::SshFailed.new("dang"))
488
-
489
- proc { cmd }.must_raise Kitchen::ActionFailed
490
- end
491
- end
492
-
493
- describe "#setup" do
494
-
495
- let(:cmd) { driver.setup(state) }
496
- let(:connection) { mock }
497
-
498
- before do
499
- state[:hostname] = "fizzy"
500
- state[:username] = "bork"
501
- end
502
-
503
- constructs_an_ssh_connection
504
-
505
- it "invokes the Verifier#install_command over ssh" do
506
- transport.stubs(:connection).yields(connection)
507
- connection.expects(:execute).with("install")
508
-
509
- cmd
510
- end
511
-
512
- it "invokes the Verifier#install_command with :http_proxy set in config" do
513
- config[:http_proxy] = "http://proxy"
514
- transport.stubs(:connection).yields(connection)
515
- connection.expects(:execute).with("env http_proxy=http://proxy install")
516
-
517
- cmd
518
- end
519
-
520
- it "invokes the Verifier#install_command with :https_proxy set in config" do
521
- config[:https_proxy] = "https://proxy"
522
- transport.stubs(:connection).yields(connection)
523
- connection.expects(:execute).with("env https_proxy=https://proxy install")
524
-
525
- cmd
526
- end
527
-
528
- it "invokes the Verifier#install_command with :ftp_proxy set in config" do
529
- config[:ftp_proxy] = "ftp://proxy"
530
- transport.stubs(:connection).yields(connection)
531
- connection.expects(:execute).with("env ftp_proxy=ftp://proxy install")
532
-
533
- cmd
534
- end
535
-
536
- it "invokes the Verifier#install_command with :http_proxy & :https_proxy & :ftp_proxy set" do
537
- config[:http_proxy] = "http://proxy"
538
- config[:https_proxy] = "https://proxy"
539
- config[:ftp_proxy] = "ftp://proxy"
540
- transport.stubs(:connection).yields(connection)
541
- connection.expects(:execute).with(
542
- "env http_proxy=http://proxy https_proxy=https://proxy ftp_proxy=ftp://proxy install")
543
-
544
- cmd
545
- end
546
-
547
- it "raises an ActionFailed when SshFailed is raised" do
548
- transport.stubs(:connection).yields(connection)
549
- connection.stubs(:execute).raises(Kitchen::Transport::SshFailed.new("dang"))
550
-
551
- proc { cmd }.must_raise Kitchen::ActionFailed
552
- end
553
- end
554
-
555
- describe "#verify" do
556
-
557
- let(:cmd) { driver.verify(state) }
558
- let(:connection) { stub(:execute => true, :upload => true) }
559
-
560
- before do
561
- state[:hostname] = "fizzy"
562
- state[:username] = "bork"
563
- transport.stubs(:connection).yields(connection)
564
- end
565
-
566
- constructs_an_ssh_connection
567
-
568
- it "creates the sandbox" do
569
- verifier.expects(:create_sandbox)
570
-
571
- cmd
572
- end
573
-
574
- it "ensures that the sandbox is cleanup up" do
575
- transport.stubs(:connection).raises
576
- verifier.expects(:cleanup_sandbox)
577
-
578
- begin
579
- cmd
580
- rescue # rubocop:disable Lint/HandleExceptions
581
- end
582
- end
583
-
584
- it "invokes the verifier commands over the transport" do
585
- order = sequence("order")
586
- connection.expects(:execute).with("init").in_sequence(order)
587
- connection.expects(:execute).with("prepare").in_sequence(order)
588
- connection.expects(:execute).with("run").in_sequence(order)
589
-
590
- cmd
591
- end
592
-
593
- %W[init prepare run].each do |phase|
594
- it "invokes Verifier##{phase}_command over ssh" do
595
- connection.expects(:execute).with(phase)
596
-
597
- cmd
598
- end
599
-
600
- it "invokes Verifier##{phase}_command with :http_proxy set in config" do
601
- config[:http_proxy] = "http://proxy"
602
- connection.expects(:execute).with("env http_proxy=http://proxy #{phase}")
603
-
604
- cmd
605
- end
606
-
607
- it "invokes Verifier##{phase}_command with :https_proxy set in config" do
608
- config[:https_proxy] = "https://proxy"
609
- connection.expects(:execute).with("env https_proxy=https://proxy #{phase}")
610
-
611
- cmd
612
- end
613
-
614
- it "invokes Verifier##{phase}_command with :ftp_proxy set in config" do
615
- config[:ftp_proxy] = "ftp://proxy"
616
- connection.expects(:execute).with("env ftp_proxy=ftp://proxy #{phase}")
617
-
618
- cmd
619
- end
620
-
621
- it "invokes Verifier##{phase}_command with :http_proxy & :https_proxy & :ftp_proxy set" do
622
- config[:http_proxy] = "http://proxy"
623
- config[:https_proxy] = "https://proxy"
624
- config[:ftp_proxy] = "ftp://proxy"
625
- connection.expects(:execute).with(
626
- "env http_proxy=http://proxy https_proxy=https://proxy ftp_proxy=ftp://proxy #{phase}")
627
-
628
- cmd
629
- end
630
- end
631
-
632
- it "logs to info" do
633
- cmd
634
-
635
- logged_output.string.
636
- must_match(/INFO -- : Transferring files to instance$/)
637
- end
638
-
639
- it "uploads sandbox files" do
640
- connection.expects(:upload).with([], "/tmp/verifier")
641
-
642
- cmd
643
- end
644
-
645
- it "logs to debug" do
646
- cmd
647
-
648
- logged_output.string.must_match(/DEBUG -- : Transfer complete$/)
649
- end
650
-
651
- it "raises an ActionFailed on transfer when TransportFailed is raised" do
652
- connection.stubs(:upload).
653
- raises(Kitchen::Transport::TransportFailed.new("dang"))
654
-
655
- proc { cmd }.must_raise Kitchen::ActionFailed
656
- end
657
-
658
- it "raises an ActionFailed when SSHFailed is raised" do
659
- connection.stubs(:execute).raises(Kitchen::Transport::SshFailed.new("dang"))
660
-
661
- proc { cmd }.must_raise Kitchen::ActionFailed
662
- end
663
- end
664
-
665
- describe "#ssh" do
666
-
667
- let(:cmd) { driver.ssh(["host", "user", { :one => "two" }], "go") }
668
- let(:connection) { mock }
669
-
670
- it "creates an SSH connection" do
671
- connection.stubs(:execute)
672
- transport.expects(:connection).with(
673
- :hostname => "host",
674
- :username => "user",
675
- :port => 22,
676
- :one => "two"
677
- ).yields(connection)
678
-
679
- cmd
680
- end
681
-
682
- it "invokes the command over ssh" do
683
- transport.expects(:connection).yields(connection)
684
- connection.expects(:execute).with("go")
685
-
686
- cmd
687
- end
688
- end
689
-
690
- describe "#remote_command" do
691
-
692
- let(:cmd) { driver.remote_command(state, "shipit") }
693
- let(:connection) { mock }
694
-
695
- before do
696
- state[:hostname] = "fizzy"
697
- state[:username] = "bork"
698
- end
699
-
700
- it "creates an SSH connection" do
701
- transport.expects(:connection).with(
702
- :hostname => "fizzy",
703
- :username => "bork",
704
- :port => 22
705
- )
706
-
707
- cmd
708
- end
709
-
710
- it "invokes the command over ssh" do
711
- transport.expects(:connection).yields(connection)
712
- connection.expects(:execute).with("shipit")
713
-
714
- cmd
715
- end
716
- end
717
-
718
- describe "#wait_for_sshd" do
719
-
720
- let(:cmd) do
721
- driver.send(:wait_for_sshd, "host", "user", :one => "two")
722
- end
723
-
724
- it "creates an SSH connection with merged options" do
725
- transport.expects(:connection).with(
726
- :hostname => "host",
727
- :username => "user",
728
- :port => 22,
729
- :one => "two"
730
- ).returns(stub(:wait_until_ready => true))
731
-
732
- cmd
733
- end
734
-
735
- it "calls wait on the SSH connection" do
736
- connection = mock
737
- transport.expects(:connection).returns(connection)
738
- connection.expects(:wait_until_ready)
739
-
740
- cmd
741
- end
742
- end
743
-
744
- describe "to maintain backwards compatibility" do
745
-
746
- let(:driver) do
747
- Kitchen::Driver::BackCompat.new(config).finalize_config!(instance)
748
- end
749
-
750
- it "#instance returns its instance" do
751
- driver.instance.must_equal instance
752
- end
753
-
754
- it "#name returns the name of the driver" do
755
- driver.name.must_equal "BackCompat"
756
- end
757
-
758
- describe "#logger" do
759
-
760
- before { @klog = Kitchen.logger }
761
- after { Kitchen.logger = @klog }
762
-
763
- it "returns the instance's logger if defined" do
764
- driver.send(:logger).must_equal logger
765
- end
766
-
767
- it "returns the default logger if instance's logger is not set" do
768
- driver = Kitchen::Driver::BackCompat.new(config)
769
- Kitchen.logger = "yep"
770
-
771
- driver.send(:logger).must_equal Kitchen.logger
772
- end
773
- end
774
-
775
- it "#puts calls logger.info" do
776
- driver.send(:puts, "yo")
777
-
778
- logged_output.string.must_match(/I, /)
779
- logged_output.string.must_match(/yo\n/)
780
- end
781
-
782
- it "#print calls logger.info" do
783
- driver.send(:print, "yo")
784
-
785
- logged_output.string.must_match(/I, /)
786
- logged_output.string.must_match(/yo\n/)
787
- end
788
-
789
- it "has a default verify dependencies method" do
790
- driver.verify_dependencies.must_be_nil
791
- end
792
-
793
- it "#busser returns the instance's verifier" do
794
- driver.send(:busser).must_equal verifier
795
- end
796
-
797
- describe ".no_parallel_for" do
798
-
799
- it "registers no serial actions when none are declared" do
800
- Kitchen::Driver::SpeedyCompat.serial_actions.must_equal nil
801
- end
802
-
803
- it "registers a single serial action method" do
804
- Kitchen::Driver::DodgyCompat.serial_actions.must_equal [:converge]
805
- end
806
-
807
- it "registers multiple serial action methods" do
808
- actions = Kitchen::Driver::SlowCompat.serial_actions
809
-
810
- actions.must_include :create
811
- actions.must_include :verify
812
- actions.must_include :destroy
813
- end
814
-
815
- it "raises a ClientError if value is not an action method" do
816
- proc {
817
- Class.new(Kitchen::Driver::BackCompat) {
818
- no_parallel_for :telling_stories
819
- }
820
- }.must_raise Kitchen::ClientError
821
- end
822
- end
823
-
824
- # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
825
- def self.constructs_an_ssh_object
826
- it "with hostname set from state" do
827
- Kitchen::SSH.expects(:new).with { |hostname, _username, _opts|
828
- hostname.must_equal "fizzy"
829
- }.returns(connection)
830
-
831
- cmd
832
- end
833
-
834
- it "with username set from state" do
835
- Kitchen::SSH.expects(:new).with { |_hostname, username, _opts|
836
- username.must_equal "bork"
837
- }.returns(connection)
838
-
839
- cmd
840
- end
841
-
842
- it "with :user_known_hosts_file option set to /dev/null" do
843
- Kitchen::SSH.expects(:new).with { |_hostname, _username, opts|
844
- opts[:user_known_hosts_file].must_equal "/dev/null"
845
- }.returns(connection)
846
-
847
- cmd
848
- end
849
-
850
- it "with :paranoid option set to false" do
851
- Kitchen::SSH.expects(:new).with { |_hostname, _username, opts|
852
- opts[:paranoid].must_equal false
853
- }.returns(connection)
854
-
855
- cmd
856
- end
857
-
858
- it "with :keys_only option set to falsey by default" do
859
- Kitchen::SSH.expects(:new).with { |_hostname, _username, opts|
860
- opts[:keys_only].nil?
861
- }.returns(connection)
862
-
863
- cmd
864
- end
865
-
866
- it "with :keys_only option set to true if :ssh_key is set in config" do
867
- config[:ssh_key] = "wicked"
868
-
869
- Kitchen::SSH.expects(:new).with { |_hostname, _username, opts|
870
- opts[:keys_only].must_equal true
871
- }.returns(connection)
872
-
873
- cmd
874
- end
875
-
876
- it "with :keys_only option set to true if :ssh_key is set in state" do
877
- state[:ssh_key] = "wicked"
878
-
879
- Kitchen::SSH.expects(:new).with { |_hostname, _username, opts|
880
- opts[:keys_only].must_equal true
881
- }.returns(connection)
882
-
883
- cmd
884
- end
885
-
886
- it "with :keys option set to falsey by default" do
887
- Kitchen::SSH.expects(:new).with { |_hostname, _username, opts|
888
- opts[:keys].nil?
889
- }.returns(connection)
890
-
891
- cmd
892
- end
893
-
894
- it "with :keys option set to an array if :ssh_key is set in config" do
895
- config[:ssh_key] = "wicked"
896
-
897
- Kitchen::SSH.expects(:new).with { |_hostname, _username, opts|
898
- opts[:keys].must_equal ["wicked"]
899
- }.returns(connection)
900
-
901
- cmd
902
- end
903
-
904
- it "with :keys option set to an array if :ssh_key is set in state" do
905
- state[:ssh_key] = "wicked"
906
-
907
- Kitchen::SSH.expects(:new).with { |_hostname, _username, opts|
908
- opts[:keys].must_equal ["wicked"]
909
- }.returns(connection)
910
-
911
- cmd
912
- end
913
-
914
- it "with :password option set to falsey by default" do
915
- Kitchen::SSH.expects(:new).with { |_hostname, _username, opts|
916
- opts[:password].nil?
917
- }.returns(connection)
918
-
919
- cmd
920
- end
921
-
922
- it "with :password option set if given in config" do
923
- config[:password] = "psst"
924
-
925
- Kitchen::SSH.expects(:new).with { |_hostname, _username, opts|
926
- opts[:password].must_equal "psst"
927
- }.returns(connection)
928
-
929
- cmd
930
- end
931
-
932
- it "with :password option set if given in state" do
933
- state[:password] = "psst"
934
-
935
- Kitchen::SSH.expects(:new).with { |_hostname, _username, opts|
936
- opts[:password].must_equal "psst"
937
- }.returns(connection)
938
-
939
- cmd
940
- end
941
-
942
- it "with :forward_agent option set to falsey by default" do
943
- Kitchen::SSH.expects(:new).with { |_hostname, _username, opts|
944
- opts[:forward_agent].nil?
945
- }.returns(connection)
946
-
947
- cmd
948
- end
949
-
950
- it "with :forward_agent option set if given in config" do
951
- config[:forward_agent] = "yeah?"
952
-
953
- Kitchen::SSH.expects(:new).with { |_hostname, _username, opts|
954
- opts[:forward_agent].must_equal "yeah?"
955
- }.returns(connection)
956
-
957
- cmd
958
- end
959
-
960
- it "with :forward_agent option set if given in state" do
961
- state[:forward_agent] = "yeah?"
962
-
963
- Kitchen::SSH.expects(:new).with { |_hostname, _username, opts|
964
- opts[:forward_agent].must_equal "yeah?"
965
- }.returns(connection)
966
-
967
- cmd
968
- end
969
-
970
- it "with :port option set to 22 by default" do
971
- Kitchen::SSH.expects(:new).with { |_hostname, _username, opts|
972
- opts[:port].must_equal 22
973
- }.returns(connection)
974
-
975
- cmd
976
- end
977
-
978
- it "with :port option set if customized in config" do
979
- config[:port] = 1234
980
-
981
- Kitchen::SSH.expects(:new).with { |_hostname, _username, opts|
982
- opts[:port].must_equal 1234
983
- }.returns(connection)
984
-
985
- cmd
986
- end
987
-
988
- it "with :port option set if customized in state" do
989
- state[:port] = 9999
990
-
991
- Kitchen::SSH.expects(:new).with { |_hostname, _username, opts|
992
- opts[:port].must_equal 9999
993
- }.returns(connection)
994
-
995
- cmd
996
- end
997
-
998
- it "with :logger option set to driver's logger" do
999
- Kitchen::SSH.expects(:new).with { |_hostname, _username, opts|
1000
- opts[:logger].must_equal logger
1001
- }.returns(connection)
1002
-
1003
- cmd
1004
- end
1005
- end
1006
- # rubocop:enable Metrics/MethodLength, Metrics/AbcSize
1007
-
1008
- describe "#run_remote" do
1009
-
1010
- let(:cmd) { driver.use_run_remote(state, "huh") }
1011
- let(:connection) { stub(:exec => true) }
1012
-
1013
- before do
1014
- state[:hostname] = "fizzy"
1015
- state[:username] = "bork"
1016
- end
1017
-
1018
- constructs_an_ssh_object
1019
-
1020
- it "invokes the #install_command with :http_proxy set in config" do
1021
- config[:http_proxy] = "http://proxy"
1022
- Kitchen::SSH.stubs(:new).returns(connection)
1023
- connection.expects(:exec).with("env http_proxy=http://proxy huh")
1024
-
1025
- cmd
1026
- end
1027
-
1028
- it "invokes the #install_command with :https_proxy set in config" do
1029
- config[:https_proxy] = "https://proxy"
1030
- Kitchen::SSH.stubs(:new).returns(connection)
1031
- connection.expects(:exec).with("env https_proxy=https://proxy huh")
1032
-
1033
- cmd
1034
- end
1035
-
1036
- it "invokes the #install_command with :ftp_proxy set in config" do
1037
- config[:ftp_proxy] = "ftp://proxy"
1038
- Kitchen::SSH.stubs(:new).returns(connection)
1039
- connection.expects(:exec).with("env ftp_proxy=ftp://proxy huh")
1040
-
1041
- cmd
1042
- end
1043
-
1044
- it "invokes the #install_command with :http_proxy & :https_proxy & :ftp_proxy set" do
1045
- config[:http_proxy] = "http://proxy"
1046
- config[:https_proxy] = "https://proxy"
1047
- config[:ftp_proxy] = "ftp://proxy"
1048
- Kitchen::SSH.stubs(:new).returns(connection)
1049
- connection.expects(:exec).with(
1050
- "env http_proxy=http://proxy https_proxy=https://proxy ftp_proxy=ftp://proxy huh")
1051
-
1052
- cmd
1053
- end
1054
-
1055
- it "doesn't invoke an ssh command if command is nil" do
1056
- Kitchen::SSH.stubs(:new).returns(mock)
1057
-
1058
- driver.use_run_remote(state, nil)
1059
- end
1060
-
1061
- it "raises an ActionFailed on transfer when SSHFailed is raised" do
1062
- Kitchen::SSH.stubs(:new).returns(connection)
1063
- connection.stubs(:exec).raises(Kitchen::SSHFailed.new("dang"))
1064
-
1065
- proc { cmd }.must_raise Kitchen::ActionFailed
1066
- end
1067
-
1068
- it "raises an ActionFailed on exec when Net::SSH:Exception is raised" do
1069
- Kitchen::SSH.stubs(:new).returns(connection)
1070
- connection.stubs(:exec).raises(Net::SSH::Exception.new("dang"))
1071
-
1072
- proc { cmd }.must_raise Kitchen::ActionFailed
1073
- end
1074
- end
1075
-
1076
- describe "#transfer_path" do
1077
-
1078
- let(:cmd) { driver.use_transfer_path(state, ["nope"], "nadda") }
1079
- let(:connection) { stub(:upload_path! => true) }
1080
-
1081
- before do
1082
- state[:hostname] = "fizzy"
1083
- state[:username] = "bork"
1084
- end
1085
-
1086
- constructs_an_ssh_object
1087
-
1088
- it "doesn't invoke an scp command if locals is nil" do
1089
- Kitchen::SSH.stubs(:new).returns(mock)
1090
-
1091
- driver.use_transfer_path(state, nil, "nope")
1092
- end
1093
-
1094
- it "doesn't invoke an scp command if locals is an empty array" do
1095
- Kitchen::SSH.stubs(:new).returns(mock)
1096
-
1097
- driver.use_transfer_path(state, [], "nope")
1098
- end
1099
-
1100
- it "raises an ActionFailed on transfer when SSHFailed is raised" do
1101
- Kitchen::SSH.stubs(:new).returns(connection)
1102
- connection.stubs(:upload_path!).raises(Kitchen::SSHFailed.new("dang"))
1103
-
1104
- proc { cmd }.must_raise Kitchen::ActionFailed
1105
- end
1106
-
1107
- it "raises an ActionFailed on exec when Net::SSH:Exception is raised" do
1108
- Kitchen::SSH.stubs(:new).returns(connection)
1109
- connection.stubs(:upload_path!).raises(Net::SSH::Exception.new("dang"))
1110
-
1111
- proc { cmd }.must_raise Kitchen::ActionFailed
1112
- end
1113
- end
1114
- end
1115
- end
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
+ require "kitchen/transport/ssh"
23
+ require "kitchen/verifier/busser"
24
+
25
+ module Kitchen
26
+
27
+ module Driver
28
+
29
+ class BackCompat < Kitchen::Driver::SSHBase
30
+
31
+ def use_run_remote(state, command)
32
+ connection = Kitchen::SSH.new(*build_ssh_args(state))
33
+ run_remote(command, connection)
34
+ end
35
+
36
+ def use_transfer_path(state, locals, remote)
37
+ connection = Kitchen::SSH.new(*build_ssh_args(state))
38
+ transfer_path(locals, remote, connection)
39
+ end
40
+ end
41
+
42
+ class SpeedyCompat < Kitchen::Driver::SSHBase
43
+ end
44
+
45
+ class DodgyCompat < Kitchen::Driver::SSHBase
46
+
47
+ no_parallel_for :converge
48
+ end
49
+
50
+ class SlowCompat < Kitchen::Driver::SSHBase
51
+
52
+ no_parallel_for :create, :destroy
53
+ no_parallel_for :verify
54
+ end
55
+ end
56
+ end
57
+
58
+ describe Kitchen::Driver::SSHBase do
59
+
60
+ let(:logged_output) { StringIO.new }
61
+ let(:logger) { Logger.new(logged_output) }
62
+ let(:config) { Hash.new }
63
+ let(:state) { Hash.new }
64
+
65
+ let(:verifier) do
66
+ v = mock("busser")
67
+ v.responds_like_instance_of(Kitchen::Verifier::Busser)
68
+ v.stubs(:install_command).returns("install")
69
+ v.stubs(:init_command).returns("init")
70
+ v.stubs(:prepare_command).returns("prepare")
71
+ v.stubs(:run_command).returns("run")
72
+ v.stubs(:create_sandbox).returns(true)
73
+ v.stubs(:cleanup_sandbox).returns(true)
74
+ v.stubs(:sandbox_path).returns("/tmp/sandbox")
75
+ v.stubs(:[]).with(:root_path).returns("/tmp/verifier")
76
+ v
77
+ end
78
+
79
+ let(:provisioner) do
80
+ stub(
81
+ :install_command => "install",
82
+ :init_command => "init",
83
+ :prepare_command => "prepare",
84
+ :run_command => "run",
85
+ :create_sandbox => true,
86
+ :cleanup_sandbox => true,
87
+ :sandbox_path => "/tmp/sandbox"
88
+ )
89
+ end
90
+
91
+ let(:transport) do
92
+ t = mock("transport")
93
+ t.responds_like_instance_of(Kitchen::Transport::Base)
94
+ t
95
+ end
96
+
97
+ let(:instance) do
98
+ stub(
99
+ :name => "coolbeans",
100
+ :logger => logger,
101
+ :verifier => verifier,
102
+ :provisioner => provisioner,
103
+ :transport => transport,
104
+ :to_str => "instance"
105
+ )
106
+ end
107
+
108
+ let(:driver) do
109
+ Kitchen::Driver::SSHBase.new(config).finalize_config!(instance)
110
+ end
111
+
112
+ it "plugin_version is not set" do
113
+ driver.diagnose_plugin[:version].must_equal nil
114
+ end
115
+
116
+ describe "configuration" do
117
+
118
+ it ":sudo defaults to true" do
119
+ driver[:sudo].must_equal true
120
+ end
121
+
122
+ it ":port defaults to 22" do
123
+ driver[:port].must_equal 22
124
+ end
125
+ end
126
+
127
+ it "#create raises a ClientError" do
128
+ proc { driver.create(state) }.must_raise Kitchen::ClientError
129
+ end
130
+
131
+ it "#destroy raises a ClientError" do
132
+ proc { driver.destroy(state) }.must_raise Kitchen::ClientError
133
+ end
134
+
135
+ # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
136
+ def self.constructs_an_ssh_connection
137
+ describe "constructs an SSH connection" do
138
+
139
+ it "with hostname set from state" do
140
+ transport.expects(:connection).with { |state|
141
+ state[:hostname].must_equal "fizzy"
142
+ }.returns(stub(:login_command => stub))
143
+
144
+ cmd
145
+ end
146
+
147
+ it "with username set from state" do
148
+ transport.expects(:connection).with { |state|
149
+ state[:username].must_equal "bork"
150
+ }.returns(stub(:login_command => stub))
151
+
152
+ cmd
153
+ end
154
+
155
+ it "with :ssh_key option set from config" do
156
+ config[:ssh_key] = "wicked"
157
+
158
+ transport.expects(:connection).with { |state|
159
+ state[:ssh_key].must_equal "wicked"
160
+ }.returns(stub(:login_command => stub))
161
+
162
+ cmd
163
+ end
164
+
165
+ it "with :ssh_key option set from state" do
166
+ state[:ssh_key] = "wicked"
167
+
168
+ transport.expects(:connection).with { |state|
169
+ state[:ssh_key].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
+ transport.expects(:connection).with { |state|
177
+ state[: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
+ transport.expects(:connection).with { |state|
187
+ state[: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
+ transport.expects(:connection).with { |state|
197
+ state[: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
+ transport.expects(:connection).with { |state|
205
+ state[: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
+ transport.expects(:connection).with { |state|
215
+ state[: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
+ transport.expects(:connection).with { |state|
225
+ state[: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
+ transport.expects(:connection).with { |state|
233
+ state[: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
+ transport.expects(:connection).with { |state|
243
+ state[: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
+ transport.expects(:connection).with { |state|
253
+ state[:port].must_equal 9999
254
+ }.returns(stub(:login_command => stub))
255
+
256
+ cmd
257
+ end
258
+ end
259
+ end
260
+ # rubocop:enable Metrics/MethodLength, Metrics/AbcSize
261
+
262
+ describe "#login_command" do
263
+
264
+ let(:cmd) { driver.login_command(state) }
265
+
266
+ before do
267
+ state[:hostname] = "fizzy"
268
+ state[:username] = "bork"
269
+ end
270
+
271
+ it "returns a LoginCommand" do
272
+ transport.stubs(:connection).returns(stub(:login_command => "command"))
273
+
274
+ cmd.must_equal "command"
275
+ end
276
+
277
+ constructs_an_ssh_connection
278
+ end
279
+
280
+ describe "#converge" do
281
+
282
+ let(:cmd) { driver.converge(state) }
283
+ let(:connection) { stub(:execute => true, :upload => true) }
284
+
285
+ before do
286
+ state[:hostname] = "fizzy"
287
+ state[:username] = "bork"
288
+ provisioner.stubs(:[]).with(:root_path).returns("/rooty")
289
+ FakeFS.activate!
290
+ FileUtils.mkdir_p("/tmp")
291
+ @original_env = ENV.to_hash
292
+ ENV.replace("http_proxy" => nil, "HTTP_PROXY" => nil,
293
+ "https_proxy" => nil, "HTTPS_PROXY" => nil,
294
+ "ftp_proxy" => nil, "FTP_PROXY" => nil,
295
+ "no_proxy" => nil, "NO_PROXY" => nil)
296
+ end
297
+
298
+ after do
299
+ FakeFS.deactivate!
300
+ FakeFS::FileSystem.clear
301
+ ENV.clear
302
+ ENV.replace(@original_env)
303
+ end
304
+
305
+ constructs_an_ssh_connection
306
+
307
+ it "creates the sandbox" do
308
+ transport.stubs(:connection).yields(connection)
309
+ provisioner.expects(:create_sandbox)
310
+
311
+ cmd
312
+ end
313
+
314
+ it "ensures that the sandbox is cleaned up" do
315
+ transport.stubs(:connection).raises
316
+ provisioner.expects(:cleanup_sandbox)
317
+
318
+ begin
319
+ cmd
320
+ rescue # rubocop:disable Lint/HandleExceptions
321
+ end
322
+ end
323
+
324
+ it "invokes the provisioner commands over ssh" do
325
+ transport.stubs(:connection).yields(connection)
326
+ order = sequence("order")
327
+ connection.expects(:execute).with("install").in_sequence(order)
328
+ connection.expects(:execute).with("init").in_sequence(order)
329
+ connection.expects(:execute).with("prepare").in_sequence(order)
330
+ connection.expects(:execute).with("run").in_sequence(order)
331
+
332
+ cmd
333
+ end
334
+
335
+ it "invokes the #install_command with :http_proxy set in config" do
336
+ config[:http_proxy] = "http://proxy"
337
+ transport.stubs(:connection).yields(connection)
338
+ connection.expects(:execute).with("env http_proxy=http://proxy install")
339
+
340
+ cmd
341
+ end
342
+
343
+ it "invokes the #install_command with ENV[\"http_proxy\"] set" do
344
+ ENV["http_proxy"] = "http://proxy"
345
+ transport.stubs(:connection).yields(connection)
346
+ if running_tests_on_windows?
347
+ connection.expects(:execute).
348
+ with("env http_proxy=http://proxy HTTP_PROXY=http://proxy install")
349
+ else
350
+ connection.expects(:execute).with("env http_proxy=http://proxy install")
351
+ end
352
+ cmd
353
+ end
354
+
355
+ it "invokes the #install_command with ENV[\"http_proxy\"] and ENV[\"no_proxy\"] set" do
356
+ ENV["http_proxy"] = "http://proxy"
357
+ ENV["no_proxy"] = "http://no"
358
+ transport.stubs(:connection).yields(connection)
359
+ if running_tests_on_windows?
360
+ connection.expects(:execute).
361
+ with("env http_proxy=http://proxy HTTP_PROXY=http://proxy " \
362
+ "no_proxy=http://no NO_PROXY=http://no install")
363
+ else
364
+ connection.expects(:execute).with("env http_proxy=http://proxy " \
365
+ "no_proxy=http://no install")
366
+ end
367
+ cmd
368
+ end
369
+
370
+ it "invokes the #install_command with :https_proxy set in config" do
371
+ config[:https_proxy] = "https://proxy"
372
+ transport.stubs(:connection).yields(connection)
373
+ connection.expects(:execute).with("env https_proxy=https://proxy install")
374
+
375
+ cmd
376
+ end
377
+
378
+ it "invokes the #install_command with ENV[\"https_proxy\"] set" do
379
+ ENV["https_proxy"] = "https://proxy"
380
+ transport.stubs(:connection).yields(connection)
381
+ if running_tests_on_windows?
382
+ connection.expects(:execute).
383
+ with("env https_proxy=https://proxy HTTPS_PROXY=https://proxy install")
384
+ else
385
+ connection.expects(:execute).with("env https_proxy=https://proxy install")
386
+ end
387
+ cmd
388
+ end
389
+
390
+ it "invokes the #install_command with ENV[\"https_proxy\"] and ENV[\"no_proxy\"] set" do
391
+ ENV["https_proxy"] = "https://proxy"
392
+ ENV["no_proxy"] = "https://no"
393
+ transport.stubs(:connection).yields(connection)
394
+ if running_tests_on_windows?
395
+ connection.expects(:execute).
396
+ with("env https_proxy=https://proxy HTTPS_PROXY=https://proxy " \
397
+ "no_proxy=https://no NO_PROXY=https://no install")
398
+ else
399
+ connection.expects(:execute).with("env https_proxy=https://proxy " \
400
+ "no_proxy=https://no install")
401
+ end
402
+ cmd
403
+ end
404
+
405
+ it "invokes the #install_command with :ftp_proxy set in config" do
406
+ config[:ftp_proxy] = "ftp://proxy"
407
+ transport.stubs(:connection).yields(connection)
408
+ connection.expects(:execute).with("env ftp_proxy=ftp://proxy install")
409
+
410
+ cmd
411
+ end
412
+
413
+ it "invokes the #install_command with ENV[\"ftp_proxy\"] set" do
414
+ ENV["ftp_proxy"] = "ftp://proxy"
415
+ transport.stubs(:connection).yields(connection)
416
+ if running_tests_on_windows?
417
+ connection.expects(:execute).
418
+ with("env ftp_proxy=ftp://proxy FTP_PROXY=ftp://proxy install")
419
+ else
420
+ connection.expects(:execute).with("env ftp_proxy=ftp://proxy install")
421
+ end
422
+ cmd
423
+ end
424
+
425
+ it "invokes the #install_command with ENV[\"ftp_proxy\"] and ENV[\"no_proxy\"] set" do
426
+ ENV["ftp_proxy"] = "ftp://proxy"
427
+ ENV["no_proxy"] = "http://no"
428
+ transport.stubs(:connection).yields(connection)
429
+ if running_tests_on_windows?
430
+ connection.expects(:execute).
431
+ with("env ftp_proxy=ftp://proxy FTP_PROXY=http://proxy " \
432
+ "no_proxy=http://no NO_PROXY=http://no install")
433
+ else
434
+ connection.expects(:execute).with("env ftp_proxy=ftp://proxy " \
435
+ "no_proxy=http://no install")
436
+ end
437
+ cmd
438
+ end
439
+
440
+ it "invokes the #install_command with :http_proxy & :https_proxy & :ftp_proxy set" do
441
+ config[:http_proxy] = "http://proxy"
442
+ config[:https_proxy] = "https://proxy"
443
+ config[:ftp_proxy] = "ftp://proxy"
444
+ transport.stubs(:connection).yields(connection)
445
+ connection.expects(:execute).with(
446
+ "env http_proxy=http://proxy https_proxy=https://proxy ftp_proxy=ftp://proxy install")
447
+
448
+ cmd
449
+ end
450
+
451
+ describe "transferring files" do
452
+
453
+ before do
454
+ transport.stubs(:connection).yields(connection)
455
+ connection.stubs(:upload)
456
+ FileUtils.mkdir_p "/tmp/sandbox/stuff"
457
+ end
458
+
459
+ it "uploads files" do
460
+ connection.expects(:upload).with(["/tmp/sandbox/stuff"], "/rooty")
461
+
462
+ cmd
463
+ end
464
+
465
+ it "logs to info" do
466
+ cmd
467
+
468
+ logged_output.string.
469
+ must_match(/INFO -- : Transferring files to instance$/)
470
+ end
471
+
472
+ it "logs to debug" do
473
+ cmd
474
+
475
+ logged_output.string.must_match(/DEBUG -- : Transfer complete$/)
476
+ end
477
+
478
+ it "raises an ActionFailed on transfer when SshFailed is raised" do
479
+ connection.stubs(:upload).raises(Kitchen::Transport::SshFailed.new("dang"))
480
+
481
+ proc { cmd }.must_raise Kitchen::ActionFailed
482
+ end
483
+ end
484
+
485
+ it "raises an ActionFailed on execute when SshFailed is raised" do
486
+ transport.stubs(:connection).yields(connection)
487
+ connection.stubs(:execute).raises(Kitchen::Transport::SshFailed.new("dang"))
488
+
489
+ proc { cmd }.must_raise Kitchen::ActionFailed
490
+ end
491
+ end
492
+
493
+ describe "#setup" do
494
+
495
+ let(:cmd) { driver.setup(state) }
496
+ let(:connection) { mock }
497
+
498
+ before do
499
+ state[:hostname] = "fizzy"
500
+ state[:username] = "bork"
501
+ end
502
+
503
+ constructs_an_ssh_connection
504
+
505
+ it "invokes the Verifier#install_command over ssh" do
506
+ transport.stubs(:connection).yields(connection)
507
+ connection.expects(:execute).with("install")
508
+
509
+ cmd
510
+ end
511
+
512
+ it "invokes the Verifier#install_command with :http_proxy set in config" do
513
+ config[:http_proxy] = "http://proxy"
514
+ transport.stubs(:connection).yields(connection)
515
+ connection.expects(:execute).with("env http_proxy=http://proxy install")
516
+
517
+ cmd
518
+ end
519
+
520
+ it "invokes the Verifier#install_command with :https_proxy set in config" do
521
+ config[:https_proxy] = "https://proxy"
522
+ transport.stubs(:connection).yields(connection)
523
+ connection.expects(:execute).with("env https_proxy=https://proxy install")
524
+
525
+ cmd
526
+ end
527
+
528
+ it "invokes the Verifier#install_command with :ftp_proxy set in config" do
529
+ config[:ftp_proxy] = "ftp://proxy"
530
+ transport.stubs(:connection).yields(connection)
531
+ connection.expects(:execute).with("env ftp_proxy=ftp://proxy install")
532
+
533
+ cmd
534
+ end
535
+
536
+ it "invokes the Verifier#install_command with :http_proxy & :https_proxy & :ftp_proxy set" do
537
+ config[:http_proxy] = "http://proxy"
538
+ config[:https_proxy] = "https://proxy"
539
+ config[:ftp_proxy] = "ftp://proxy"
540
+ transport.stubs(:connection).yields(connection)
541
+ connection.expects(:execute).with(
542
+ "env http_proxy=http://proxy https_proxy=https://proxy ftp_proxy=ftp://proxy install")
543
+
544
+ cmd
545
+ end
546
+
547
+ it "raises an ActionFailed when SshFailed is raised" do
548
+ transport.stubs(:connection).yields(connection)
549
+ connection.stubs(:execute).raises(Kitchen::Transport::SshFailed.new("dang"))
550
+
551
+ proc { cmd }.must_raise Kitchen::ActionFailed
552
+ end
553
+ end
554
+
555
+ describe "#verify" do
556
+
557
+ let(:cmd) { driver.verify(state) }
558
+ let(:connection) { stub(:execute => true, :upload => true) }
559
+
560
+ before do
561
+ state[:hostname] = "fizzy"
562
+ state[:username] = "bork"
563
+ transport.stubs(:connection).yields(connection)
564
+ end
565
+
566
+ constructs_an_ssh_connection
567
+
568
+ it "creates the sandbox" do
569
+ verifier.expects(:create_sandbox)
570
+
571
+ cmd
572
+ end
573
+
574
+ it "ensures that the sandbox is cleanup up" do
575
+ transport.stubs(:connection).raises
576
+ verifier.expects(:cleanup_sandbox)
577
+
578
+ begin
579
+ cmd
580
+ rescue # rubocop:disable Lint/HandleExceptions
581
+ end
582
+ end
583
+
584
+ it "invokes the verifier commands over the transport" do
585
+ order = sequence("order")
586
+ connection.expects(:execute).with("init").in_sequence(order)
587
+ connection.expects(:execute).with("prepare").in_sequence(order)
588
+ connection.expects(:execute).with("run").in_sequence(order)
589
+
590
+ cmd
591
+ end
592
+
593
+ %W[init prepare run].each do |phase|
594
+ it "invokes Verifier##{phase}_command over ssh" do
595
+ connection.expects(:execute).with(phase)
596
+
597
+ cmd
598
+ end
599
+
600
+ it "invokes Verifier##{phase}_command with :http_proxy set in config" do
601
+ config[:http_proxy] = "http://proxy"
602
+ connection.expects(:execute).with("env http_proxy=http://proxy #{phase}")
603
+
604
+ cmd
605
+ end
606
+
607
+ it "invokes Verifier##{phase}_command with :https_proxy set in config" do
608
+ config[:https_proxy] = "https://proxy"
609
+ connection.expects(:execute).with("env https_proxy=https://proxy #{phase}")
610
+
611
+ cmd
612
+ end
613
+
614
+ it "invokes Verifier##{phase}_command with :ftp_proxy set in config" do
615
+ config[:ftp_proxy] = "ftp://proxy"
616
+ connection.expects(:execute).with("env ftp_proxy=ftp://proxy #{phase}")
617
+
618
+ cmd
619
+ end
620
+
621
+ it "invokes Verifier##{phase}_command with :http_proxy & :https_proxy & :ftp_proxy set" do
622
+ config[:http_proxy] = "http://proxy"
623
+ config[:https_proxy] = "https://proxy"
624
+ config[:ftp_proxy] = "ftp://proxy"
625
+ connection.expects(:execute).with(
626
+ "env http_proxy=http://proxy https_proxy=https://proxy ftp_proxy=ftp://proxy #{phase}")
627
+
628
+ cmd
629
+ end
630
+ end
631
+
632
+ it "logs to info" do
633
+ cmd
634
+
635
+ logged_output.string.
636
+ must_match(/INFO -- : Transferring files to instance$/)
637
+ end
638
+
639
+ it "uploads sandbox files" do
640
+ connection.expects(:upload).with([], "/tmp/verifier")
641
+
642
+ cmd
643
+ end
644
+
645
+ it "logs to debug" do
646
+ cmd
647
+
648
+ logged_output.string.must_match(/DEBUG -- : Transfer complete$/)
649
+ end
650
+
651
+ it "raises an ActionFailed on transfer when TransportFailed is raised" do
652
+ connection.stubs(:upload).
653
+ raises(Kitchen::Transport::TransportFailed.new("dang"))
654
+
655
+ proc { cmd }.must_raise Kitchen::ActionFailed
656
+ end
657
+
658
+ it "raises an ActionFailed when SSHFailed is raised" do
659
+ connection.stubs(:execute).raises(Kitchen::Transport::SshFailed.new("dang"))
660
+
661
+ proc { cmd }.must_raise Kitchen::ActionFailed
662
+ end
663
+ end
664
+
665
+ describe "#ssh" do
666
+
667
+ let(:cmd) { driver.ssh(["host", "user", { :one => "two" }], "go") }
668
+ let(:connection) { mock }
669
+
670
+ it "creates an SSH connection" do
671
+ connection.stubs(:execute)
672
+ transport.expects(:connection).with(
673
+ :hostname => "host",
674
+ :username => "user",
675
+ :port => 22,
676
+ :one => "two"
677
+ ).yields(connection)
678
+
679
+ cmd
680
+ end
681
+
682
+ it "invokes the command over ssh" do
683
+ transport.expects(:connection).yields(connection)
684
+ connection.expects(:execute).with("go")
685
+
686
+ cmd
687
+ end
688
+ end
689
+
690
+ describe "#remote_command" do
691
+
692
+ let(:cmd) { driver.remote_command(state, "shipit") }
693
+ let(:connection) { mock }
694
+
695
+ before do
696
+ state[:hostname] = "fizzy"
697
+ state[:username] = "bork"
698
+ end
699
+
700
+ it "creates an SSH connection" do
701
+ transport.expects(:connection).with(
702
+ :hostname => "fizzy",
703
+ :username => "bork",
704
+ :port => 22
705
+ )
706
+
707
+ cmd
708
+ end
709
+
710
+ it "invokes the command over ssh" do
711
+ transport.expects(:connection).yields(connection)
712
+ connection.expects(:execute).with("shipit")
713
+
714
+ cmd
715
+ end
716
+ end
717
+
718
+ describe "#wait_for_sshd" do
719
+
720
+ let(:cmd) do
721
+ driver.send(:wait_for_sshd, "host", "user", :one => "two")
722
+ end
723
+
724
+ it "creates an SSH connection with merged options" do
725
+ transport.expects(:connection).with(
726
+ :hostname => "host",
727
+ :username => "user",
728
+ :port => 22,
729
+ :one => "two"
730
+ ).returns(stub(:wait_until_ready => true))
731
+
732
+ cmd
733
+ end
734
+
735
+ it "calls wait on the SSH connection" do
736
+ connection = mock
737
+ transport.expects(:connection).returns(connection)
738
+ connection.expects(:wait_until_ready)
739
+
740
+ cmd
741
+ end
742
+ end
743
+
744
+ describe "to maintain backwards compatibility" do
745
+
746
+ let(:driver) do
747
+ Kitchen::Driver::BackCompat.new(config).finalize_config!(instance)
748
+ end
749
+
750
+ it "#instance returns its instance" do
751
+ driver.instance.must_equal instance
752
+ end
753
+
754
+ it "#name returns the name of the driver" do
755
+ driver.name.must_equal "BackCompat"
756
+ end
757
+
758
+ describe "#logger" do
759
+
760
+ before { @klog = Kitchen.logger }
761
+ after { Kitchen.logger = @klog }
762
+
763
+ it "returns the instance's logger if defined" do
764
+ driver.send(:logger).must_equal logger
765
+ end
766
+
767
+ it "returns the default logger if instance's logger is not set" do
768
+ driver = Kitchen::Driver::BackCompat.new(config)
769
+ Kitchen.logger = "yep"
770
+
771
+ driver.send(:logger).must_equal Kitchen.logger
772
+ end
773
+ end
774
+
775
+ it "#puts calls logger.info" do
776
+ driver.send(:puts, "yo")
777
+
778
+ logged_output.string.must_match(/I, /)
779
+ logged_output.string.must_match(/yo\n/)
780
+ end
781
+
782
+ it "#print calls logger.info" do
783
+ driver.send(:print, "yo")
784
+
785
+ logged_output.string.must_match(/I, /)
786
+ logged_output.string.must_match(/yo\n/)
787
+ end
788
+
789
+ it "has a default verify dependencies method" do
790
+ driver.verify_dependencies.must_be_nil
791
+ end
792
+
793
+ it "#busser returns the instance's verifier" do
794
+ driver.send(:busser).must_equal verifier
795
+ end
796
+
797
+ describe ".no_parallel_for" do
798
+
799
+ it "registers no serial actions when none are declared" do
800
+ Kitchen::Driver::SpeedyCompat.serial_actions.must_equal nil
801
+ end
802
+
803
+ it "registers a single serial action method" do
804
+ Kitchen::Driver::DodgyCompat.serial_actions.must_equal [:converge]
805
+ end
806
+
807
+ it "registers multiple serial action methods" do
808
+ actions = Kitchen::Driver::SlowCompat.serial_actions
809
+
810
+ actions.must_include :create
811
+ actions.must_include :verify
812
+ actions.must_include :destroy
813
+ end
814
+
815
+ it "raises a ClientError if value is not an action method" do
816
+ proc {
817
+ Class.new(Kitchen::Driver::BackCompat) {
818
+ no_parallel_for :telling_stories
819
+ }
820
+ }.must_raise Kitchen::ClientError
821
+ end
822
+ end
823
+
824
+ # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
825
+ def self.constructs_an_ssh_object
826
+ it "with hostname set from state" do
827
+ Kitchen::SSH.expects(:new).with { |hostname, _username, _opts|
828
+ hostname.must_equal "fizzy"
829
+ }.returns(connection)
830
+
831
+ cmd
832
+ end
833
+
834
+ it "with username set from state" do
835
+ Kitchen::SSH.expects(:new).with { |_hostname, username, _opts|
836
+ username.must_equal "bork"
837
+ }.returns(connection)
838
+
839
+ cmd
840
+ end
841
+
842
+ it "with :user_known_hosts_file option set to /dev/null" do
843
+ Kitchen::SSH.expects(:new).with { |_hostname, _username, opts|
844
+ opts[:user_known_hosts_file].must_equal "/dev/null"
845
+ }.returns(connection)
846
+
847
+ cmd
848
+ end
849
+
850
+ it "with :paranoid option set to false" do
851
+ Kitchen::SSH.expects(:new).with { |_hostname, _username, opts|
852
+ opts[:paranoid].must_equal false
853
+ }.returns(connection)
854
+
855
+ cmd
856
+ end
857
+
858
+ it "with :keys_only option set to falsey by default" do
859
+ Kitchen::SSH.expects(:new).with { |_hostname, _username, opts|
860
+ opts[:keys_only].nil?
861
+ }.returns(connection)
862
+
863
+ cmd
864
+ end
865
+
866
+ it "with :keys_only option set to true if :ssh_key is set in config" do
867
+ config[:ssh_key] = "wicked"
868
+
869
+ Kitchen::SSH.expects(:new).with { |_hostname, _username, opts|
870
+ opts[:keys_only].must_equal true
871
+ }.returns(connection)
872
+
873
+ cmd
874
+ end
875
+
876
+ it "with :keys_only option set to true if :ssh_key is set in state" do
877
+ state[:ssh_key] = "wicked"
878
+
879
+ Kitchen::SSH.expects(:new).with { |_hostname, _username, opts|
880
+ opts[:keys_only].must_equal true
881
+ }.returns(connection)
882
+
883
+ cmd
884
+ end
885
+
886
+ it "with :keys option set to falsey by default" do
887
+ Kitchen::SSH.expects(:new).with { |_hostname, _username, opts|
888
+ opts[:keys].nil?
889
+ }.returns(connection)
890
+
891
+ cmd
892
+ end
893
+
894
+ it "with :keys option set to an array if :ssh_key is set in config" do
895
+ config[:ssh_key] = "wicked"
896
+
897
+ Kitchen::SSH.expects(:new).with { |_hostname, _username, opts|
898
+ opts[:keys].must_equal ["wicked"]
899
+ }.returns(connection)
900
+
901
+ cmd
902
+ end
903
+
904
+ it "with :keys option set to an array if :ssh_key is set in state" do
905
+ state[:ssh_key] = "wicked"
906
+
907
+ Kitchen::SSH.expects(:new).with { |_hostname, _username, opts|
908
+ opts[:keys].must_equal ["wicked"]
909
+ }.returns(connection)
910
+
911
+ cmd
912
+ end
913
+
914
+ it "with :password option set to falsey by default" do
915
+ Kitchen::SSH.expects(:new).with { |_hostname, _username, opts|
916
+ opts[:password].nil?
917
+ }.returns(connection)
918
+
919
+ cmd
920
+ end
921
+
922
+ it "with :password option set if given in config" do
923
+ config[:password] = "psst"
924
+
925
+ Kitchen::SSH.expects(:new).with { |_hostname, _username, opts|
926
+ opts[:password].must_equal "psst"
927
+ }.returns(connection)
928
+
929
+ cmd
930
+ end
931
+
932
+ it "with :password option set if given in state" do
933
+ state[:password] = "psst"
934
+
935
+ Kitchen::SSH.expects(:new).with { |_hostname, _username, opts|
936
+ opts[:password].must_equal "psst"
937
+ }.returns(connection)
938
+
939
+ cmd
940
+ end
941
+
942
+ it "with :forward_agent option set to falsey by default" do
943
+ Kitchen::SSH.expects(:new).with { |_hostname, _username, opts|
944
+ opts[:forward_agent].nil?
945
+ }.returns(connection)
946
+
947
+ cmd
948
+ end
949
+
950
+ it "with :forward_agent option set if given in config" do
951
+ config[:forward_agent] = "yeah?"
952
+
953
+ Kitchen::SSH.expects(:new).with { |_hostname, _username, opts|
954
+ opts[:forward_agent].must_equal "yeah?"
955
+ }.returns(connection)
956
+
957
+ cmd
958
+ end
959
+
960
+ it "with :forward_agent option set if given in state" do
961
+ state[:forward_agent] = "yeah?"
962
+
963
+ Kitchen::SSH.expects(:new).with { |_hostname, _username, opts|
964
+ opts[:forward_agent].must_equal "yeah?"
965
+ }.returns(connection)
966
+
967
+ cmd
968
+ end
969
+
970
+ it "with :port option set to 22 by default" do
971
+ Kitchen::SSH.expects(:new).with { |_hostname, _username, opts|
972
+ opts[:port].must_equal 22
973
+ }.returns(connection)
974
+
975
+ cmd
976
+ end
977
+
978
+ it "with :port option set if customized in config" do
979
+ config[:port] = 1234
980
+
981
+ Kitchen::SSH.expects(:new).with { |_hostname, _username, opts|
982
+ opts[:port].must_equal 1234
983
+ }.returns(connection)
984
+
985
+ cmd
986
+ end
987
+
988
+ it "with :port option set if customized in state" do
989
+ state[:port] = 9999
990
+
991
+ Kitchen::SSH.expects(:new).with { |_hostname, _username, opts|
992
+ opts[:port].must_equal 9999
993
+ }.returns(connection)
994
+
995
+ cmd
996
+ end
997
+
998
+ it "with :logger option set to driver's logger" do
999
+ Kitchen::SSH.expects(:new).with { |_hostname, _username, opts|
1000
+ opts[:logger].must_equal logger
1001
+ }.returns(connection)
1002
+
1003
+ cmd
1004
+ end
1005
+ end
1006
+ # rubocop:enable Metrics/MethodLength, Metrics/AbcSize
1007
+
1008
+ describe "#run_remote" do
1009
+
1010
+ let(:cmd) { driver.use_run_remote(state, "huh") }
1011
+ let(:connection) { stub(:exec => true) }
1012
+
1013
+ before do
1014
+ state[:hostname] = "fizzy"
1015
+ state[:username] = "bork"
1016
+ end
1017
+
1018
+ constructs_an_ssh_object
1019
+
1020
+ it "invokes the #install_command with :http_proxy set in config" do
1021
+ config[:http_proxy] = "http://proxy"
1022
+ Kitchen::SSH.stubs(:new).returns(connection)
1023
+ connection.expects(:exec).with("env http_proxy=http://proxy huh")
1024
+
1025
+ cmd
1026
+ end
1027
+
1028
+ it "invokes the #install_command with :https_proxy set in config" do
1029
+ config[:https_proxy] = "https://proxy"
1030
+ Kitchen::SSH.stubs(:new).returns(connection)
1031
+ connection.expects(:exec).with("env https_proxy=https://proxy huh")
1032
+
1033
+ cmd
1034
+ end
1035
+
1036
+ it "invokes the #install_command with :ftp_proxy set in config" do
1037
+ config[:ftp_proxy] = "ftp://proxy"
1038
+ Kitchen::SSH.stubs(:new).returns(connection)
1039
+ connection.expects(:exec).with("env ftp_proxy=ftp://proxy huh")
1040
+
1041
+ cmd
1042
+ end
1043
+
1044
+ it "invokes the #install_command with :http_proxy & :https_proxy & :ftp_proxy set" do
1045
+ config[:http_proxy] = "http://proxy"
1046
+ config[:https_proxy] = "https://proxy"
1047
+ config[:ftp_proxy] = "ftp://proxy"
1048
+ Kitchen::SSH.stubs(:new).returns(connection)
1049
+ connection.expects(:exec).with(
1050
+ "env http_proxy=http://proxy https_proxy=https://proxy ftp_proxy=ftp://proxy huh")
1051
+
1052
+ cmd
1053
+ end
1054
+
1055
+ it "doesn't invoke an ssh command if command is nil" do
1056
+ Kitchen::SSH.stubs(:new).returns(mock)
1057
+
1058
+ driver.use_run_remote(state, nil)
1059
+ end
1060
+
1061
+ it "raises an ActionFailed on transfer when SSHFailed is raised" do
1062
+ Kitchen::SSH.stubs(:new).returns(connection)
1063
+ connection.stubs(:exec).raises(Kitchen::SSHFailed.new("dang"))
1064
+
1065
+ proc { cmd }.must_raise Kitchen::ActionFailed
1066
+ end
1067
+
1068
+ it "raises an ActionFailed on exec when Net::SSH:Exception is raised" do
1069
+ Kitchen::SSH.stubs(:new).returns(connection)
1070
+ connection.stubs(:exec).raises(Net::SSH::Exception.new("dang"))
1071
+
1072
+ proc { cmd }.must_raise Kitchen::ActionFailed
1073
+ end
1074
+ end
1075
+
1076
+ describe "#transfer_path" do
1077
+
1078
+ let(:cmd) { driver.use_transfer_path(state, ["nope"], "nadda") }
1079
+ let(:connection) { stub(:upload_path! => true) }
1080
+
1081
+ before do
1082
+ state[:hostname] = "fizzy"
1083
+ state[:username] = "bork"
1084
+ end
1085
+
1086
+ constructs_an_ssh_object
1087
+
1088
+ it "doesn't invoke an scp command if locals is nil" do
1089
+ Kitchen::SSH.stubs(:new).returns(mock)
1090
+
1091
+ driver.use_transfer_path(state, nil, "nope")
1092
+ end
1093
+
1094
+ it "doesn't invoke an scp command if locals is an empty array" do
1095
+ Kitchen::SSH.stubs(:new).returns(mock)
1096
+
1097
+ driver.use_transfer_path(state, [], "nope")
1098
+ end
1099
+
1100
+ it "raises an ActionFailed on transfer when SSHFailed is raised" do
1101
+ Kitchen::SSH.stubs(:new).returns(connection)
1102
+ connection.stubs(:upload_path!).raises(Kitchen::SSHFailed.new("dang"))
1103
+
1104
+ proc { cmd }.must_raise Kitchen::ActionFailed
1105
+ end
1106
+
1107
+ it "raises an ActionFailed on exec when Net::SSH:Exception is raised" do
1108
+ Kitchen::SSH.stubs(:new).returns(connection)
1109
+ connection.stubs(:upload_path!).raises(Net::SSH::Exception.new("dang"))
1110
+
1111
+ proc { cmd }.must_raise Kitchen::ActionFailed
1112
+ end
1113
+ end
1114
+ end
1115
+ end