test-kitchen 1.2.1 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (114) hide show
  1. checksums.yaml +4 -4
  2. data/.cane +1 -1
  3. data/.rubocop.yml +3 -0
  4. data/.travis.yml +20 -9
  5. data/CHANGELOG.md +219 -108
  6. data/Gemfile +10 -6
  7. data/Guardfile +38 -9
  8. data/README.md +11 -1
  9. data/Rakefile +21 -37
  10. data/bin/kitchen +4 -4
  11. data/features/kitchen_action_commands.feature +161 -0
  12. data/features/kitchen_console_command.feature +34 -0
  13. data/features/kitchen_diagnose_command.feature +64 -0
  14. data/features/kitchen_init_command.feature +29 -17
  15. data/features/kitchen_list_command.feature +2 -2
  16. data/features/kitchen_login_command.feature +56 -0
  17. data/features/{sink_command.feature → kitchen_sink_command.feature} +0 -0
  18. data/features/kitchen_test_command.feature +88 -0
  19. data/features/step_definitions/gem_steps.rb +8 -6
  20. data/features/step_definitions/git_steps.rb +4 -2
  21. data/features/step_definitions/output_steps.rb +5 -0
  22. data/features/support/env.rb +12 -9
  23. data/lib/kitchen.rb +60 -38
  24. data/lib/kitchen/base64_stream.rb +55 -0
  25. data/lib/kitchen/busser.rb +124 -58
  26. data/lib/kitchen/cli.rb +121 -38
  27. data/lib/kitchen/collection.rb +3 -3
  28. data/lib/kitchen/color.rb +4 -4
  29. data/lib/kitchen/command.rb +78 -11
  30. data/lib/kitchen/command/action.rb +3 -2
  31. data/lib/kitchen/command/console.rb +12 -5
  32. data/lib/kitchen/command/diagnose.rb +17 -3
  33. data/lib/kitchen/command/driver_discover.rb +26 -7
  34. data/lib/kitchen/command/exec.rb +41 -0
  35. data/lib/kitchen/command/list.rb +44 -14
  36. data/lib/kitchen/command/login.rb +2 -1
  37. data/lib/kitchen/command/sink.rb +2 -1
  38. data/lib/kitchen/command/test.rb +5 -4
  39. data/lib/kitchen/config.rb +146 -14
  40. data/lib/kitchen/configurable.rb +314 -0
  41. data/lib/kitchen/data_munger.rb +522 -18
  42. data/lib/kitchen/diagnostic.rb +43 -4
  43. data/lib/kitchen/driver.rb +4 -4
  44. data/lib/kitchen/driver/base.rb +80 -115
  45. data/lib/kitchen/driver/dummy.rb +34 -6
  46. data/lib/kitchen/driver/proxy.rb +14 -3
  47. data/lib/kitchen/driver/ssh_base.rb +61 -7
  48. data/lib/kitchen/errors.rb +109 -9
  49. data/lib/kitchen/generator/driver_create.rb +39 -5
  50. data/lib/kitchen/generator/init.rb +130 -45
  51. data/lib/kitchen/instance.rb +162 -28
  52. data/lib/kitchen/lazy_hash.rb +79 -7
  53. data/lib/kitchen/loader/yaml.rb +159 -27
  54. data/lib/kitchen/logger.rb +267 -21
  55. data/lib/kitchen/logging.rb +30 -3
  56. data/lib/kitchen/login_command.rb +11 -2
  57. data/lib/kitchen/metadata_chopper.rb +2 -2
  58. data/lib/kitchen/provisioner.rb +4 -4
  59. data/lib/kitchen/provisioner/base.rb +107 -103
  60. data/lib/kitchen/provisioner/chef/berkshelf.rb +36 -8
  61. data/lib/kitchen/provisioner/chef/librarian.rb +40 -11
  62. data/lib/kitchen/provisioner/chef_base.rb +206 -167
  63. data/lib/kitchen/provisioner/chef_solo.rb +25 -7
  64. data/lib/kitchen/provisioner/chef_zero.rb +105 -29
  65. data/lib/kitchen/provisioner/dummy.rb +1 -1
  66. data/lib/kitchen/provisioner/shell.rb +21 -6
  67. data/lib/kitchen/rake_tasks.rb +8 -3
  68. data/lib/kitchen/shell_out.rb +15 -18
  69. data/lib/kitchen/ssh.rb +122 -27
  70. data/lib/kitchen/state_file.rb +24 -7
  71. data/lib/kitchen/thor_tasks.rb +9 -4
  72. data/lib/kitchen/util.rb +43 -118
  73. data/lib/kitchen/version.rb +1 -1
  74. data/lib/vendor/hash_recursive_merge.rb +10 -2
  75. data/spec/kitchen/base64_stream_spec.rb +77 -0
  76. data/spec/kitchen/busser_spec.rb +490 -0
  77. data/spec/kitchen/collection_spec.rb +10 -10
  78. data/spec/kitchen/color_spec.rb +2 -2
  79. data/spec/kitchen/config_spec.rb +234 -62
  80. data/spec/kitchen/configurable_spec.rb +490 -0
  81. data/spec/kitchen/data_munger_spec.rb +1070 -862
  82. data/spec/kitchen/diagnostic_spec.rb +79 -0
  83. data/spec/kitchen/driver/base_spec.rb +80 -85
  84. data/spec/kitchen/driver/dummy_spec.rb +43 -14
  85. data/spec/kitchen/driver/proxy_spec.rb +134 -0
  86. data/spec/kitchen/driver/ssh_base_spec.rb +644 -0
  87. data/spec/kitchen/driver_spec.rb +15 -15
  88. data/spec/kitchen/errors_spec.rb +309 -0
  89. data/spec/kitchen/instance_spec.rb +143 -46
  90. data/spec/kitchen/lazy_hash_spec.rb +36 -9
  91. data/spec/kitchen/loader/yaml_spec.rb +237 -226
  92. data/spec/kitchen/logger_spec.rb +419 -0
  93. data/spec/kitchen/logging_spec.rb +59 -0
  94. data/spec/kitchen/login_command_spec.rb +49 -0
  95. data/spec/kitchen/metadata_chopper_spec.rb +82 -0
  96. data/spec/kitchen/platform_spec.rb +4 -4
  97. data/spec/kitchen/provisioner/base_spec.rb +65 -125
  98. data/spec/kitchen/provisioner/chef_base_spec.rb +798 -0
  99. data/spec/kitchen/provisioner/chef_solo_spec.rb +316 -0
  100. data/spec/kitchen/provisioner/chef_zero_spec.rb +624 -0
  101. data/spec/kitchen/provisioner/shell_spec.rb +269 -0
  102. data/spec/kitchen/provisioner_spec.rb +6 -6
  103. data/spec/kitchen/shell_out_spec.rb +143 -0
  104. data/spec/kitchen/ssh_spec.rb +683 -0
  105. data/spec/kitchen/state_file_spec.rb +28 -21
  106. data/spec/kitchen/suite_spec.rb +7 -7
  107. data/spec/kitchen/util_spec.rb +68 -10
  108. data/spec/kitchen_spec.rb +107 -0
  109. data/spec/spec_helper.rb +18 -13
  110. data/support/chef-client-zero.rb +10 -9
  111. data/support/chef_helpers.sh +16 -0
  112. data/support/download_helpers.sh +109 -0
  113. data/test-kitchen.gemspec +42 -33
  114. 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 '../../spec_helper'
