test-kitchen 1.5.0 → 1.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/CHANGELOG.md +977 -863
- data/CONTRIBUTING.md +3 -6
- data/Rakefile +9 -0
- data/lib/kitchen/command/driver_discover.rb +10 -4
- data/lib/kitchen/driver/ssh_base.rb +4 -0
- data/lib/kitchen/instance.rb +19 -1
- data/lib/kitchen/platform.rb +8 -2
- data/lib/kitchen/provisioner/base.rb +10 -2
- data/lib/kitchen/provisioner/chef_apply.rb +125 -0
- data/lib/kitchen/provisioner/chef_base.rb +12 -5
- data/lib/kitchen/transport/winrm.rb +36 -148
- data/lib/kitchen/version.rb +1 -1
- data/spec/kitchen/provisioner/base_spec.rb +33 -0
- data/spec/kitchen/provisioner/chef_apply_spec.rb +136 -0
- data/spec/kitchen/provisioner/chef_base_spec.rb +11 -5
- data/spec/kitchen/ssh_spec.rb +6 -3
- data/spec/kitchen/transport/ssh_spec.rb +6 -4
- data/spec/kitchen/transport/winrm_spec.rb +70 -254
- data/spec/kitchen/verifier/shell_spec.rb +1 -0
- data/test-kitchen.gemspec +3 -3
- data/testing_windows.md +37 -0
- metadata +25 -27
data/lib/kitchen/version.rb
CHANGED
@@ -330,6 +330,39 @@ describe Kitchen::Provisioner::Base do
|
|
330
330
|
end
|
331
331
|
end
|
332
332
|
|
333
|
+
describe "#sudo_command" do
|
334
|
+
|
335
|
+
describe "with :sudo set" do
|
336
|
+
|
337
|
+
before { config[:sudo] = true }
|
338
|
+
|
339
|
+
it "returns the default sudo_command" do
|
340
|
+
provisioner.send(:sudo_command).must_equal("sudo -E")
|
341
|
+
end
|
342
|
+
|
343
|
+
it "returns the custom sudo_command" do
|
344
|
+
config[:sudo_command] = "mysudo"
|
345
|
+
|
346
|
+
provisioner.send(:sudo_command).must_equal("mysudo")
|
347
|
+
end
|
348
|
+
end
|
349
|
+
|
350
|
+
describe "with :sudo falsey" do
|
351
|
+
|
352
|
+
before { config[:sudo] = false }
|
353
|
+
|
354
|
+
it "returns empty string for default sudo_command" do
|
355
|
+
provisioner.send(:sudo_command).must_equal("")
|
356
|
+
end
|
357
|
+
|
358
|
+
it "returns empty string for custom sudo_command" do
|
359
|
+
config[:sudo_command] = "mysudo"
|
360
|
+
|
361
|
+
provisioner.send(:sudo_command).must_equal("")
|
362
|
+
end
|
363
|
+
end
|
364
|
+
end
|
365
|
+
|
333
366
|
describe "#prefix_command" do
|
334
367
|
|
335
368
|
describe "with :command_prefix set" do
|
@@ -0,0 +1,136 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# Author:: SAWANOBORI Yukihiko <sawanoboriyu@higanworks.com>)
|
4
|
+
#
|
5
|
+
# Copyright (C) 2015, HiganWorks LLC
|
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/provisioner/chef_apply"
|
23
|
+
|
24
|
+
describe Kitchen::Provisioner::ChefApply do
|
25
|
+
|
26
|
+
let(:logged_output) { StringIO.new }
|
27
|
+
let(:logger) { Logger.new(logged_output) }
|
28
|
+
let(:platform) { stub(:os_type => nil) }
|
29
|
+
let(:suite) { stub(:name => "fries") }
|
30
|
+
|
31
|
+
let(:config) do
|
32
|
+
{ :test_base_path => "/b", :kitchen_root => "/r", :log_level => :info }
|
33
|
+
end
|
34
|
+
|
35
|
+
let(:instance) do
|
36
|
+
stub(
|
37
|
+
:name => "coolbeans",
|
38
|
+
:logger => logger,
|
39
|
+
:suite => suite,
|
40
|
+
:platform => platform
|
41
|
+
)
|
42
|
+
end
|
43
|
+
|
44
|
+
let(:provisioner) do
|
45
|
+
Kitchen::Provisioner::ChefApply.new(config).finalize_config!(instance)
|
46
|
+
end
|
47
|
+
|
48
|
+
it "provisioner api_version is 2" do
|
49
|
+
provisioner.diagnose_plugin[:api_version].must_equal 2
|
50
|
+
end
|
51
|
+
|
52
|
+
it "plugin_version is set to Kitchen::VERSION" do
|
53
|
+
provisioner.diagnose_plugin[:version].must_equal Kitchen::VERSION
|
54
|
+
end
|
55
|
+
|
56
|
+
describe "default config" do
|
57
|
+
|
58
|
+
it "sets :chef_apply_path to a path using :chef_omnibus_root" do
|
59
|
+
config[:chef_omnibus_root] = "/nice/place"
|
60
|
+
|
61
|
+
provisioner[:chef_apply_path].must_equal "/nice/place/bin/chef-apply"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "#create_sandbox" do
|
66
|
+
|
67
|
+
before do
|
68
|
+
@root = Dir.mktmpdir
|
69
|
+
config[:kitchen_root] = @root
|
70
|
+
end
|
71
|
+
|
72
|
+
after do
|
73
|
+
FileUtils.remove_entry(@root)
|
74
|
+
begin
|
75
|
+
provisioner.cleanup_sandbox
|
76
|
+
rescue # rubocop:disable Lint/HandleExceptions
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
describe "#run_command" do
|
82
|
+
|
83
|
+
before do
|
84
|
+
config[:run_list] = %w[appry_recipe1 appry_recipe2]
|
85
|
+
end
|
86
|
+
|
87
|
+
let(:cmd) { provisioner.run_command }
|
88
|
+
|
89
|
+
describe "for bourne shells" do
|
90
|
+
|
91
|
+
before { platform.stubs(:shell_type).returns("bourne") }
|
92
|
+
|
93
|
+
it "uses bourne shell" do
|
94
|
+
cmd.must_match(/\Ash -c '$/)
|
95
|
+
cmd.must_match(/'\Z/)
|
96
|
+
end
|
97
|
+
|
98
|
+
it "uses sudo for chef-apply when configured" do
|
99
|
+
config[:chef_omnibus_root] = "/c"
|
100
|
+
config[:sudo] = true
|
101
|
+
|
102
|
+
cmd.must_match regexify("sudo -E /c/bin/chef-apply apply/appry_recipe1.rb ", :partial_line)
|
103
|
+
cmd.must_match regexify("sudo -E /c/bin/chef-apply apply/appry_recipe2.rb ", :partial_line)
|
104
|
+
end
|
105
|
+
|
106
|
+
it "does not use sudo for chef-apply when configured" do
|
107
|
+
config[:chef_omnibus_root] = "/c"
|
108
|
+
config[:sudo] = false
|
109
|
+
|
110
|
+
cmd.must_match regexify("chef-apply apply/appry_recipe1.rb ", :partial_line)
|
111
|
+
cmd.must_match regexify("chef-apply apply/appry_recipe2.rb ", :partial_line)
|
112
|
+
cmd.wont_match regexify("sudo -E /c/bin/chef-apply ")
|
113
|
+
end
|
114
|
+
|
115
|
+
it "sets log level flag on chef-apply to auto by default" do
|
116
|
+
cmd.must_match regexify(" --log_level auto", :partial_line)
|
117
|
+
end
|
118
|
+
|
119
|
+
it "set log level flag for custom level" do
|
120
|
+
config[:log_level] = :extreme
|
121
|
+
|
122
|
+
cmd.must_match regexify(" --log_level extreme", :partial_line)
|
123
|
+
end
|
124
|
+
|
125
|
+
it "sets no color flag on chef-apply" do
|
126
|
+
cmd.must_match regexify(" --no-color", :partial_line)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def regexify(str, line = :whole_line)
|
132
|
+
r = Regexp.escape(str)
|
133
|
+
r = "^\s*#{r}$" if line == :whole_line
|
134
|
+
Regexp.new(r)
|
135
|
+
end
|
136
|
+
end
|
@@ -150,8 +150,8 @@ describe Kitchen::Provisioner::ChefBase do
|
|
150
150
|
|
151
151
|
let(:install_opts) {
|
152
152
|
{ :omnibus_url => "https://www.chef.io/chef/install.sh",
|
153
|
-
:project => nil, :install_flags => nil, :
|
154
|
-
:https_proxy => nil }
|
153
|
+
:project => nil, :install_flags => nil, :sudo_command => "sudo -E",
|
154
|
+
:http_proxy => nil, :https_proxy => nil }
|
155
155
|
}
|
156
156
|
|
157
157
|
it "returns nil if :require_chef_omnibus is falsey" do
|
@@ -323,17 +323,21 @@ describe Kitchen::Provisioner::ChefBase do
|
|
323
323
|
it "prepends sudo for sh commands when :sudo is set" do
|
324
324
|
config[:sudo] = true
|
325
325
|
config[:sudo_command] = "my_sudo_command"
|
326
|
+
install_opts_clone = install_opts.clone
|
327
|
+
install_opts_clone[:sudo_command] = config[:sudo_command]
|
326
328
|
|
327
329
|
Mixlib::Install.expects(:new).
|
328
|
-
with(default_version, false,
|
330
|
+
with(default_version, false, install_opts_clone).returns(installer)
|
329
331
|
cmd.must_equal "my_sudo_command my_install_command"
|
330
332
|
end
|
331
333
|
|
332
334
|
it "does not sudo for sh commands when :sudo is falsey" do
|
333
335
|
config[:sudo] = false
|
334
336
|
|
337
|
+
install_opts_clone = install_opts.clone
|
338
|
+
install_opts_clone[:sudo_command] = ""
|
335
339
|
Mixlib::Install.expects(:new).
|
336
|
-
with(default_version, false,
|
340
|
+
with(default_version, false, install_opts_clone).returns(installer)
|
337
341
|
cmd.must_equal "my_install_command"
|
338
342
|
end
|
339
343
|
end
|
@@ -347,8 +351,10 @@ describe Kitchen::Provisioner::ChefBase do
|
|
347
351
|
end
|
348
352
|
|
349
353
|
it "sets the powershell flag for Mixlib::Install" do
|
354
|
+
install_opts_clone = install_opts.clone
|
355
|
+
install_opts_clone[:sudo_command] = ""
|
350
356
|
Mixlib::Install.expects(:new).
|
351
|
-
with("", true,
|
357
|
+
with("", true, install_opts_clone).returns(installer)
|
352
358
|
cmd
|
353
359
|
end
|
354
360
|
end
|
data/spec/kitchen/ssh_spec.rb
CHANGED
@@ -18,7 +18,6 @@
|
|
18
18
|
|
19
19
|
require_relative "../spec_helper"
|
20
20
|
|
21
|
-
require "net/ssh/test"
|
22
21
|
require "kitchen/ssh"
|
23
22
|
require "tmpdir"
|
24
23
|
|
@@ -55,7 +54,7 @@ end
|
|
55
54
|
# `IO.select` with a version for testing Net::SSH code. Unfortunetly this
|
56
55
|
# impacts other code, so we'll "un-patch" this after each spec and "re-patch"
|
57
56
|
# it before the next one.
|
58
|
-
|
57
|
+
require "net/ssh/test"
|
59
58
|
def depatch_io
|
60
59
|
IO.class_exec do
|
61
60
|
class << self
|
@@ -63,6 +62,10 @@ def depatch_io
|
|
63
62
|
end
|
64
63
|
end
|
65
64
|
end
|
65
|
+
# We need to immediately call depatch so that `IO.select` is in a good state
|
66
|
+
# _right now_. The require immediately monkeypatches it and we only want
|
67
|
+
# it monkey patched inside each ssh test
|
68
|
+
depatch_io
|
66
69
|
|
67
70
|
def repatch_io
|
68
71
|
IO.class_exec do
|
@@ -82,7 +85,7 @@ end
|
|
82
85
|
# `LocalPacket` which can deal with the `"pty-req"` type.
|
83
86
|
#
|
84
87
|
# An upstream patch to Net::SSH will be required to retire this yak shave ;)
|
85
|
-
|
88
|
+
require "net/ssh/test/channel"
|
86
89
|
module Net
|
87
90
|
|
88
91
|
module SSH
|
@@ -18,8 +18,6 @@
|
|
18
18
|
|
19
19
|
require_relative "../../spec_helper"
|
20
20
|
|
21
|
-
require "net/ssh/test"
|
22
|
-
|
23
21
|
require "kitchen/transport/ssh"
|
24
22
|
|
25
23
|
# Hack to sort results in `Dir.entries` only within the yielded block, to limit
|
@@ -55,7 +53,7 @@ end
|
|
55
53
|
# `IO.select` with a version for testing Net::SSH code. Unfortunetly this
|
56
54
|
# impacts other code, so we'll "un-patch" this after each spec and "re-patch"
|
57
55
|
# it before the next one.
|
58
|
-
|
56
|
+
require "net/ssh/test"
|
59
57
|
def depatch_io
|
60
58
|
IO.class_exec do
|
61
59
|
class << self
|
@@ -63,6 +61,10 @@ def depatch_io
|
|
63
61
|
end
|
64
62
|
end
|
65
63
|
end
|
64
|
+
# We need to immediately call depatch so that `IO.select` is in a good state
|
65
|
+
# _right now_. The require immediately monkeypatches it and we only want
|
66
|
+
# it monkey patched inside each ssh test
|
67
|
+
depatch_io
|
66
68
|
|
67
69
|
def repatch_io
|
68
70
|
IO.class_exec do
|
@@ -82,7 +84,7 @@ end
|
|
82
84
|
# `LocalPacket` which can deal with the `"pty-req"` type.
|
83
85
|
#
|
84
86
|
# An upstream patch to Net::SSH will be required to retire this yak shave ;)
|
85
|
-
|
87
|
+
require "net/ssh/test/channel"
|
86
88
|
module Net
|
87
89
|
|
88
90
|
module SSH
|
@@ -20,9 +20,7 @@ require_relative "../../spec_helper"
|
|
20
20
|
|
21
21
|
require "kitchen/transport/winrm"
|
22
22
|
require "winrm"
|
23
|
-
require "winrm
|
24
|
-
require "winrm/transport/shell_closer"
|
25
|
-
require "winrm/transport/file_transporter"
|
23
|
+
require "winrm-fs"
|
26
24
|
|
27
25
|
module Kitchen
|
28
26
|
|
@@ -107,8 +105,8 @@ describe Kitchen::Transport::Winrm do
|
|
107
105
|
transport[:max_wait_until_ready].must_equal 600
|
108
106
|
end
|
109
107
|
|
110
|
-
it "sets :winrm_transport to :
|
111
|
-
transport[:winrm_transport].must_equal :
|
108
|
+
it "sets :winrm_transport to :negotiate" do
|
109
|
+
transport[:winrm_transport].must_equal :negotiate
|
112
110
|
end
|
113
111
|
end
|
114
112
|
|
@@ -150,25 +148,17 @@ describe Kitchen::Transport::Winrm do
|
|
150
148
|
make_connection
|
151
149
|
end
|
152
150
|
|
153
|
-
it "sets the :winrm_transport to :
|
151
|
+
it "sets the :winrm_transport to :negotiate" do
|
154
152
|
klass.expects(:new).with do |hash|
|
155
|
-
hash[:winrm_transport] == :
|
153
|
+
hash[:winrm_transport] == :negotiate
|
156
154
|
end
|
157
155
|
|
158
156
|
make_connection
|
159
157
|
end
|
160
158
|
|
161
|
-
it "sets the :disable_sspi to
|
159
|
+
it "sets the :disable_sspi to false" do
|
162
160
|
klass.expects(:new).with do |hash|
|
163
|
-
hash[:disable_sspi] ==
|
164
|
-
end
|
165
|
-
|
166
|
-
make_connection
|
167
|
-
end
|
168
|
-
|
169
|
-
it "sets the :basic_auth_only to true" do
|
170
|
-
klass.expects(:new).with do |hash|
|
171
|
-
hash[:basic_auth_only] == true
|
161
|
+
hash[:disable_sspi] == false
|
172
162
|
end
|
173
163
|
|
174
164
|
make_connection
|
@@ -336,42 +326,20 @@ describe Kitchen::Transport::Winrm do
|
|
336
326
|
make_connection
|
337
327
|
end
|
338
328
|
|
339
|
-
describe "when
|
329
|
+
describe "when negotiate is set in config" do
|
340
330
|
before do
|
341
|
-
config[:winrm_transport] = "
|
331
|
+
config[:winrm_transport] = "negotiate"
|
342
332
|
end
|
343
333
|
|
344
|
-
|
345
|
-
before do
|
346
|
-
RbConfig::CONFIG.stubs(:[]).with("host_os").returns("mingw32")
|
347
|
-
end
|
348
|
-
|
349
|
-
it "sets :winrm_transport to sspinegotiate on Windows" do
|
350
|
-
|
351
|
-
klass.expects(:new).with do |hash|
|
352
|
-
hash[:winrm_transport] == :sspinegotiate &&
|
353
|
-
hash[:disable_sspi] == false &&
|
354
|
-
hash[:basic_auth_only] == false
|
355
|
-
end
|
334
|
+
it "sets :winrm_transport to negotiate" do
|
356
335
|
|
357
|
-
|
336
|
+
klass.expects(:new).with do |hash|
|
337
|
+
hash[:winrm_transport] == :negotiate &&
|
338
|
+
hash[:disable_sspi] == false &&
|
339
|
+
hash[:basic_auth_only] == false
|
358
340
|
end
|
359
|
-
end
|
360
341
|
|
361
|
-
|
362
|
-
before do
|
363
|
-
RbConfig::CONFIG.stubs(:[]).with("host_os").returns("darwin14")
|
364
|
-
end
|
365
|
-
|
366
|
-
it "sets :winrm_transport to plaintext" do
|
367
|
-
klass.expects(:new).with do |hash|
|
368
|
-
hash[:winrm_transport] == :plaintext &&
|
369
|
-
hash[:disable_sspi] == true &&
|
370
|
-
hash[:basic_auth_only] == true
|
371
|
-
end
|
372
|
-
|
373
|
-
make_connection
|
374
|
-
end
|
342
|
+
make_connection
|
375
343
|
end
|
376
344
|
end
|
377
345
|
|
@@ -438,48 +406,46 @@ describe Kitchen::Transport::Winrm do
|
|
438
406
|
end
|
439
407
|
|
440
408
|
describe "#load_needed_dependencies" do
|
441
|
-
describe "winrm-
|
409
|
+
describe "winrm-fs" do
|
442
410
|
before do
|
443
|
-
# force loading of winrm-
|
444
|
-
require "winrm
|
411
|
+
# force loading of winrm-fs to get the version constant
|
412
|
+
require "winrm-fs"
|
445
413
|
end
|
446
414
|
|
447
415
|
it "logs a message to debug that code will be loaded" do
|
448
|
-
transport.stubs(:require)
|
449
416
|
transport
|
450
417
|
|
451
418
|
logged_output.string.must_match debug_line_with(
|
452
|
-
"
|
419
|
+
"winrm-fs requested, loading winrm-fs gem")
|
453
420
|
end
|
454
421
|
|
455
422
|
it "logs a message to debug when library is initially loaded" do
|
456
423
|
transport = Kitchen::Transport::Winrm.new(config)
|
457
|
-
transport.stubs(:require)
|
458
|
-
transport.stubs(:
|
459
|
-
|
424
|
+
transport.stubs(:require).with("winrm", anything)
|
425
|
+
transport.stubs(:require).with("winrm-fs").returns(true)
|
460
426
|
transport.finalize_config!(instance)
|
461
427
|
|
462
428
|
logged_output.string.must_match(
|
463
|
-
/
|
429
|
+
/winrm-fs is loaded/
|
464
430
|
)
|
465
431
|
end
|
466
432
|
|
467
433
|
it "logs a message to debug when library is previously loaded" do
|
468
434
|
transport = Kitchen::Transport::Winrm.new(config)
|
469
|
-
transport.stubs(:require)
|
470
|
-
transport.stubs(:
|
471
|
-
|
435
|
+
transport.stubs(:require).with("winrm", anything)
|
436
|
+
transport.stubs(:require).with("winrm-fs").returns(false)
|
472
437
|
transport.finalize_config!(instance)
|
473
438
|
|
474
439
|
logged_output.string.must_match(
|
475
|
-
/
|
440
|
+
/winrm-fs was already loaded/
|
476
441
|
)
|
477
442
|
end
|
478
443
|
|
479
444
|
it "logs a message to fatal when libraries cannot be loaded" do
|
480
445
|
transport = Kitchen::Transport::Winrm.new(config)
|
481
|
-
transport.stubs(:require)
|
482
|
-
transport.stubs(:
|
446
|
+
transport.stubs(:require).with("winrm", anything)
|
447
|
+
transport.stubs(:require).with("winrm-fs").
|
448
|
+
raises(LoadError, "uh oh")
|
483
449
|
begin
|
484
450
|
transport.finalize_config!(instance)
|
485
451
|
rescue # rubocop:disable Lint/HandleExceptions
|
@@ -487,64 +453,61 @@ describe Kitchen::Transport::Winrm do
|
|
487
453
|
end
|
488
454
|
|
489
455
|
logged_output.string.must_match fatal_line_with(
|
490
|
-
"The `winrm-
|
456
|
+
"The `winrm-fs` gem is missing and must be installed")
|
491
457
|
end
|
492
458
|
|
493
459
|
it "raises a UserError when libraries cannot be loaded" do
|
494
460
|
transport = Kitchen::Transport::Winrm.new(config)
|
495
|
-
transport.stubs(:require)
|
496
|
-
transport.stubs(:
|
461
|
+
transport.stubs(:require).with("winrm", anything)
|
462
|
+
transport.stubs(:require).with("winrm-fs").
|
463
|
+
raises(LoadError, "uh oh")
|
497
464
|
|
498
465
|
err = proc {
|
499
466
|
transport.finalize_config!(instance)
|
500
467
|
}.must_raise Kitchen::UserError
|
501
|
-
err.message.must_match(/^Could not load or activate winrm-
|
468
|
+
err.message.must_match(/^Could not load or activate winrm-fs\. /)
|
502
469
|
end
|
503
470
|
end
|
504
471
|
|
505
|
-
describe "winrm
|
506
|
-
before do
|
507
|
-
RbConfig::CONFIG.stubs(:[]).with("host_os").returns("mingw32")
|
508
|
-
end
|
509
|
-
|
472
|
+
describe "winrm" do
|
510
473
|
it "logs a message to debug that code will be loaded" do
|
511
474
|
transport = Kitchen::Transport::Winrm.new(config)
|
512
|
-
transport.stubs(:
|
475
|
+
transport.stubs(:require).with("winrm-fs", anything)
|
513
476
|
transport.stubs(:require)
|
514
477
|
transport.finalize_config!(instance)
|
515
478
|
|
516
479
|
logged_output.string.must_match debug_line_with(
|
517
|
-
"
|
480
|
+
"winrm requested, loading winrm gem")
|
518
481
|
end
|
519
482
|
|
520
483
|
it "logs a message to debug when library is initially loaded" do
|
521
484
|
transport = Kitchen::Transport::Winrm.new(config)
|
522
|
-
transport.stubs(:
|
523
|
-
transport.stubs(:
|
485
|
+
transport.stubs(:require).with("winrm-fs", anything)
|
486
|
+
transport.stubs(:require).returns(true)
|
524
487
|
|
525
488
|
transport.finalize_config!(instance)
|
526
489
|
|
527
490
|
logged_output.string.must_match(
|
528
|
-
/winrm
|
491
|
+
/winrm is loaded/
|
529
492
|
)
|
530
493
|
end
|
531
494
|
|
532
495
|
it "logs a message to debug when library is previously loaded" do
|
533
496
|
transport = Kitchen::Transport::Winrm.new(config)
|
534
|
-
transport.stubs(:
|
535
|
-
transport.stubs(:
|
497
|
+
transport.stubs(:require).with("winrm-fs", anything)
|
498
|
+
transport.stubs(:require).returns(false)
|
536
499
|
|
537
500
|
transport.finalize_config!(instance)
|
538
501
|
|
539
502
|
logged_output.string.must_match(
|
540
|
-
/winrm
|
503
|
+
/winrm was already loaded/
|
541
504
|
)
|
542
505
|
end
|
543
506
|
|
544
507
|
it "logs a message to fatal when libraries cannot be loaded" do
|
545
508
|
transport = Kitchen::Transport::Winrm.new(config)
|
546
|
-
transport.stubs(:
|
547
|
-
transport.stubs(:
|
509
|
+
transport.stubs(:require).with("winrm-fs", anything)
|
510
|
+
transport.stubs(:require).raises(LoadError, "uh oh")
|
548
511
|
begin
|
549
512
|
transport.finalize_config!(instance)
|
550
513
|
rescue # rubocop:disable Lint/HandleExceptions
|
@@ -552,18 +515,18 @@ describe Kitchen::Transport::Winrm do
|
|
552
515
|
end
|
553
516
|
|
554
517
|
logged_output.string.must_match fatal_line_with(
|
555
|
-
"The `winrm
|
518
|
+
"The `winrm` gem is missing and must be installed")
|
556
519
|
end
|
557
520
|
|
558
521
|
it "raises a UserError when libraries cannot be loaded" do
|
559
522
|
transport = Kitchen::Transport::Winrm.new(config)
|
560
|
-
transport.stubs(:
|
561
|
-
transport.stubs(:
|
523
|
+
transport.stubs(:require).with("winrm-fs", anything)
|
524
|
+
transport.stubs(:require).raises(LoadError, "uh oh")
|
562
525
|
|
563
526
|
err = proc {
|
564
527
|
transport.finalize_config!(instance)
|
565
528
|
}.must_raise Kitchen::UserError
|
566
|
-
err.message.must_match(/^Could not load or activate winrm
|
529
|
+
err.message.must_match(/^Could not load or activate winrm\. /)
|
567
530
|
end
|
568
531
|
end
|
569
532
|
end
|
@@ -602,7 +565,7 @@ describe Kitchen::Transport::Winrm::Connection do
|
|
602
565
|
|
603
566
|
let(:executor) do
|
604
567
|
s = mock("command_executor")
|
605
|
-
s.responds_like_instance_of(WinRM::
|
568
|
+
s.responds_like_instance_of(WinRM::CommandExecutor)
|
606
569
|
s
|
607
570
|
end
|
608
571
|
|
@@ -611,6 +574,8 @@ describe Kitchen::Transport::Winrm::Connection do
|
|
611
574
|
end
|
612
575
|
|
613
576
|
before do
|
577
|
+
WinRM::WinRMWebService.stubs(:new).returns(winrm_session)
|
578
|
+
winrm_session.stubs(:logger=)
|
614
579
|
logger.level = Logger::DEBUG
|
615
580
|
end
|
616
581
|
|
@@ -624,29 +589,12 @@ describe Kitchen::Transport::Winrm::Connection do
|
|
624
589
|
end
|
625
590
|
|
626
591
|
before do
|
627
|
-
|
628
|
-
# disable finalizer as service is a fake anyway
|
629
|
-
ObjectSpace.stubs(:define_finalizer).
|
630
|
-
with { |obj, _| obj.class == Kitchen::Transport::Winrm::Connection }
|
631
|
-
executor.stubs(:open).returns("shell-123")
|
632
|
-
executor.stubs(:shell).returns("shell-123")
|
592
|
+
winrm_session.stubs(:create_executor).returns(executor)
|
633
593
|
executor.stubs(:close)
|
634
594
|
executor.stubs(:run_powershell_script).
|
635
595
|
with("doit").yields("ok\n", nil).returns(response)
|
636
596
|
end
|
637
597
|
|
638
|
-
it "logger displays closing connection on debug" do
|
639
|
-
connection.execute("doit")
|
640
|
-
connection.close
|
641
|
-
|
642
|
-
logged_output.string.must_match debug_line(
|
643
|
-
"[WinRM] closing remote shell shell-123 on #{info}"
|
644
|
-
)
|
645
|
-
logged_output.string.must_match debug_line(
|
646
|
-
"[WinRM] remote shell shell-123 closed"
|
647
|
-
)
|
648
|
-
end
|
649
|
-
|
650
598
|
it "only closes the shell once for multiple calls" do
|
651
599
|
executor.expects(:close).once
|
652
600
|
|
@@ -660,10 +608,7 @@ describe Kitchen::Transport::Winrm::Connection do
|
|
660
608
|
describe "#execute" do
|
661
609
|
|
662
610
|
before do
|
663
|
-
|
664
|
-
# disable finalizer as service is a fake anyway
|
665
|
-
ObjectSpace.stubs(:define_finalizer).
|
666
|
-
with { |obj, _| obj.class == Kitchen::Transport::Winrm::Connection }
|
611
|
+
winrm_session.stubs(:create_executor).returns(executor)
|
667
612
|
end
|
668
613
|
|
669
614
|
describe "for a successful command" do
|
@@ -679,7 +624,6 @@ describe Kitchen::Transport::Winrm::Connection do
|
|
679
624
|
end
|
680
625
|
|
681
626
|
before do
|
682
|
-
executor.expects(:open).returns("shell-123")
|
683
627
|
executor.expects(:run_powershell_script).
|
684
628
|
with("doit").yields("ok\n", nil).returns(response)
|
685
629
|
end
|
@@ -691,17 +635,6 @@ describe Kitchen::Transport::Winrm::Connection do
|
|
691
635
|
"[WinRM] #{info} (doit)")
|
692
636
|
end
|
693
637
|
|
694
|
-
it "logger displays establishing connection on debug" do
|
695
|
-
connection.execute("doit")
|
696
|
-
|
697
|
-
logged_output.string.must_match debug_line(
|
698
|
-
"[WinRM] opening remote shell on #{info}"
|
699
|
-
)
|
700
|
-
logged_output.string.must_match debug_line(
|
701
|
-
"[WinRM] remote shell shell-123 is open on #{info}"
|
702
|
-
)
|
703
|
-
end
|
704
|
-
|
705
638
|
it "logger captures stdout" do
|
706
639
|
connection.execute("doit")
|
707
640
|
|
@@ -741,10 +674,9 @@ describe Kitchen::Transport::Winrm::Connection do
|
|
741
674
|
end
|
742
675
|
|
743
676
|
before do
|
744
|
-
executor.expects(:
|
745
|
-
|
746
|
-
|
747
|
-
yields("ok\n", nil).returns(response)
|
677
|
+
executor.expects(:run_powershell_script).with(
|
678
|
+
%{powershell -ExecutionPolicy Bypass -File "$env:TEMP/kitchen/coolbeans-long_script.ps1"}
|
679
|
+
).yields("ok\n", nil).returns(response)
|
748
680
|
end
|
749
681
|
|
750
682
|
it "uploads the long command" do
|
@@ -786,12 +718,11 @@ describe Kitchen::Transport::Winrm::Connection do
|
|
786
718
|
end
|
787
719
|
|
788
720
|
before do
|
789
|
-
executor.expects(:open).returns("shell-123")
|
790
721
|
executor.expects(:run_powershell_script).
|
791
722
|
with("doit").yields("nope\n", nil).returns(response)
|
792
723
|
end
|
793
724
|
|
794
|
-
# rubocop:disable Metrics/MethodLength
|
725
|
+
# rubocop:disable Metrics/MethodLength
|
795
726
|
def self.common_failed_command_specs
|
796
727
|
it "logger displays command on debug" do
|
797
728
|
begin
|
@@ -805,21 +736,6 @@ describe Kitchen::Transport::Winrm::Connection do
|
|
805
736
|
)
|
806
737
|
end
|
807
738
|
|
808
|
-
it "logger displays establishing connection on debug" do
|
809
|
-
begin
|
810
|
-
connection.execute("doit")
|
811
|
-
rescue # rubocop:disable Lint/HandleExceptions
|
812
|
-
# the raise is not what is being tested here, rather its side-effect
|
813
|
-
end
|
814
|
-
|
815
|
-
logged_output.string.must_match debug_line(
|
816
|
-
"[WinRM] opening remote shell on #{info}"
|
817
|
-
)
|
818
|
-
logged_output.string.must_match debug_line(
|
819
|
-
"[WinRM] remote shell shell-123 is open on #{info}"
|
820
|
-
)
|
821
|
-
end
|
822
|
-
|
823
739
|
it "logger captures stdout" do
|
824
740
|
begin
|
825
741
|
connection.execute("doit")
|
@@ -854,7 +770,7 @@ MSG
|
|
854
770
|
end
|
855
771
|
end
|
856
772
|
end
|
857
|
-
# rubocop:enable Metrics/MethodLength
|
773
|
+
# rubocop:enable Metrics/MethodLength
|
858
774
|
|
859
775
|
describe "when a non-zero exit code is returned" do
|
860
776
|
|
@@ -897,64 +813,12 @@ MSG
|
|
897
813
|
|
898
814
|
options[:connection_retries] = 3
|
899
815
|
options[:connection_retry_sleep] = 7
|
900
|
-
|
901
|
-
executor.stubs(:open).raises(k)
|
816
|
+
winrm_session.stubs(:create_executor).raises(k)
|
902
817
|
end
|
903
818
|
|
904
819
|
it "reraises the #{klass} exception" do
|
905
820
|
proc { connection.execute("nope") }.must_raise klass
|
906
821
|
end
|
907
|
-
|
908
|
-
it "attempts to connect :connection_retries times" do
|
909
|
-
begin
|
910
|
-
connection.execute("nope")
|
911
|
-
rescue # rubocop:disable Lint/HandleExceptions
|
912
|
-
# the raise is not what is being tested here, rather its side-effect
|
913
|
-
end
|
914
|
-
|
915
|
-
logged_output.string.lines.count { |l|
|
916
|
-
l =~ debug_line("[WinRM] opening remote shell on #{info}")
|
917
|
-
}.must_equal 3
|
918
|
-
logged_output.string.lines.count { |l|
|
919
|
-
l =~ debug_line("[WinRM] remote shell shell-123 is open on #{info}")
|
920
|
-
}.must_equal 0
|
921
|
-
end
|
922
|
-
|
923
|
-
it "sleeps for :connection_retry_sleep seconds between retries" do
|
924
|
-
connection.unstub(:sleep)
|
925
|
-
connection.expects(:sleep).with(7).twice
|
926
|
-
|
927
|
-
begin
|
928
|
-
connection.execute("nope")
|
929
|
-
rescue # rubocop:disable Lint/HandleExceptions
|
930
|
-
# the raise is not what is being tested here, rather its side-effect
|
931
|
-
end
|
932
|
-
end
|
933
|
-
|
934
|
-
it "logs the first 2 retry failures on info" do
|
935
|
-
begin
|
936
|
-
connection.execute("nope")
|
937
|
-
rescue # rubocop:disable Lint/HandleExceptions
|
938
|
-
# the raise is not what is being tested here, rather its side-effect
|
939
|
-
end
|
940
|
-
|
941
|
-
logged_output.string.lines.count { |l|
|
942
|
-
l =~ info_line_with(
|
943
|
-
"[WinRM] connection failed, retrying in 7 seconds")
|
944
|
-
}.must_equal 2
|
945
|
-
end
|
946
|
-
|
947
|
-
it "logs the last retry failures on warn" do
|
948
|
-
begin
|
949
|
-
connection.execute("nope")
|
950
|
-
rescue # rubocop:disable Lint/HandleExceptions
|
951
|
-
# the raise is not what is being tested here, rather its side-effect
|
952
|
-
end
|
953
|
-
|
954
|
-
logged_output.string.lines.count { |l|
|
955
|
-
l =~ warn_line_with("[WinRM] connection failed, terminating ")
|
956
|
-
}.must_equal 1
|
957
|
-
end
|
958
822
|
end
|
959
823
|
end
|
960
824
|
end
|
@@ -1131,38 +995,33 @@ MSG
|
|
1131
995
|
|
1132
996
|
let(:transporter) do
|
1133
997
|
t = mock("file_transporter")
|
1134
|
-
t.responds_like_instance_of(WinRM::
|
998
|
+
t.responds_like_instance_of(WinRM::FS::Core::FileTransporter)
|
1135
999
|
t
|
1136
1000
|
end
|
1137
1001
|
|
1138
1002
|
before do
|
1139
|
-
|
1140
|
-
ObjectSpace.stubs(:define_finalizer).
|
1141
|
-
with { |obj, _| obj.class == Kitchen::Transport::Winrm::Connection }
|
1003
|
+
winrm_session.stubs(:create_executor).returns(executor)
|
1142
1004
|
|
1143
|
-
WinRM::
|
1144
|
-
|
1145
|
-
|
1146
|
-
WinRM::Transport::FileTransporter.stubs(:new).
|
1147
|
-
with(executor, logger).returns(transporter)
|
1005
|
+
WinRM::FS::Core::FileTransporter.stubs(:new).
|
1006
|
+
with(executor).returns(transporter)
|
1148
1007
|
transporter.stubs(:upload)
|
1149
1008
|
end
|
1150
1009
|
|
1151
1010
|
def self.common_specs_for_upload
|
1152
1011
|
it "builds a Winrm::FileTransporter" do
|
1153
|
-
WinRM::
|
1012
|
+
WinRM::FS::Core::FileTransporter.unstub(:new)
|
1154
1013
|
|
1155
|
-
WinRM::
|
1156
|
-
with(executor
|
1014
|
+
WinRM::FS::Core::FileTransporter.expects(:new).
|
1015
|
+
with(executor).returns(transporter)
|
1157
1016
|
|
1158
1017
|
upload
|
1159
1018
|
end
|
1160
1019
|
|
1161
1020
|
it "reuses the Winrm::FileTransporter" do
|
1162
|
-
WinRM::
|
1021
|
+
WinRM::FS::Core::FileTransporter.unstub(:new)
|
1163
1022
|
|
1164
|
-
WinRM::
|
1165
|
-
with(executor
|
1023
|
+
WinRM::FS::Core::FileTransporter.expects(:new).
|
1024
|
+
with(executor).returns(transporter).once
|
1166
1025
|
|
1167
1026
|
upload
|
1168
1027
|
upload
|
@@ -1192,49 +1051,8 @@ MSG
|
|
1192
1051
|
describe "#wait_until_ready" do
|
1193
1052
|
|
1194
1053
|
before do
|
1195
|
-
|
1196
|
-
# disable finalizer as service is a fake anyway
|
1197
|
-
ObjectSpace.stubs(:define_finalizer).
|
1198
|
-
with { |obj, _| obj.class == Kitchen::Transport::Winrm::Connection }
|
1054
|
+
winrm_session.stubs(:create_executor).returns(executor)
|
1199
1055
|
options[:max_wait_until_ready] = 300
|
1200
|
-
connection.stubs(:sleep)
|
1201
|
-
end
|
1202
|
-
|
1203
|
-
describe "when failing to connect" do
|
1204
|
-
|
1205
|
-
before do
|
1206
|
-
executor.stubs(:open).raises(Errno::ECONNREFUSED)
|
1207
|
-
end
|
1208
|
-
|
1209
|
-
it "attempts to connect :max_wait_until_ready / 3 times if failing" do
|
1210
|
-
begin
|
1211
|
-
connection.wait_until_ready
|
1212
|
-
rescue # rubocop:disable Lint/HandleExceptions
|
1213
|
-
# the raise is not what is being tested here, rather its side-effect
|
1214
|
-
end
|
1215
|
-
|
1216
|
-
logged_output.string.lines.count { |l|
|
1217
|
-
l =~ info_line_with(
|
1218
|
-
"Waiting for WinRM service on http://foo:5985/wsman, retrying in 3 seconds")
|
1219
|
-
}.must_equal((300 / 3) - 1)
|
1220
|
-
logged_output.string.lines.count { |l|
|
1221
|
-
l =~ debug_line_with("[WinRM] connection failed ")
|
1222
|
-
}.must_equal((300 / 3) - 1)
|
1223
|
-
logged_output.string.lines.count { |l|
|
1224
|
-
l =~ warn_line_with("[WinRM] connection failed, terminating ")
|
1225
|
-
}.must_equal 1
|
1226
|
-
end
|
1227
|
-
|
1228
|
-
it "sleeps for 3 seconds between retries" do
|
1229
|
-
connection.unstub(:sleep)
|
1230
|
-
connection.expects(:sleep).with(3).times((300 / 3) - 1)
|
1231
|
-
|
1232
|
-
begin
|
1233
|
-
connection.wait_until_ready
|
1234
|
-
rescue # rubocop:disable Lint/HandleExceptions
|
1235
|
-
# the raise is not what is being tested here, rather its side-effect
|
1236
|
-
end
|
1237
|
-
end
|
1238
1056
|
end
|
1239
1057
|
|
1240
1058
|
describe "when connection is successful" do
|
@@ -1247,7 +1065,6 @@ MSG
|
|
1247
1065
|
end
|
1248
1066
|
|
1249
1067
|
before do
|
1250
|
-
executor.stubs(:open).returns("shell-123")
|
1251
1068
|
executor.expects(:run_powershell_script).
|
1252
1069
|
with("Write-Host '[WinRM] Established\n'").returns(response)
|
1253
1070
|
end
|
@@ -1267,7 +1084,6 @@ MSG
|
|
1267
1084
|
end
|
1268
1085
|
|
1269
1086
|
before do
|
1270
|
-
executor.stubs(:open).returns("shell-123")
|
1271
1087
|
executor.expects(:run_powershell_script).
|
1272
1088
|
with("Write-Host '[WinRM] Established\n'").returns(response)
|
1273
1089
|
end
|