rspec-puppet 2.2.0 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 99267b05af6dbb02ad504453ec338ea2617e1768
4
- data.tar.gz: ffb1e195adc74932acdbc6581eae52317018dc08
3
+ metadata.gz: c9c6c2a6e166342f02c503667f8312efd1d411e5
4
+ data.tar.gz: 407d9b0fc06f52c63428320819fd634eee4cf049
5
5
  SHA512:
6
- metadata.gz: f1036132529e546b54f1e475c69f437402c994328795cf8d2828a619cd2e7cb2e1d7a6e51fc01dd95860e4623f650bac6983f3eaf432d8c664ea223370ba2ec3
7
- data.tar.gz: 9d0e5709f38c09486749c1cd4bea517aa2757988e2bb55f430b241ed029d88bb2afa939392924378bf7f15924625d13a051fddef342b04052642241971cbb5bc
6
+ metadata.gz: e1c780ece606028d4a134797cec9740204529a597b2b4a14400dd4dbf623c8b689ba067726d4ebcac7f09ce792c7867ab47860b8d5fbd82304e1204be46c5b74
7
+ data.tar.gz: c5b11365c94d792e111b804c87a225583461f68570b5e29be03bb1e87a621cef66b08283c04e5bf42eb120c50afaae57375a8483a0be33f1ea569eaf2fa71617
data/CHANGELOG.md CHANGED
@@ -2,6 +2,46 @@
2
2
  All notable changes to this project will be documented in this file. This