20
- require 'logger'
21
- require 'stringio'
19
+ require_relative "../../spec_helper"
20
+ require "logger"
21
+ require "stringio"
22
22
 
23
- require 'kitchen'
23
+ require "kitchen"
24
24
 
25
25
  module Kitchen
26
26
 
27
27
  module Driver
28
28
 
29
- class StaticDefaults < Base
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 SubclassDefaults < StaticDefaults
32
+ class Dodgy < Base
37
33
 
38
- default_config :yea, "ya"
34
+ no_parallel_for :converge
39
35
  end
40
36
 
41
- class ComputedDefaults < Base
42
-
43
- default_config :beans, "kidney"
44
- default_config :fetch_command, "curl"
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(:instance) do
66
- stub(:name => "coolbeans", :logger => logger, :to_str => "instance")
52
+ let(:busser) do
53
+ stub(:setup_cmd => "setup", :sync_cmd => "sync", :run_cmd => "run")
67
54
  end
68
55
 
69
- describe "user config" do
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
- let(:driver) do
72
- d = Kitchen::Driver::Base.new(config)
73
- d.instance = instance
74
- d
75
- end
65
+ let(:driver) do
66
+ Kitchen::Driver::Base.new(config).finalize_config!(instance)
67
+ end
76
68
 
77
- it "injects config into driver" do
78
- config[:fruit] = %w{apples oranges}
79
- config[:cool_enough] = true
69
+ it "#instance returns its instance" do
70
+ driver.instance.must_equal instance
71
+ end
80
72
 
