test-kitchen 1.3.1 → 1.4.0.beta.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.cane +2 -0
- data/.gitignore +4 -0
- data/CHANGELOG.md +45 -0
- data/Rakefile +15 -0
- data/features/kitchen_action_commands.feature +12 -9
- data/features/kitchen_defaults.feature +38 -0
- data/features/kitchen_init_command.feature +0 -1
- data/features/kitchen_list_command.feature +2 -2
- data/features/kitchen_login_command.feature +7 -1
- data/features/kitchen_test_command.feature +4 -4
- data/lib/kitchen.rb +40 -11
- data/lib/kitchen/cli.rb +38 -22
- data/lib/kitchen/command/list.rb +5 -2
- data/lib/kitchen/config.rb +45 -18
- data/lib/kitchen/configurable.rb +137 -1
- data/lib/kitchen/data_munger.rb +248 -17
- data/lib/kitchen/driver.rb +1 -1
- data/lib/kitchen/driver/base.rb +1 -83
- data/lib/kitchen/driver/dummy.rb +0 -5
- data/lib/kitchen/driver/ssh_base.rb +177 -22
- data/lib/kitchen/instance.rb +140 -20
- data/lib/kitchen/logger.rb +43 -8
- data/lib/kitchen/login_command.rb +14 -5
- data/lib/kitchen/platform.rb +19 -0
- data/lib/kitchen/provisioner.rb +5 -3
- data/lib/kitchen/provisioner/base.rb +46 -48
- data/lib/kitchen/provisioner/chef/common_sandbox.rb +322 -0
- data/lib/kitchen/provisioner/chef_base.rb +179 -286
- data/lib/kitchen/provisioner/chef_solo.rb +11 -5
- data/lib/kitchen/provisioner/chef_zero.rb +108 -94
- data/lib/kitchen/provisioner/dummy.rb +47 -0
- data/lib/kitchen/provisioner/shell.rb +45 -12
- data/lib/kitchen/rake_tasks.rb +1 -1
- data/lib/kitchen/ssh.rb +1 -1
- data/lib/kitchen/thor_tasks.rb +1 -1
- data/lib/kitchen/transport.rb +54 -0
- data/lib/kitchen/transport/base.rb +146 -0
- data/lib/kitchen/transport/dummy.rb +75 -0
- data/lib/kitchen/transport/ssh.rb +325 -0
- data/lib/kitchen/transport/winrm.rb +508 -0
- data/lib/kitchen/transport/winrm/command_executor.rb +188 -0
- data/lib/kitchen/transport/winrm/file_transporter.rb +454 -0
- data/lib/kitchen/transport/winrm/logging.rb +50 -0
- data/lib/kitchen/transport/winrm/template.rb +74 -0
- data/lib/kitchen/transport/winrm/tmp_zip.rb +187 -0
- data/lib/kitchen/verifier.rb +55 -0
- data/lib/kitchen/verifier/base.rb +191 -0
- data/lib/kitchen/verifier/busser.rb +266 -0
- data/lib/kitchen/verifier/dummy.rb +75 -0
- data/lib/kitchen/version.rb +1 -1
- data/spec/kitchen/cli_spec.rb +56 -0
- data/spec/kitchen/config_spec.rb +61 -20
- data/spec/kitchen/configurable_spec.rb +327 -1
- data/spec/kitchen/data_munger_spec.rb +777 -14
- data/spec/kitchen/driver/base_spec.rb +7 -38
- data/spec/kitchen/driver/dummy_spec.rb +0 -29
- data/spec/kitchen/driver/ssh_base_spec.rb +580 -236
- data/spec/kitchen/driver_spec.rb +1 -0
- data/spec/kitchen/instance_spec.rb +383 -83
- data/spec/kitchen/login_command_spec.rb +29 -10
- data/spec/kitchen/platform_spec.rb +58 -2
- data/spec/kitchen/provisioner/base_spec.rb +170 -18
- data/spec/kitchen/provisioner/chef_base_spec.rb +454 -104
- data/spec/kitchen/provisioner/chef_solo_spec.rb +307 -104
- data/spec/kitchen/provisioner/chef_zero_spec.rb +561 -230
- data/spec/kitchen/provisioner/dummy_spec.rb +91 -0
- data/spec/kitchen/provisioner/shell_spec.rb +158 -56
- data/spec/kitchen/provisioner_spec.rb +37 -0
- data/spec/kitchen/ssh_spec.rb +19 -19
- data/spec/kitchen/transport/base_spec.rb +89 -0
- data/spec/kitchen/transport/ssh_spec.rb +1147 -0
- data/spec/kitchen/transport/winrm/command_executor_spec.rb +400 -0
- data/spec/kitchen/transport/winrm/file_transporter_spec.rb +876 -0
- data/spec/kitchen/transport/winrm/logging_spec.rb +92 -0
- data/spec/kitchen/transport/winrm/template_spec.rb +51 -0
- data/spec/kitchen/transport/winrm/tmp_zip_spec.rb +132 -0
- data/spec/kitchen/transport/winrm_spec.rb +1069 -0
- data/spec/kitchen/transport_spec.rb +112 -0
- data/spec/kitchen/verifier/base_spec.rb +310 -0
- data/spec/kitchen/verifier/busser_spec.rb +540 -0
- data/spec/kitchen/verifier/dummy_spec.rb +91 -0
- data/spec/kitchen/verifier_spec.rb +120 -0
- data/spec/kitchen_spec.rb +7 -0
- data/spec/spec_helper.rb +8 -0
- data/spec/support/powershell_max_size_spec.rb +40 -0
- data/support/busser_install_command.ps1 +14 -0
- data/support/busser_install_command.sh +15 -0
- data/support/check_files.ps1.erb +48 -0
- data/support/chef_base_init_command.ps1 +18 -0
- data/support/chef_base_init_command.sh +2 -0
- data/support/chef_base_install_command.ps1 +76 -0
- data/support/chef_base_install_command.sh +137 -0
- data/support/chef_zero_prepare_command_legacy.ps1 +9 -0
- data/support/chef_zero_prepare_command_legacy.sh +10 -0
- data/support/decode_files.ps1.erb +61 -0
- data/test-kitchen.gemspec +2 -0
- metadata +97 -8
- data/lib/kitchen/busser.rb +0 -316
- data/spec/kitchen/busser_spec.rb +0 -490
- data/support/chef_helpers.sh +0 -16
@@ -0,0 +1,112 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# Author:: Matt Wrock (<matt@mattwrock.com>)
|
4
|
+
#
|
5
|
+
# Copyright (C) 2014, Matt Wrock
|
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/configurable"
|
22
|
+
require "kitchen/errors"
|
23
|
+
require "kitchen/logging"
|
24
|
+
require "kitchen/transport"
|
25
|
+
require "kitchen/transport/base"
|
26
|
+
|
27
|
+
module Kitchen
|
28
|
+
|
29
|
+
module Transport
|
30
|
+
|
31
|
+
class Coolbeans < Kitchen::Transport::Base
|
32
|
+
end
|
33
|
+
|
34
|
+
class ItDepends < Kitchen::Transport::Base
|
35
|
+
|
36
|
+
attr_reader :verify_call_count
|
37
|
+
|
38
|
+
def initialize(config = {})
|
39
|
+
@verify_call_count = 0
|
40
|
+
super
|
41
|
+
end
|
42
|
+
|
43
|
+
def verify_dependencies
|
44
|
+
@verify_call_count += 1
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class UnstableDepends < Kitchen::Transport::Base
|
49
|
+
|
50
|
+
def verify_dependencies
|
51
|
+
raise UserError, "Oh noes, you don't have software!"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe Kitchen::Transport do
|
58
|
+
|
59
|
+
describe ".for_plugin" do
|
60
|
+
|
61
|
+
before do
|
62
|
+
Kitchen::Transport.stubs(:require).returns(true)
|
63
|
+
end
|
64
|
+
|
65
|
+
it "returns a transport object of the correct class" do
|
66
|
+
transport = Kitchen::Transport.for_plugin("coolbeans", {})
|
67
|
+
|
68
|
+
transport.must_be_kind_of Kitchen::Transport::Coolbeans
|
69
|
+
end
|
70
|
+
|
71
|
+
it "returns a transport initialized with its config" do
|
72
|
+
transport = Kitchen::Transport.for_plugin("coolbeans", :foo => "bar")
|
73
|
+
|
74
|
+
transport[:foo].must_equal "bar"
|
75
|
+
end
|
76
|
+
|
77
|
+
it "calls #verify_dependencies on the transport object" do
|
78
|
+
transport = Kitchen::Transport.for_plugin("it_depends", {})
|
79
|
+
|
80
|
+
transport.verify_call_count.must_equal 1
|
81
|
+
end
|
82
|
+
|
83
|
+
it "calls #verify_dependencies once per transport require" do
|
84
|
+
Kitchen::Transport.stubs(:require).returns(true, false)
|
85
|
+
transport1 = Kitchen::Transport.for_plugin("it_depends", {})
|
86
|
+
transport1.verify_call_count.must_equal 1
|
87
|
+
transport2 = Kitchen::Transport.for_plugin("it_depends", {})
|
88
|
+
|
89
|
+
transport2.verify_call_count.must_equal 0
|
90
|
+
end
|
91
|
+
|
92
|
+
it "raises ClientError if the transport could not be required" do
|
93
|
+
Kitchen::Transport.stubs(:require).raises(LoadError)
|
94
|
+
|
95
|
+
proc { Kitchen::Transport.for_plugin("coolbeans", {}) }.
|
96
|
+
must_raise Kitchen::ClientError
|
97
|
+
end
|
98
|
+
|
99
|
+
it "raises ClientError if the transport's class constant was not found" do
|
100
|
+
# pretend require worked
|
101
|
+
Kitchen::Transport.stubs(:require).returns(true)
|
102
|
+
|
103
|
+
proc { Kitchen::Transport.for_plugin("nope", {}) }.
|
104
|
+
must_raise Kitchen::ClientError
|
105
|
+
end
|
106
|
+
|
107
|
+
it "raises UserError if #verify_dependencies failes" do
|
108
|
+
proc { Kitchen::Transport.for_plugin("unstable_depends", {}) }.
|
109
|
+
must_raise Kitchen::UserError
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,310 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# Author:: Fletcher Nichol (<fnichol@nichol.ca>)
|
4
|
+
#
|
5
|
+
# Copyright (C) 2015, 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 "logger"
|
22
|
+
require "stringio"
|
23
|
+
|
24
|
+
require "kitchen/verifier/base"
|
25
|
+
require "kitchen/transport/base"
|
26
|
+
|
27
|
+
module Kitchen
|
28
|
+
|
29
|
+
module Verifier
|
30
|
+
|
31
|
+
class TestingDummy < Kitchen::Verifier::Base
|
32
|
+
|
33
|
+
attr_reader :called_create_sandbox, :called_cleanup_sandbox
|
34
|
+
|
35
|
+
def install_command
|
36
|
+
"install"
|
37
|
+
end
|
38
|
+
|
39
|
+
def init_command
|
40
|
+
"init"
|
41
|
+
end
|
42
|
+
|
43
|
+
def prepare_command
|
44
|
+
"prepare"
|
45
|
+
end
|
46
|
+
|
47
|
+
def run_command
|
48
|
+
"run"
|
49
|
+
end
|
50
|
+
|
51
|
+
def create_sandbox
|
52
|
+
@called_create_sandbox = true
|
53
|
+
end
|
54
|
+
|
55
|
+
def cleanup_sandbox
|
56
|
+
@called_cleanup_sandbox = true
|
57
|
+
end
|
58
|
+
|
59
|
+
def sandbox_path
|
60
|
+
"/tmp/sandbox"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe Kitchen::Verifier::Base do
|
67
|
+
|
68
|
+
let(:logged_output) { StringIO.new }
|
69
|
+
let(:logger) { Logger.new(logged_output) }
|
70
|
+
let(:platform) { stub(:os_type => nil, :shell_type => nil) }
|
71
|
+
let(:suite) { stub(:name => "germany") }
|
72
|
+
let(:config) { Hash.new }
|
73
|
+
|
74
|
+
let(:transport) do
|
75
|
+
t = mock("transport")
|
76
|
+
t.responds_like_instance_of(Kitchen::Transport::Base)
|
77
|
+
t
|
78
|
+
end
|
79
|
+
|
80
|
+
let(:instance) do
|
81
|
+
stub(
|
82
|
+
:name => "coolbeans",
|
83
|
+
:to_str => "instance",
|
84
|
+
:logger => logger,
|
85
|
+
:platform => platform,
|
86
|
+
:suite => suite,
|
87
|
+
:transport => transport
|
88
|
+
)
|
89
|
+
end
|
90
|
+
|
91
|
+
let(:verifier) do
|
92
|
+
Kitchen::Verifier::Base.new(config).finalize_config!(instance)
|
93
|
+
end
|
94
|
+
|
95
|
+
describe "configuration" do
|
96
|
+
|
97
|
+
describe "for unix operating systems" do
|
98
|
+
|
99
|
+
before { platform.stubs(:os_type).returns("unix") }
|
100
|
+
|
101
|
+
it ":sudo defaults to true" do
|
102
|
+
verifier[:sudo].must_equal true
|
103
|
+
end
|
104
|
+
|
105
|
+
it ":root_path defaults to '/tmp/verifier'" do
|
106
|
+
verifier[:root_path].must_equal "/tmp/verifier"
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
describe "for windows operating systems" do
|
111
|
+
|
112
|
+
before { platform.stubs(:os_type).returns("windows") }
|
113
|
+
|
114
|
+
it ":sudo defaults to nil" do
|
115
|
+
verifier[:sudo].must_equal nil
|
116
|
+
end
|
117
|
+
|
118
|
+
it ":root_path defaults to $env:TEMP\\verifier" do
|
119
|
+
verifier[:root_path].must_equal "$env:TEMP\\verifier"
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
it ":suite_name defaults to the passed in suite name" do
|
124
|
+
verifier[:suite_name].must_equal "germany"
|
125
|
+
end
|
126
|
+
|
127
|
+
it ":http_proxy defaults to nil" do
|
128
|
+
verifier[:http_proxy].must_equal nil
|
129
|
+
end
|
130
|
+
|
131
|
+
it ":http_proxys defaults to nil" do
|
132
|
+
verifier[:https_proxy].must_equal nil
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
describe "#call" do
|
137
|
+
|
138
|
+
let(:state) { Hash.new }
|
139
|
+
let(:cmd) { verifier.call(state) }
|
140
|
+
|
141
|
+
let(:connection) do
|
142
|
+
c = mock("transport_connection")
|
143
|
+
c.responds_like_instance_of(Kitchen::Transport::Base::Connection)
|
144
|
+
c
|
145
|
+
end
|
146
|
+
|
147
|
+
let(:verifier) do
|
148
|
+
Kitchen::Verifier::TestingDummy.new(config).finalize_config!(instance)
|
149
|
+
end
|
150
|
+
|
151
|
+
before do
|
152
|
+
FakeFS.activate!
|
153
|
+
FileUtils.mkdir_p(File.join(verifier.sandbox_path, "stuff"))
|
154
|
+
transport.stubs(:connection).yields(connection)
|
155
|
+
connection.stubs(:execute)
|
156
|
+
connection.stubs(:upload)
|
157
|
+
end
|
158
|
+
|
159
|
+
after do
|
160
|
+
FakeFS.deactivate!
|
161
|
+
FakeFS::FileSystem.clear
|
162
|
+
end
|
163
|
+
|
164
|
+
it "creates the sandbox" do
|
165
|
+
verifier.expects(:create_sandbox)
|
166
|
+
|
167
|
+
cmd
|
168
|
+
end
|
169
|
+
|
170
|
+
it "ensures that the sandbox is cleanup up" do
|
171
|
+
transport.stubs(:connection).raises
|
172
|
+
verifier.expects(:cleanup_sandbox)
|
173
|
+
|
174
|
+
begin
|
175
|
+
cmd
|
176
|
+
rescue # rubocop:disable Lint/HandleExceptions
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
it "yields a connection given the state" do
|
181
|
+
state[:a] = "b"
|
182
|
+
transport.expects(:connection).with(state).yields(connection)
|
183
|
+
|
184
|
+
cmd
|
185
|
+
end
|
186
|
+
|
187
|
+
it "invokes the verifier commands over the transport" do
|
188
|
+
order = sequence("order")
|
189
|
+
connection.expects(:execute).with("install").in_sequence(order)
|
190
|
+
connection.expects(:execute).with("init").in_sequence(order)
|
191
|
+
connection.expects(:execute).with("prepare").in_sequence(order)
|
192
|
+
connection.expects(:execute).with("run").in_sequence(order)
|
193
|
+
|
194
|
+
cmd
|
195
|
+
end
|
196
|
+
|
197
|
+
it "logs to info" do
|
198
|
+
cmd
|
199
|
+
|
200
|
+
logged_output.string.
|
201
|
+
must_match(/INFO -- : Transferring files to instance$/)
|
202
|
+
end
|
203
|
+
|
204
|
+
it "uploads sandbox files" do
|
205
|
+
connection.expects(:upload).with(["/tmp/sandbox/stuff"], "/tmp/verifier")
|
206
|
+
|
207
|
+
cmd
|
208
|
+
end
|
209
|
+
|
210
|
+
it "logs to debug" do
|
211
|
+
cmd
|
212
|
+
|
213
|
+
logged_output.string.must_match(/DEBUG -- : Transfer complete$/)
|
214
|
+
end
|
215
|
+
|
216
|
+
it "raises an ActionFailed on transfer when TransportFailed is raised" do
|
217
|
+
connection.stubs(:upload).
|
218
|
+
raises(Kitchen::Transport::TransportFailed.new("dang"))
|
219
|
+
|
220
|
+
proc { cmd }.must_raise Kitchen::ActionFailed
|
221
|
+
end
|
222
|
+
|
223
|
+
it "raises an ActionFailed on execute when TransportFailed is raised" do
|
224
|
+
connection.stubs(:execute).
|
225
|
+
raises(Kitchen::Transport::TransportFailed.new("dang"))
|
226
|
+
|
227
|
+
proc { cmd }.must_raise Kitchen::ActionFailed
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
[:init_command, :install_command, :prepare_command, :run_command].each do |cmd|
|
232
|
+
|
233
|
+
it "has a #{cmd} method" do
|
234
|
+
verifier.public_send(cmd).must_be_nil
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
describe "sandbox" do
|
239
|
+
|
240
|
+
after do
|
241
|
+
begin
|
242
|
+
verifier.cleanup_sandbox
|
243
|
+
rescue # rubocop:disable Lint/HandleExceptions
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
it "raises ClientError if #sandbox_path is called before #create_sandbox" do
|
248
|
+
proc { verifier.sandbox_path }.must_raise Kitchen::ClientError
|
249
|
+
end
|
250
|
+
|
251
|
+
it "#create_sandbox creates a temporary directory" do
|
252
|
+
verifier.create_sandbox
|
253
|
+
|
254
|
+
File.directory?(verifier.sandbox_path).must_equal true
|
255
|
+
format("%o", File.stat(verifier.sandbox_path).mode)[1, 4].
|
256
|
+
must_equal "0755"
|
257
|
+
end
|
258
|
+
|
259
|
+
it "#create_sandbox logs an info message" do
|
260
|
+
verifier.create_sandbox
|
261
|
+
|
262
|
+
logged_output.string.must_match info_line("Preparing files for transfer")
|
263
|
+
end
|
264
|
+
|
265
|
+
it "#create_sandbox logs a debug message" do
|
266
|
+
verifier.create_sandbox
|
267
|
+
|
268
|
+
logged_output.string.
|
269
|
+
must_match debug_line_starting_with("Creating local sandbox in ")
|
270
|
+
end
|
271
|
+
|
272
|
+
it "#cleanup_sandbox deletes the sandbox directory" do
|
273
|
+
verifier.create_sandbox
|
274
|
+
verifier.cleanup_sandbox
|
275
|
+
|
276
|
+
File.directory?(verifier.sandbox_path).must_equal false
|
277
|
+
end
|
278
|
+
|
279
|
+
it "#cleanup_sandbox logs a debug message" do
|
280
|
+
verifier.create_sandbox
|
281
|
+
verifier.cleanup_sandbox
|
282
|
+
|
283
|
+
logged_output.string.
|
284
|
+
must_match debug_line_starting_with("Cleaning up local sandbox in ")
|
285
|
+
end
|
286
|
+
|
287
|
+
def info_line(msg)
|
288
|
+
%r{^I, .* : #{Regexp.escape(msg)}$}
|
289
|
+
end
|
290
|
+
|
291
|
+
def debug_line_starting_with(msg)
|
292
|
+
%r{^D, .* : #{Regexp.escape(msg)}}
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
describe "#sudo" do
|
297
|
+
|
298
|
+
it "if :sudo is set, prepend sudo command" do
|
299
|
+
config[:sudo] = true
|
300
|
+
|
301
|
+
verifier.send(:sudo, "wakka").must_equal("sudo -E wakka")
|
302
|
+
end
|
303
|
+
|
304
|
+
it "if :sudo is falsy, do not include sudo command" do
|
305
|
+
config[:sudo] = false
|
306
|
+
|
307
|
+
verifier.send(:sudo, "wakka").must_equal("wakka")
|
308
|
+
end
|
309
|
+
end
|
310
|
+
end
|
@@ -0,0 +1,540 @@
|
|
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/verifier/busser"
|
23
|
+
|
24
|
+
describe Kitchen::Verifier::Busser do
|
25
|
+
|
26
|
+
let(:logged_output) { StringIO.new }
|
27
|
+
let(:logger) { Logger.new(logged_output) }
|
28
|
+
let(:config) { Hash.new }
|
29
|
+
let(:platform) { stub(:os_type => nil, :shell_type => nil) }
|
30
|
+
let(:suite) { stub(:name => "germany") }
|
31
|
+
|
32
|
+
let(:instance) do
|
33
|
+
stub(
|
34
|
+
:name => "coolbeans",
|
35
|
+
:logger => logger,
|
36
|
+
:platform => platform,
|
37
|
+
:suite => suite,
|
38
|
+
:to_str => "instance"
|
39
|
+
)
|
40
|
+
end
|
41
|
+
|
42
|
+
let(:verifier) do
|
43
|
+
Kitchen::Verifier::Busser.new(config).finalize_config!(instance)
|
44
|
+
end
|
45
|
+
|
46
|
+
let(:files) do
|
47
|
+
{
|
48
|
+
"mondospec/charlie" => {
|
49
|
+
:content => "charlie",
|
50
|
+
:perms => "0764"
|
51
|
+
},
|
52
|
+
"minispec/beta" => {
|
53
|
+
:content => "beta",
|
54
|
+
:perms => "0644"
|
55
|
+
},
|
56
|
+
"abba/alpha" => {
|
57
|
+
:content => "alpha",
|
58
|
+
:perms => "0440"
|
59
|
+
}
|
60
|
+
}
|
61
|
+
end
|
62
|
+
|
63
|
+
let(:helper_files) do
|
64
|
+
{
|
65
|
+
"minispec/spec_helper" => {
|
66
|
+
:content => "helping",
|
67
|
+
:perms => "0644"
|
68
|
+
},
|
69
|
+
"abba/common" => {
|
70
|
+
:content => "yeppers",
|
71
|
+
:perms => "0664"
|
72
|
+
}
|
73
|
+
}
|
74
|
+
end
|
75
|
+
|
76
|
+
before do
|
77
|
+
@root = Dir.mktmpdir
|
78
|
+
config[:test_base_path] = @root
|
79
|
+
end
|
80
|
+
|
81
|
+
after do
|
82
|
+
FileUtils.remove_entry(@root)
|
83
|
+
end
|
84
|
+
|
85
|
+
# TODO: deal with this:
|
86
|
+
# it "raises a UserError if the suite name is 'helper'" do
|
87
|
+
# proc {
|
88
|
+
# Kitchen::Busser.new("helper", config)
|
89
|
+
# }.must_raise Kitchen::UserError
|
90
|
+
# end
|
91
|
+
|
92
|
+
describe "configuration" do
|
93
|
+
|
94
|
+
describe "for unix operating systems" do
|
95
|
+
|
96
|
+
before { platform.stubs(:os_type).returns("unix") }
|
97
|
+
|
98
|
+
it ":ruby_bindir defaults the an Omnibus Chef installation" do
|
99
|
+
verifier[:ruby_bindir].must_equal "/opt/chef/embedded/bin"
|
100
|
+
end
|
101
|
+
|
102
|
+
it ":busser_bin defaults to a binstub under :root_path" do
|
103
|
+
config[:root_path] = "/beep"
|
104
|
+
|
105
|
+
verifier[:busser_bin].must_equal "/beep/bin/busser"
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
describe "for windows operating systems" do
|
110
|
+
|
111
|
+
before { platform.stubs(:os_type).returns("windows") }
|
112
|
+
|
113
|
+
it ":ruby_bindir defaults the an Omnibus Chef installation" do
|
114
|
+
verifier[:ruby_bindir].
|
115
|
+
must_equal "$env:systemdrive\\opscode\\chef\\embedded\\bin"
|
116
|
+
end
|
117
|
+
|
118
|
+
it ":busser_bin defaults to a binstub under :root_path" do
|
119
|
+
config[:root_path] = "\\beep"
|
120
|
+
|
121
|
+
verifier[:busser_bin].must_equal "\\beep\\bin\\busser.bat"
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
it ":version defaults to 'busser'" do
|
126
|
+
verifier[:version].must_equal "busser"
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
131
|
+
def self.common_bourne_variable_specs
|
132
|
+
it "uses bourne shell" do
|
133
|
+
cmd.must_match(/\Ash -c '$/)
|
134
|
+
cmd.must_match(/'\Z/)
|
135
|
+
end
|
136
|
+
|
137
|
+
it "ends with a single quote" do
|
138
|
+
cmd.must_match(/'\Z/)
|
139
|
+
end
|
140
|
+
|
141
|
+
it "sets the BUSSER_ROOT environment variable" do
|
142
|
+
cmd.must_match regexify(%{BUSSER_ROOT="/r"; export BUSSER_ROOT})
|
143
|
+
end
|
144
|
+
|
145
|
+
it "sets the GEM_HOME environment variable" do
|
146
|
+
cmd.must_match regexify(%{GEM_HOME="/r/gems"; export GEM_HOME})
|
147
|
+
end
|
148
|
+
|
149
|
+
it "sets the GEM_PATH environment variable" do
|
150
|
+
cmd.must_match regexify(%{GEM_PATH="/r/gems"; export GEM_PATH})
|
151
|
+
end
|
152
|
+
|
153
|
+
it "sets the GEM_CACHE environment variable" do
|
154
|
+
cmd.must_match regexify(%{GEM_CACHE="/r/gems/cache"; export GEM_CACHE})
|
155
|
+
end
|
156
|
+
end
|
157
|
+
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
158
|
+
|
159
|
+
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
160
|
+
def self.common_powershell_variable_specs
|
161
|
+
it "sets the BUSSER_ROOT environment variable" do
|
162
|
+
cmd.must_match regexify(%{$env:BUSSER_ROOT = "\\r"})
|
163
|
+
end
|
164
|
+
|
165
|
+
it "sets the GEM_HOME environment variable" do
|
166
|
+
cmd.must_match regexify(%{$env:GEM_HOME = "\\r\\gems"})
|
167
|
+
end
|
168
|
+
|
169
|
+
it "sets the GEM_PATH environment variable" do
|
170
|
+
cmd.must_match regexify(%{$env:GEM_PATH = "\\r\\gems"})
|
171
|
+
end
|
172
|
+
|
173
|
+
it "sets the GEM_CACHE environment variable" do
|
174
|
+
cmd.must_match regexify(%{$env:GEM_CACHE = "\\r\\gems\\cache"})
|
175
|
+
end
|
176
|
+
end
|
177
|
+
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
178
|
+
|
179
|
+
describe "#install_command" do
|
180
|
+
|
181
|
+
let(:cmd) { verifier.install_command }
|
182
|
+
|
183
|
+
describe "with no suite test files" do
|
184
|
+
|
185
|
+
describe "for bourne shells" do
|
186
|
+
|
187
|
+
before { platform.stubs(:shell_type).returns("bourne") }
|
188
|
+
|
189
|
+
it "returns nil" do
|
190
|
+
cmd.must_equal nil
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
describe "for powershell shells on windows os types" do
|
195
|
+
|
196
|
+
before do
|
197
|
+
platform.stubs(:shell_type).returns("powershell")
|
198
|
+
platform.stubs(:os_type).returns("windows")
|
199
|
+
end
|
200
|
+
|
201
|
+
it "returns nil" do
|
202
|
+
cmd.must_equal nil
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
describe "with suite test files" do
|
208
|
+
|
209
|
+
describe "for bourne shells" do
|
210
|
+
|
211
|
+
before do
|
212
|
+
platform.stubs(:shell_type).returns("bourne")
|
213
|
+
create_test_files
|
214
|
+
config[:ruby_bindir] = "/rbd"
|
215
|
+
config[:root_path] = "/r"
|
216
|
+
end
|
217
|
+
|
218
|
+
common_bourne_variable_specs
|
219
|
+
|
220
|
+
it "sets path to ruby command" do
|
221
|
+
cmd.must_match regexify(%{ruby="/rbd/ruby"})
|
222
|
+
end
|
223
|
+
|
224
|
+
it "sets path to gem command" do
|
225
|
+
cmd.must_match regexify(%{gem="/rbd/gem"})
|
226
|
+
end
|
227
|
+
|
228
|
+
it "sets version for busser" do
|
229
|
+
config[:version] = "the_best"
|
230
|
+
|
231
|
+
cmd.must_match regexify(%{version="the_best"})
|
232
|
+
end
|
233
|
+
|
234
|
+
it "sets gem install arguments" do
|
235
|
+
cmd.must_match regexify(
|
236
|
+
%{gem_install_args="busser --no-rdoc --no-ri"})
|
237
|
+
end
|
238
|
+
|
239
|
+
it "prepends sudo for busser binstub command when :sudo is set" do
|
240
|
+
cmd.must_match regexify(%{busser="sudo -E /r/bin/busser"})
|
241
|
+
end
|
242
|
+
|
243
|
+
it "does not sudo for busser binstub command when :sudo is falsey" do
|
244
|
+
config[:sudo] = false
|
245
|
+
|
246
|
+
cmd.must_match regexify(%{busser="/r/bin/busser"})
|
247
|
+
end
|
248
|
+
|
249
|
+
it "sets the busser plugins list" do
|
250
|
+
cmd.must_match regexify(
|
251
|
+
%{plugins="busser-abba busser-minispec busser-mondospec"})
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
describe "for powershell shells on windows os types" do
|
256
|
+
|
257
|
+
before do
|
258
|
+
platform.stubs(:shell_type).returns("powershell")
|
259
|
+
platform.stubs(:os_type).returns("windows")
|
260
|
+
create_test_files
|
261
|
+
config[:ruby_bindir] = "\\rbd"
|
262
|
+
config[:root_path] = "\\r"
|
263
|
+
end
|
264
|
+
|
265
|
+
common_powershell_variable_specs
|
266
|
+
|
267
|
+
it "sets path to ruby command" do
|
268
|
+
cmd.must_match regexify(%{$ruby = "\\rbd\\ruby.exe"})
|
269
|
+
end
|
270
|
+
|
271
|
+
it "sets path to gem command" do
|
272
|
+
cmd.must_match regexify(%{$gem = "\\rbd\\gem"})
|
273
|
+
end
|
274
|
+
|
275
|
+
it "sets version for busser" do
|
276
|
+
config[:version] = "the_best"
|
277
|
+
|
278
|
+
cmd.must_match regexify(%{$version = "the_best"})
|
279
|
+
end
|
280
|
+
|
281
|
+
it "sets gem install arguments" do
|
282
|
+
cmd.must_match regexify(
|
283
|
+
%{$gem_install_args = "busser --no-rdoc --no-ri"})
|
284
|
+
end
|
285
|
+
|
286
|
+
it "sets path to busser binstub command" do
|
287
|
+
cmd.must_match regexify(%{$busser = "\\r\\bin\\busser.bat"})
|
288
|
+
end
|
289
|
+
|
290
|
+
it "sets the busser plugins list" do
|
291
|
+
cmd.must_match regexify(
|
292
|
+
%{$plugins = "busser-abba busser-minispec busser-mondospec"})
|
293
|
+
end
|
294
|
+
end
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
describe "#init_command" do
|
299
|
+
|
300
|
+
let(:cmd) { verifier.init_command }
|
301
|
+
|
302
|
+
describe "with no suite test files" do
|
303
|
+
|
304
|
+
describe "for bourne shells" do
|
305
|
+
|
306
|
+
before { platform.stubs(:shell_type).returns("bourne") }
|
307
|
+
|
308
|
+
it "returns nil" do
|
309
|
+
cmd.must_equal nil
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
describe "for powershell shells on windows os types" do
|
314
|
+
|
315
|
+
before do
|
316
|
+
platform.stubs(:shell_type).returns("powershell")
|
317
|
+
platform.stubs(:os_type).returns("windows")
|
318
|
+
end
|
319
|
+
|
320
|
+
it "returns nil" do
|
321
|
+
cmd.must_equal nil
|
322
|
+
end
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
describe "with suite test files" do
|
327
|
+
|
328
|
+
describe "for bourne shells" do
|
329
|
+
|
330
|
+
before do
|
331
|
+
platform.stubs(:shell_type).returns("bourne")
|
332
|
+
create_test_files
|
333
|
+
config[:ruby_bindir] = "/rbd"
|
334
|
+
config[:root_path] = "/r"
|
335
|
+
end
|
336
|
+
|
337
|
+
common_bourne_variable_specs
|
338
|
+
|
339
|
+
it "runs busser's suite cleanup with sudo, if set" do
|
340
|
+
config[:root_path] = "/b"
|
341
|
+
config[:sudo] = true
|
342
|
+
|
343
|
+
cmd.must_match regexify(%{sudo -E /b/bin/busser suite cleanup})
|
344
|
+
end
|
345
|
+
|
346
|
+
it "runs busser's suite cleanup without sudo, if falsey" do
|
347
|
+
config[:root_path] = "/b"
|
348
|
+
config[:sudo] = false
|
349
|
+
|
350
|
+
cmd.wont_match regexify(%{sudo -E /b/bin/busser suite cleanup})
|
351
|
+
cmd.must_match regexify(%{/b/bin/busser suite cleanup})
|
352
|
+
end
|
353
|
+
end
|
354
|
+
|
355
|
+
describe "for powershell shells on windows os types" do
|
356
|
+
|
357
|
+
before do
|
358
|
+
platform.stubs(:shell_type).returns("powershell")
|
359
|
+
platform.stubs(:os_type).returns("windows")
|
360
|
+
create_test_files
|
361
|
+
config[:ruby_bindir] = "\\rbd"
|
362
|
+
config[:root_path] = "\\r"
|
363
|
+
end
|
364
|
+
|
365
|
+
common_powershell_variable_specs
|
366
|
+
|
367
|
+
it "runs busser's suite cleanup" do
|
368
|
+
config[:root_path] = "\\b"
|
369
|
+
|
370
|
+
cmd.must_match regexify(%{& \\b\\bin\\busser.bat suite cleanup})
|
371
|
+
end
|
372
|
+
end
|
373
|
+
end
|
374
|
+
end
|
375
|
+
|
376
|
+
describe "#run_command" do
|
377
|
+
|
378
|
+
let(:cmd) { verifier.run_command }
|
379
|
+
|
380
|
+
describe "with no suite test files" do
|
381
|
+
|
382
|
+
describe "for bourne shells" do
|
383
|
+
|
384
|
+
before { platform.stubs(:shell_type).returns("bourne") }
|
385
|
+
|
386
|
+
it "returns nil" do
|
387
|
+
cmd.must_equal nil
|
388
|
+
end
|
389
|
+
end
|
390
|
+
|
391
|
+
describe "for powershell shells on windows os types" do
|
392
|
+
|
393
|
+
before do
|
394
|
+
platform.stubs(:shell_type).returns("powershell")
|
395
|
+
platform.stubs(:os_type).returns("windows")
|
396
|
+
end
|
397
|
+
|
398
|
+
it "returns nil" do
|
399
|
+
cmd.must_equal nil
|
400
|
+
end
|
401
|
+
end
|
402
|
+
end
|
403
|
+
|
404
|
+
describe "with suite test files" do
|
405
|
+
|
406
|
+
describe "for bourne shells" do
|
407
|
+
|
408
|
+
before do
|
409
|
+
platform.stubs(:shell_type).returns("bourne")
|
410
|
+
create_test_files
|
411
|
+
config[:ruby_bindir] = "/rbd"
|
412
|
+
config[:root_path] = "/r"
|
413
|
+
end
|
414
|
+
|
415
|
+
common_bourne_variable_specs
|
416
|
+
|
417
|
+
it "uses sudo for busser test when configured" do
|
418
|
+
config[:sudo] = true
|
419
|
+
config[:busser_bin] = "/p/b"
|
420
|
+
|
421
|
+
cmd.must_match regexify("sudo -E /p/b test", :partial_line)
|
422
|
+
end
|
423
|
+
|
424
|
+
it "does not use sudo for busser test when configured" do
|
425
|
+
config[:sudo] = false
|
426
|
+
config[:busser_bin] = "/p/b"
|
427
|
+
|
428
|
+
cmd.must_match regexify("/p/b test", :partial_line)
|
429
|
+
cmd.wont_match regexify("sudo -E /p/b test", :partial_line)
|
430
|
+
end
|
431
|
+
end
|
432
|
+
|
433
|
+
describe "for powershell shells on windows os types" do
|
434
|
+
|
435
|
+
before do
|
436
|
+
platform.stubs(:shell_type).returns("powershell")
|
437
|
+
platform.stubs(:os_type).returns("windows")
|
438
|
+
create_test_files
|
439
|
+
config[:ruby_bindir] = "\\rbd"
|
440
|
+
config[:root_path] = "\\r"
|
441
|
+
end
|
442
|
+
|
443
|
+
common_powershell_variable_specs
|
444
|
+
|
445
|
+
it "runs busser's test" do
|
446
|
+
config[:root_path] = "\\b"
|
447
|
+
|
448
|
+
cmd.must_match regexify(%{& \\b\\bin\\busser.bat test})
|
449
|
+
end
|
450
|
+
end
|
451
|
+
end
|
452
|
+
end
|
453
|
+
|
454
|
+
describe "#create_sandbox" do
|
455
|
+
|
456
|
+
before do
|
457
|
+
create_test_files
|
458
|
+
end
|
459
|
+
|
460
|
+
it "copies each suite file into the suites directory in sandbox" do
|
461
|
+
verifier.create_sandbox
|
462
|
+
|
463
|
+
files.each do |f, md|
|
464
|
+
file = sandbox_path("suites/#{f}")
|
465
|
+
|
466
|
+
file.file?.must_equal true
|
467
|
+
file.stat.mode.to_s(8)[2, 4].must_equal md[:perms]
|
468
|
+
IO.read(file).must_equal md[:content]
|
469
|
+
end
|
470
|
+
end
|
471
|
+
|
472
|
+
it "copies each helper file into the suites directory in sandbox" do
|
473
|
+
verifier.create_sandbox
|
474
|
+
|
475
|
+
helper_files.each do |f, md|
|
476
|
+
file = sandbox_path("suites/#{f}")
|
477
|
+
|
478
|
+
file.file?.must_equal true
|
479
|
+
file.stat.mode.to_s(8)[2, 4].must_equal md[:perms]
|
480
|
+
IO.read(file).must_equal md[:content]
|
481
|
+
end
|
482
|
+
end
|
483
|
+
|
484
|
+
def sandbox_path(path)
|
485
|
+
Pathname.new(verifier.sandbox_path).join(path)
|
486
|
+
end
|
487
|
+
end
|
488
|
+
|
489
|
+
describe "Busser legacy behavior for code calling old method names" do
|
490
|
+
|
491
|
+
let(:busser) { verifier }
|
492
|
+
|
493
|
+
it "responds to #setup_cmd which calls #install_command" do
|
494
|
+
busser.stubs(:install_command).returns("install")
|
495
|
+
|
496
|
+
busser.setup_cmd.must_equal "install"
|
497
|
+
end
|
498
|
+
|
499
|
+
it "responds to #run_cmd which calls #run_command" do
|
500
|
+
busser.stubs(:run_command).returns("run")
|
501
|
+
|
502
|
+
busser.run_cmd.must_equal "run"
|
503
|
+
end
|
504
|
+
|
505
|
+
it "responds to #sync_cmd which logs a warning" do
|
506
|
+
busser.sync_cmd
|
507
|
+
|
508
|
+
logged_output.string.must_match warn_line_with(
|
509
|
+
"Legacy call to #sync_cmd cannot be preserved")
|
510
|
+
end
|
511
|
+
end
|
512
|
+
|
513
|
+
def create_file(file, content, perms)
|
514
|
+
FileUtils.mkdir_p(File.dirname(file))
|
515
|
+
File.open(file, "wb") { |f| f.write(content) }
|
516
|
+
FileUtils.chmod(perms.to_i(8), file)
|
517
|
+
end
|
518
|
+
|
519
|
+
def create_test_files
|
520
|
+
base = "#{config[:test_base_path]}/germany"
|
521
|
+
hbase = "#{config[:test_base_path]}/helpers"
|
522
|
+
|
523
|
+
files.map { |f, md| [File.join(base, f), md] }.each do |f, md|
|
524
|
+
create_file(f, md[:content], md[:perms])
|
525
|
+
end
|
526
|
+
helper_files.map { |f, md| [File.join(hbase, f), md] }.each do |f, md|
|
527
|
+
create_file(f, md[:content], md[:perms])
|
528
|
+
end
|
529
|
+
end
|
530
|
+
|
531
|
+
def regexify(str, line = :whole_line)
|
532
|
+
r = Regexp.escape(str)
|
533
|
+
r = "^\s*#{r}$" if line == :whole_line
|
534
|
+
Regexp.new(r)
|
535
|
+
end
|
536
|
+
|
537
|
+
def warn_line_with(msg)
|
538
|
+
%r{^W, .* : #{Regexp.escape(msg)}}
|
539
|
+
end
|
540
|
+
end
|