3
3
  project adheres to [Semantic Versioning](http://semver.org/).
4
4
 
5
+ ## [2.3.0]
6
+
7
+ Rspec-puppet now supports testing custom types, `:undef` values in params, structured facts, and checks resource dependencies recursively.
8
+
9
+ The settings in `module_path` and `manifest` are now respected throughout the code base. The former default for `module_path` (`'/etc/puppet/modules'`) was dropped to avoid accidentally poisoning the test environment with unrelated code.
10
+
11
+ To reduce the maintenance overhead of boilerplate code, rspec-puppet now provides some of the code that rspec-puppet-init deployed in helper files that you can just `require` instead.
12
+
13
+ This release also reduces memory usage on bigger testsuites drastically by reducing the caching of compiled catalogs.
14
+
15
+ ### Changed
16
+ - Limit the catalogue cache to 16 entries. Significant memory savings and reduced runtime were observed in testing this.
17
+ - Prevent Puppet 3's \_timestamp fact from invalidating cache.
18
+ - Extracted catalog cache from RSpec::Puppet::Support.
19
+ - Updated README to use the rspec 3 syntax, and additional explanations.
20
+ - `contain_file(...).with_content(...)` will now only show the diff and not the full contents of the file.
21
+
22
+ ### Added
23
+ - Custom type testing example group and matcher.
24
+ - before/require/subscribe/notify checking now searches recursively through all dependencies. `File[a] -> File[b] -> File[c]` is now matched by `contain_file('a').that_comes_before('File[c]')`, whereas earlier versions would have missed that.
25
+ - `let(:params)` now allows `:undef` to pass a literal undef value through to the subject.
26
+ - Support structured facts with keys as symbols or strings (\#295).
27
+ - rspec-puppet-init now creates smaller files, using rspec-puppet helpers, instead of pasting code into the module.
28
+ - Added a list of related projects to the README.
29
+
30
+ ### Fixed
31
+ - Fix #276: `compile.and_raise_error` now correctly considers successful compilation an error
32
+ - Puppet's `modulepath` can now contain multiple entries and rspec-puppet will configure puppet to load code from all of them
33
+ - Support running with rspec 2.99 again
34
+ - non-class resources are now covered by the coverage code
35
+ - Fix #323/MODULES-2374: autorequires checking doesn't abort on "undefined method \`[]' for nil:NilClass"
36
+ - improved documentation for hiera integration, added example spec
37
+ - document the `scope` property
38
+
39
+ ### Credits
40
+
41
+ Thanks to Adrien Thebo, Alex Harvey, Brian, Dan Bode, Dominic Cleal, Javier Palacios, Jeff McCune, Jordan Moldow, Peter van Zetten, Raphaël Pinson, Simon Kohlmeyer, and Tristan Colgate for their contributions to this release.
42
+
43
+ -- David Schmitt
44
+
5
45
  ## [2.2.0]
6
46
  ### Added
7
47
  - Settings for ordering, strict_variables, stringify_facts, and trusted_node_data
@@ -47,6 +87,9 @@ project adheres to [Semantic Versioning](http://semver.org/).
47
87
  ## 1.0.1 and earlier
48
88
  For changelog of versions 1.0.1 and earlier, see http://rspec-puppet.com/changelog/
49
89
 
90
+ [2.x]: https://github.com/rodjek/rspec-puppet/compare/v2.3.0...master
91
+ [2.3.0]: https://github.com/rodjek/rspec-puppet/compare/v2.2.0...v2.3.0
92
+ [2.2.0]: https://github.com/rodjek/rspec-puppet/compare/v2.1.0...v2.2.0
50
93
  [2.1.0]: https://github.com/rodjek/rspec-puppet/compare/v2.0.1...v2.1.0
51
94
  [2.0.1]: https://github.com/rodjek/rspec-puppet/compare/v2.0.0...v2.0.1
52
95
  [2.0.0]: https://github.com/rodjek/rspec-puppet/compare/v1.0.1...v2.0.0
data/README.md CHANGED
@@ -1,9 +1,19 @@
1
- # RSpec tests for your Puppet manifests & modules [![Build Status](https://travis-ci.org/rodjek/rspec-puppet.png)](https://travis-ci.org/rodjek/rspec-puppet)
1
+ # RSpec tests for your Puppet manifests & modules
2
+ [![Build Status](https://travis-ci.org/rodjek/rspec-puppet.png)](https://travis-ci.org/rodjek/rspec-puppet)
3
+ [![Coverage Status](https://coveralls.io/repos/rodjek/rspec-puppet/badge.svg?branch=master)](https://coveralls.io/r/rodjek/rspec-puppet?branch=master)
2
4
 
3
5
  ## Installation
4
6
 
5
7
  gem install rspec-puppet
6
8
 
9
+ > Note for ruby 1.8 users: while rspec-puppet itself supports ruby 1.8, you'll
10
+ > need to pin rspec itself to `~> 3.1.0`, as later rspec versions do not work
11
+ > on old rubies anymore.
12
+
13
+ ## Starting out with a new module
14
+
15
+ When you start out on a new module, run `rspec-puppet-init` to create the necessary files to configure rspec-puppet for your module's tests.
16
+
7
17
  ## Naming conventions
8
18
 
9
19
  For clarity and consistency, I recommend that you use the following directory
@@ -31,6 +41,10 @@ structure and naming convention.
31
41
  | |
32
42
  | +-- <function_name>_spec.rb
33
43
  |
44
+ +-- types
45
+ | |
46
+ | +-- <type_name>_spec.rb
47
+ |
34
48
  +-- hosts
35
49
  |
36
50
  +-- <host_name>_spec.rb
@@ -54,6 +68,10 @@ describe 'myfunction', :type => :puppet_function do
54
68
  ...
55
69
  end
56
70
 
71
+ describe 'mytype', :type => :type do
72
+ ...
73
+ end
74
+
57
75
  describe 'myhost.example.com', :type => :host do
58
76
  ...
59
77
  end
@@ -63,76 +81,96 @@ end
63
81
 
64
82
  ### Matchers
65
83
 
84
+ #### Checking if the catalog compiles
85
+
86
+ You can test whether the subject catalog compiles cleanly with `compile`.
87
+
88
+ ```ruby
89
+ it { is_expected.to compile }
90
+ ```
91
+
92
+ To check the error messages of your class, you can check for raised error messages.
93
+
94
+ ```ruby
95
+ it { is_expected.to compile.and_raise_error(/error message match/) }
96
+ ```
97
+
66
98
  #### Checking if a resource exists
67
99
 
68
100
  You can test if a resource exists in the catalogue with the generic
69
101
  `contain_<resource type>` matcher.
70
102
 
71
103
  ```ruby
72
- it { should contain_augeas('bleh') }
104
+ it { is_expected.to contain_augeas('bleh') }
73
105
  ```
74
106
 
75
107
  You can also test if a class has been included in the catalogue with the
76
108
  same matcher.
77
109
 
78
110
  ```ruby
79
- it { should contain_class('foo') }
111
+ it { is_expected.to contain_class('foo') }
80
112
  ```
81
113
 
114
+ Note that rspec-puppet does none of the class name parsing and lookup that the puppet parser would do for you. The matcher only accepts fully qualified classnames without any leading colons. That is a class `foo::bar` will only be matched by `foo::bar`, but not by `::foo::bar`, or `bar` alone.
115
+
82
116
  If your resource type includes :: (e.g.
83
117
  `foo::bar` simply replace the :: with __ (two underscores).
84
118
 
85
119
  ```ruby
86
- it { should contain_foo__bar('baz') }
120
+ it { is_expected.to contain_foo__bar('baz') }
87
121
  ```
88
122
 
89
123
  You can further test the parameters that have been passed to the resources with
90
124
  the generic `with_<parameter>` chains.
91
125
 
92
126
  ```ruby
93
- it { should contain_package('mysql-server').with_ensure('present') }
127
+ it { is_expected.to contain_package('mysql-server').with_ensure('present') }
94
128
  ```
95
129
 
96
130
  If you want to specify that the given parameters should be the only ones passed
97
131
  to the resource, use the `only_with_<parameter>` chains.
98
132
 
99
133
  ```ruby
100
- it { should contain_package('httpd').only_with_ensure('latest') }
134
+ it { is_expected.to contain_package('httpd').only_with_ensure('latest') }
101
135
  ```
102
136
 
103
137
  You can use the `with` method to verify the value of multiple parameters.
104
138
 
105
139
  ```ruby
106
- it do should contain_service('keystone').with(
107
- 'ensure' => 'running',
108
- 'enable' => 'true',
109
- 'hasstatus' => 'true',
110
- 'hasrestart' => 'true'
111
- ) end
140
+ it do
141
+ is_expected.to contain_service('keystone').with(
142
+ 'ensure' => 'running',
143
+ 'enable' => 'true',
144
+ 'hasstatus' => 'true',
145
+ 'hasrestart' => 'true'
146
+ )
147
+ end
112
148
  ```
113
149
 
114
150
  The same holds for the `only_with` method, which in addition verifies the exact
115
151
  set of parameters and values for the resource in the catalogue.
116
152
 
117
153
  ```ruby
118
- it do should contain_user('luke').only_with(
119
- 'ensure' => 'present',
120
- 'uid' => '501'
121
- ) end
154
+ it do
155
+ is_expected.to contain_user('luke').only_with(
156
+ 'ensure' => 'present',
157
+ 'uid' => '501'
158
+ )
159
+ end
122
160
  ```
123
161
 
124
162
  You can also test that specific parameters have been left undefined with the
125
163
  generic `without_<parameter>` chains.
126
164
 
127
165
  ```ruby
128
- it { should contain_file('/foo/bar').without_mode }
166
+ it { is_expected.to contain_file('/foo/bar').without_mode }
129
167
  ```
130
168
 
131
169
  You can use the without method to verify that a list of parameters have not been
132
170
  defined
133
171
 
134
172
  ```ruby
135
- it { should contain_service('keystone').without(
173
+ it { is_expected.to contain_service('keystone').without(
136
174
  ['restart', 'status']
137
175
  )}
138
176
  ```
@@ -143,28 +181,28 @@ You can test the number of resources in the catalogue with the
143
181
  `have_resource_count` matcher.
144
182
 
145
183
  ```ruby
146
- it { should have_resource_count(2) }
184
+ it { is_expected.to have_resource_count(2) }
147
185
  ```
148
186
 
149
187
  The number of classes in the catalogue can be checked with the
150
188
  `have_class_count` matcher.
151
189
 
152
190
  ```ruby
153
- it { should have_class_count(2) }
191
+ it { is_expected.to have_class_count(2) }
154
192
  ```
155
193
 
156
194
  You can also test the number of a specific resource type, by using the generic
157
195
  `have_<resource type>_resource_count` matcher.
158
196
 
159
197
  ```ruby
160
- it { should have_exec_resource_count(1) }
198
+ it { is_expected.to have_exec_resource_count(1) }
161
199
  ```
162
200
 
163
201
  This last matcher also works for defined types. If the resource type contains
164
202
  ::, you can replace it with __ (two underscores).
165
203
 
166
204
  ```ruby
167
- it { should have_logrotate__rule_resource_count(3) }
205
+ it { is_expected.to have_logrotate__rule_resource_count(3) }
168
206
  ```
169
207
 
170
208
  *NOTE*: when testing a class, the catalogue generated will always contain at
@@ -177,19 +215,19 @@ catalogue generated when testing a defined type will have at least one resource
177
215
  The following methods will allow you to test the relationships between the resources in your catalogue, regardless of how the relationship is defined. This means that it doesn’t matter if you prefer to define your relationships with the metaparameters (**require**, **before**, **notify** and **subscribe**) or the chaining arrows (**->**, **~>**, **<-** and **<~**), they’re all tested the same.
178
216
 
179
217
  ```ruby
180
- it { should contain_file('foo').that_requires('File[bar]') }
181
- it { should contain_file('foo').that_comes_before('File[bar]') }
182
- it { should contain_file('foo').that_notifies('File[bar]') }
183
- it { should contain_file('foo').that_subscribes_to('File[bar]') }
218
+ it { is_expected.to contain_file('foo').that_requires('File[bar]') }
219
+ it { is_expected.to contain_file('foo').that_comes_before('File[bar]') }
220
+ it { is_expected.to contain_file('foo').that_notifies('File[bar]') }
221
+ it { is_expected.to contain_file('foo').that_subscribes_to('File[bar]') }
184
222
  ```
185
223
 
186
224
  An array can be used to test a resource for multiple relationships
187
225
 
188
226
  ```ruby
189
- it { should contain_file('foo').that_requires(['File[bar]', 'File[baz]']) }
190
- it { should contain_file('foo').that_comes_before(['File[bar]','File[baz]']) }
191
- it { should contain_file('foo').that_notifies(['File[bar]', 'File[baz]']) }
192
- it { should contain_file('foo').that_subscribes_to(['File[bar]', 'File[baz]']) }
227
+ it { is_expected.to contain_file('foo').that_requires(['File[bar]', 'File[baz]']) }
228
+ it { is_expected.to contain_file('foo').that_comes_before(['File[bar]','File[baz]']) }
229
+ it { is_expected.to contain_file('foo').that_notifies(['File[bar]', 'File[baz]']) }
230
+ it { is_expected.to contain_file('foo').that_subscribes_to(['File[bar]', 'File[baz]']) }
193
231
  ```
194
232
 
195
233
  You can also test the reverse direction of the relationship, so if you have the following bit of Puppet code
@@ -204,14 +242,83 @@ notify { 'bar':
204
242
  You can test that **Notify[bar]** comes before **Notify[foo]**
205
243
 
206
244
  ```ruby
207
- it { should contain_notify('bar').that_comes_before('Notify[foo]') }
245
+ it { is_expected.to contain_notify('bar').that_comes_before('Notify[foo]') }
208
246
  ```
209
247
  Or, you can test that **Notify[foo]** requires **Notify[bar]**
210
248
 
211
249
  ```ruby
212
- it { should contain_notify('foo').that_requires('Notify[bar]') }
250
+ it { is_expected.to contain_notify('foo').that_requires('Notify[bar]') }
251
+ ```
252
+
253
+ ##### Match target syntax
254
+
255
+ Note that this notation does not support any of the features you're used from the puppet language. Only a single resource with a single, unquoted title can be referenced here. Class names need to be always fully qualified and not have the leading `::`. It currently does not support inline arrays or quoting.
256
+
257
+ These work
258
+ * `Notify[foo]`
259
+ * `Class[profile::apache]`
260
+
261
+ These will not work
262
+ * `Notify['foo']`
263
+ * `Notify[foo, bar]`
264
+ * `Class[::profile::apache]`
265
+
266
+ ##### Recursive dependencies
267
+
268
+ The relationship matchers are recursive in two directions:
269
+
270
+ * vertical recursion, which checks for dependencies with parents of the resource
271
+ (i.e. the resource is contained, directly or not, in the class involved in the relationship).
272
+ E.g. where `Package['foo']` comes before `File['/foo']`:
273
+
274
+ ```puppet
275
+ class { 'foo::install': } ->
276
+ class { 'foo::config': }
277
+
278
+ class foo::install {
279
+ package { 'foo': }
280
+ }
281
+
282
+ class foo::config {
283
+ file { '/foo': }
284
+ }
213
285
  ```
214
286
 
287
+ * horizontal recursion, which follows indirect dependencies (dependencies of dependencies).
288
+ E.g. where `Yumrepo['foo']` comes before `File['/foo']`:
289
+
290
+ ```puppet
291
+ class { 'foo::repo': } ->
292
+ class { 'foo::install': } ->
293
+ class { 'foo::config': }
294
+
295
+ class foo::repo {
296
+ yumrepo { 'foo': }
297
+ }
298
+
299
+ class foo::install {
300
+ package { 'foo': }
301
+ }
302
+
303
+ class foo::config {
304
+ file { '/foo': }
305
+ }
306
+ ```
307
+
308
+ ##### Autorequires
309
+
310
+ Autorequires are considered in dependency checks.
311
+
312
+ #### Type matcher
313
+
314
+ When testing custom types, the `be_valid_type` matcher provides a range of expectations:
315
+
316
+ * `with_provider(<provider_name>)`: check that the right provider was selected
317
+ * `with_properties(<property_list>)`: check that the specified properties are available
318
+ * `with_parameters(<parameter_list>)`: check that the specified parameters are available
319
+ * `with_features(<feature_list>)`: check that the specified features are available
320
+ * `with_set_attributes(<param_value_hash>)`: check that the specified attributes are set
321
+
215
322
  ### Writing tests
216
323
 
217
324
  #### Basic test structure
@@ -235,7 +342,7 @@ describe 'sysctl' do
235
342
  let(:title) { 'baz' }
236
343
  let(:params) { { :value => 'foo' } }
237
344
 
238
- it { should contain_exec('sysctl/reload').with_command("/sbin/sysctl -p /etc/sysctl.conf") }
345
+ it { is_expected.to contain_exec('sysctl/reload').with_command("/sbin/sysctl -p /etc/sysctl.conf") }
239
346
  end
240
347
  ```
241
348
 
@@ -245,12 +352,18 @@ end
245
352
  let(:title) { 'foo' }
246
353
  ```
247
354
 
248
- #### Specifying the parameters to pass to a resources or parametised class
355
+ #### Specifying the parameters to pass to a resources or parameterised class
249
356
 
250
357
  ```ruby
251
358
  let(:params) { {:ensure => 'present', ...} }
252
359
  ```
253
360
 
361
+ ##### Passing Puppet's `undef` as a parameter value
362
+
363
+ ```ruby
364
+ let(:params) { {:user => :undef, ...} }
365
+ ```
366
+
254
367
  #### Specifying the FQDN of the test node
255
368
 
256
369
  If the manifest you're testing expects to run on host with a particular name,
@@ -278,6 +391,14 @@ You can set them with a hash
278
391
  let(:facts) { {:operatingsystem => 'Debian', :kernel => 'Linux', ...} }
279
392
  ```
280
393
 
394
+ Facts may be expressed as a value (shown in the previous example) or a structure. Fact keys
395
+ may be expressed as either symbols or strings. A key will be converted to a lower case
396
+ string to align with the Facter standard
397
+
398
+ ```ruby
399
+ let(:facts) { {:os => { :family => 'RedHat', :release => { :major => '7', :minor => '1', :full => '7.1.1503' } } } }
400
+ ```
401
+
281
402
  You can also create a set of default facts provided to all specs in your spec_helper:
282
403
 
283
404
  ``` ruby
@@ -325,7 +446,7 @@ For your convenience though, a `run` matcher exists to provide easier to
325
446
  understand test cases.
326
447
 
327
448
  ```ruby
328
- it { should run.with_params('foo').and_return('bar') }
449
+ it { is_expected.to run.with_params('foo').and_return('bar') }
329
450
  ```
330
451
 
331
452
  ### Writing tests
@@ -354,7 +475,7 @@ You can specify the arguments to pass to your function during the test(s) using
354
475
  either the `with_params` chain method in the `run` matcher
355
476
 
356
477
  ```ruby
357
- it { should run.with_params('foo', 'bar', ['baz']) }
478
+ it { is_expected.to run.with_params('foo', 'bar', ['baz']) }
358
479
  ```
359
480
 
360
481
  Or by using the `call` method on the subject directly
@@ -371,7 +492,7 @@ You can test the result of a function (if it produces one) using either the
371
492
  `and_returns` chain method in the `run` matcher
372
493
 
373
494
  ```ruby
374
- it { should run.with_params('foo').and_return('bar') }
495
+ it { is_expected.to run.with_params('foo').and_return('bar') }
375
496
  ```
376
497
 
377
498
  Or by using any of the existing RSpec matchers on the subject directly
@@ -389,8 +510,8 @@ You can test whether the function throws an exception using either the
389
510
  `and_raises_error` chain method in the `run` matcher
390
511
 
391
512
  ```ruby
392
- it { should run.with_params('a', 'b').and_raise_error(Puppet::ParseError) }
393
- it { should_not run.with_params('a').and_raise_error(Puppet::ParseError) }
513
+ it { is_expected.to run.with_params('a', 'b').and_raise_error(Puppet::ParseError) }
514
+ it { is_expected.not_to run.with_params('a').and_raise_error(Puppet::ParseError) }
394
515
  ```
395
516
 
396
517
  Or by using the existing `raises_error` RSpec matcher
@@ -402,6 +523,16 @@ it 'something' do
402
523
  end
403
524
  ```
404
525
 
526
+ #### Accessing the parser scope where the function is running
527
+
528
+ Some complex functions require access to the current parser's scope, e.g. for
529
+ stubbing other parts of the system.
530
+
531
+ ```ruby
532
+ before(:each) { scope.expects(:lookupvar).with('some_variable').returns('some_value') }
533
+ it { is_expected.to run.with_params('...').and_return('...') }
534
+ ```
535
+
405
536
  ## Hiera integration
406
537
 
407
538
  ### Configuration
@@ -455,6 +586,18 @@ RSpec.configure do |c|
455
586
  end
456
587
  ```
457
588
 
589
+ spec/fixtures/hiera/hiera.yaml
590
+ ```yaml
591
+ ---
592
+ :backends:
593
+ - yaml
594
+ :yaml:
595
+ :datadir: spec/fixtures/hieradata
596
+ :hierarchy:
597
+ - common
598
+ ```
599
+
600
+
458
601
  ## Producing coverage reports
459
602
 
460
603
  You can output a basic resource coverage report with the following in
@@ -467,3 +610,16 @@ at_exit { RSpec::Puppet::Coverage.report! }
467
610
  This checks which Puppet resources have been explicitly checked as part
468
611
  of the current test run and outputs both a coverage percentage and a
469
612
  list of untouched resources.
613
+
614
+ ## Related projects
615
+
616
+ * [puppetlabs_spec_helper](https://github.com/puppetlabs/puppetlabs_spec_helper): shared spec helpers to setup puppet
617
+ * [rspec-puppet-augeas](https://github.com/domcleal/rspec-puppet-augeas): RSpec tests for Augeas resources inside Puppet manifests
618
+ * [jimdo-rspec-puppet-helpers](https://github.com/Jimdo/jimdo-rspec-puppet-helpers): Tests the contents of a file with a source
619
+
620
+ * Fact providers
621
+ * [rspec-puppet-facts](https://github.com/mcanevet/rspec-puppet-facts): Simplify your unit tests by looping on every supported Operating System and populating facts.
622
+ * [rspec-puppet-osmash](https://github.com/Aethylred/rspec-puppet-osmash): Provides Operation System hashes and validations for rspec-puppet
623
+ * [puppet_spec_facts](https://github.com/danieldreier/puppet_spec_facts): Gem to provide puppet fact hashes for rspec-puppet testing
624
+
625
+ For a list of other module development tools see https://puppet.community/plugins/
@@ -0,0 +1,30 @@
1
+ module RSpec::Puppet
2
+ class Cache
3
+
4
+ MAX_ENTRIES = 16
5
+
6
+ # @param [Proc] default_proc The default proc to use to fetch objects on cache miss
7
+ def initialize(&default_proc)
8
+ @default_proc = default_proc
9
+ @cache = {}
10
+ @lra = []
11
+ end
12
+
13
+ def get(*args, &blk)
14
+ if !@cache.has_key? args
15
+ @cache[args] = (blk || @default_proc).call(*args)
16
+ @lra << args
17
+ expire!
18
+ end
19
+
20
+ @cache[args]
21
+ end
22
+
23
+ private
24
+
25
+ def expire!
26
+ expired = @lra.slice!(0, @lra.size - MAX_ENTRIES)
27
+ expired.each { |key| @cache.delete(key) } if expired
28
+ end
29
+ end
30
+ end
@@ -28,31 +28,8 @@ module RSpec::Puppet
28
28
 
29
29
  # add all resources from catalog declared in module test_module
30
30
  def add_from_catalog(catalog, test_module)
31
- catalog.to_a.each do |resource|
32
- # check filters
33
- next if @filters.include?(resource.to_s)
34
- if resource.type == 'Class'
35
- # if the resource is a class, make sure the class belongs to
36
- # module test_module
37
- module_name = resource.title.split('::').first.downcase
38
- next if module_name != test_module
39
- elsif resource.file
40
- # otherwise, the source file should be available, so make
41
- # sure the manifest declaring the resource is in
42
- # test_module's directory tree or the site manifest(s)
43
- if Puppet.version.to_f >= 4.0
44
- paths = [
45
- (Pathname.new(Puppet[:environmentpath]) + 'fixtures' + test_module + 'manifests').to_s,
46
- (Pathname.new(Puppet[:environmentpath]) + 'fixtures' + 'manifests' + 'site.pp').to_s
47
- ]
48
- else
49
- paths = Puppet[:modulepath].split(File::PATH_SEPARATOR).map do |dir|
50
- (Pathname.new(dir) + test_module + 'manifests').to_s
51
- end
52
- paths << Puppet[:manifest]
53
- end
54
- next unless paths.any? { |path| resource.file.include?(path) }
55
- end
31
+ coverable_resources = catalog.to_a.select { |resource| !filter_resource?(resource, test_module) }
32
+ coverable_resources.each do |resource|
56
33
  add(resource)
57
34
  end
58
35
  end
@@ -105,39 +82,91 @@ module RSpec::Puppet
105
82
 
106
83
  private
107
84
 
108
- def find(resource)
109
- @collection[resource.to_s]
85
+ # Should this resource be excluded from coverage reports?
86
+ #
87
+ # The resource is not included in coverage reports if any of the conditions hold:
88
+ #
89
+ # * The resource has been explicitly filtered out.
90
+ # * Examples: autogenerated resources such as 'Stage[main]'
91
+ # * The resource is a class but does not belong to the module under test.
92
+ # * Examples: Class dependencies included from a fixture module
93
+ # * The resource was declared in a file outside of the test module or site.pp
94
+ # * Examples: Resources declared in a dependency of this module.
95
+ #
96
+ # @param resource [Puppet::Resource] The resource that may be filtered
97
+ # @param test_module [String] The name of the module under test
98
+ # @return [true, false]
99
+ def filter_resource?(resource, test_module)
100
+ if @filters.include?(resource.to_s)
101
+ return true
110
102
  end
111
103
 
112
- def exists?(resource)
113
- !find(resource).nil?
104
+ if resource.type == 'Class'
105
+ module_name = resource.title.split('::').first.downcase
106
+ if module_name != test_module
107
+ return true
108
+ end
114
109
  end
115
110
 
116
- class ResourceWrapper
117
- attr_reader :resource
118
-
119
- def initialize(resource = nil)
120
- @resource = resource
111
+ if resource.file
112
+ paths = module_paths(test_module)
113
+ unless paths.any? { |path| resource.file.include?(path) }
114
+ return true
121
115
  end
116
+ end
122
117
 
123
- def to_s
124
- @resource.to_s
125
- end
118
+ return false
119
+ end
126
120
 
127
- def to_hash
128
- {
129
- 'touched' => touched?,
130
- }
121
+ # Find all paths that may contain testable resources for a module.
122
+ #
123
+ # @return [Array<String>]
124
+ def module_paths(test_module)
125
+ if Puppet.version.to_f >= 4.0
126
+ modulepath = RSpec.configuration.module_path || File.join(Puppet[:environmentpath], 'fixtures', 'modules')
127
+ manifest = RSpec.configuration.manifest || File.join(Puppet[:environmentpath], 'fixtures', 'manifests', 'site.pp')
128
+ paths = [File.join(modulepath, test_module, 'manifests'), manifest]
129
+ else
130
+ paths = Puppet[:modulepath].split(File::PATH_SEPARATOR).map do |dir|
131
+ File.join(dir, test_module, 'manifests')
131
132
  end
133
+ paths << Puppet[:manifest]
134
+ end
135
+ paths
136
+ end
132
137
 
133
- def touch!
134
- @touched = true
135
- end
138
+ def find(resource)
139
+ @collection[resource.to_s]
140
+ end
136
141
 
137
- def touched?
138
- !!@touched
139
- end
142
+ def exists?(resource)
143
+ !find(resource).nil?
144
+ end
145
+
146
+ class ResourceWrapper
147
+ attr_reader :resource
148
+
149
+ def initialize(resource = nil)
150
+ @resource = resource
151
+ end
152
+
153
+ def to_s
154
+ @resource.to_s
140
155
  end
141
156
 
157
+ def to_hash
158
+ {
159
+ 'touched' => touched?,
160
+ }
161
+ end
162
+
163
+ def touch!
164
+ @touched = true
165
+ end
166
+
167
+ def touched?
168
+ !!@touched
169
+ end
170
+ end
142
171
  end
143
172
  end