81
- driver[:fruit].must_equal ['apples', 'oranges']
82
- driver[:cool_enough].must_equal true
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 "static default config" do
77
+ describe "#logger" do
87
78
 
88
- let(:driver) do
89
- d = Kitchen::Driver::StaticDefaults.new(config)
90
- d.instance = instance
91
- d
92
- end
79
+ before { @klog = Kitchen.logger }
80
+ after { Kitchen.logger = @klog }
93
81
 
94
- it "uses default config" do
95
- driver[:beans].must_equal "kidney"
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 "uses user config over default config" do
101
- config[:beans] = "pinto"
102
- config[:edible] = false
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[:beans].must_equal "pinto"
105
- driver[:edible].must_equal false
90
+ driver.send(:logger).must_equal Kitchen.logger
106
91
  end
107
92
  end
108
93
 
109
- describe "inherited static default config" do
94
+ it "#puts calls logger.info" do
95
+ driver.send(:puts, "yo")
110
96
 
111
- let(:driver) do
112
- p = Kitchen::Driver::SubclassDefaults.new(config)
113
- p.instance = instance
114
- p
115
- end
97
+ logged_output.string.must_match(/I, /)
98
+ logged_output.string.must_match(/yo\n/)
99
+ end
116
100
 
117
- it "contains defaults from superclass" do
118
- driver[:beans].must_equal "kidney"
119
- driver[:tunables]['flimflam'].must_equal 'positate'
120
- driver[:edible].must_equal true
121
- driver[:yea].must_equal "ya"
122
- end
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
- it "uses user config over default config" do
125
- config[:beans] = "pinto"
126
- config[:edible] = false
108
+ [:create, :converge, :setup, :verify, :destroy].each do |action|
127
109
 
128
- driver[:beans].must_equal "pinto"
129
- driver[:edible].must_equal false
130
- driver[:yea].must_equal "ya"
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
- describe "computed default config" do
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
- let(:driver) do
137
- d = Kitchen::Driver::ComputedDefaults.new(config)
138
- d.instance = instance
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
- it "uses computed config" do
143
- driver[:beans_url].must_equal "http://gim.me/kidney"
144
- driver[:command].must_equal "curl http://gim.me/kidney"
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 "has access to instance object" do
148
- driver[:fetch_url].must_equal "http://gim.me/beans-for/coolbeans"
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 "uses user config over default config" do
152
- config[:command] = "echo listentome"
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
- driver[:command].must_equal "echo listentome"
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 '../../spec_helper'
20
- require 'logger'
21
- require 'stringio'
19
+ require_relative "../../spec_helper"
20
+ require "logger"
21
+ require "stringio"
22
22
 
23
- require 'kitchen/driver/dummy'
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
- d = Kitchen::Driver::Dummy.new(config)
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 /^coolbeans-/
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 => ex
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 /^.+ INFO .+ \[Dummy\] Create on .+$/
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 /^.+ INFO .+ \[Dummy\] Converge on .+$/
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 /^.+ INFO .+ \[Dummy\] Setup on .+$/
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 /^.+ INFO .+ \[Dummy\] Verify on .+$/
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 /^.+ INFO .+ \[Dummy\] Destroy on .+$/
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