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.
Files changed (50) hide show
  1. data/Gemfile +8 -0
  2. data/LICENSE +20 -0
  3. data/README.md +357 -0
  4. data/Rakefile +7 -0
  5. data/lib/rspec-puppet.rb +47 -0
  6. data/lib/rspec-puppet/errors.rb +46 -0
  7. data/lib/rspec-puppet/example.rb +27 -0
  8. data/lib/rspec-puppet/example/class_example_group.rb +10 -0
  9. data/lib/rspec-puppet/example/define_example_group.rb +10 -0
  10. data/lib/rspec-puppet/example/function_example_group.rb +46 -0
  11. data/lib/rspec-puppet/example/host_example_group.rb +10 -0
  12. data/lib/rspec-puppet/matchers.rb +6 -0
  13. data/lib/rspec-puppet/matchers/compile.rb +133 -0
  14. data/lib/rspec-puppet/matchers/count_generic.rb +73 -0
  15. data/lib/rspec-puppet/matchers/create_generic.rb +156 -0
  16. data/lib/rspec-puppet/matchers/dynamic_matchers.rb +17 -0
  17. data/lib/rspec-puppet/matchers/include_class.rb +19 -0
  18. data/lib/rspec-puppet/matchers/parameter_matcher.rb +110 -0
  19. data/lib/rspec-puppet/matchers/run.rb +94 -0
  20. data/lib/rspec-puppet/setup.rb +167 -0
  21. data/lib/rspec-puppet/support.rb +165 -0
  22. data/rspec-puppet-womble.gemspec +18 -0
  23. data/spec/classes/array_spec.rb +74 -0
  24. data/spec/classes/boolean_regexp_spec.rb +13 -0
  25. data/spec/classes/boolean_spec.rb +11 -0
  26. data/spec/classes/cycle_bad_spec.rb +5 -0
  27. data/spec/classes/cycle_good_spec.rb +5 -0
  28. data/spec/classes/escape_spec.rb +7 -0
  29. data/spec/classes/hash_spec.rb +68 -0
  30. data/spec/classes/sysctl_common_spec.rb +83 -0
  31. data/spec/defines/escape_def_spec.rb +8 -0
  32. data/spec/defines/sysctl_before_spec.rb +25 -0
  33. data/spec/defines/sysctl_spec.rb +21 -0
  34. data/spec/fixtures/manifests/site.pp +26 -0
  35. data/spec/fixtures/modules/boolean/manifests/init.pp +12 -0
  36. data/spec/fixtures/modules/cycle/manifests/bad.pp +8 -0
  37. data/spec/fixtures/modules/cycle/manifests/good.pp +7 -0
  38. data/spec/fixtures/modules/cycle/manifests/init.pp +0 -0
  39. data/spec/fixtures/modules/escape/manifests/def.pp +6 -0
  40. data/spec/fixtures/modules/escape/manifests/init.pp +6 -0
  41. data/spec/fixtures/modules/structured_data/manifests/def.pp +5 -0
  42. data/spec/fixtures/modules/structured_data/manifests/init.pp +5 -0
  43. data/spec/fixtures/modules/sysctl/manifests/init.pp +39 -0
  44. data/spec/functions/split_spec.rb +30 -0
  45. data/spec/hosts/bad_dep_host_spec.rb +5 -0
  46. data/spec/hosts/foo_spec.rb +6 -0
  47. data/spec/hosts/good_dep_host_spec.rb +5 -0
  48. data/spec/hosts/testhost_spec.rb +5 -0
  49. data/spec/spec_helper.rb +6 -0
  50. 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
@@ -0,0 +1,7 @@
1
+ require 'rake'
2
+ require 'rspec/core/rake_task'
3
+
4
+ task :default => :test
5
+ task :spec => :test
6
+
7
+ RSpec::Core::RakeTask.new(:test)
@@ -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