minitest-chef-handler 0.3.0 → 0.4.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/History.txt +8 -1
- data/LICENSE +1 -0
- data/README.md +58 -2
- data/Rakefile +15 -0
- data/examples/{cookbooks → chef-handler-cookbook/cookbooks}/chef_handler/README.md +0 -0
- data/examples/{cookbooks → chef-handler-cookbook/cookbooks}/chef_handler/attributes/default.rb +0 -0
- data/examples/{cookbooks → chef-handler-cookbook/cookbooks}/chef_handler/files/default/handlers/README +0 -0
- data/examples/{cookbooks → chef-handler-cookbook/cookbooks}/chef_handler/metadata.json +0 -0
- data/examples/{cookbooks → chef-handler-cookbook/cookbooks}/chef_handler/metadata.rb +0 -0
- data/examples/{cookbooks → chef-handler-cookbook/cookbooks}/chef_handler/providers/default.rb +0 -0
- data/examples/{cookbooks → chef-handler-cookbook/cookbooks}/chef_handler/recipes/default.rb +0 -0
- data/examples/{cookbooks → chef-handler-cookbook/cookbooks}/chef_handler/recipes/json_file.rb +0 -0
- data/examples/{cookbooks → chef-handler-cookbook/cookbooks}/chef_handler/recipes/minitest.rb +0 -0
- data/examples/{cookbooks → chef-handler-cookbook/cookbooks}/chef_handler/resources/default.rb +0 -0
- data/examples/{cookbooks → simple-solo/cookbooks}/foo/recipes/default.rb +0 -0
- data/examples/{cookbooks → simple-solo/cookbooks}/foo/test/test_foo.rb +0 -0
- data/examples/{dna.json → simple-solo/dna.json} +0 -0
- data/examples/simple-solo/solo.rb +6 -0
- data/examples/simple-solo/spec/foo_spec.rb +9 -0
- data/examples/{test → simple-solo/test}/test_foo.rb +0 -0
- data/examples/spec_examples/attributes/default.rb +8 -0
- data/examples/spec_examples/files/default/tests/minitest/example_test.rb +232 -0
- data/examples/spec_examples/metadata.rb +5 -0
- data/examples/spec_examples/recipes/default.rb +68 -0
- data/examples/spec_examples/templates/default/foo.erb +3 -0
- data/lib/minitest-chef-handler.rb +8 -23
- data/lib/minitest-chef-handler/assertions.rb +129 -0
- data/lib/minitest-chef-handler/context.rb +16 -0
- data/lib/minitest-chef-handler/infections.rb +37 -0
- data/lib/minitest-chef-handler/resources.rb +54 -0
- data/lib/minitest-chef-handler/runner.rb +12 -0
- data/lib/minitest-chef-handler/spec.rb +19 -0
- data/lib/minitest-chef-handler/unit.rb +11 -0
- data/minitest-chef-handler.gemspec +3 -1
- data/spec/minitest-chef-handler/assertions_spec.rb +293 -0
- data/spec/minitest-chef-handler/infections_spec.rb +31 -0
- data/spec/minitest-chef-handler/resources_spec.rb +51 -0
- data/spec/spec_helper.rb +16 -0
- metadata +65 -22
- data/examples/solo.rb +0 -4
data/History.txt
CHANGED
data/LICENSE
CHANGED
data/README.md
CHANGED
@@ -17,7 +17,7 @@ $ gem install minitest-chef-handler
|
|
17
17
|
|
18
18
|
## Usage
|
19
19
|
|
20
|
-
|
20
|
+
Add the report handler to your client.rb or solo.rb file:
|
21
21
|
|
22
22
|
```ruby
|
23
23
|
require 'minitest-chef-handler'
|
@@ -25,7 +25,9 @@ require 'minitest-chef-handler'
|
|
25
25
|
report_handlers << MiniTest::Chef::Handler.new
|
26
26
|
```
|
27
27
|
|
28
|
-
|
28
|
+
### Test cases
|
29
|
+
|
30
|
+
Write your tests as normal MiniTest cases extending from MiniTest::Chef::TestCase:
|
29
31
|
|
30
32
|
```ruby
|
31
33
|
class TestNginx < MiniTest::Chef::TestCase
|
@@ -45,6 +47,60 @@ class TestNginx < MiniTest::Chef::TestCase
|
|
45
47
|
end
|
46
48
|
```
|
47
49
|
|
50
|
+
### Spec cases
|
51
|
+
|
52
|
+
Wrap your descriptions with a class extending from MiniTest::Chef::Spec:
|
53
|
+
|
54
|
+
```ruby
|
55
|
+
class NginxSpec < MiniTest::Chef::Spec
|
56
|
+
describe 'configuration' do
|
57
|
+
it 'creates nginx.conf'
|
58
|
+
end
|
59
|
+
end
|
60
|
+
```
|
61
|
+
|
62
|
+
Use the prefix `recipe::` in your descriptions:
|
63
|
+
|
64
|
+
```ruby
|
65
|
+
describe "recipe::nginx::configuration" do
|
66
|
+
it 'creates nginx.conf'
|
67
|
+
end
|
68
|
+
```
|
69
|
+
|
70
|
+
Or use `describe_recipe` to define your specs:
|
71
|
+
|
72
|
+
```ruby
|
73
|
+
describe_recipe "nginx::configuration" do
|
74
|
+
it 'creates nginx.conf'
|
75
|
+
end
|
76
|
+
```
|
77
|
+
|
78
|
+
You still have access to Chef's `run_status`, `node` and `run_context` from your specs:
|
79
|
+
|
80
|
+
```ruby
|
81
|
+
describe_recipe 'nginx:configuration' do
|
82
|
+
it 'installs version 1.0.15' do
|
83
|
+
node[:nginx][:version].should == '1.0.15'
|
84
|
+
end
|
85
|
+
end
|
86
|
+
```
|
87
|
+
|
88
|
+
### Custom assertions
|
89
|
+
|
90
|
+
By including `MiniTest::Chef::Resources` and `MiniTest::Chef::Assertions` you
|
91
|
+
can also make assertions like these:
|
92
|
+
|
93
|
+
```ruby
|
94
|
+
file("/etc/fstab").must_have(:mode, "644")
|
95
|
+
package("less").must_be_installed
|
96
|
+
service("chef-client").must_be_running
|
97
|
+
```
|
98
|
+
|
99
|
+
The resources supported are: `cron`, `directory`, `file`, `group`, `ifconfig`,
|
100
|
+
`link`, `mount`, `package`, `service` and `user`.
|
101
|
+
|
102
|
+
For example usage see the tests under the `examples/spec_examples` directory.
|
103
|
+
|
48
104
|
## Further configuration
|
49
105
|
|
50
106
|
These are the options the handler accepts:
|
data/Rakefile
CHANGED
@@ -1,2 +1,17 @@
|
|
1
1
|
#!/usr/bin/env rake
|
2
2
|
require "bundler/gem_tasks"
|
3
|
+
require "rake/testtask"
|
4
|
+
|
5
|
+
desc 'Verify that nothing is broken against the simple solo example'
|
6
|
+
task :test do
|
7
|
+
Dir.chdir('./examples/simple-solo') do
|
8
|
+
sh 'ruby -I../../lib -S chef-solo -c solo.rb -j dna.json'
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
Rake::TestTask.new do |t|
|
13
|
+
t.name = 'spec'
|
14
|
+
t.pattern = 'spec/**/*_spec.rb'
|
15
|
+
end
|
16
|
+
|
17
|
+
task :default => [:spec, :test]
|
File without changes
|
data/examples/{cookbooks → chef-handler-cookbook/cookbooks}/chef_handler/attributes/default.rb
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
data/examples/{cookbooks → chef-handler-cookbook/cookbooks}/chef_handler/providers/default.rb
RENAMED
File without changes
|
File without changes
|
data/examples/{cookbooks → chef-handler-cookbook/cookbooks}/chef_handler/recipes/json_file.rb
RENAMED
File without changes
|
data/examples/{cookbooks → chef-handler-cookbook/cookbooks}/chef_handler/recipes/minitest.rb
RENAMED
File without changes
|
data/examples/{cookbooks → chef-handler-cookbook/cookbooks}/chef_handler/resources/default.rb
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,232 @@
|
|
1
|
+
require 'minitest/spec'
|
2
|
+
#
|
3
|
+
# Cookbook Name:: spec_examples
|
4
|
+
# Spec:: default
|
5
|
+
#
|
6
|
+
# Copyright 2012, Opscode, Inc.
|
7
|
+
#
|
8
|
+
describe_recipe 'spec_examples::default' do
|
9
|
+
|
10
|
+
# It's often convenient to load these includes in a separate helper along with
|
11
|
+
# your own helper methods, but here we just include them directly:
|
12
|
+
include MiniTest::Chef::Assertions
|
13
|
+
include MiniTest::Chef::Context
|
14
|
+
include MiniTest::Chef::Resources
|
15
|
+
|
16
|
+
describe "files" do
|
17
|
+
|
18
|
+
# = Testing that a file exists =
|
19
|
+
#
|
20
|
+
# The simplest assertion is that a file exists following the Chef run:
|
21
|
+
it "creates the config file" do
|
22
|
+
file("/etc/fstab").must_exist
|
23
|
+
end
|
24
|
+
|
25
|
+
# All of the matchers starting with 'must_' also have a negative 'wont_'.
|
26
|
+
# So conversely we can also check that a file does not exist:
|
27
|
+
it "ensures that the foobar file is removed if present" do
|
28
|
+
file("/etc/foobar").wont_exist
|
29
|
+
end
|
30
|
+
|
31
|
+
# = Testing for behaviour =
|
32
|
+
#
|
33
|
+
# Chef has multiple resource types that create files. We use file to test
|
34
|
+
# all of them.
|
35
|
+
#
|
36
|
+
# This is not valid:
|
37
|
+
#
|
38
|
+
# cookbook_file(file_path).must_exist
|
39
|
+
#
|
40
|
+
# Testing the behaviour - is the file is created with the right content?
|
41
|
+
# - is preferable to testing how the file gets there. This way if your
|
42
|
+
# recipe switches from using a cookbook_file resource to a template resource
|
43
|
+
# your tests should still work.
|
44
|
+
|
45
|
+
# Let's go beyond just checking for existence to testing the other file
|
46
|
+
# attributes.
|
47
|
+
|
48
|
+
# = Other file attributes =
|
49
|
+
|
50
|
+
# Use .with on a resource and specify the attribute and expected value:
|
51
|
+
it "has the expected ownership and permissions" do
|
52
|
+
file("/etc/fstab").must_exist.with(:owner, "root")
|
53
|
+
end
|
54
|
+
|
55
|
+
# You can also use .must_have:
|
56
|
+
it "only root can modify the config file" do
|
57
|
+
file("/etc/fstab").must_have(:mode, "644")
|
58
|
+
end
|
59
|
+
|
60
|
+
# And you can chain attributes together if you are asserting several.
|
61
|
+
# You don't want to get too carried away doing this but it can be useful.
|
62
|
+
it "only root can modify the config file" do
|
63
|
+
file("/etc/fstab").must_have(:mode, "644").with(:owner, "root").and(:group, "root")
|
64
|
+
end
|
65
|
+
|
66
|
+
# Alternatively you could express it like this so each assertion is nicely
|
67
|
+
# self-contained:
|
68
|
+
describe "only root can modify the config file - alternate syntax" do
|
69
|
+
let(:config) { file("/etc/fstab") }
|
70
|
+
it { config.must_have(:mode, "644") }
|
71
|
+
it { config.must_have(:owner, "root") }
|
72
|
+
it { config.must_have(:group, "root") }
|
73
|
+
end
|
74
|
+
|
75
|
+
# = Checking file content =
|
76
|
+
|
77
|
+
# You can check if a config file contains a string:
|
78
|
+
it "sets phasers to stun" do
|
79
|
+
file('/tmp/foo').must_include 'phaser_setting=stun'
|
80
|
+
end
|
81
|
+
|
82
|
+
# Or if a file matches a regular expression:
|
83
|
+
it "sets phasers to off or stun" do
|
84
|
+
file('/tmp/foo').must_match /^phaser_setting=(off|stun)$/
|
85
|
+
file('/tmp/foo').wont_match /^phaser_setting=kill$/
|
86
|
+
end
|
87
|
+
|
88
|
+
# = Checking file timestamps =
|
89
|
+
it "touches the config to force a reload" do
|
90
|
+
file("/tmp/foo").must_be_modified_after(run_status.start_time)
|
91
|
+
end
|
92
|
+
|
93
|
+
it "leaves the hosts file alone" do
|
94
|
+
file("/etc/hosts").wont_be_modified_after(run_status.start_time)
|
95
|
+
end
|
96
|
+
|
97
|
+
# = Directories =
|
98
|
+
|
99
|
+
# The file existence and permissions matchers are also valid for
|
100
|
+
# directories:
|
101
|
+
it { directory("/etc/").must_exist.with(:owner, "root") }
|
102
|
+
|
103
|
+
# = Links =
|
104
|
+
|
105
|
+
it "symlinks the foo in" do
|
106
|
+
link("/tmp/foo-symbolic").must_exist.with(
|
107
|
+
:link_type, :symbolic).and(:to, "/tmp/foo")
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
|
112
|
+
describe "packages" do
|
113
|
+
|
114
|
+
# = Checking for package install =
|
115
|
+
it "installs my favorite pager" do
|
116
|
+
package("less").must_be_installed
|
117
|
+
end
|
118
|
+
|
119
|
+
it "doesn't install emacs" do
|
120
|
+
package("emacs").wont_be_installed
|
121
|
+
end
|
122
|
+
|
123
|
+
# = Package names =
|
124
|
+
#
|
125
|
+
# When writing cookbooks intended for use on multiple different operating
|
126
|
+
# systems or flavors you will often need to supply a different package
|
127
|
+
# name based on the node.platform.
|
128
|
+
#
|
129
|
+
# If you choose to test for package installation in your tests then you
|
130
|
+
# will also need to provide the right package name, which can lead to
|
131
|
+
# duplication.
|
132
|
+
|
133
|
+
it "installs my favorite pager" do
|
134
|
+
package(node['spec_examples']['pager']).must_be_installed
|
135
|
+
end
|
136
|
+
|
137
|
+
# = Package versions =
|
138
|
+
it "installs the package with the right version" do
|
139
|
+
package("less").must_be_installed.with(:version, "436-1")
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
describe "services" do
|
144
|
+
|
145
|
+
# You can assert that a service must be running following the converge:
|
146
|
+
it "runs as a daemon" do
|
147
|
+
service("chef-client").must_be_running
|
148
|
+
end
|
149
|
+
|
150
|
+
# And that it will start when the server boots:
|
151
|
+
it "boots on startup" do
|
152
|
+
service("chef-client").must_be_enabled
|
153
|
+
end
|
154
|
+
|
155
|
+
end
|
156
|
+
|
157
|
+
describe "users and groups" do
|
158
|
+
|
159
|
+
# = Users =
|
160
|
+
|
161
|
+
# Check if a user has been created:
|
162
|
+
it "creates a user for the daemon to run as" do
|
163
|
+
user("sshd").must_exist
|
164
|
+
end
|
165
|
+
|
166
|
+
# You can also use .with here to test attributes:
|
167
|
+
it "creates the user with the expected properties" do
|
168
|
+
user("sshd").must_exist.with(:home, '/var/run/sshd')
|
169
|
+
end
|
170
|
+
|
171
|
+
it "has an informative comment against the user" do
|
172
|
+
user("list").must_have(:comment, 'Mailing List Manager')
|
173
|
+
end
|
174
|
+
|
175
|
+
it "has the expected uid" do
|
176
|
+
user("root").must_have(:uid, 0)
|
177
|
+
end
|
178
|
+
|
179
|
+
# = Groups =
|
180
|
+
|
181
|
+
it "creates the users group" do
|
182
|
+
group("chipmunks").must_exist
|
183
|
+
end
|
184
|
+
|
185
|
+
# Check for group membership, you can pass a single user or an array of
|
186
|
+
# users:
|
187
|
+
it "grants group membership to the expected users" do
|
188
|
+
group("chipmunks").must_include('alvin')
|
189
|
+
group("chipmunks").must_include(['alvin', 'simon'])
|
190
|
+
group("chipmunks").wont_include('michelangelo')
|
191
|
+
end
|
192
|
+
|
193
|
+
# Alternatively rather than checking if the group includes specific users
|
194
|
+
# you can test that the group is made up of exactly the users you specify:
|
195
|
+
it "grants group membership only to specific users" do
|
196
|
+
group("chipmunks").must_have(:members, ['alvin', 'simon', 'theodore'])
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
describe "cron entries" do
|
201
|
+
|
202
|
+
it "creates a crontab entry" do
|
203
|
+
cron("noop").must_exist.with(:hour, "5").and(:minute, "0").and(:day, "*")
|
204
|
+
end
|
205
|
+
|
206
|
+
it "removes the self-destruct countdown" do
|
207
|
+
cron("self-destruct").wont_exist
|
208
|
+
end
|
209
|
+
|
210
|
+
end
|
211
|
+
|
212
|
+
# Note that the syntax for testing the mount resource is slightly different.
|
213
|
+
# You need to specify the device in the call to mount.
|
214
|
+
describe "mount" do
|
215
|
+
it { mount("/mnt", :device => "/dev/null").must_be_mounted }
|
216
|
+
it { mount("/mnt", :device => "/dev/null").must_be_enabled.with(:fstype, "tmpfs") }
|
217
|
+
it { mount("/mnt", :device => "/dev/olympus").wont_be_mounted }
|
218
|
+
end
|
219
|
+
|
220
|
+
describe "networking" do
|
221
|
+
|
222
|
+
# = Test network interface settings =
|
223
|
+
describe "ifconfig" do
|
224
|
+
it "has the expected network interfaces configured" do
|
225
|
+
ifconfig(node['ipaddress'], :device => "eth0").must_exist
|
226
|
+
ifconfig(node['ipaddress'], :device => "eth1").wont_exist
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
end
|
231
|
+
|
232
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
#
|
2
|
+
# Cookbook Name:: spec_examples
|
3
|
+
# Recipe:: default
|
4
|
+
#
|
5
|
+
# Copyright 2012, Opscode, Inc.
|
6
|
+
#
|
7
|
+
|
8
|
+
template "/tmp/foo" do
|
9
|
+
variables({
|
10
|
+
'phasers' => 'stun'
|
11
|
+
})
|
12
|
+
action :create
|
13
|
+
end
|
14
|
+
|
15
|
+
file "/tmp/foo" do
|
16
|
+
action :touch
|
17
|
+
end
|
18
|
+
|
19
|
+
package "less" do
|
20
|
+
action :install
|
21
|
+
end
|
22
|
+
|
23
|
+
package node['spec_examples']['pager'] do
|
24
|
+
action :install
|
25
|
+
end
|
26
|
+
|
27
|
+
chipmunks = %w{alvin simon theodore}
|
28
|
+
chipmunks.each do |chipmunk|
|
29
|
+
user chipmunk do
|
30
|
+
action :create
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
group "chipmunks" do
|
35
|
+
members chipmunks
|
36
|
+
action :create
|
37
|
+
end
|
38
|
+
|
39
|
+
%w{hard symbolic}.each do |link_type|
|
40
|
+
link "/tmp/foo-#{link_type}" do
|
41
|
+
to "/tmp/foo"
|
42
|
+
link_type link_type
|
43
|
+
action :create
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
package "cron" do
|
48
|
+
action :install
|
49
|
+
end
|
50
|
+
|
51
|
+
cron "noop" do
|
52
|
+
hour "5"
|
53
|
+
minute "0"
|
54
|
+
command "/bin/true"
|
55
|
+
end
|
56
|
+
|
57
|
+
mount "/mnt" do
|
58
|
+
pass 0
|
59
|
+
fstype "tmpfs"
|
60
|
+
device "/dev/null"
|
61
|
+
options "nr_inodes=999k,mode=755,size=500m"
|
62
|
+
action [:mount, :enable]
|
63
|
+
end
|
64
|
+
|
65
|
+
ifconfig "192.168.20.2" do
|
66
|
+
device "eth0"
|
67
|
+
action :add
|
68
|
+
end
|