rspec-puppet-womble 0.1.6.womble1 → 0.1.6.womble2
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +8 -0
- data/LICENSE +20 -0
- data/README.md +357 -0
- data/Rakefile +7 -0
- data/lib/rspec-puppet.rb +47 -0
- data/lib/rspec-puppet/errors.rb +46 -0
- data/lib/rspec-puppet/example.rb +27 -0
- data/lib/rspec-puppet/example/class_example_group.rb +10 -0
- data/lib/rspec-puppet/example/define_example_group.rb +10 -0
- data/lib/rspec-puppet/example/function_example_group.rb +46 -0
- data/lib/rspec-puppet/example/host_example_group.rb +10 -0
- data/lib/rspec-puppet/matchers.rb +6 -0
- data/lib/rspec-puppet/matchers/compile.rb +133 -0
- data/lib/rspec-puppet/matchers/count_generic.rb +73 -0
- data/lib/rspec-puppet/matchers/create_generic.rb +156 -0
- data/lib/rspec-puppet/matchers/dynamic_matchers.rb +17 -0
- data/lib/rspec-puppet/matchers/include_class.rb +19 -0
- data/lib/rspec-puppet/matchers/parameter_matcher.rb +110 -0
- data/lib/rspec-puppet/matchers/run.rb +94 -0
- data/lib/rspec-puppet/setup.rb +167 -0
- data/lib/rspec-puppet/support.rb +165 -0
- data/rspec-puppet-womble.gemspec +18 -0
- data/spec/classes/array_spec.rb +74 -0
- data/spec/classes/boolean_regexp_spec.rb +13 -0
- data/spec/classes/boolean_spec.rb +11 -0
- data/spec/classes/cycle_bad_spec.rb +5 -0
- data/spec/classes/cycle_good_spec.rb +5 -0
- data/spec/classes/escape_spec.rb +7 -0
- data/spec/classes/hash_spec.rb +68 -0
- data/spec/classes/sysctl_common_spec.rb +83 -0
- data/spec/defines/escape_def_spec.rb +8 -0
- data/spec/defines/sysctl_before_spec.rb +25 -0
- data/spec/defines/sysctl_spec.rb +21 -0
- data/spec/fixtures/manifests/site.pp +26 -0
- data/spec/fixtures/modules/boolean/manifests/init.pp +12 -0
- data/spec/fixtures/modules/cycle/manifests/bad.pp +8 -0
- data/spec/fixtures/modules/cycle/manifests/good.pp +7 -0
- data/spec/fixtures/modules/cycle/manifests/init.pp +0 -0
- data/spec/fixtures/modules/escape/manifests/def.pp +6 -0
- data/spec/fixtures/modules/escape/manifests/init.pp +6 -0
- data/spec/fixtures/modules/structured_data/manifests/def.pp +5 -0
- data/spec/fixtures/modules/structured_data/manifests/init.pp +5 -0
- data/spec/fixtures/modules/sysctl/manifests/init.pp +39 -0
- data/spec/functions/split_spec.rb +30 -0
- data/spec/hosts/bad_dep_host_spec.rb +5 -0
- data/spec/hosts/foo_spec.rb +6 -0
- data/spec/hosts/good_dep_host_spec.rb +5 -0
- data/spec/hosts/testhost_spec.rb +5 -0
- data/spec/spec_helper.rb +6 -0
- metadata +50 -1
data/Gemfile
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
puppetversion = ENV.key?('PUPPET_VERSION') ? "= #{ENV['PUPPET_VERSION']}" : ['>= 2.7']
|
4
|
+
rspecversion = ENV.key?('RSPEC_VERSION') ? "= #{ENV['RSPEC_VERSION']}" : ['>= 2.9']
|
5
|
+
|
6
|
+
gem 'rake'
|
7
|
+
gem 'rspec', rspecversion
|
8
|
+
gem 'puppet', puppetversion
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Tim Sharpe
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
17
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
18
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
19
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
20
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,357 @@
|
|
1
|
+
# RSpec tests for your Puppet manifests & modules
|
2
|
+
|
3
|
+
## Installation
|
4
|
+
|
5
|
+
gem install rspec-puppet
|
6
|
+
|
7
|
+
## Naming conventions
|
8
|
+
|
9
|
+
For clarity and consistency, I recommend that you use the following directory
|
10
|
+
structure and naming convention.
|
11
|
+
|
12
|
+
module
|
13
|
+
|
|
14
|
+
+-- manifests
|
15
|
+
|
|
16
|
+
+-- lib
|
17
|
+
|
|
18
|
+
+-- spec
|
19
|
+
|
|
20
|
+
+-- spec_helper.rb
|
21
|
+
|
|
22
|
+
+-- classes
|
23
|
+
| |
|
24
|
+
| +-- <class_name>_spec.rb
|
25
|
+
|
|
26
|
+
+-- defines
|
27
|
+
| |
|
28
|
+
| +-- <define_name>_spec.rb
|
29
|
+
|
|
30
|
+
+-- functions
|
31
|
+
| |
|
32
|
+
| +-- <function_name>_spec.rb
|
33
|
+
|
|
34
|
+
+-- hosts
|
35
|
+
|
|
36
|
+
+-- <host_name>_spec.rb
|
37
|
+
|
38
|
+
## Example groups
|
39
|
+
|
40
|
+
If you use the above directory structure, your examples will automatically be
|
41
|
+
placed in the correct groups and have access to the custom matchers. *If you
|
42
|
+
choose not to*, you can force the examples into the required groups as follows.
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
describe 'myclass', :type => :class do
|
46
|
+
...
|
47
|
+
end
|
48
|
+
|
49
|
+
describe 'mydefine', :type => :define do
|
50
|
+
...
|
51
|
+
end
|
52
|
+
|
53
|
+
describe 'myfunction', :type => :puppet_function do
|
54
|
+
...
|
55
|
+
end
|
56
|
+
|
57
|
+
describe 'myhost.example.com', :type => :host do
|
58
|
+
...
|
59
|
+
end
|
60
|
+
```
|
61
|
+
|
62
|
+
## Defined Types & Classes
|
63
|
+
|
64
|
+
### Matchers
|
65
|
+
|
66
|
+
#### Checking if a class has been included
|
67
|
+
|
68
|
+
You can test if a class has been included in the catalogue with the
|
69
|
+
`include_class` matcher. It takes the class name as a string as its only
|
70
|
+
argument
|
71
|
+
|
72
|
+
```ruby
|
73
|
+
it { should include_class('foo') }
|
74
|
+
```
|
75
|
+
|
76
|
+
#### Checking if a resource exists
|
77
|
+
|
78
|
+
You can test if a resource exists in the catalogue with the generic
|
79
|
+
`contain_<resource type>` matcher.
|
80
|
+
|
81
|
+
```ruby
|
82
|
+
it { should contain_augeas('bleh') }
|
83
|
+
```
|
84
|
+
|
85
|
+
If your resource type includes :: (e.g.
|
86
|
+
`foo::bar` simply replace the :: with __ (two underscores).
|
87
|
+
|
88
|
+
```ruby
|
89
|
+
it { should contain_foo__bar('baz') }
|
90
|
+
```
|
91
|
+
|
92
|
+
You can further test the parameters that have been passed to the resources with
|
93
|
+
the generic `with_<parameter>` chains.
|
94
|
+
|
95
|
+
```ruby
|
96
|
+
it { should contain_package('mysql-server').with_ensure('present') }
|
97
|
+
```
|
98
|
+
|
99
|
+
If you want to specify that the given parameters should be the only ones passed
|
100
|
+
to the resource, use the `only_with_<parameter>` chains.
|
101
|
+
|
102
|
+
```ruby
|
103
|
+
it { should contain_package('httpd').only_with_ensure('latest') }
|
104
|
+
```
|
105
|
+
|
106
|
+
You can use the `with` method to verify the value of multiple parameters.
|
107
|
+
|
108
|
+
```ruby
|
109
|
+
it do should contain_service('keystone').with(
|
110
|
+
'ensure' => 'running',
|
111
|
+
'enable' => 'true',
|
112
|
+
'hasstatus' => 'true',
|
113
|
+
'hasrestart' => 'true'
|
114
|
+
) end
|
115
|
+
```
|
116
|
+
|
117
|
+
The same holds for the `only_with` method, which in addition verifies the exact
|
118
|
+
set of parameters and values for the resource in the catalogue.
|
119
|
+
|
120
|
+
```ruby
|
121
|
+
it do should contain_user('luke').only_with(
|
122
|
+
'ensure' => 'present',
|
123
|
+
'uid' => '501'
|
124
|
+
) end
|
125
|
+
```
|
126
|
+
|
127
|
+
You can also test that specific parameters have been left undefined with the
|
128
|
+
generic `without_<parameter>` chains.
|
129
|
+
|
130
|
+
```ruby
|
131
|
+
it { should contain_file('/foo/bar').without_mode }
|
132
|
+
```
|
133
|
+
|
134
|
+
You can use the without method to verify that a list of parameters have not been
|
135
|
+
defined
|
136
|
+
|
137
|
+
```ruby
|
138
|
+
it { should contain_service('keystone').without(
|
139
|
+
['restart', 'status']
|
140
|
+
)}
|
141
|
+
```
|
142
|
+
|
143
|
+
#### Checking the number of resources
|
144
|
+
|
145
|
+
You can test the number of resources in the catalogue with the
|
146
|
+
`have_resource_count` matcher.
|
147
|
+
|
148
|
+
```ruby
|
149
|
+
it { should have_resource_count(2) }
|
150
|
+
```
|
151
|
+
|
152
|
+
The number of classes in the catalogue can be checked with the
|
153
|
+
`have_class_count` matcher.
|
154
|
+
|
155
|
+
```ruby
|
156
|
+
it { should have_class_count(2) }
|
157
|
+
```
|
158
|
+
|
159
|
+
You can also test the number of a specific resource type, by using the generic
|
160
|
+
`have_<resource type>_resource_count` matcher.
|
161
|
+
|
162
|
+
```ruby
|
163
|
+
it { should have_exec_resource_count(1) }
|
164
|
+
```
|
165
|
+
|
166
|
+
This last matcher also works for defined types. If the resource type contains
|
167
|
+
::, you can replace it with __ (two underscores).
|
168
|
+
|
169
|
+
```ruby
|
170
|
+
it { should have_logrotate__rule_resource_count(3) }
|
171
|
+
```
|
172
|
+
|
173
|
+
*NOTE*: when testing a class, the catalogue generated will always contain at
|
174
|
+
least one class, the class under test. The same holds for defined types, the
|
175
|
+
catalogue generated when testing a defined type will have at least one resource
|
176
|
+
(the defined type itself).
|
177
|
+
|
178
|
+
### Writing tests
|
179
|
+
|
180
|
+
#### Basic test structure
|
181
|
+
|
182
|
+
To test that
|
183
|
+
|
184
|
+
sysctl { 'baz'
|
185
|
+
value => 'foo',
|
186
|
+
}
|
187
|
+
|
188
|
+
Will cause the following resource to be in included in catalogue for a host
|
189
|
+
|
190
|
+
exec { 'sysctl/reload':
|
191
|
+
command => '/sbin/sysctl -p /etc/sysctl.conf',
|
192
|
+
}
|
193
|
+
|
194
|
+
We can write the following testcase (in `spec/defines/sysctl_spec.rb`)
|
195
|
+
|
196
|
+
```ruby
|
197
|
+
describe 'sysctl' do
|
198
|
+
let(:title) { 'baz' }
|
199
|
+
let(:params) { { :value => 'foo' } }
|
200
|
+
|
201
|
+
it { should contain_exec('sysctl/reload').with_command("/sbin/sysctl -p /etc/sysctl.conf") }
|
202
|
+
end
|
203
|
+
```
|
204
|
+
|
205
|
+
#### Specifying the title of a resource
|
206
|
+
|
207
|
+
```ruby
|
208
|
+
let(:title) { 'foo' }
|
209
|
+
```
|
210
|
+
|
211
|
+
#### Specifying the parameters to pass to a resources or parametised class
|
212
|
+
|
213
|
+
```ruby
|
214
|
+
let(:params) { {:ensure => 'present', ...} }
|
215
|
+
```
|
216
|
+
|
217
|
+
#### Specifying the FQDN of the test node
|
218
|
+
|
219
|
+
If the manifest you're testing expects to run on host with a particular name,
|
220
|
+
you can specify this as follows
|
221
|
+
|
222
|
+
```ruby
|
223
|
+
let(:node) { 'testhost.example.com' }
|
224
|
+
```
|
225
|
+
|
226
|
+
#### Specifying the facts that should be available to your manifest
|
227
|
+
|
228
|
+
By default, the test environment contains no facts for your manifest to use.
|
229
|
+
You can set them with a hash
|
230
|
+
|
231
|
+
```ruby
|
232
|
+
let(:facts) { {:operatingsystem => 'Debian', :kernel => 'Linux', ...} }
|
233
|
+
```
|
234
|
+
|
235
|
+
You can also create a set of default facts provided to all specs in your spec_helper:
|
236
|
+
|
237
|
+
``` ruby
|
238
|
+
RSpec.configure do |c|
|
239
|
+
c.default_facts = {
|
240
|
+
:operatingsystem => 'Ubuntu'
|
241
|
+
}
|
242
|
+
end
|
243
|
+
```
|
244
|
+
|
245
|
+
Any facts you provide with `let(:facts)` in a spec will automatically be merged on top
|
246
|
+
of the default facts.
|
247
|
+
|
248
|
+
#### Specifying the path to find your modules
|
249
|
+
|
250
|
+
I recommend setting a default module path by adding the following code to your
|
251
|
+
`spec_helper.rb`
|
252
|
+
|
253
|
+
```ruby
|
254
|
+
RSpec.configure do |c|
|
255
|
+
c.module_path = '/path/to/your/module/dir'
|
256
|
+
end
|
257
|
+
```
|
258
|
+
|
259
|
+
However, if you want to specify it in each example, you can do so
|
260
|
+
|
261
|
+
```ruby
|
262
|
+
let(:module_path) { '/path/to/your/module/dir' }
|
263
|
+
```
|
264
|
+
|
265
|
+
## Functions
|
266
|
+
|
267
|
+
### Matchers
|
268
|
+
|
269
|
+
All of the standard RSpec matchers are available for you to use when testing
|
270
|
+
Puppet functions.
|
271
|
+
|
272
|
+
```ruby
|
273
|
+
it 'should be able to do something' do
|
274
|
+
subject.call(['foo']) == 'bar'
|
275
|
+
end
|
276
|
+
```
|
277
|
+
|
278
|
+
For your convenience though, a `run` matcher exists to provide easier to
|
279
|
+
understand test cases.
|
280
|
+
|
281
|
+
```ruby
|
282
|
+
it { should run.with_params('foo').and_return('bar') }
|
283
|
+
```
|
284
|
+
|
285
|
+
### Writing tests
|
286
|
+
|
287
|
+
#### Basic test structure
|
288
|
+
|
289
|
+
```ruby
|
290
|
+
require 'spec_helper'
|
291
|
+
|
292
|
+
describe '<function name>' do
|
293
|
+
...
|
294
|
+
end
|
295
|
+
```
|
296
|
+
|
297
|
+
#### Specifying the name of the function to test
|
298
|
+
|
299
|
+
The name of the function must be provided in the top level description, e.g.
|
300
|
+
|
301
|
+
```ruby
|
302
|
+
describe 'split' do
|
303
|
+
```
|
304
|
+
|
305
|
+
#### Specifying the arguments to pass to the function
|
306
|
+
|
307
|
+
You can specify the arguments to pass to your function during the test(s) using
|
308
|
+
either the `with_params` chain method in the `run` matcher
|
309
|
+
|
310
|
+
```ruby
|
311
|
+
it { should run.with_params('foo', 'bar', ['baz']) }
|
312
|
+
```
|
313
|
+
|
314
|
+
Or by using the `call` method on the subject directly
|
315
|
+
|
316
|
+
```ruby
|
317
|
+
it 'something' do
|
318
|
+
subject.call(['foo', 'bar', ['baz']])
|
319
|
+
end
|
320
|
+
```
|
321
|
+
|
322
|
+
#### Testing the results of the function
|
323
|
+
|
324
|
+
You can test the result of a function (if it produces one) using either the
|
325
|
+
`and_returns` chain method in the `run` matcher
|
326
|
+
|
327
|
+
```ruby
|
328
|
+
it { should run.with_params('foo').and_return('bar') }
|
329
|
+
```
|
330
|
+
|
331
|
+
Or by using any of the existing RSpec matchers on the subject directly
|
332
|
+
|
333
|
+
```ruby
|
334
|
+
it 'something' do
|
335
|
+
subject.call(['foo']) == 'bar'
|
336
|
+
subject.call(['baz']).should be_an Array
|
337
|
+
end
|
338
|
+
```
|
339
|
+
|
340
|
+
#### Testing the errors thrown by the function
|
341
|
+
|
342
|
+
You can test whether the function throws an exception using either the
|
343
|
+
`and_raises_error` chain method in the `run` matcher
|
344
|
+
|
345
|
+
```ruby
|
346
|
+
it { should run.with_params('a', 'b').and_raise_error(Puppet::ParseError) }
|
347
|
+
it { should_not run.with_params('a').and_raise_error(Puppet::ParseError) }
|
348
|
+
```
|
349
|
+
|
350
|
+
Or by using the existing `raises_error` RSpec matcher
|
351
|
+
|
352
|
+
```ruby
|
353
|
+
it 'something' do
|
354
|
+
expect { subject.call(['a', 'b']) }.should raise_error(Puppet::ParseError)
|
355
|
+
expect { subject.call(['a']) }.should_not raise_error(Puppet::ParseError)
|
356
|
+
end
|
357
|
+
```
|
data/Rakefile
ADDED
data/lib/rspec-puppet.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'puppet'
|
2
|
+
require 'rspec'
|
3
|
+
require 'fileutils'
|
4
|
+
require 'tmpdir'
|
5
|
+
require 'rspec-puppet/errors'
|
6
|
+
require 'rspec-puppet/matchers'
|
7
|
+
require 'rspec-puppet/example'
|
8
|
+
require 'rspec-puppet/setup'
|
9
|
+
|
10
|
+
begin
|
11
|
+
require 'puppet/test/test_helper'
|
12
|
+
rescue LoadError
|
13
|
+
end
|
14
|
+
|
15
|
+
RSpec.configure do |c|
|
16
|
+
c.add_setting :module_path, :default => '/etc/puppet/modules'
|
17
|
+
c.add_setting :manifest_dir, :default => nil
|
18
|
+
c.add_setting :manifest, :default => nil
|
19
|
+
c.add_setting :template_dir, :default => nil
|
20
|
+
c.add_setting :config, :default => nil
|
21
|
+
c.add_setting :confdir, :default => '/etc/puppet'
|
22
|
+
c.add_setting :default_facts, :default => {}
|
23
|
+
|
24
|
+
if defined?(Puppet::Test::TestHelper)
|
25
|
+
begin
|
26
|
+
Puppet::Test::TestHelper.initialize
|
27
|
+
rescue NoMethodError
|
28
|
+
Puppet::Test::TestHelper.before_each_test
|
29
|
+
end
|
30
|
+
|
31
|
+
c.before :all do
|
32
|
+
Puppet::Test::TestHelper.before_all_tests
|
33
|
+
end
|
34
|
+
|
35
|
+
c.after :all do
|
36
|
+
Puppet::Test::TestHelper.after_all_tests
|
37
|
+
end
|
38
|
+
|
39
|
+
c.before :each do
|
40
|
+
Puppet::Test::TestHelper.before_each_test
|
41
|
+
end
|
42
|
+
|
43
|
+
c.after :each do
|
44
|
+
Puppet::Test::TestHelper.after_each_test
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module RSpec::Puppet
|
2
|
+
module Errors
|
3
|
+
class MatchError < StandardError
|
4
|
+
attr_reader :param, :expected, :actual, :negative
|
5
|
+
|
6
|
+
def initialize(param, expected, actual, negative)
|
7
|
+
@param = param
|
8
|
+
@expected = expected.inspect
|
9
|
+
@actual = actual.inspect
|
10
|
+
@negative = negative
|
11
|
+
end
|
12
|
+
|
13
|
+
def message
|
14
|
+
if negative == true
|
15
|
+
"#{param} not set to #{expected} but it is set to #{actual}"
|
16
|
+
else
|
17
|
+
"#{param} set to #{expected} but it is set to #{actual}"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_s
|
22
|
+
message
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class RegexpMatchError < MatchError
|
27
|
+
def message
|
28
|
+
if negative == true
|
29
|
+
"#{param} not matching #{expected} but its value of #{actual} does"
|
30
|
+
else
|
31
|
+
"#{param} matching #{expected} but its value of #{actual} does not"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class ProcMatchError < MatchError
|
37
|
+
def message
|
38
|
+
if negative == true
|
39
|
+
"#{param} passed to the block would not return `#{expected}` but it did"
|
40
|
+
else
|
41
|
+
"#{param} passed to the block would return `#{expected}` but it is `#{actual}`"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|