test-kitchen 1.2.1 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.cane +1 -1
- data/.rubocop.yml +3 -0
- data/.travis.yml +20 -9
- data/CHANGELOG.md +219 -108
- data/Gemfile +10 -6
- data/Guardfile +38 -9
- data/README.md +11 -1
- data/Rakefile +21 -37
- data/bin/kitchen +4 -4
- data/features/kitchen_action_commands.feature +161 -0
- data/features/kitchen_console_command.feature +34 -0
- data/features/kitchen_diagnose_command.feature +64 -0
- data/features/kitchen_init_command.feature +29 -17
- data/features/kitchen_list_command.feature +2 -2
- data/features/kitchen_login_command.feature +56 -0
- data/features/{sink_command.feature → kitchen_sink_command.feature} +0 -0
- data/features/kitchen_test_command.feature +88 -0
- data/features/step_definitions/gem_steps.rb +8 -6
- data/features/step_definitions/git_steps.rb +4 -2
- data/features/step_definitions/output_steps.rb +5 -0
- data/features/support/env.rb +12 -9
- data/lib/kitchen.rb +60 -38
- data/lib/kitchen/base64_stream.rb +55 -0
- data/lib/kitchen/busser.rb +124 -58
- data/lib/kitchen/cli.rb +121 -38
- data/lib/kitchen/collection.rb +3 -3
- data/lib/kitchen/color.rb +4 -4
- data/lib/kitchen/command.rb +78 -11
- data/lib/kitchen/command/action.rb +3 -2
- data/lib/kitchen/command/console.rb +12 -5
- data/lib/kitchen/command/diagnose.rb +17 -3
- data/lib/kitchen/command/driver_discover.rb +26 -7
- data/lib/kitchen/command/exec.rb +41 -0
- data/lib/kitchen/command/list.rb +44 -14
- data/lib/kitchen/command/login.rb +2 -1
- data/lib/kitchen/command/sink.rb +2 -1
- data/lib/kitchen/command/test.rb +5 -4
- data/lib/kitchen/config.rb +146 -14
- data/lib/kitchen/configurable.rb +314 -0
- data/lib/kitchen/data_munger.rb +522 -18
- data/lib/kitchen/diagnostic.rb +43 -4
- data/lib/kitchen/driver.rb +4 -4
- data/lib/kitchen/driver/base.rb +80 -115
- data/lib/kitchen/driver/dummy.rb +34 -6
- data/lib/kitchen/driver/proxy.rb +14 -3
- data/lib/kitchen/driver/ssh_base.rb +61 -7
- data/lib/kitchen/errors.rb +109 -9
- data/lib/kitchen/generator/driver_create.rb +39 -5
- data/lib/kitchen/generator/init.rb +130 -45
- data/lib/kitchen/instance.rb +162 -28
- data/lib/kitchen/lazy_hash.rb +79 -7
- data/lib/kitchen/loader/yaml.rb +159 -27
- data/lib/kitchen/logger.rb +267 -21
- data/lib/kitchen/logging.rb +30 -3
- data/lib/kitchen/login_command.rb +11 -2
- data/lib/kitchen/metadata_chopper.rb +2 -2
- data/lib/kitchen/provisioner.rb +4 -4
- data/lib/kitchen/provisioner/base.rb +107 -103
- data/lib/kitchen/provisioner/chef/berkshelf.rb +36 -8
- data/lib/kitchen/provisioner/chef/librarian.rb +40 -11
- data/lib/kitchen/provisioner/chef_base.rb +206 -167
- data/lib/kitchen/provisioner/chef_solo.rb +25 -7
- data/lib/kitchen/provisioner/chef_zero.rb +105 -29
- data/lib/kitchen/provisioner/dummy.rb +1 -1
- data/lib/kitchen/provisioner/shell.rb +21 -6
- data/lib/kitchen/rake_tasks.rb +8 -3
- data/lib/kitchen/shell_out.rb +15 -18
- data/lib/kitchen/ssh.rb +122 -27
- data/lib/kitchen/state_file.rb +24 -7
- data/lib/kitchen/thor_tasks.rb +9 -4
- data/lib/kitchen/util.rb +43 -118
- data/lib/kitchen/version.rb +1 -1
- data/lib/vendor/hash_recursive_merge.rb +10 -2
- data/spec/kitchen/base64_stream_spec.rb +77 -0
- data/spec/kitchen/busser_spec.rb +490 -0
- data/spec/kitchen/collection_spec.rb +10 -10
- data/spec/kitchen/color_spec.rb +2 -2
- data/spec/kitchen/config_spec.rb +234 -62
- data/spec/kitchen/configurable_spec.rb +490 -0
- data/spec/kitchen/data_munger_spec.rb +1070 -862
- data/spec/kitchen/diagnostic_spec.rb +79 -0
- data/spec/kitchen/driver/base_spec.rb +80 -85
- data/spec/kitchen/driver/dummy_spec.rb +43 -14
- data/spec/kitchen/driver/proxy_spec.rb +134 -0
- data/spec/kitchen/driver/ssh_base_spec.rb +644 -0
- data/spec/kitchen/driver_spec.rb +15 -15
- data/spec/kitchen/errors_spec.rb +309 -0
- data/spec/kitchen/instance_spec.rb +143 -46
- data/spec/kitchen/lazy_hash_spec.rb +36 -9
- data/spec/kitchen/loader/yaml_spec.rb +237 -226
- data/spec/kitchen/logger_spec.rb +419 -0
- data/spec/kitchen/logging_spec.rb +59 -0
- data/spec/kitchen/login_command_spec.rb +49 -0
- data/spec/kitchen/metadata_chopper_spec.rb +82 -0
- data/spec/kitchen/platform_spec.rb +4 -4
- data/spec/kitchen/provisioner/base_spec.rb +65 -125
- data/spec/kitchen/provisioner/chef_base_spec.rb +798 -0
- data/spec/kitchen/provisioner/chef_solo_spec.rb +316 -0
- data/spec/kitchen/provisioner/chef_zero_spec.rb +624 -0
- data/spec/kitchen/provisioner/shell_spec.rb +269 -0
- data/spec/kitchen/provisioner_spec.rb +6 -6
- data/spec/kitchen/shell_out_spec.rb +143 -0
- data/spec/kitchen/ssh_spec.rb +683 -0
- data/spec/kitchen/state_file_spec.rb +28 -21
- data/spec/kitchen/suite_spec.rb +7 -7
- data/spec/kitchen/util_spec.rb +68 -10
- data/spec/kitchen_spec.rb +107 -0
- data/spec/spec_helper.rb +18 -13
- data/support/chef-client-zero.rb +10 -9
- data/support/chef_helpers.sh +16 -0
- data/support/download_helpers.sh +109 -0
- data/test-kitchen.gemspec +42 -33
- metadata +107 -33
@@ -0,0 +1,79 @@
|
|
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/diagnostic"
|
22
|
+
|
23
|
+
describe Kitchen::Diagnostic do
|
24
|
+
|
25
|
+
let(:loader) do
|
26
|
+
stub(:diagnose => { :who => "loader" })
|
27
|
+
end
|
28
|
+
|
29
|
+
let(:instances) do
|
30
|
+
[
|
31
|
+
stub(:name => "i1", :diagnose => { :stuff => "sup" }),
|
32
|
+
stub(:name => "i2", :diagnose => { :stuff => "yo" })
|
33
|
+
]
|
34
|
+
end
|
35
|
+
|
36
|
+
it "#read returns a Hash" do
|
37
|
+
Kitchen::Diagnostic.new.read.must_be_instance_of Hash
|
38
|
+
end
|
39
|
+
|
40
|
+
it "#read returns the version of Test Kitchen" do
|
41
|
+
Kitchen::Diagnostic.new.read["kitchen_version"].must_equal Kitchen::VERSION
|
42
|
+
end
|
43
|
+
|
44
|
+
it "#read returns a timestamp in UTC" do
|
45
|
+
Time.stubs(:now).returns(Time.at(0))
|
46
|
+
|
47
|
+
Kitchen::Diagnostic.new.read["timestamp"].
|
48
|
+
must_equal "1970-01-01 00:00:00 UTC"
|
49
|
+
end
|
50
|
+
|
51
|
+
it "#read doesn't return a loader hash if not given one" do
|
52
|
+
Kitchen::Diagnostic.new.read.key?("loader").must_equal false
|
53
|
+
end
|
54
|
+
|
55
|
+
it "#read returns the loader's diganose hash if a loader is present" do
|
56
|
+
Kitchen::Diagnostic.new(:loader => loader).
|
57
|
+
read["loader"].must_equal("who" => "loader")
|
58
|
+
end
|
59
|
+
|
60
|
+
it "#read returns an error hash for loader if error hash is passed in" do
|
61
|
+
Kitchen::Diagnostic.new(:loader => { :error => "damn" }).
|
62
|
+
read["loader"].must_equal("error" => "damn")
|
63
|
+
end
|
64
|
+
|
65
|
+
it "#read returns an empty hash if no instances were given" do
|
66
|
+
Kitchen::Diagnostic.new.read["instances"].must_equal Hash.new
|
67
|
+
end
|
68
|
+
|
69
|
+
it "#read returns the instances' diganose hashes if instances are present" do
|
70
|
+
Kitchen::Diagnostic.new(:instances => instances).
|
71
|
+
read["instances"].
|
72
|
+
must_equal("i1" => { "stuff" => "sup" }, "i2" => { "stuff" => "yo" })
|
73
|
+
end
|
74
|
+
|
75
|
+
it "#read returns an error hash for instances if error hash is passed in" do
|
76
|
+
Kitchen::Diagnostic.new(:instances => { :error => "shoot" }).
|
77
|
+
read["instances"].must_equal("error" => "shoot")
|
78
|
+
end
|
79
|
+
end
|
@@ -16,41 +16,28 @@
|
|
16
16
|
# See the License for the specific language governing permissions and
|
17
17
|
# limitations under the License.
|
18
18
|
|
19
|
-
require_relative
|
20
|
-
require
|
21
|
-
require
|
19
|
+
require_relative "../../spec_helper"
|
20
|
+
require "logger"
|
21
|
+
require "stringio"
|
22
22
|
|
23
|
-
require
|
23
|
+
require "kitchen"
|
24
24
|
|
25
25
|
module Kitchen
|
26
26
|
|
27
27
|
module Driver
|
28
28
|
|
29
|
-
class
|
30
|
-
|
31
|
-
default_config :beans, "kidney"
|
32
|
-
default_config :tunables, { 'flimflam' => 'positate' }
|
33
|
-
default_config :edible, true
|
29
|
+
class Speedy < Base
|
34
30
|
end
|
35
31
|
|
36
|
-
class
|
32
|
+
class Dodgy < Base
|
37
33
|
|
38
|
-
|
34
|
+
no_parallel_for :converge
|
39
35
|
end
|
40
36
|
|
41
|
-
class
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
default_config :beans_url do |driver|
|
46
|
-
"http://gim.me/#{driver[:beans]}"
|
47
|
-
end
|
48
|
-
default_config :command do |driver|
|
49
|
-
"#{driver[:fetch_command]} #{driver[:beans_url]}"
|
50
|
-
end
|
51
|
-
default_config :fetch_url do |driver|
|
52
|
-
"http://gim.me/beans-for/#{driver.instance.name}"
|
53
|
-
end
|
37
|
+
class Slow < Base
|
38
|
+
|
39
|
+
no_parallel_for :create, :destroy
|
40
|
+
no_parallel_for :verify
|
54
41
|
end
|
55
42
|
end
|
56
43
|
end
|
@@ -62,96 +49,104 @@ describe Kitchen::Driver::Base do
|
|
62
49
|
let(:config) { Hash.new }
|
63
50
|
let(:state) { Hash.new }
|
64
51
|
|
65
|
-
let(:
|
66
|
-
stub(:
|
52
|
+
let(:busser) do
|
53
|
+
stub(:setup_cmd => "setup", :sync_cmd => "sync", :run_cmd => "run")
|
67
54
|
end
|
68
55
|
|
69
|
-
|
56
|
+
let(:instance) do
|
57
|
+
stub(
|
58
|
+
:name => "coolbeans",
|
59
|
+
:logger => logger,
|
60
|
+
:busser => busser,
|
61
|
+
:to_str => "instance"
|
62
|
+
)
|
63
|
+
end
|
70
64
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
d
|
75
|
-
end
|
65
|
+
let(:driver) do
|
66
|
+
Kitchen::Driver::Base.new(config).finalize_config!(instance)
|
67
|
+
end
|
76
68
|
|
77
|
-
|
78
|
-
|
79
|
-
|
69
|
+
it "#instance returns its instance" do
|
70
|
+
driver.instance.must_equal instance
|
71
|
+
end
|
80
72
|
|
81
|
-
|
82
|
-
|
83
|
-
end
|
73
|
+
it "#name returns the name of the driver" do
|
74
|
+
driver.name.must_equal "Base"
|
84
75
|
end
|
85
76
|
|
86
|
-
describe "
|
77
|
+
describe "#logger" do
|
87
78
|
|
88
|
-
|
89
|
-
|
90
|
-
d.instance = instance
|
91
|
-
d
|
92
|
-
end
|
79
|
+
before { @klog = Kitchen.logger }
|
80
|
+
after { Kitchen.logger = @klog }
|
93
81
|
|
94
|
-
it "
|
95
|
-
driver
|
96
|
-
driver[:tunables]['flimflam'].must_equal 'positate'
|
97
|
-
driver[:edible].must_equal true
|
82
|
+
it "returns the instance's logger if defined" do
|
83
|
+
driver.send(:logger).must_equal logger
|
98
84
|
end
|
99
85
|
|
100
|
-
it "
|
101
|
-
|
102
|
-
|
86
|
+
it "returns the default logger if instance's logger is not set" do
|
87
|
+
driver = Kitchen::Driver::Base.new(config)
|
88
|
+
Kitchen.logger = "yep"
|
103
89
|
|
104
|
-
driver
|
105
|
-
driver[:edible].must_equal false
|
90
|
+
driver.send(:logger).must_equal Kitchen.logger
|
106
91
|
end
|
107
92
|
end
|
108
93
|
|
109
|
-
|
94
|
+
it "#puts calls logger.info" do
|
95
|
+
driver.send(:puts, "yo")
|
110
96
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
p
|
115
|
-
end
|
97
|
+
logged_output.string.must_match(/I, /)
|
98
|
+
logged_output.string.must_match(/yo\n/)
|
99
|
+
end
|
116
100
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
101
|
+
it "#print calls logger.info" do
|
102
|
+
driver.send(:print, "yo")
|
103
|
+
|
104
|
+
logged_output.string.must_match(/I, /)
|
105
|
+
logged_output.string.must_match(/yo\n/)
|
106
|
+
end
|
123
107
|
|
124
|
-
|
125
|
-
config[:beans] = "pinto"
|
126
|
-
config[:edible] = false
|
108
|
+
[:create, :converge, :setup, :verify, :destroy].each do |action|
|
127
109
|
|
128
|
-
|
129
|
-
|
130
|
-
driver
|
110
|
+
it "has a #{action} method that takes state" do
|
111
|
+
state = Hash.new
|
112
|
+
driver.public_send(action, state).must_be_nil
|
131
113
|
end
|
132
114
|
end
|
133
115
|
|
134
|
-
|
116
|
+
it "has a login command that raises ActionFailed by default" do
|
117
|
+
proc { driver.login_command(Hash.new) }.must_raise Kitchen::ActionFailed
|
118
|
+
end
|
135
119
|
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
d
|
140
|
-
end
|
120
|
+
it "has a default verify dependencies method" do
|
121
|
+
driver.verify_dependencies.must_be_nil
|
122
|
+
end
|
141
123
|
|
142
|
-
|
143
|
-
|
144
|
-
|
124
|
+
it "#busser returns the instance's busser" do
|
125
|
+
driver.send(:busser).must_equal busser
|
126
|
+
end
|
127
|
+
|
128
|
+
describe ".no_parallel_for" do
|
129
|
+
|
130
|
+
it "registers no serial actions when none are declared" do
|
131
|
+
Kitchen::Driver::Speedy.serial_actions.must_equal nil
|
145
132
|
end
|
146
133
|
|
147
|
-
it "
|
148
|
-
|
134
|
+
it "registers a single serial action method" do
|
135
|
+
Kitchen::Driver::Dodgy.serial_actions.must_equal [:converge]
|
149
136
|
end
|
150
137
|
|
151
|
-
it "
|
152
|
-
|
138
|
+
it "registers multiple serial action methods" do
|
139
|
+
actions = Kitchen::Driver::Slow.serial_actions
|
140
|
+
|
141
|
+
actions.must_include :create
|
142
|
+
actions.must_include :verify
|
143
|
+
actions.must_include :destroy
|
144
|
+
end
|
153
145
|
|
154
|
-
|
146
|
+
it "raises a ClientError if value is not an action method" do
|
147
|
+
proc {
|
148
|
+
Class.new(Kitchen::Driver::Base) { no_parallel_for :telling_stories }
|
149
|
+
}.must_raise Kitchen::ClientError
|
155
150
|
end
|
156
151
|
end
|
157
152
|
end
|
@@ -16,11 +16,11 @@
|
|
16
16
|
# See the License for the specific language governing permissions and
|
17
17
|
# limitations under the License.
|
18
18
|
|
19
|
-
require_relative
|
20
|
-
require
|
21
|
-
require
|
19
|
+
require_relative "../../spec_helper"
|
20
|
+
require "logger"
|
21
|
+
require "stringio"
|
22
22
|
|
23
|
-
require
|
23
|
+
require "kitchen/driver/dummy"
|
24
24
|
|
25
25
|
describe Kitchen::Driver::Dummy do
|
26
26
|
|
@@ -34,9 +34,7 @@ describe Kitchen::Driver::Dummy do
|
|
34
34
|
end
|
35
35
|
|
36
36
|
let(:driver) do
|
37
|
-
|
38
|
-
d.instance = instance
|
39
|
-
d
|
37
|
+
Kitchen::Driver::Dummy.new(config).finalize_config!(instance)
|
40
38
|
end
|
41
39
|
|
42
40
|
describe "default_config" do
|
@@ -55,7 +53,7 @@ describe Kitchen::Driver::Dummy do
|
|
55
53
|
it "sets :my_id to a unique value as an example" do
|
56
54
|
driver.create(state)
|
57
55
|
|
58
|
-
state[:my_id].must_match
|
56
|
+
state[:my_id].must_match(/^coolbeans-/)
|
59
57
|
end
|
60
58
|
|
61
59
|
it "calls sleep if :sleep value is greater than 0" do
|
@@ -65,6 +63,12 @@ describe Kitchen::Driver::Dummy do
|
|
65
63
|
driver.create(state)
|
66
64
|
end
|
67
65
|
|
66
|
+
it "raises ActionFailed if :fail_create is set" do
|
67
|
+
config[:fail_create] = true
|
68
|
+
|
69
|
+
proc { driver.create(state) }.must_raise Kitchen::ActionFailed
|
70
|
+
end
|
71
|
+
|
68
72
|
it "randomly raises ActionFailed if :random_failure is set" do
|
69
73
|
config[:random_failure] = true
|
70
74
|
driver.stubs(:randomly_fail?).returns(true)
|
@@ -77,16 +81,17 @@ describe Kitchen::Driver::Dummy do
|
|
77
81
|
|
78
82
|
begin
|
79
83
|
driver.create(state)
|
80
|
-
rescue Kitchen::ActionFailed
|
84
|
+
rescue Kitchen::ActionFailed
|
81
85
|
# If exception is anything other than Kitchen::ActionFailed, this spec
|
82
86
|
# will fail
|
87
|
+
true
|
83
88
|
end
|
84
89
|
end
|
85
90
|
|
86
91
|
it "logs a create event to INFO" do
|
87
92
|
driver.create(state)
|
88
93
|
|
89
|
-
logged_output.string.must_match
|
94
|
+
logged_output.string.must_match(/^.+ INFO .+ \[Dummy\] Create on .+$/)
|
90
95
|
end
|
91
96
|
end
|
92
97
|
|
@@ -99,6 +104,12 @@ describe Kitchen::Driver::Dummy do
|
|
99
104
|
driver.create(state)
|
100
105
|
end
|
101
106
|
|
107
|
+
it "raises ActionFailed if :fail_converge is set" do
|
108
|
+
config[:fail_converge] = true
|
109
|
+
|
110
|
+
proc { driver.converge(state) }.must_raise Kitchen::ActionFailed
|
111
|
+
end
|
112
|
+
|
102
113
|
it "randomly raises ActionFailed if :random_failure is set" do
|
103
114
|
config[:random_failure] = true
|
104
115
|
driver.stubs(:randomly_fail?).returns(true)
|
@@ -109,7 +120,7 @@ describe Kitchen::Driver::Dummy do
|
|
109
120
|
it "logs a converge event to INFO" do
|
110
121
|
driver.converge(state)
|
111
122
|
|
112
|
-
logged_output.string.must_match
|
123
|
+
logged_output.string.must_match(/^.+ INFO .+ \[Dummy\] Converge on .+$/)
|
113
124
|
end
|
114
125
|
end
|
115
126
|
|
@@ -122,6 +133,12 @@ describe Kitchen::Driver::Dummy do
|
|
122
133
|
driver.setup(state)
|
123
134
|
end
|
124
135
|
|
136
|
+
it "raises ActionFailed if :fail_setup is set" do
|
137
|
+
config[:fail_setup] = true
|
138
|
+
|
139
|
+
proc { driver.setup(state) }.must_raise Kitchen::ActionFailed
|
140
|
+
end
|
141
|
+
|
125
142
|
it "randomly raises ActionFailed if :random_failure is set" do
|
126
143
|
config[:random_failure] = true
|
127
144
|
driver.stubs(:randomly_fail?).returns(true)
|
@@ -132,7 +149,7 @@ describe Kitchen::Driver::Dummy do
|
|
132
149
|
it "logs a setup event to INFO" do
|
133
150
|
driver.setup(state)
|
134
151
|
|
135
|
-
logged_output.string.must_match
|
152
|
+
logged_output.string.must_match(/^.+ INFO .+ \[Dummy\] Setup on .+$/)
|
136
153
|
end
|
137
154
|
end
|
138
155
|
|
@@ -145,6 +162,12 @@ describe Kitchen::Driver::Dummy do
|
|
145
162
|
driver.verify(state)
|
146
163
|
end
|
147
164
|
|
165
|
+
it "raises ActionFailed if :fail_verify is set" do
|
166
|
+
config[:fail_verify] = true
|
167
|
+
|
168
|
+
proc { driver.verify(state) }.must_raise Kitchen::ActionFailed
|
169
|
+
end
|
170
|
+
|
148
171
|
it "randomly raises ActionFailed if :random_failure is set" do
|
149
172
|
config[:random_failure] = true
|
150
173
|
driver.stubs(:randomly_fail?).returns(true)
|
@@ -155,7 +178,7 @@ describe Kitchen::Driver::Dummy do
|
|
155
178
|
it "logs a verify event to INFO" do
|
156
179
|
driver.verify(state)
|
157
180
|
|
158
|
-
logged_output.string.must_match
|
181
|
+
logged_output.string.must_match(/^.+ INFO .+ \[Dummy\] Verify on .+$/)
|
159
182
|
end
|
160
183
|
end
|
161
184
|
|
@@ -175,6 +198,12 @@ describe Kitchen::Driver::Dummy do
|
|
175
198
|
driver.verify(state)
|
176
199
|
end
|
177
200
|
|
201
|
+
it "raises ActionFailed if :fail_destroy is set" do
|
202
|
+
config[:fail_destroy] = true
|
203
|
+
|
204
|
+
proc { driver.destroy(state) }.must_raise Kitchen::ActionFailed
|
205
|
+
end
|
206
|
+
|
178
207
|
it "randomly raises ActionFailed if :random_failure is set" do
|
179
208
|
config[:random_failure] = true
|
180
209
|
driver.stubs(:randomly_fail?).returns(true)
|
@@ -185,7 +214,7 @@ describe Kitchen::Driver::Dummy do
|
|
185
214
|
it "logs a destroy event to INFO" do
|
186
215
|
driver.destroy(state)
|
187
216
|
|
188
|
-
logged_output.string.must_match
|
217
|
+
logged_output.string.must_match(/^.+ INFO .+ \[Dummy\] Destroy on .+$/)
|
189
218
|
end
|
190
219
|
end
|
191
220
|
end
|
@@ -0,0 +1,134 @@
|
|
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/driver/proxy"
|
22
|
+
|
23
|
+
describe Kitchen::Driver::Proxy do
|
24
|
+
|
25
|
+
let(:logged_output) { StringIO.new }
|
26
|
+
let(:logger) { Logger.new(logged_output) }
|
27
|
+
let(:state) { Hash.new }
|
28
|
+
|
29
|
+
let(:config) do
|
30
|
+
{ :host => "foobnoobs.com", :reset_command => "mulligan" }
|
31
|
+
end
|
32
|
+
|
33
|
+
let(:instance) do
|
34
|
+
stub(:name => "coolbeans", :logger => logger, :to_str => "instance")
|
35
|
+
end
|
36
|
+
|
37
|
+
let(:driver) do
|
38
|
+
Kitchen::Driver::Proxy.new(config).finalize_config!(instance)
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "non-parallel action" do
|
42
|
+
|
43
|
+
it "create must be serially executed" do
|
44
|
+
Kitchen::Driver::Proxy.serial_actions.must_include :create
|
45
|
+
end
|
46
|
+
|
47
|
+
it "destroy must be serially executed" do
|
48
|
+
Kitchen::Driver::Proxy.serial_actions.must_include :destroy
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "required_config" do
|
53
|
+
|
54
|
+
[:host, :reset_command].each do |attr|
|
55
|
+
it "requires :#{attr}" do
|
56
|
+
config.delete(attr)
|
57
|
+
|
58
|
+
begin
|
59
|
+
driver
|
60
|
+
flunk "UserError must be raised for missing :#{attr}"
|
61
|
+
rescue Kitchen::UserError => e
|
62
|
+
e.message.must_match regexify("config[:#{attr}] cannot be blank")
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def regexify(str)
|
68
|
+
Regexp.new(Regexp.escape(str))
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe "#create" do
|
73
|
+
|
74
|
+
it "sets :hostname in state config" do
|
75
|
+
driver.stubs(:ssh)
|
76
|
+
driver.create(state)
|
77
|
+
|
78
|
+
state[:hostname].must_equal "foobnoobs.com"
|
79
|
+
end
|
80
|
+
|
81
|
+
it "calls the reset command over ssh" do
|
82
|
+
driver.expects(:ssh).with do |ssh_args, cmd|
|
83
|
+
ssh_args[0].must_equal "foobnoobs.com"
|
84
|
+
cmd.must_equal "mulligan"
|
85
|
+
end
|
86
|
+
|
87
|
+
driver.create(state)
|
88
|
+
end
|
89
|
+
|
90
|
+
it "skips ssh call if :reset_command is falsey" do
|
91
|
+
config[:reset_command] = false
|
92
|
+
driver.expects(:ssh).never
|
93
|
+
|
94
|
+
driver.create(state)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
describe "#destroy" do
|
99
|
+
|
100
|
+
before do
|
101
|
+
state[:hostname] = "beep"
|
102
|
+
end
|
103
|
+
|
104
|
+
it "deletes :hostname in state config" do
|
105
|
+
driver.stubs(:ssh)
|
106
|
+
driver.destroy(state)
|
107
|
+
|
108
|
+
state[:hostname].must_equal nil
|
109
|
+
end
|
110
|
+
|
111
|
+
it "calls the reset command over ssh" do
|
112
|
+
driver.expects(:ssh).with do |ssh_args, cmd|
|
113
|
+
ssh_args[0].must_equal "beep"
|
114
|
+
cmd.must_equal "mulligan"
|
115
|
+
end
|
116
|
+
|
117
|
+
driver.destroy(state)
|
118
|
+
end
|
119
|
+
|
120
|
+
it "skips ssh call if :hostname is not in state config" do
|
121
|
+
state.delete(:hostname)
|
122
|
+
driver.expects(:ssh).never
|
123
|
+
|
124
|
+
driver.destroy(state)
|
125
|
+
end
|
126
|
+
|
127
|
+
it "skips ssh call if :reset_command is falsey" do
|
128
|
+
config[:reset_command] = false
|
129
|
+
driver.expects(:ssh).never
|
130
|
+
|
131
|
+
driver.destroy(state)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|