test-kitchen 1.7.0 → 1.7.1.dev

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 (181) hide show
  1. checksums.yaml +4 -4
  2. data/.cane +8 -8
  3. data/.gitattributes +3 -0
  4. data/.github/ISSUE_TEMPLATE.md +55 -55
  5. data/.gitignore +28 -28
  6. data/.kitchen.ci.yml +23 -23
  7. data/.kitchen.proxy.yml +27 -27
  8. data/.rubocop.yml +3 -3
  9. data/.travis.yml +70 -70
  10. data/.yardopts +3 -3
  11. data/Berksfile +3 -3
  12. data/CHANGELOG.md +1090 -1083
  13. data/CONTRIBUTING.md +14 -14
  14. data/Gemfile +19 -19
  15. data/Gemfile.proxy_tests +4 -4
  16. data/Guardfile +42 -42
  17. data/LICENSE +15 -15
  18. data/MAINTAINERS.md +23 -23
  19. data/README.md +135 -135
  20. data/Rakefile +61 -61
  21. data/appveyor.yml +44 -44
  22. data/features/kitchen_action_commands.feature +164 -164
  23. data/features/kitchen_command.feature +16 -16
  24. data/features/kitchen_console_command.feature +34 -34
  25. data/features/kitchen_defaults.feature +38 -38
  26. data/features/kitchen_diagnose_command.feature +96 -96
  27. data/features/kitchen_driver_create_command.feature +64 -64
  28. data/features/kitchen_driver_discover_command.feature +25 -25
  29. data/features/kitchen_help_command.feature +16 -16
  30. data/features/kitchen_init_command.feature +274 -274
  31. data/features/kitchen_list_command.feature +104 -104
  32. data/features/kitchen_login_command.feature +62 -62
  33. data/features/kitchen_sink_command.feature +30 -30
  34. data/features/kitchen_test_command.feature +88 -88
  35. data/features/step_definitions/gem_steps.rb +36 -36
  36. data/features/step_definitions/git_steps.rb +5 -5
  37. data/features/step_definitions/output_steps.rb +5 -5
  38. data/features/support/env.rb +75 -75
  39. data/lib/kitchen.rb +150 -150
  40. data/lib/kitchen/base64_stream.rb +55 -55
  41. data/lib/kitchen/cli.rb +419 -419
  42. data/lib/kitchen/collection.rb +55 -55
  43. data/lib/kitchen/color.rb +65 -65
  44. data/lib/kitchen/command.rb +185 -185
  45. data/lib/kitchen/command/action.rb +45 -45
  46. data/lib/kitchen/command/console.rb +58 -58
  47. data/lib/kitchen/command/diagnose.rb +92 -92
  48. data/lib/kitchen/command/driver_discover.rb +105 -105
  49. data/lib/kitchen/command/exec.rb +41 -41
  50. data/lib/kitchen/command/list.rb +119 -119
  51. data/lib/kitchen/command/login.rb +43 -43
  52. data/lib/kitchen/command/sink.rb +54 -54
  53. data/lib/kitchen/command/test.rb +51 -51
  54. data/lib/kitchen/config.rb +322 -322
  55. data/lib/kitchen/configurable.rb +529 -529
  56. data/lib/kitchen/data_munger.rb +959 -959
  57. data/lib/kitchen/diagnostic.rb +141 -141
  58. data/lib/kitchen/driver.rb +56 -56
  59. data/lib/kitchen/driver/base.rb +134 -134
  60. data/lib/kitchen/driver/dummy.rb +108 -108
  61. data/lib/kitchen/driver/proxy.rb +72 -72
  62. data/lib/kitchen/driver/ssh_base.rb +357 -357
  63. data/lib/kitchen/errors.rb +229 -229
  64. data/lib/kitchen/generator/driver_create.rb +177 -177
  65. data/lib/kitchen/generator/init.rb +296 -296
  66. data/lib/kitchen/instance.rb +662 -662
  67. data/lib/kitchen/lazy_hash.rb +142 -142
  68. data/lib/kitchen/loader/yaml.rb +349 -349
  69. data/lib/kitchen/logger.rb +423 -423
  70. data/lib/kitchen/logging.rb +56 -56
  71. data/lib/kitchen/login_command.rb +52 -52
  72. data/lib/kitchen/metadata_chopper.rb +52 -52
  73. data/lib/kitchen/platform.rb +67 -67
  74. data/lib/kitchen/provisioner.rb +54 -54
  75. data/lib/kitchen/provisioner/base.rb +236 -236
  76. data/lib/kitchen/provisioner/chef/berkshelf.rb +114 -114
  77. data/lib/kitchen/provisioner/chef/common_sandbox.rb +322 -322
  78. data/lib/kitchen/provisioner/chef/librarian.rb +112 -112
  79. data/lib/kitchen/provisioner/chef_apply.rb +124 -124
  80. data/lib/kitchen/provisioner/chef_base.rb +341 -341
  81. data/lib/kitchen/provisioner/chef_solo.rb +88 -88
  82. data/lib/kitchen/provisioner/chef_zero.rb +245 -245
  83. data/lib/kitchen/provisioner/dummy.rb +79 -79
  84. data/lib/kitchen/provisioner/shell.rb +138 -138
  85. data/lib/kitchen/rake_tasks.rb +63 -63
  86. data/lib/kitchen/shell_out.rb +93 -93
  87. data/lib/kitchen/ssh.rb +276 -276
  88. data/lib/kitchen/state_file.rb +120 -120
  89. data/lib/kitchen/suite.rb +51 -51
  90. data/lib/kitchen/thor_tasks.rb +66 -66
  91. data/lib/kitchen/transport.rb +54 -54
  92. data/lib/kitchen/transport/base.rb +176 -176
  93. data/lib/kitchen/transport/dummy.rb +79 -79
  94. data/lib/kitchen/transport/ssh.rb +364 -364
  95. data/lib/kitchen/transport/winrm.rb +486 -486
  96. data/lib/kitchen/util.rb +147 -147
  97. data/lib/kitchen/verifier.rb +55 -55
  98. data/lib/kitchen/verifier/base.rb +235 -235
  99. data/lib/kitchen/verifier/busser.rb +277 -277
  100. data/lib/kitchen/verifier/dummy.rb +79 -79
  101. data/lib/kitchen/verifier/shell.rb +101 -101
  102. data/lib/kitchen/version.rb +21 -21
  103. data/lib/vendor/hash_recursive_merge.rb +82 -82
  104. data/spec/kitchen/base64_stream_spec.rb +77 -77
  105. data/spec/kitchen/cli_spec.rb +56 -56
  106. data/spec/kitchen/collection_spec.rb +80 -80
  107. data/spec/kitchen/color_spec.rb +54 -54
  108. data/spec/kitchen/config_spec.rb +408 -408
  109. data/spec/kitchen/configurable_spec.rb +1095 -1095
  110. data/spec/kitchen/data_munger_spec.rb +2694 -2694
  111. data/spec/kitchen/diagnostic_spec.rb +129 -129
  112. data/spec/kitchen/driver/base_spec.rb +121 -121
  113. data/spec/kitchen/driver/dummy_spec.rb +199 -199
  114. data/spec/kitchen/driver/proxy_spec.rb +138 -138
  115. data/spec/kitchen/driver/ssh_base_spec.rb +1115 -1115
  116. data/spec/kitchen/driver_spec.rb +112 -112
  117. data/spec/kitchen/errors_spec.rb +309 -309
  118. data/spec/kitchen/instance_spec.rb +1419 -1419
  119. data/spec/kitchen/lazy_hash_spec.rb +117 -117
  120. data/spec/kitchen/loader/yaml_spec.rb +774 -774
  121. data/spec/kitchen/logger_spec.rb +429 -429
  122. data/spec/kitchen/logging_spec.rb +59 -59
  123. data/spec/kitchen/login_command_spec.rb +68 -68
  124. data/spec/kitchen/metadata_chopper_spec.rb +82 -82
  125. data/spec/kitchen/platform_spec.rb +89 -89
  126. data/spec/kitchen/provisioner/base_spec.rb +386 -386
  127. data/spec/kitchen/provisioner/chef_apply_spec.rb +136 -136
  128. data/spec/kitchen/provisioner/chef_base_spec.rb +1161 -1161
  129. data/spec/kitchen/provisioner/chef_solo_spec.rb +557 -557
  130. data/spec/kitchen/provisioner/chef_zero_spec.rb +1001 -1001
  131. data/spec/kitchen/provisioner/dummy_spec.rb +99 -99
  132. data/spec/kitchen/provisioner/shell_spec.rb +566 -566
  133. data/spec/kitchen/provisioner_spec.rb +107 -107
  134. data/spec/kitchen/shell_out_spec.rb +150 -150
  135. data/spec/kitchen/ssh_spec.rb +693 -693
  136. data/spec/kitchen/state_file_spec.rb +129 -129
  137. data/spec/kitchen/suite_spec.rb +62 -62
  138. data/spec/kitchen/transport/base_spec.rb +89 -89
  139. data/spec/kitchen/transport/ssh_spec.rb +1255 -1255
  140. data/spec/kitchen/transport/winrm_spec.rb +1143 -1143
  141. data/spec/kitchen/transport_spec.rb +112 -112
  142. data/spec/kitchen/util_spec.rb +165 -165
  143. data/spec/kitchen/verifier/base_spec.rb +362 -362
  144. data/spec/kitchen/verifier/busser_spec.rb +610 -610
  145. data/spec/kitchen/verifier/dummy_spec.rb +99 -99
  146. data/spec/kitchen/verifier/shell_spec.rb +160 -160
  147. data/spec/kitchen/verifier_spec.rb +120 -120
  148. data/spec/kitchen_spec.rb +114 -114
  149. data/spec/spec_helper.rb +85 -85
  150. data/spec/support/powershell_max_size_spec.rb +40 -40
  151. data/support/busser_install_command.ps1 +14 -14
  152. data/support/busser_install_command.sh +14 -14
  153. data/support/chef-client-zero.rb +77 -77
  154. data/support/chef_base_init_command.ps1 +18 -18
  155. data/support/chef_base_init_command.sh +2 -2
  156. data/support/chef_base_install_command.ps1 +85 -85
  157. data/support/chef_base_install_command.sh +229 -229
  158. data/support/chef_zero_prepare_command_legacy.ps1 +9 -9
  159. data/support/chef_zero_prepare_command_legacy.sh +10 -10
  160. data/support/download_helpers.sh +109 -109
  161. data/support/dummy-validation.pem +27 -27
  162. data/templates/driver/CHANGELOG.md.erb +3 -3
  163. data/templates/driver/Gemfile.erb +3 -3
  164. data/templates/driver/README.md.erb +64 -64
  165. data/templates/driver/Rakefile.erb +21 -21
  166. data/templates/driver/driver.rb.erb +23 -23
  167. data/templates/driver/gemspec.erb +29 -29
  168. data/templates/driver/gitignore.erb +17 -17
  169. data/templates/driver/license_apachev2.erb +15 -15
  170. data/templates/driver/license_lgplv3.erb +16 -16
  171. data/templates/driver/license_mit.erb +22 -22
  172. data/templates/driver/license_reserved.erb +5 -5
  173. data/templates/driver/tailor.erb +4 -4
  174. data/templates/driver/travis.yml.erb +11 -11
  175. data/templates/driver/version.rb.erb +12 -12
  176. data/templates/init/chefignore.erb +1 -1
  177. data/templates/init/kitchen.yml.erb +18 -18
  178. data/test-kitchen.gemspec +62 -62
  179. data/test/integration/default/default_spec.rb +3 -3
  180. data/testing_windows.md +37 -37
  181. metadata +5 -4
@@ -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