rspec-puppet 2.7.8 → 2.10.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
  SHA256:
3
- metadata.gz: dd000960b92cf4b8a24b042dd07d4d91bd333b98f83a554e6b7bb8cf776deb40
4
- data.tar.gz: ab87e51803b7ec899ca1389041f00b39a8766b76a141a673e3058c3ed22bc677
3
+ metadata.gz: 5080461a94379bc7c865bed5eaa5584f911379ea08bdf7af878ffd24ff23424c
4
+ data.tar.gz: eac73ffab8b13a3ded43d3533c4c454a168d61511f8b73bea4fb94227232cb66
5
5
  SHA512:
6
- metadata.gz: f1730e3df44bebb5b49f9cd9c83ae1aac317398568002e9777d25c4a34105be371e5f9683ccb07cdd36fb6891aaee1a045837e9a9e5be034e8bbb4b5acf83cc6
7
- data.tar.gz: 29056e119989fdaf2e16eea9bb7208caf5b551431098194ed9f4f42697ef512d1ef47594fb3c9d3f1a2f2aa7af655be8ca76a3de45720bf824a719ba17a860d1
6
+ metadata.gz: 7b5c1d81b22bca79e3b5c7edde653396d7cbc3506c66d60d69be618066fcdbe75782b29adffe35f89046dafcb3b7db2faec5b30a25eb6b57f5d91d1e12631bf8
7
+ data.tar.gz: 35833aa537d9f12c11131108bd2f664e74e0ea47f8d8c7029efd9a86c2b344c2ea3a9dfe10dca91eb96efe2128ba748320b805ea4778ed72b8578cda7069c634
data/CHANGELOG.md CHANGED
@@ -2,6 +2,66 @@
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.10.0]
6
+ The release sees rspec-puppet move into the puppetlabs namespace
7
+
8
+ ### Added
9
+ * Add ruby 3 support ([GH-11](https://github.com/puppetlabs/rspec-puppet/pull/11))
10
+
11
+ ## [2.9.0]
12
+
13
+ ### Added
14
+ * Allow users to disable app_management for Puppet 4
15
+ * Added support for regexp arguments to Sensitive
16
+ * Handle all auto*, not just autorequire
17
+ * Set up loaders so that 4.x functions resolve properly
18
+
19
+ ## [2.8.0]
20
+
21
+ ### Breaking Changes
22
+ * As of the 2.8.0 release, the `rspec-puppet` project no longer guarantees compatibility
23
+ with Puppet 2.x or 3.x (running under Ruby 1.8.7) or Puppet 4.x (running under Ruby 1.9.3).
24
+ * This release adds support for the [`Sensitive`](https://puppet.com/docs/puppet/latest/lang_data_sensitive.html)
25
+ data type, however existing tests that were expecting `String` content may need to be updated
26
+ to wrap the expected value in the new `sensitive` helper:
27
+
28
+ ```ruby
29
+ # Old
30
+ it { is_expected.to contain_file('/etc/mysecret.conf').with_content("top secret\n") }
31
+
32
+ # New
33
+ it { is_expected.to contain_file('/etc/mysecret.conf').with_content(sensitive("top secret\n")) }
34
+ ```
35
+
36
+ ### Added
37
+ * Added support for [trusted external fact data](https://github.com/puppetlabs/rspec-puppet#specifying-trusted-external-data).
38
+ * Added the ability to exclude resources from the coverage report calculations using a regular expression.
39
+ (See [documentation](https://rspec-puppet.com/documentation/coverage/#excluded-resources) for an example.
40
+ * Added `have_unique_values_for_all` matcher to assert a specific resource parameter value is unique across
41
+ the entire catalogue.
42
+ (See [documentation](https://rspec-puppet.com/documentation/classes/#test-resource-parameter-values-for-uniqueness).)
43
+ * Added ability to customize module-layer Hiera configuration via new settings. See
44
+ [documentation](https://rspec-puppet.com/documentation/configuration/#disable_module_hiera) for details.
45
+
46
+ ### Changed
47
+ * `RSpec::Puppet::Cache` now evicts least recently used entries when it reaches max size.
48
+ * `rspec-puppet`'s implementation of `match_manifests` will no longer look in `init.pp` for class
49
+ declarations if a manifest file exactly matching the class name exists.
50
+
51
+ ### Fixed
52
+ * Resolved compatibility issues with Ruby 2.7.x and added Ruby 2.7.x to the test matrix.
53
+ * Resolved issues calculating coverage and reporting results when there are 0 tested resources.
54
+ * Resolved compatibility issue with `rspec-expectations` 3.10.0.
55
+
56
+ ## [2.7.10]
57
+
58
+ ### Fixed
59
+ * Fix issues with removal of `default_env` method in Puppet 6.17.0.
60
+
61
+ ## [2.7.9]
62
+
63
+ This release had unintended breaking changes and was withdrawn.
64
+
5
65
  ## [2.7.8]
6
66
 
7
67
  ### Fixed
@@ -500,13 +560,43 @@ Thanks to Adrien Thebo, Alex Harvey, Brian, Dan Bode, Dominic Cleal, Javier Pala
500
560
  ## 1.0.1 and earlier
501
561
  For changelog of versions 1.0.1 and earlier, see http://rspec-puppet.com/changelog/
502
562
 
503
- [2.x]: https://github.com/rodjek/rspec-puppet/compare/v2.5.0...master
504
- [2.5.0]: https://github.com/rodjek/rspec-puppet/compare/v2.4.0...v2.5.0
505
- [2.4.0]: https://github.com/rodjek/rspec-puppet/compare/v2.3.2...v2.4.0
506
- [2.3.2]: https://github.com/rodjek/rspec-puppet/compare/v2.3.1...v2.3.2
507
- [2.3.1]: https://github.com/rodjek/rspec-puppet/compare/v2.3.0...v2.3.1
508
- [2.3.0]: https://github.com/rodjek/rspec-puppet/compare/v2.2.0...v2.3.0
509
- [2.2.0]: https://github.com/rodjek/rspec-puppet/compare/v2.1.0...v2.2.0
510
- [2.1.0]: https://github.com/rodjek/rspec-puppet/compare/v2.0.1...v2.1.0
511
- [2.0.1]: https://github.com/rodjek/rspec-puppet/compare/v2.0.0...v2.0.1
512
- [2.0.0]: https://github.com/rodjek/rspec-puppet/compare/v1.0.1...v2.0.0
563
+ [2.x]: https://github.com/puppetlabs/rspec-puppet/compare/v2.10.0...master
564
+ [2.10.0]: https://github.com/puppetlabs/rspec-puppet/compare/v2.9.0...v2.10.0
565
+ [2.9.0]: https://github.com/puppetlabs/rspec-puppet/compare/v2.8.0...v2.9.0
566
+ [2.8.0]: https://github.com/puppetlabs/rspec-puppet/compare/v2.7.10...v2.8.0
567
+ [2.7.10]: https://github.com/puppetlabs/rspec-puppet/compare/v2.7.9...v2.7.10
568
+ [2.7.9]: https://github.com/puppetlabs/rspec-puppet/compare/v2.7.8...v2.7.9
569
+ [2.7.8]: https://github.com/puppetlabs/rspec-puppet/compare/v2.7.7...v2.7.8
570
+ [2.7.7]: https://github.com/puppetlabs/rspec-puppet/compare/v2.7.6...v2.7.7
571
+ [2.7.6]: https://github.com/puppetlabs/rspec-puppet/compare/v2.7.5...v2.7.6
572
+ [2.7.5]: https://github.com/puppetlabs/rspec-puppet/compare/v2.7.4...v2.7.5
573
+ [2.7.4]: https://github.com/puppetlabs/rspec-puppet/compare/v2.7.3...v2.7.4
574
+ [2.7.3]: https://github.com/puppetlabs/rspec-puppet/compare/v2.7.2...v2.7.3
575
+ [2.7.2]: https://github.com/puppetlabs/rspec-puppet/compare/v2.7.1...v2.7.2
576
+ [2.7.1]: https://github.com/puppetlabs/rspec-puppet/compare/v2.7.0...v2.7.1
577
+ [2.7.0]: https://github.com/puppetlabs/rspec-puppet/compare/v2.6.15...v2.7.0
578
+ [2.6.15]: https://github.com/puppetlabs/rspec-puppet/compare/v2.6.14...v2.6.15
579
+ [2.6.14]: https://github.com/puppetlabs/rspec-puppet/compare/v2.6.13...v2.6.14
580
+ [2.6.13]: https://github.com/puppetlabs/rspec-puppet/compare/v2.6.12...v2.6.13
581
+ [2.6.12]: https://github.com/puppetlabs/rspec-puppet/compare/v2.6.11...v2.6.12
582
+ [2.6.11]: https://github.com/puppetlabs/rspec-puppet/compare/v2.6.10...v2.6.11
583
+ [2.6.10]: https://github.com/puppetlabs/rspec-puppet/compare/v2.6.9...v2.6.10
584
+ [2.6.9]: https://github.com/puppetlabs/rspec-puppet/compare/v2.6.8...v2.6.9
585
+ [2.6.8]: https://github.com/puppetlabs/rspec-puppet/compare/v2.6.7...v2.6.8
586
+ [2.6.7]: https://github.com/puppetlabs/rspec-puppet/compare/v2.6.6...v2.6.7
587
+ [2.6.6]: https://github.com/puppetlabs/rspec-puppet/compare/v2.6.5...v2.6.6
588
+ [2.6.5]: https://github.com/puppetlabs/rspec-puppet/compare/v2.6.4...v2.6.5
589
+ [2.6.4]: https://github.com/puppetlabs/rspec-puppet/compare/v2.6.3...v2.6.4
590
+ [2.6.3]: https://github.com/puppetlabs/rspec-puppet/compare/v2.6.2...v2.6.3
591
+ [2.6.2]: https://github.com/puppetlabs/rspec-puppet/compare/v2.6.1...v2.6.2
592
+ [2.6.1]: https://github.com/puppetlabs/rspec-puppet/compare/v2.6.0...v2.6.1
593
+ [2.6.0]: https://github.com/puppetlabs/rspec-puppet/compare/2.5.0...v2.6.0
594
+ [2.5.0]: https://github.com/puppetlabs/rspec-puppet/compare/v2.4.0...v2.5.0
595
+ [2.4.0]: https://github.com/puppetlabs/rspec-puppet/compare/v2.3.2...v2.4.0
596
+ [2.3.2]: https://github.com/puppetlabs/rspec-puppet/compare/v2.3.1...v2.3.2
597
+ [2.3.1]: https://github.com/puppetlabs/rspec-puppet/compare/v2.3.0...v2.3.1
598
+ [2.3.0]: https://github.com/puppetlabs/rspec-puppet/compare/v2.2.0...v2.3.0
599
+ [2.2.0]: https://github.com/puppetlabs/rspec-puppet/compare/v2.1.0...v2.2.0
600
+ [2.1.0]: https://github.com/puppetlabs/rspec-puppet/compare/v2.0.1...v2.1.0
601
+ [2.0.1]: https://github.com/puppetlabs/rspec-puppet/compare/v2.0.0...v2.0.1
602
+ [2.0.0]: https://github.com/puppetlabs/rspec-puppet/compare/v1.0.1...v2.0.0
data/README.md CHANGED
@@ -2,6 +2,20 @@
2
2
  [![Build Status](https://travis-ci.org/rodjek/rspec-puppet.svg?branch=master)](https://travis-ci.org/rodjek/rspec-puppet)
3
3
  [![Coverage Status](https://coveralls.io/repos/rodjek/rspec-puppet/badge.svg?branch=master)](https://coveralls.io/r/rodjek/rspec-puppet?branch=master)
4
4
 
5
+ #### Table of Contents
6
+
7
+ * [Installation](#installation)
8
+ * [Starting out with a new module](#starting-out-with-a-new-module)
9
+ * [Configure manifests for Puppet 4](#configure-manifests-for-puppet-4)
10
+ * [Configuration](#configuration)
11
+ * [Naming conventions](#naming-conventions)
12
+ * [Example groups](#example-groups)
13
+ * [Defined Types, Classes & Applications](#defined-types-classes--applications)
14
+ * [Functions](#functions)
15
+ * [Hiera integration](#hiera-integration)
16
+ * [Producing coverage reports](#producing-coverage-reports)
17
+ * [Related projects](#related-projects)
18
+
5
19
  ## Installation
6
20
 
7
21
  gem install rspec-puppet
@@ -759,6 +773,30 @@ RSpec.configure do |c|
759
773
  end
760
774
  ```
761
775
 
776
+ #### Specifying trusted external data
777
+
778
+ When testing with Puppet >= 6.14, the trusted facts hash will have an additional `external`
779
+ key for trusted external data.
780
+
781
+ By default, the test environment contains no trusted external data (as usually obtained from
782
+ trusted external commands and found in the `external` key). If you need to test against specific
783
+ trusted external data you can set those with a hash. The hash will then be available in
784
+ `$trusted['external']`
785
+
786
+ ```ruby
787
+ let(:trusted_external_data) { {'foo' => 'bar'} }
788
+ ```
789
+
790
+ You can also create a set of default trusted external data provided to all specs in your spec_helper:
791
+
792
+ ```ruby
793
+ RSpec.configure do |c|
794
+ c.default_trusted_external_data = {
795
+ 'foo' => 'bar'
796
+ }
797
+ end
798
+ ```
799
+
762
800
  #### Testing Exported Resources
763
801
 
764
802
  You can test if a resource was exported from the catalogue by using the
data/lib/rspec-puppet.rb CHANGED
@@ -42,6 +42,7 @@ RSpec.configure do |c|
42
42
  c.add_setting :default_facts, :default => {}
43
43
  c.add_setting :default_node_params, :default => {}
44
44
  c.add_setting :default_trusted_facts, :default => {}
45
+ c.add_setting :default_trusted_external_data, :default => {}
45
46
  c.add_setting :hiera_config, :default => Puppet::Util::Platform.actually_windows? ? 'c:/nul/' : '/dev/null'
46
47
  c.add_setting :parser, :default => 'current'
47
48
  c.add_setting :trusted_node_data, :default => false
@@ -54,6 +55,10 @@ RSpec.configure do |c|
54
55
  c.add_setting :platform, :default => Puppet::Util::Platform.actual_platform
55
56
  c.add_setting :vendormoduledir, :default => Puppet::Util::Platform.actually_windows? ? 'c:/nul/' : '/dev/null'
56
57
  c.add_setting :basemodulepath, :default => Puppet::Util::Platform.actually_windows? ? 'c:/nul/' : '/dev/null'
58
+ c.add_setting :disable_module_hiera, :default => false
59
+ c.add_setting :fixture_hiera_configs, :default => {}
60
+ c.add_setting :use_fixture_spec_hiera, :default => false
61
+ c.add_setting :fallback_to_default_hiera, :default => true
57
62
 
58
63
  c.instance_eval do
59
64
  def trusted_server_facts
@@ -139,7 +139,8 @@ module RSpec::Puppet
139
139
  Puppet.push_context(
140
140
  {
141
141
  :environments => loader,
142
- :current_environment => env
142
+ :current_environment => env,
143
+ :loaders => (Puppet::Pops::Loaders.new(env) if Gem::Version.new(Puppet.version) >= Gem::Version.new('6.0.0')),
143
144
  },
144
145
  "Setup rspec-puppet environments"
145
146
  )
@@ -11,12 +11,17 @@ module RSpec::Puppet
11
11
  end
12
12
 
13
13
  def get(*args, &blk)
14
- # decouple the hash key from whatever the blk might do to it
15
14
  key = Marshal.load(Marshal.dump(args))
16
- if !@cache.has_key? key
17
- @cache[key] = (blk || @default_proc).call(*args)
18
- @lra << key
15
+ if @cache.has_key?(key)
16
+ # Cache hit
17
+ # move that entry last to make it "most recenty used"
18
+ @lra.insert(-1, @lra.delete_at(@lra.index(args)))
19
+ else
20
+ # Cache miss
21
+ # Ensure room by evicting least recently used if no space left
19
22
  expire!
23
+ @cache[args] = (blk || @default_proc).call(*args)
24
+ @lra << args
20
25
  end
21
26
 
22
27
  @cache[key]
@@ -25,8 +30,8 @@ module RSpec::Puppet
25
30
  private
26
31
 
27
32
  def expire!
28
- expired = @lra.slice!(0, @lra.size - MAX_ENTRIES)
29
- expired.each { |key| @cache.delete(key) } if expired
33
+ # delete one entry (the oldest) when there is no room in cache
34
+ @cache.delete(@lra.shift) if @cache.size == MAX_ENTRIES
30
35
  end
31
36
  end
32
37
  end
@@ -17,13 +17,25 @@ end
17
17
  module RSpec::Puppet
18
18
  class Coverage
19
19
 
20
- attr_accessor :filters
20
+ attr_accessor :filters, :filters_regex
21
21
 
22
22
  class << self
23
23
  extend Forwardable
24
- def_delegators(:instance, :add, :cover!, :report!,
25
- :filters, :add_filter, :add_from_catalog,
26
- :results)
24
+
25
+ delegated_methods = [
26
+ :instance,
27
+ :add,
28
+ :cover!,
29
+ :report!,
30
+ :filters,
31
+ :filters_regex,
32
+ :add_filter,
33
+ :add_filter_regex,
34
+ :add_from_catalog,
35
+ :results,
36
+ ]
37
+
38
+ def_delegators(*delegated_methods)
27
39
 
28
40
  attr_writer :instance
29
41
 
@@ -35,6 +47,7 @@ module RSpec::Puppet
35
47
  def initialize
36
48
  @collection = {}
37
49
  @filters = ['Stage[main]', 'Class[Settings]', 'Class[main]', 'Node[default]']
50
+ @filters_regex = []
38
51
  end
39
52
 
40
53
  def save_results
@@ -42,6 +55,9 @@ module RSpec::Puppet
42
55
  File.open(File.join(Dir.tmpdir, "rspec-puppet-filter-#{slug}"), 'w+') do |f|
43
56
  f.puts @filters.to_json
44
57
  end
58
+ File.open(File.join(Dir.tmpdir, "rspec-puppet-filter_regex-#{slug}"), 'w+') do |f|
59
+ f.puts @filters_regex.to_json
60
+ end
45
61
  File.open(File.join(Dir.tmpdir, "rspec-puppet-coverage-#{slug}"), 'w+') do |f|
46
62
  f.puts @collection.to_json
47
63
  end
@@ -57,10 +73,17 @@ module RSpec::Puppet
57
73
 
58
74
  def merge_filters
59
75
  pattern = File.join(Dir.tmpdir, "rspec-puppet-filter-#{Digest::MD5.hexdigest(Dir.pwd)}-*")
76
+ regex_filter_pattern = File.join(Dir.tmpdir, "rspec-puppet-filter_regex-#{Digest::MD5.hexdigest(Dir.pwd)}-*")
77
+
60
78
  Dir[pattern].each do |result_file|
61
79
  load_filters(result_file)
62
80
  FileUtils.rm(result_file)
63
81
  end
82
+
83
+ Dir[regex_filter_pattern].each do |result_file|
84
+ load_filters_regex(result_file)
85
+ FileUtils.rm(result_file)
86
+ end
64
87
  end
65
88
 
66
89
  def load_results(path)
@@ -79,6 +102,15 @@ module RSpec::Puppet
79
102
  end
80
103
  end
81
104
 
105
+ def load_filters_regex(path)
106
+ saved_regex_filters = JSON.parse(File.read(path))
107
+ saved_regex_filters.each do |pattern|
108
+ regex = Regexp.new(pattern)
109
+ @filters_regex << regex
110
+ @collection.delete_if { |resource, _| resource =~ regex }
111
+ end
112
+ end
113
+
82
114
  def add(resource)
83
115
  if !exists?(resource) && !filtered?(resource)
84
116
  @collection[resource.to_s] = ResourceWrapper.new(resource)
@@ -86,11 +118,8 @@ module RSpec::Puppet
86
118
  end
87
119
 
88
120
  def add_filter(type, title)
89
- def capitalize_name(name)
90
- name.split('::').map { |subtitle| subtitle.capitalize }.join('::')
91
- end
92
-
93
121
  type = capitalize_name(type)
122
+
94
123
  if type == 'Class'
95
124
  title = capitalize_name(title)
96
125
  end
@@ -98,6 +127,34 @@ module RSpec::Puppet
98
127
  @filters << "#{type}[#{title}]"
99
128
  end
100
129
 
130
+ def add_filter_regex(type, pattern)
131
+ raise ArgumentError.new('pattern argument must be a Regexp') unless pattern.is_a?(Regexp)
132
+
133
+ type = capitalize_name(type)
134
+
135
+ # avoid recompiling the regular expression during processing
136
+ src = pattern.source
137
+
138
+ # switch from anchors to wildcards since it is embedded into a larger pattern
139
+ src = if src.start_with?('\\A', '^')
140
+ src.gsub(/\A(?:\\A|\^)/, '')
141
+ else
142
+ # no anchor at the start
143
+ ".*#{src}"
144
+ end
145
+
146
+ # match an even number of backslashes before the anchor - this indicates that the anchor was not escaped
147
+ # note the necessity for the negative lookbehind `(?<!)` to assert that there is no backslash before this
148
+ src = if src.match(/(?<!\\)(\\\\)*(?:\\[zZ]|\$)\z/)
149
+ src.gsub(/(?:\\[zZ]|\$)\z/, '')
150
+ else
151
+ # no anchor at the end
152
+ "#{src}.*"
153
+ end
154
+
155
+ @filters_regex << /\A#{Regexp.escape(type)}\[#{src}\]\z/
156
+ end
157
+
101
158
  # add all resources from catalog declared in module test_module
102
159
  def add_from_catalog(catalog, test_module)
103
160
  coverable_resources = catalog.to_a.reject { |resource| !test_module.nil? && filter_resource?(resource, test_module) }
@@ -107,7 +164,10 @@ module RSpec::Puppet
107
164
  end
108
165
 
109
166
  def filtered?(resource)
110
- filters.include?(resource.to_s)
167
+ return true if filters.include?(resource.to_s)
168
+ return true if filters_regex.any? { |f| resource.to_s =~ f }
169
+
170
+ false
111
171
  end
112
172
 
113
173
  def cover!(resource)
@@ -136,7 +196,7 @@ module RSpec::Puppet
136
196
  end
137
197
 
138
198
  def run_report(coverage_desired = nil)
139
- if ENV['TEST_ENV_NUMBER']
199
+ if parallel_tests?
140
200
  merge_filters
141
201
  merge_results
142
202
  end
@@ -145,7 +205,7 @@ module RSpec::Puppet
145
205
 
146
206
  coverage_test(coverage_desired, report)
147
207
 
148
- puts report[:text]
208
+ puts "\n\nCoverage Report:\n\n#{report[:text]}"
149
209
  end
150
210
 
151
211
  def coverage_test(coverage_desired, report)
@@ -187,7 +247,9 @@ module RSpec::Puppet
187
247
  report[:total] = @collection.size
188
248
  report[:touched] = @collection.count { |_, resource| resource.touched? }
189
249
  report[:untouched] = report[:total] - report[:touched]
190
- report[:coverage] = "%5.2f" % ((report[:touched].to_f / report[:total].to_f) * 100)
250
+
251
+ coverage = report[:total].to_f > 0 ? ((report[:touched].to_f / report[:total].to_f) * 100) : 100.0
252
+ report[:coverage] = "%5.2f" % coverage
191
253
 
192
254
  report[:resources] = Hash[*@collection.map do |name, wrapper|
193
255
  [name, wrapper.to_hash]
@@ -226,7 +288,7 @@ module RSpec::Puppet
226
288
  # @param test_module [String] The name of the module under test
227
289
  # @return [true, false]
228
290
  def filter_resource?(resource, test_module)
229
- if @filters.include?(resource.to_s)
291
+ if filtered?(resource)
230
292
  return true
231
293
  end
232
294
 
@@ -267,6 +329,10 @@ module RSpec::Puppet
267
329
  !find(resource).nil?
268
330
  end
269
331
 
332
+ def capitalize_name(name)
333
+ name.split('::').map { |subtitle| subtitle.capitalize }.join('::')
334
+ end
335
+
270
336
  class ResourceWrapper
271
337
  attr_reader :resource
272
338
 
@@ -7,3 +7,4 @@ require 'rspec-puppet/matchers/dynamic_matchers'
7
7
  require 'rspec-puppet/matchers/type_matchers'
8
8
  require 'rspec-puppet/matchers/allow_value'
9
9
  require 'rspec-puppet/matchers/raise_error'
10
+ require 'rspec-puppet/matchers/unique_values'
@@ -7,13 +7,15 @@ module RSpec::Puppet
7
7
  'Stage[main]',
8
8
  ].freeze
9
9
 
10
+ attr_reader :resource_type
11
+
10
12
  def initialize(type, count, *method)
11
13
  if type.nil?
12
14
  @type = method[0].to_s.gsub(/^have_(.+)_resource_count$/, '\1')
13
15
  else
14
16
  @type = type
15
17
  end
16
- @referenced_type = referenced_type(@type)
18
+ @resource_type = referenced_type(@type)
17
19
  @expected_number = count.to_i
18
20
  end
19
21
 
@@ -30,7 +32,7 @@ module RSpec::Puppet
30
32
  end
31
33
  else
32
34
  resources.count do |res|
33
- res.type == @referenced_type
35
+ res.type == @resource_type
34
36
  end
35
37
  end
36
38
 
@@ -45,7 +47,7 @@ module RSpec::Puppet
45
47
  desc << "#{@expected_number == 1 ? "class" : "classes" }"
46
48
  else
47
49
  unless @type == "resource"
48
- desc << "#{@referenced_type}"
50
+ desc << "#{@resource_type}"
49
51
  end
50
52
  desc << "#{@expected_number == 1 ? "resource" : "resources" }"
51
53
  end
@@ -89,6 +89,11 @@ module RSpec::Puppet
89
89
  else
90
90
  RSpec::Puppet::Coverage.cover!(resource)
91
91
  rsrc_hsh = resource.to_hash
92
+ if resource.respond_to?(:sensitive_parameters)
93
+ resource.sensitive_parameters.each do |s_param|
94
+ rsrc_hsh[s_param] = ::Puppet::Pops::Types::PSensitiveType::Sensitive.new(rsrc_hsh[s_param])
95
+ end
96
+ end
92
97
 
93
98
  if resource.builtin_type?
94
99
  namevar = resource.resource_type.key_attributes.first.to_s
@@ -302,14 +307,17 @@ module RSpec::Puppet
302
307
  end
303
308
  end
304
309
 
305
- # Add autorequires if any
306
- if type == :require and resource.resource_type.respond_to? :eachautorequire
307
- resource.resource_type.eachautorequire do |t, b|
308
- Array(resource.to_ral.instance_eval(&b)).each do |dep|
309
- res = "#{t.to_s.capitalize}[#{dep}]"
310
- if r = relationship_refs(res, type, visited)
311
- results << res
312
- results << r
310
+ # Add auto* (autorequire etc) if any
311
+ if [:before, :notify, :require, :subscribe].include?(type)
312
+ func = "eachauto#{type}".to_sym
313
+ if resource.resource_type.respond_to?(func)
314
+ resource.resource_type.send(func) do |t, b|
315
+ Array(resource.to_ral.instance_eval(&b)).each do |dep|
316
+ res = "#{t.to_s.capitalize}[#{dep}]"
317
+ if r = relationship_refs(res, type, visited)
318
+ results << res
319
+ results << r
320
+ end
313
321
  end
314
322
  end
315
323
  end
@@ -4,7 +4,7 @@ module RSpec::Puppet
4
4
 
5
5
  matcher :include_class do |expected_class|
6
6
  match do |catalogue|
7
- RSpec.deprecate(:include_class, :replacement => :contain_class)
7
+ RSpec.deprecate('include_class()', :replacement => 'contain_class()')
8
8
  catalogue.call.classes.include?(expected_class)
9
9
  end
10
10
 
@@ -21,10 +21,7 @@ module RSpec::Puppet
21
21
  #
22
22
  # @return [true, false]
23
23
  def matches?(resource)
24
-
25
- @resource = resource
26
-
27
- actual = @resource[@parameter]
24
+ actual = resource[@parameter]
28
25
  expected = @value
29
26
 
30
27
  # Puppet flattens an array with a single value into just the value and
@@ -65,6 +62,8 @@ module RSpec::Puppet
65
62
  check_hash(expected, actual)
66
63
  when Array
67
64
  check_array(expected, actual)
65
+ when RSpec::Puppet::Sensitive
66
+ expected == actual
68
67
  else
69
68
  check_string(expected, actual)
70
69
  end
@@ -16,8 +16,8 @@ module RSpec::Puppet
16
16
  end
17
17
  end
18
18
 
19
- def raise_error(*args, &block)
20
- RaiseError.new(*args, &block)
19
+ def raise_error(error=defined?(RSpec::Matchers::BuiltIn::RaiseError::UndefinedValue) ? RSpec::Matchers::BuiltIn::RaiseError::UndefinedValue : nil, message=nil, &block)
20
+ RaiseError.new(error, message, &block)
21
21
  end
22
22
  end
23
23
  end
@@ -52,9 +52,6 @@ module RSpec::Puppet
52
52
  self
53
53
  end
54
54
 
55
- #def with_autorequires(autorequires))
56
- #end
57
-
58
55
  #
59
56
  # this is the method that drives all of the validation
60
57
  #
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RSpec
4
+ module Puppet
5
+ module ManifestMatchers
6
+ extend RSpec::Matchers::DSL
7
+
8
+ matcher :have_unique_values_for_all do |type, attribute|
9
+ match do |catalogue|
10
+ catalogue.call.resources.select { |rsrc| rsrc.type == type.capitalize }
11
+ .group_by { |rsrc| rsrc[attribute.to_sym] }
12
+ .all? { |_, group| group.size == 1 }
13
+ end
14
+
15
+ description do
16
+ "have unique attribute values for #{type.capitalize}[#{attribute.to_sym}]"
17
+ end
18
+
19
+ if RSpec::Version::STRING < '3'
20
+ failure_message_for_should do |_actual|
21
+ "expected that the catalogue would have no duplicate values for #{type.capitalize}[#{attribute.to_sym}]"
22
+ end
23
+ else
24
+ failure_message do |_actual|
25
+ "expected that the catalogue would have no duplicate values for #{type.capitalize}[#{attribute.to_sym}]"
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -132,6 +132,16 @@ module Puppet
132
132
  end
133
133
 
134
134
  module Util
135
+ # Fix for removal of default_env function
136
+ # Bug: https://github.com/rodjek/rspec-puppet/issues/796
137
+ # Upstream: https://github.com/puppetlabs/puppet/commit/94df3c1a3992d89b2d7d5db8a70373c135bdd86b
138
+ if !respond_to?(:default_env)
139
+ def default_env()
140
+ DEFAULT_ENV
141
+ end
142
+ module_function :default_env
143
+ end
144
+
135
145
  if respond_to?(:get_env)
136
146
  alias :old_get_env :get_env
137
147
  module_function :old_get_env
@@ -258,6 +268,40 @@ module Puppet
258
268
  end
259
269
  end
260
270
  end
271
+
272
+ if Puppet::Util::Package.versioncmp(Puppet.version, '4.9.0') >= 0
273
+ class Module
274
+ old_hiera_conf_file = instance_method(:hiera_conf_file)
275
+ define_method(:hiera_conf_file) do
276
+ if RSpec::Puppet.rspec_puppet_example?
277
+ if RSpec.configuration.disable_module_hiera
278
+ return nil
279
+ elsif RSpec.configuration.fixture_hiera_configs.key?(name)
280
+ config = RSpec.configuration.fixture_hiera_configs[name]
281
+ config = File.absolute_path(config, path) unless config.nil?
282
+ return config
283
+ elsif RSpec.configuration.use_fixture_spec_hiera
284
+ config = RSpec::Puppet.current_example.fixture_spec_hiera_conf(self)
285
+ return config unless config.nil? && RSpec.configuration.fallback_to_default_hiera
286
+ end
287
+ end
288
+ old_hiera_conf_file.bind(self).call
289
+ end
290
+ end
291
+
292
+ class Pops::Lookup::ModuleDataProvider
293
+ old_configuration_path = instance_method(:configuration_path)
294
+ define_method(:configuration_path) do |lookup_invocation|
295
+ if RSpec::Puppet.rspec_puppet_example?
296
+ env = lookup_invocation.scope.environment
297
+ mod = env.module(module_name)
298
+ raise Puppet::DataBinding::LookupError, _("Environment '%{env}', cannot find module '%{module_name}'") % { :env => env.name, :module_name => module_name } unless mod
299
+ return Pathname.new(mod.hiera_conf_file)
300
+ end
301
+ old_configuration_path.bind(self).call(lookup_invocation)
302
+ end
303
+ end
304
+ end
261
305
  end
262
306
 
263
307
  class Pathname
@@ -292,6 +336,24 @@ class Pathname
292
336
  end
293
337
  end
294
338
 
339
+ # Puppet loads init.pp, then foo.pp, to find class "mod::foo". If
340
+ # class "mod" has been mocked using pre_condition when testing
341
+ # "mod::foo", this causes duplicate declaration for "mod".
342
+ # This monkey patch only loads "init.pp" if "foo.pp" does not exist.
343
+ class Puppet::Module
344
+ if [:match_manifests, 'match_manifests'].any? { |r| instance_methods.include?(r) }
345
+ old_match_manifests = instance_method(:match_manifests)
346
+
347
+ define_method(:match_manifests) do |rest|
348
+ result = old_match_manifests.bind(self).call(rest)
349
+ if result.length > 1 && File.basename(result[0]) == 'init.pp'
350
+ result.shift
351
+ end
352
+ result
353
+ end
354
+ end
355
+ end
356
+
295
357
  # Prevent the File type from munging paths (which uses File.expand_path to
296
358
  # normalise paths, which does very bad things to *nix paths on Windows.
297
359
  file_path_munge = Puppet::Type.type(:file).paramclass(:path).instance_method(:unsafe_munge)
@@ -0,0 +1,51 @@
1
+ module RSpec::Puppet
2
+ if defined?(::Puppet::Pops::Types::PSensitiveType::Sensitive)
3
+ # A wrapper representing Sensitive data type, eg. in class params.
4
+ class Sensitive < ::Puppet::Pops::Types::PSensitiveType::Sensitive
5
+ # Create a new Sensitive object
6
+ # @param [Object] value to wrap
7
+ def initialize(value)
8
+ @value = value
9
+ end
10
+
11
+ # @return the wrapped value
12
+ def unwrap
13
+ @value
14
+ end
15
+
16
+ # @return true
17
+ def sensitive?
18
+ true
19
+ end
20
+
21
+ # @return inspect of the wrapped value, inside Sensitive()
22
+ def inspect
23
+ "Sensitive(#{@value.inspect})"
24
+ end
25
+
26
+ # Check for equality with another value.
27
+ # If compared to Puppet Sensitive type, it compares the wrapped values.
28
+
29
+ # @param other [#unwrap, Object] value to compare to
30
+ def == other
31
+ if other.respond_to? :unwrap
32
+ if unwrap.kind_of?(Regexp)
33
+ return unwrap =~ other.unwrap
34
+ else
35
+ return unwrap == other.unwrap
36
+ end
37
+ else
38
+ super
39
+ end
40
+ end
41
+ end
42
+ else
43
+ #:nocov:
44
+ class Sensitive
45
+ def initialize(value)
46
+ raise 'The use of the Sensitive data type is not supported by this Puppet version'
47
+ end
48
+ end
49
+ #:nocov:
50
+ end
51
+ end
@@ -1,12 +1,14 @@
1
1
  require 'rspec-puppet/cache'
2
2
  require 'rspec-puppet/adapters'
3
3
  require 'rspec-puppet/raw_string'
4
+ require 'rspec-puppet/sensitive'
4
5
 
5
6
  module RSpec::Puppet
6
7
  module Support
7
8
  include GenericMatchers
8
9
 
9
10
  @@cache = RSpec::Puppet::Cache.new
11
+ @@fixture_hiera_configs = Hash.new { |h, k| h[k] = nil }
10
12
 
11
13
  def subject
12
14
  lambda { catalogue }
@@ -86,10 +88,29 @@ module RSpec::Puppet
86
88
  hiera_config_value = self.respond_to?(:hiera_config) ? hiera_config : nil
87
89
  hiera_data_value = self.respond_to?(:hiera_data) ? hiera_data : nil
88
90
 
91
+ rspec_config_values = [
92
+ :trusted_server_facts,
93
+ :disable_module_hiera,
94
+ :use_fixture_spec_hiera,
95
+ :fixture_hiera_configs,
96
+ :fallback_to_default_hiera,
97
+ ].map { |setting| RSpec.configuration.send(setting) }
98
+
89
99
  build_facts = facts_hash(node_name)
90
- catalogue = build_catalog(node_name, build_facts, trusted_facts_hash(node_name), hiera_config_value,
91
- build_code(type, manifest_opts), exported, node_params_hash, hiera_data_value,
92
- RSpec.configuration.trusted_server_facts)
100
+ catalogue = build_catalog(
101
+ nodename: node_name,
102
+ facts_val: build_facts,
103
+ trusted_facts_val: trusted_facts_hash(node_name),
104
+ hiera_config_val: hiera_config_value,
105
+ code: build_code(type, manifest_opts),
106
+ exported: exported,
107
+ node_params: node_params_hash,
108
+ trusted_external_data: trusted_external_data_hash,
109
+ ignored_cache_params: {
110
+ hiera_data_value: hiera_data_value,
111
+ rspec_config_values: rspec_config_values,
112
+ }
113
+ )
93
114
 
94
115
  test_module = type == :host ? nil : class_name.split('::').first
95
116
  if type == :define
@@ -293,6 +314,19 @@ module RSpec::Puppet
293
314
  extensions
294
315
  end
295
316
 
317
+ def trusted_external_data_hash
318
+ return {} unless Puppet::Util::Package.versioncmp(Puppet.version, '6.14.0') >= 0
319
+
320
+ external_data = {}
321
+
322
+ if RSpec.configuration.default_trusted_external_data.any?
323
+ external_data.merge!(munge_facts(RSpec.configuration.default_trusted_external_data))
324
+ end
325
+
326
+ external_data.merge!(munge_facts(trusted_external_data)) if self.respond_to?(:trusted_external_data)
327
+ external_data
328
+ end
329
+
296
330
  def server_facts_hash
297
331
  server_facts = {}
298
332
 
@@ -358,7 +392,7 @@ module RSpec::Puppet
358
392
 
359
393
  # Enable app_management by default for Puppet versions that support it
360
394
  if Puppet::Util::Package.versioncmp(Puppet.version, '4.3.0') >= 0 && Puppet.version.to_i < 5
361
- Puppet[:app_management] = true
395
+ Puppet[:app_management] = ENV.include?('PUPPET_NOAPP_MANAGMENT') ? false : true
362
396
  end
363
397
 
364
398
  adapter.modulepath.map do |d|
@@ -380,6 +414,29 @@ module RSpec::Puppet
380
414
  end
381
415
 
382
416
  def build_catalog_without_cache(nodename, facts_val, trusted_facts_val, hiera_config_val, code, exported, node_params, *_)
417
+ build_catalog_without_cache_v2({
418
+ nodename: nodename,
419
+ facts_val: facts_val,
420
+ trusted_facts_val: trusted_facts_val,
421
+ hiera_config_val: hiera_config_val,
422
+ code: code,
423
+ exported: exported,
424
+ node_params: node_params,
425
+ trusted_external: {},
426
+ })
427
+ end
428
+
429
+ def build_catalog_without_cache_v2(
430
+ nodename: nil,
431
+ facts_val: nil,
432
+ trusted_facts_val: nil,
433
+ hiera_config_val: nil,
434
+ code: nil,
435
+ exported: nil,
436
+ node_params: nil,
437
+ trusted_external_data: nil,
438
+ ignored_cache_params: {}
439
+ )
383
440
 
384
441
  # If we're going to rebuild the catalog, we should clear the cached instance
385
442
  # of Hiera that Puppet is using. This opens the possibility of the catalog
@@ -401,10 +458,14 @@ module RSpec::Puppet
401
458
 
402
459
  node_obj = Puppet::Node.new(nodename, { :parameters => node_params, :facts => node_facts })
403
460
 
461
+ trusted_info = ['remote', nodename, trusted_facts_val]
462
+ if Puppet::Util::Package.versioncmp(Puppet.version, '6.14.0') >= 0
463
+ trusted_info.push(trusted_external_data)
464
+ end
404
465
  if Puppet::Util::Package.versioncmp(Puppet.version, '4.3.0') >= 0
405
466
  Puppet.push_context(
406
467
  {
407
- :trusted_information => Puppet::Context::TrustedInformation.new('remote', nodename, trusted_facts_val)
468
+ :trusted_information => Puppet::Context::TrustedInformation.new(*trusted_info)
408
469
  },
409
470
  "Context for spec trusted hash"
410
471
  )
@@ -423,7 +484,11 @@ module RSpec::Puppet
423
484
 
424
485
  def build_catalog(*args)
425
486
  @@cache.get(*args) do |*args|
426
- build_catalog_without_cache(*args)
487
+ if args.length == 1 && args.first.is_a?(Hash)
488
+ build_catalog_without_cache_v2(**args.first)
489
+ else
490
+ build_catalog_without_cache(*args)
491
+ end
427
492
  end
428
493
  end
429
494
 
@@ -440,8 +505,7 @@ module RSpec::Puppet
440
505
  end
441
506
 
442
507
  def escape_special_chars(string)
443
- string.gsub!(/\$/, "\\$")
444
- string
508
+ string.gsub(/\$/, "\\$")
445
509
  end
446
510
 
447
511
  def rspec_compatibility
@@ -452,6 +516,23 @@ module RSpec::Puppet
452
516
  end
453
517
  end
454
518
 
519
+ def fixture_spec_hiera_conf(mod)
520
+ return @@fixture_hiera_configs[mod.name] if @@fixture_hiera_configs.key?(mod.name)
521
+
522
+ path = Pathname.new(mod.path)
523
+ if path.join('spec').exist?
524
+ path.join('spec').find do |file|
525
+ Find.prune if %w[modules work-dir].any? do |dir|
526
+ file.relative_path_from(path).to_s.start_with?("spec/fixtures/#{dir}")
527
+ end
528
+ if file.basename.to_s.eql?(Puppet::Pops::Lookup::HieraConfig::CONFIG_FILE_NAME)
529
+ return @@fixture_hiera_configs[mod.name] = file.to_s
530
+ end
531
+ end
532
+ end
533
+ @@fixture_hiera_configs[mod.name]
534
+ end
535
+
455
536
  # Helper to return a resource/node reference, so it gets translated in params to a raw string
456
537
  # without quotes.
457
538
  #
@@ -462,6 +543,14 @@ module RSpec::Puppet
462
543
  return RSpec::Puppet::RawString.new("#{type}['#{title}']")
463
544
  end
464
545
 
546
+ # Helper to return value wrapped in Sensitive type.
547
+ #
548
+ # @param [Object] value to wrap
549
+ # @return [RSpec::Puppet::Sensitive] a new Sensitive wrapper with the new value
550
+ def sensitive(value)
551
+ return RSpec::Puppet::Sensitive.new(value)
552
+ end
553
+
465
554
  # @!attribute [r] adapter
466
555
  # @api private
467
556
  # @return [Class < RSpec::Puppet::Adapters::Base]
metadata CHANGED
@@ -1,14 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rspec-puppet
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.7.8
4
+ version: 2.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tim Sharpe
8
- autorequire:
8
+ - Puppet, Inc.
9
+ - Community Contributors
10
+ autorequire:
9
11
  bindir: bin
10
12
  cert_chain: []
11
- date: 2019-10-31 00:00:00.000000000 Z
13
+ date: 2021-08-02 00:00:00.000000000 Z
12
14
  dependencies:
13
15
  - !ruby/object:Gem::Dependency
14
16
  name: rspec
@@ -25,7 +27,9 @@ dependencies:
25
27
  - !ruby/object:Gem::Version
26
28
  version: '0'
27
29
  description: RSpec tests for your Puppet manifests
28
- email: tim@sharpe.id.au
30
+ email:
31
+ - tim@sharpe.id.au
32
+ - modules-team@puppet.com
29
33
  executables:
30
34
  - rspec-puppet-init
31
35
  extensions: []
@@ -60,21 +64,23 @@ files:
60
64
  - lib/rspec-puppet/matchers/raise_error.rb
61
65
  - lib/rspec-puppet/matchers/run.rb
62
66
  - lib/rspec-puppet/matchers/type_matchers.rb
67
+ - lib/rspec-puppet/matchers/unique_values.rb
63
68
  - lib/rspec-puppet/monkey_patches.rb
64
69
  - lib/rspec-puppet/monkey_patches/win32/registry.rb
65
70
  - lib/rspec-puppet/monkey_patches/win32/taskscheduler.rb
66
71
  - lib/rspec-puppet/monkey_patches/windows/taskschedulerconstants.rb
67
72
  - lib/rspec-puppet/rake_task.rb
68
73
  - lib/rspec-puppet/raw_string.rb
74
+ - lib/rspec-puppet/sensitive.rb
69
75
  - lib/rspec-puppet/setup.rb
70
76
  - lib/rspec-puppet/spec_helper.rb
71
77
  - lib/rspec-puppet/support.rb
72
78
  - lib/rspec-puppet/tasks/release_test.rb
73
- homepage: https://github.com/rodjek/rspec-puppet/
79
+ homepage: https://github.com/puppetlabs/rspec-puppet/
74
80
  licenses:
75
81
  - MIT
76
82
  metadata: {}
77
- post_install_message:
83
+ post_install_message:
78
84
  rdoc_options: []
79
85
  require_paths:
80
86
  - lib
@@ -89,8 +95,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
89
95
  - !ruby/object:Gem::Version
90
96
  version: '0'
91
97
  requirements: []
92
- rubygems_version: 3.0.3
93
- signing_key:
98
+ rubyforge_project:
99
+ rubygems_version: 2.7.6.2
100
+ signing_key:
94
101
  specification_version: 4
95
102
  summary: RSpec tests for your Puppet manifests
96
103
  test_files: []