rspec-puppet-womble 0.1.6.womble1 → 0.1.6.womble2

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.
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