chef-workflow-testlib 0.1.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.
data/.gitignore ADDED
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ .chef-workflow
19
+ html
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in chef-workflow-testlib.gemspec
4
+ gemspec
5
+
6
+ if ENV["ERIKH_LOCAL"]
7
+ gem 'chef-workflow', :path => '~/repos/ht/chef-workflow'
8
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Erik Hollensbe
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,316 @@
1
+ # Chef Workflow - Test Libraries and Tooling
2
+
3
+ This gem provides a set of libraries to drive
4
+ [minitest](https://github.com/seattlerb/minitest) integration for a number of things:
5
+
6
+ 1. spawning whole networks of machines
7
+ 2. testing their converge successes
8
+ 3. testing interoperability between machines
9
+ 4. testing advanced functionality in chef, like search.
10
+
11
+ **It is not intended for testing individual cookbooks.** The default
12
+ provisioning systems expect roles, for example, but it's a different tool for a
13
+ different problem. If you want to verify your open-source cookbooks against a
14
+ variety of environments, I strongly suggest you look at
15
+ [test-kitchen](https://github.com/opscode/test-kitchen), which is intended to
16
+ solve this problem.
17
+
18
+ ## Installation
19
+
20
+ Add this line to your application's Gemfile:
21
+
22
+ gem 'chef-workflow-testlib'
23
+
24
+ And then execute:
25
+
26
+ $ bundle
27
+
28
+ Or install it yourself as:
29
+
30
+ $ gem install chef-workflow-testlib
31
+
32
+ ## Quick Start
33
+
34
+ The easiest way to get started is to integrate
35
+ [chef-workflow-tasklib](https://github.com/chef-workflow/chef-workflow-tasklib)
36
+ into your environment. This has a number of benefits, such as working within
37
+ the same system to control machine provisioning, building a chef server,
38
+ uploading your repository to a chef server, several options for driving tests,
39
+ and so on. Once you've set that up, use the instructions over there to build a
40
+ test chef server.
41
+
42
+ So, after you've done that go ahead and create a `test` directory at the root
43
+ of your repository. Inside that, create a `test_mytest.rb` that provisions a
44
+ few machines and performs a search on them. This actually doesn't have much
45
+ real-world application, but it'll get you familiar with the workflow.
46
+
47
+ You will need some working roles to perform this test. We'll name these roles
48
+ `my_role` and `my_other_role` in the example, but you'll need to replace them
49
+ with roles you actually use.
50
+
51
+ This test will use `vagrant` to provision your machines, bootstrap them with
52
+ knife, then run your tests. After it's done, it will tear those machines down.
53
+ If the nodes fail to come up for any reason, your test should yield an error
54
+ and deprovision the machines.
55
+
56
+ ```ruby
57
+ require 'chef-workflow/helper'
58
+ class MyTest < MiniTest::Unit::VagrantTestCase
59
+ def self.before_suite
60
+ provision('my_role')
61
+ provision('my_other_role')
62
+ wait_for('my_role')
63
+ wait_for('my_other_role')
64
+ end
65
+
66
+ def self.after_suite
67
+ deprovision('my_role')
68
+ deprovision('my_other_role')
69
+ end
70
+
71
+ def test_searching_one
72
+ assert_search_count(:node, 'roles:my_role', 1)
73
+ end
74
+
75
+ def test_searching_two
76
+ assert_search_count(:node, 'roles:my_other_role', 1)
77
+ end
78
+ end
79
+ ```
80
+
81
+ Then run your test suite with `bundle exec rake test:build`, which will perform
82
+ an upload of your repository to the test chef server, and run your tests.
83
+
84
+ We're quite aware this takes a while to run, and does very little. There are a
85
+ couple of ways to deal with this, but involve understanding the system a little
86
+ more; something we're about to cover.
87
+
88
+ ## Dealing with Slow
89
+
90
+ Ok, so we got our test suite off the ground, and boy do those tests take a
91
+ while to run. I have two bits of good news for you:
92
+
93
+ You aren't locked into using Vagrant, and while Vagrant has limitations which
94
+ make it impossible to parallelize, machine provisions don't have to be serial.
95
+ EC2 support allows you to provision many machines in parallel, which can
96
+ improve run time. The provisioning system is also flexible enough to support
97
+ other systems too, so if you'd like to see your favorite system get some love,
98
+ the best way to do so is to file an issue or pull request.
99
+
100
+ The second is that in most scenarios, you have a few servers that you don't
101
+ really care about for this test, but need to be available for the machine to
102
+ function or converge properly, like a DNS or syslog server. All provisioning is
103
+ tracked and the state information is actually written to disk in your
104
+ `.chef-workflow` directory. What that means is that if you don't need to
105
+ rebuild your machines, you don't actually have to until you're ready to.
106
+
107
+ ### State Management with MiniTest Subclasses
108
+
109
+ Let's start off easy. Take our example above, and remove the deprovisioning
110
+ lines in the `after_suite` call:
111
+
112
+ ```ruby
113
+ require 'chef-workflow/helper'
114
+ class MyTest < MiniTest::Unit::VagrantTestCase
115
+ def self.before_suite
116
+ provision('my_role')
117
+ provision('my_other_role')
118
+ wait_for('my_role')
119
+ wait_for('my_other_role')
120
+ end
121
+
122
+ def self.after_suite
123
+ # omg, where did they go?
124
+ end
125
+
126
+ def test_searching_one
127
+ assert_search_count(:node, 'roles:my_role', 1)
128
+ end
129
+
130
+ def test_searching_two
131
+ assert_search_count(:node, 'roles:my_other_role', 1)
132
+ end
133
+ end
134
+ ```
135
+
136
+ And run your tests again. Go ahead, run them twice. The second time should be
137
+ pretty quick, in the order of a second or so. This is because your machines
138
+ weren't provisioned the second time; the system determined they were already
139
+ built and didn't have to provision them again.
140
+
141
+ So how do we clean them up? `bundle exec rake chef:clean:machines`, or add our
142
+ deprovisioning lines back in and run the suite again. The state for a provision
143
+ lasts until the machine is deprovisioned, whether or not that's the same test
144
+ run. The rake task just reaps everything except for your chef server.
145
+
146
+ Now that we've seen the obvious performance increase, what is this good for?
147
+
148
+ ### Pre-baking essential infra with MiniTest subclasses
149
+
150
+ MiniTest (and all SUnit alikes) leverage subclassing pretty heavily when done
151
+ right to manage a common set of test dependencies. For example, we have a
152
+ subclass called 'WithInfra' in our test suite that looks like this:
153
+
154
+ ```ruby
155
+ class MiniTest::Unit::VagrantTestCase::WithInfra < MiniTest::Unit::VagrantTestCase
156
+ include SSHHelper
157
+
158
+ def self.before_suite
159
+ super
160
+
161
+ provision('bind_master')
162
+ provision('syslog_server')
163
+
164
+ wait_for('bind_master', 'syslog_server')
165
+
166
+ ssh_role_command('bind_master', 'chef-client')
167
+ ssh_role_command('syslog_server', 'chef-client')
168
+ end
169
+ end
170
+ ```
171
+
172
+ `SSHHelper` is a small mixin that provides `ssh_role_command` and other bits of
173
+ ssh-related functionality. In this case, our syslog depends on working DNS and
174
+ our BIND depends on working syslog; while they have cookbooks that are smart
175
+ enough to walk past those dependencies in the first chef run, once they're both
176
+ up converging them again will resolve each other and configure them
177
+ appropriately.
178
+
179
+ The good news is that we don't have to (but can) tear these servers down during
180
+ a run or even between runs if they're not causing problems, and you can always
181
+ check from a fresh provision by running the `chef:clean:machines` task before
182
+ `test`, or simply `test:rebuild`, which does a full deprovision, repository
183
+ upload, and test run. This saves you time (and money, in the EC2 case) and
184
+ still gives you a way to do a "full" run without a lot of extra work.
185
+
186
+ An actual test suite that uses this looks like this:
187
+
188
+ ```ruby
189
+ class TestBIND < MiniTest::Unit::VagrantTestCase::WithInfra
190
+ def self.before_suite
191
+ provision('bind_slave', 1, %w[bind_master syslog_server])
192
+ wait_for('bind_slave')
193
+ end
194
+
195
+ def test_something
196
+ # maybe a test that nsupdates the master and ensures it made it to slave
197
+ # could go here
198
+ end
199
+
200
+ def self.after_suite
201
+ deprovision('bind_slave')
202
+ end
203
+ end
204
+ ```
205
+
206
+ This test when run will create, test, and destroy the bind slave, but leave the
207
+ master and the syslog server alone -- something that we will undoubtedly need
208
+ for the next test case.
209
+
210
+ ### Dependency-based Provisioning
211
+
212
+ All provisions have a dependency list. Until they are satisfied, the stated
213
+ provision will not happen. This is mostly noticable in threaded provisioning
214
+ mode where multiple provisions can occur at once.
215
+
216
+ To wait for a specific machine to provision before continuing the test process,
217
+ use the `wait_for` method.
218
+
219
+ We can see this in our example above:
220
+
221
+ ```ruby
222
+ def self.before_suite
223
+ provision('bind_slave', 1, %w[bind_master syslog_server])
224
+ wait_for('bind_slave')
225
+ end
226
+ ```
227
+
228
+ In this instance, a `bind_slave` provision is scheduled, which depends on the
229
+ `bind_master` and `syslog_server` provisions. The `wait_for` statement is used
230
+ to control the test flow, so that it does not continue before `bind_slave`
231
+ provisions, which is what we want to actually test in this test case. Properly
232
+ used, this can enhance provisioning times by letting the scheduler provision
233
+ things as soon as they are capable of being provisioned, where you just care
234
+ about the servers you wish to test at any given point, instead of having to
235
+ manage this problem yourself.
236
+
237
+ You can't declare provisions that are dependent on provisions that don't exist
238
+ -- this will raise an exception. So, don't worry about fat-fingering it. :)
239
+
240
+ Here's a more advanced example that abuses the performance characteristics of the
241
+ scheduler. In this instance, we intend to test our monitoring system, which
242
+ will assert the "alive" status of many servers. We provision numerous ones in
243
+ the setup, and only wait for what we care about in each unit test.
244
+
245
+ ```ruby
246
+ class TestNagios < MiniTest::Unit::VagrantTestCase
247
+ def self.before_suite
248
+ provision('syslog_server')
249
+ provision('bind_master', 1, %w[syslog_server])
250
+ # we just care about bind for all these
251
+ provision('bind_slave', 1, %w[bind_master])
252
+ provision('web_server', 1, %w[bind_master])
253
+ provision('db_server', 1, %w[bind_master])
254
+ provision('nagios_server', 1, %w[bind_master])
255
+ # we need the nagios server available for all tests, so wait for that
256
+ wait_for('nagios_server')
257
+ end
258
+
259
+ def test_dns_monitoring
260
+ wait_for('bind_master', 'bind_slave')
261
+ # ensure monitoring works
262
+ end
263
+
264
+ def test_web_monitoring
265
+ wait_for('web_server')
266
+ # ensure monitoring works
267
+ end
268
+
269
+ def test_db_monitoring
270
+ wait_for('db_server')
271
+ # ensure monitoring works
272
+ end
273
+
274
+ def self.after_suite
275
+ %w[
276
+ bind_master
277
+ bind_slave
278
+ syslog_server
279
+ web_server
280
+ db_server
281
+ nagios_server
282
+ ].each { |x| deprovision(x) }
283
+ end
284
+ end
285
+ ```
286
+
287
+ The flow of this test is as such:
288
+
289
+ As soon as `bind_master` completes, `bind_slave`, `web_server`, `db_server`,
290
+ and `nagios_server` will begin provisioning. `setup` will wait until
291
+ `nagios_server` completes, and normal testing will begin. Each test waits for
292
+ its testable unit to finish provisioning before running the actual tests
293
+ against those units. With rare exception, after a test or two, the `wait_for`
294
+ commands will succeed immediately, largely because they have been provsioning
295
+ in the background while the other tests have been running.
296
+
297
+ If you're curious how all this works under the hood, see the
298
+ [chef-workflow](https://github.com/chef-workflow/chef-workflow) documentation on
299
+ the subject.
300
+
301
+ ## Contributing
302
+
303
+ 1. Fork it
304
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
305
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
306
+ 4. Push to the branch (`git push origin my-new-feature`)
307
+ 5. Create new Pull Request
308
+ 6. Adjustment of the license terms or the author credits will result in a
309
+ rejected pull request. It ain't cool, yo.
310
+
311
+ ## Authors
312
+
313
+ This work was partially sponsored by [HotelTonight](http://hoteltonight.com),
314
+ and you should check them out. They use this system for testing their
315
+ infrastructure. The programming was done primarily by [Erik
316
+ Hollensbe](https://github.com/erikh).
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'rdoc/task'
4
+
5
+ RDoc::Task.new do |r|
6
+ r.main = "README.md"
7
+ r.rdoc_files.include(r.main, "LICENSE.txt", "lib/**/*.rb")
8
+ r.options << "--all"
9
+ end
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'chef-workflow-testlib/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "chef-workflow-testlib"
8
+ gem.version = Chef::Workflow::Testlib::VERSION
9
+ gem.authors = ["Erik Hollensbe"]
10
+ gem.email = ["erik+github@hollensbe.org"]
11
+ gem.description = %q{Test helpers and assertions for chef-workflow}
12
+ gem.summary = %q{Test helpers and assertions for chef-workflow}
13
+ gem.homepage = "https://github.com/chef-workflow/chef-workflow-testlib"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+
20
+ gem.add_dependency 'chef-workflow', '~> 0.1.0'
21
+ gem.add_dependency 'minitest', '~> 4.3.0'
22
+ gem.add_dependency 'net-ssh', '~> 2.6.0'
23
+
24
+ gem.add_development_dependency 'rdoc'
25
+ gem.add_development_dependency 'rake'
26
+ end
@@ -0,0 +1,12 @@
1
+ require 'chef-workflow'
2
+ require 'chef-workflow/helpers/minitest'
3
+ require 'chef-workflow/test-case/ec2'
4
+ require 'chef-workflow/test-case/vagrant'
5
+ require 'minitest/unit'
6
+
7
+ class MiniTest::Unit::TestCase
8
+ include MiniTest::Assertions::RemoteChef
9
+ end
10
+
11
+ require 'chef-workflow/runner/provisioned'
12
+ require 'minitest/autorun'
@@ -0,0 +1,15 @@
1
+ require 'chef/search/query'
2
+ require 'chef/config'
3
+
4
+ #
5
+ # Small helper library, intended to be mixed into others that provides short
6
+ # helpers for doing complicated things with the Chef API.
7
+ #
8
+ module ChefHelper
9
+ #
10
+ # Perform a search and return the names of the nodes that match the search.
11
+ #
12
+ def perform_search(type, query)
13
+ Chef::Search::Query.new.search(type, query).first.map(&:name)
14
+ end
15
+ end
@@ -0,0 +1,39 @@
1
+ require 'chef-workflow/helpers/chef'
2
+ require 'minitest/unit'
3
+
4
+ #
5
+ # Small assertion library for minitest to assist with remote chef tests.
6
+ #
7
+ module MiniTest::Assertions::RemoteChef
8
+ include ChefHelper
9
+
10
+ #
11
+ # Assert that a search included the node names.
12
+ #
13
+ def assert_search(type, query, node_names)
14
+ assert_equal(node_names.sort, perform_search(type, query).sort)
15
+ end
16
+
17
+ #
18
+ # Refute that a search included the node names.
19
+ #
20
+ def refute_search(type, query, node_names)
21
+ refute_equal(node_names.sort, perform_search(type, query).sort)
22
+ end
23
+
24
+ #
25
+ # Assert the search included `count` elements. Does not verify what that
26
+ # count is of.
27
+ #
28
+ def assert_search_count(type, query, count)
29
+ assert_equal(count, perform_search(type, query).count)
30
+ end
31
+
32
+ #
33
+ # Refute the search included `count` elements. Does not verify what that
34
+ # count is of.
35
+ #
36
+ def refute_search_count(type, query, count)
37
+ refute_equal(count, perform_search(type, query).count)
38
+ end
39
+ end
@@ -0,0 +1,36 @@
1
+ require 'chef-workflow/support/scheduler'
2
+
3
+ $SCHEDULER ||= Scheduler.new
4
+
5
+ #
6
+ # Helper for provisioning. Intended to be instanced and assigned to the
7
+ # provision_helper attribute of a ProvisionedTestCase.
8
+ #
9
+ # All methods except `provision`, which is shorthand, are passed directly to
10
+ # the scheduler.
11
+ #
12
+ class ProvisionHelper
13
+ def schedule_provision(*args)
14
+ $SCHEDULER.schedule_provision(*args)
15
+ end
16
+
17
+ def deprovision(group_name)
18
+ $SCHEDULER.deprovision_group(group_name)
19
+ end
20
+
21
+ def wait_for(*args)
22
+ $SCHEDULER.wait_for(*args)
23
+ end
24
+
25
+ def serial=(arg)
26
+ $SCHEDULER.serial = arg
27
+ end
28
+
29
+ def run
30
+ $SCHEDULER.run
31
+ end
32
+
33
+ def provision(group_name, number_of_servers, dependencies)
34
+ raise "Please override this method"
35
+ end
36
+ end
@@ -0,0 +1,99 @@
1
+ require 'chef-workflow/support/ip'
2
+ require 'chef-workflow/support/knife'
3
+ require 'chef-workflow/support/debug'
4
+ require 'net/ssh'
5
+
6
+ #
7
+ # Helper for performing SSH on groups of servers. Intended to be mixed into
8
+ # test case classes.
9
+ #
10
+ module SSHHelper
11
+ include KnifePluginSupport
12
+ include DebugSupport
13
+
14
+ #
15
+ # run a command against a group of servers. These commands are run in
16
+ # parallel, but the command itself does not complete until all the threads
17
+ # have finished running.
18
+ #
19
+ def ssh_role_command(role, command)
20
+ t = []
21
+ IPSupport.singleton.get_role_ips(role).each do |ip|
22
+ t.push(
23
+ Thread.new do
24
+ ssh_command(ip, command)
25
+ end
26
+ )
27
+ end
28
+ t.each(&:join)
29
+ end
30
+
31
+ #
32
+ # takes a block which it uses inside of the open_channel block that Net::SSH
33
+ # uses. Intended to provide a consistent way of setting up Net::SSH Makes
34
+ # heavy use of KnifeSupport to determine how to drive the command.
35
+ #
36
+ def configure_ssh_command(ip, command)
37
+ command = "#{KnifeSupport.singleton.use_sudo ? 'sudo ': ''}#{command}"
38
+
39
+ options = { }
40
+
41
+ options[:password] = KnifeSupport.singleton.ssh_password if KnifeSupport.singleton.ssh_password
42
+ options[:keys] = [KnifeSupport.singleton.ssh_identity_file] if KnifeSupport.singleton.ssh_identity_file
43
+
44
+ Net::SSH.start(ip, KnifeSupport.singleton.ssh_user, options) do |ssh|
45
+ ssh.open_channel do |ch|
46
+ ch.on_open_failed do |ch, code, desc|
47
+ raise "Connection Error to #{ip}: #{desc}"
48
+ end
49
+
50
+ ch.exec(command) do |ch, success|
51
+ yield ch, success
52
+ end
53
+ end
54
+
55
+ ssh.loop
56
+ end
57
+ end
58
+
59
+ #
60
+ # Run a command against a single IP. Returns the exit status.
61
+ #
62
+ #
63
+ def ssh_command(ip, command)
64
+ configure_ssh_command(ip, command) do |ch, success|
65
+ return 1 unless success
66
+
67
+ if_debug(2) do
68
+ ch.on_data do |ch, data|
69
+ $stderr.puts data
70
+ end
71
+ end
72
+
73
+ ch.on_request("exit-status") do |ch, data|
74
+ return data.read_long
75
+ end
76
+ end
77
+ end
78
+
79
+ #
80
+ # run a command, and instead of capturing the exit status, return the data
81
+ # captured during the command run.
82
+ #
83
+ def ssh_capture(ip, command)
84
+ retval = ""
85
+ configure_ssh_command(ip, command) do |ch, success|
86
+ return "" unless success
87
+
88
+ ch.on_data do |ch, data|
89
+ retval << data
90
+ end
91
+
92
+ ch.on_request("exit-status") do |ch, data|
93
+ return retval
94
+ end
95
+ end
96
+
97
+ return retval
98
+ end
99
+ end
@@ -0,0 +1,23 @@
1
+ require 'minitest/unit'
2
+
3
+ class MiniTest::Unit::TestCase
4
+ def self.before_suite; end
5
+ def self.after_suite; end
6
+ v = $VERBOSE
7
+ $VERBOSE = nil
8
+ const_set(:SUPPORTS_INFO_SIGNAL, nil)
9
+ $VERBOSE = v
10
+ end
11
+
12
+ class MiniTest::Unit::ProvisionedRunner < MiniTest::Unit
13
+ def _run_suite(suite, type)
14
+ begin
15
+ suite.before_suite unless suite.test_methods.empty?
16
+ super(suite, type)
17
+ ensure
18
+ suite.after_suite unless suite.test_methods.empty?
19
+ end
20
+ end
21
+ end
22
+
23
+ MiniTest::Unit.runner = MiniTest::Unit::ProvisionedRunner.new
@@ -0,0 +1,41 @@
1
+ require 'chef-workflow/support/vm/ec2'
2
+ require 'chef-workflow/support/vm/knife'
3
+ require 'tempfile'
4
+ require 'chef-workflow/test-case/provisioned'
5
+ require 'chef-workflow/helpers/provision'
6
+ require 'chef-workflow/helpers/ssh'
7
+
8
+ #
9
+ # Subclass of ProvisionHelper, centered around EC2. Pulls some
10
+ # configuration from KnifeSupport and then drives VM::EC2Provisioner and
11
+ # VM::KnifeProvisioner.
12
+ #
13
+ class EC2ProvisionHelper < ProvisionHelper
14
+ def provision(group_name, number_of_servers=1, dependencies=[])
15
+ kp = VM::KnifeProvisioner.new
16
+ kp.username = KnifeSupport.singleton.ssh_user
17
+ kp.password = KnifeSupport.singleton.ssh_password
18
+ kp.use_sudo = KnifeSupport.singleton.use_sudo
19
+ kp.ssh_key = KnifeSupport.singleton.ssh_identity_file
20
+ kp.environment = KnifeSupport.singleton.test_environment
21
+
22
+ schedule_provision(
23
+ group_name,
24
+ [
25
+ VM::EC2Provisioner.new(group_name, number_of_servers),
26
+ kp
27
+ ],
28
+ dependencies
29
+ )
30
+ end
31
+ end
32
+
33
+ #
34
+ # ProvisionedTestCase that uses EC2ProvisionHelper
35
+ #
36
+ class MiniTest::Unit::EC2TestCase < MiniTest::Unit::ProvisionedTestCase
37
+ include SSHHelper
38
+ extend SSHHelper
39
+
40
+ self.provision_helper = EC2ProvisionHelper.new
41
+ end
@@ -0,0 +1,88 @@
1
+ require 'chef-workflow/support/knife'
2
+ require 'chef-workflow/runner/provisioned'
3
+
4
+ #
5
+ # Basic provisioned test case. Generally not intended for direct use but
6
+ # provides the scaffolding for subclasses.
7
+ #
8
+ # Set the class attribute `provision_helper` to configure your provision
9
+ # helper, which will be used for many methods this class provides.
10
+ #
11
+ class MiniTest::Unit::ProvisionedTestCase < MiniTest::Unit::TestCase
12
+ module ProvisionHelper
13
+ def inherited(klass)
14
+ unless klass.provision_helper
15
+ klass.provision_helper = self.provision_helper
16
+ end
17
+
18
+ MiniTest::Unit::TestCase.inherited(klass)
19
+ end
20
+
21
+ #
22
+ # Retrieves the provision helper.
23
+ #
24
+ def provision_helper
25
+ @provision_helper || (self.class.provision_helper rescue nil)
26
+ end
27
+
28
+ #
29
+ # Sets the provision helper.
30
+ #
31
+ def provision_helper=(arg)
32
+ @provision_helper = arg
33
+ end
34
+
35
+ #
36
+ # wait for a provision. takes a list of server group names. delegates to the
37
+ # provision helper.
38
+ #
39
+ def wait_for(*deps)
40
+ provision_helper.wait_for(*deps)
41
+ end
42
+
43
+ #
44
+ # Provision a server group. Takes a name, number of servers, and a list of
45
+ # dependencies (server group names). Delegates to the provision helper.
46
+ #
47
+ def provision(role, number_of_servers=1, addl_dependencies=[])
48
+ provision_helper.provision(role, number_of_servers, addl_dependencies)
49
+ provision_helper.run
50
+ end
51
+
52
+ #
53
+ # De-Provision a server group. Takes a name. Delegates to the provision
54
+ # helper.
55
+ #
56
+ def deprovision(role)
57
+ provision_helper.deprovision(role)
58
+ end
59
+
60
+ #
61
+ # Obtains the IP addresses for a given role as an array.
62
+ #
63
+ def get_role_ips(role)
64
+ IPSupport.singleton.get_role_ips(role)
65
+ end
66
+
67
+ #
68
+ # Easy way to reference KnifeSupport for getting configuration data.
69
+ #
70
+ def knife_config
71
+ KnifeSupport.singleton
72
+ end
73
+ end
74
+
75
+ include ProvisionHelper
76
+ extend ProvisionHelper
77
+
78
+ #
79
+ # Hook before the suite starts. Be sure in your subclasses to call this with
80
+ # `super`. Provisions machines configured as dependencies and starts the
81
+ # scheduler.
82
+ #
83
+ def self.before_suite
84
+ super
85
+
86
+ Chef::Config.from_file(KnifeSupport.singleton.knife_config_path)
87
+ end
88
+ end
@@ -0,0 +1,44 @@
1
+ require 'chef-workflow/support/vagrant'
2
+ require 'chef-workflow/support/vm/vagrant'
3
+ require 'chef-workflow/support/vm/knife'
4
+ require 'tempfile'
5
+ require 'chef-workflow/test-case/provisioned'
6
+ require 'chef-workflow/helpers/provision'
7
+ require 'chef-workflow/helpers/ssh'
8
+
9
+ #
10
+ # Subclass of ProvisionHelper, centered around Vagrant. Pulls some
11
+ # configuration from KnifeSupport and then drives VM::VagrantProvisioner and
12
+ # VM::KnifeProvisioner.
13
+ #
14
+ class VagrantProvisionHelper < ProvisionHelper
15
+ def provision(group_name, number_of_servers=1, dependencies=[])
16
+ self.serial = true
17
+
18
+ kp = VM::KnifeProvisioner.new
19
+ kp.username = KnifeSupport.singleton.ssh_user
20
+ kp.password = KnifeSupport.singleton.ssh_password
21
+ kp.use_sudo = KnifeSupport.singleton.use_sudo
22
+ kp.ssh_key = KnifeSupport.singleton.ssh_identity_file
23
+ kp.environment = KnifeSupport.singleton.test_environment
24
+
25
+ schedule_provision(
26
+ group_name,
27
+ [
28
+ VM::VagrantProvisioner.new(group_name, number_of_servers),
29
+ kp
30
+ ],
31
+ dependencies
32
+ )
33
+ end
34
+ end
35
+
36
+ #
37
+ # ProvisionedTestCase that uses VagrantProvisionHelper.
38
+ #
39
+ class MiniTest::Unit::VagrantTestCase < MiniTest::Unit::ProvisionedTestCase
40
+ include SSHHelper
41
+ extend SSHHelper
42
+
43
+ self.provision_helper = VagrantProvisionHelper.new
44
+ end
@@ -0,0 +1,7 @@
1
+ class Chef
2
+ module Workflow
3
+ module Testlib
4
+ VERSION = "0.1.0"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1 @@
1
+ require "chef-workflow-testlib/version"
metadata ADDED
@@ -0,0 +1,143 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: chef-workflow-testlib
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Erik Hollensbe
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-12-21 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: chef-workflow
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 0.1.0
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: 0.1.0
30
+ - !ruby/object:Gem::Dependency
31
+ name: minitest
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: 4.3.0
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 4.3.0
46
+ - !ruby/object:Gem::Dependency
47
+ name: net-ssh
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: 2.6.0
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 2.6.0
62
+ - !ruby/object:Gem::Dependency
63
+ name: rdoc
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: rake
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ description: Test helpers and assertions for chef-workflow
95
+ email:
96
+ - erik+github@hollensbe.org
97
+ executables: []
98
+ extensions: []
99
+ extra_rdoc_files: []
100
+ files:
101
+ - .gitignore
102
+ - Gemfile
103
+ - LICENSE.txt
104
+ - README.md
105
+ - Rakefile
106
+ - chef-workflow-testlib.gemspec
107
+ - lib/chef-workflow-testlib.rb
108
+ - lib/chef-workflow-testlib/version.rb
109
+ - lib/chef-workflow/helper.rb
110
+ - lib/chef-workflow/helpers/chef.rb
111
+ - lib/chef-workflow/helpers/minitest.rb
112
+ - lib/chef-workflow/helpers/provision.rb
113
+ - lib/chef-workflow/helpers/ssh.rb
114
+ - lib/chef-workflow/runner/provisioned.rb
115
+ - lib/chef-workflow/test-case/ec2.rb
116
+ - lib/chef-workflow/test-case/provisioned.rb
117
+ - lib/chef-workflow/test-case/vagrant.rb
118
+ homepage: https://github.com/chef-workflow/chef-workflow-testlib
119
+ licenses: []
120
+ post_install_message:
121
+ rdoc_options: []
122
+ require_paths:
123
+ - lib
124
+ required_ruby_version: !ruby/object:Gem::Requirement
125
+ none: false
126
+ requirements:
127
+ - - ! '>='
128
+ - !ruby/object:Gem::Version
129
+ version: '0'
130
+ required_rubygems_version: !ruby/object:Gem::Requirement
131
+ none: false
132
+ requirements:
133
+ - - ! '>='
134
+ - !ruby/object:Gem::Version
135
+ version: '0'
136
+ requirements: []
137
+ rubyforge_project:
138
+ rubygems_version: 1.8.24
139
+ signing_key:
140
+ specification_version: 3
141
+ summary: Test helpers and assertions for chef-workflow
142
+ test_files: []
143
+ has_rdoc: