rspec-puppet 2.7.6 → 2.9.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
- SHA1:
3
- metadata.gz: fa9949d6cb9b79c951ecd504f85344d100a40e70
4
- data.tar.gz: 2571507918bf8e77cc750501c6b24b0da1731c01
2
+ SHA256:
3
+ metadata.gz: 420f47c99ab3190a3e97c2b172e694694a5d997a56e70366bd168c8338c21fb9
4
+ data.tar.gz: 21f2d247e5169ba70e490d6b9c66fc8542a1c3c1cd99d1e5895a1322a9cfac1b
5
5
  SHA512:
6
- metadata.gz: a31eda49f0aa0933c87a9b90fdbd704103690b8f230e9eca9b9c5b785a889db60a2ccbbcba7c3d468c24dcd15b554c5f2bf27f3423e4b6b50782d3854e12b9d9
7
- data.tar.gz: bc3107e48272088eb124c8cca18cee099c44d0541ef8ebc9a323c93b1b158294be4f48e409d1a10d50403534b761799f37300efeae22449cf9a927eac5539c44
6
+ metadata.gz: a5b2ef185120131a07fc6e063a7ee2d2cb191db8a765bb5cdda1fce92081547c4d0aea83b386faaf1d20e8051d51d84ba05facc5f9deb74f3aecdeea67798b86
7
+ data.tar.gz: 4714dac2b13e5a4eb44a8c965a61e08cc7e2ded172271ea61f85bfae22d43f51dde5d609f0a1d3515844fb5924b48ad8441fbb071eef267c0af6f886c0e21c9c
data/CHANGELOG.md CHANGED
@@ -2,6 +2,74 @@
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.9.0]
6
+
7
+ ### Added
8
+ * Allow users to disable app_management for Puppet 4
9
+ * Added support for regexp arguments to Sensitive
10
+ * Handle all auto*, not just autorequire
11
+ * Set up loaders so that 4.x functions resolve properly
12
+
13
+ ## [2.8.0]
14
+
15
+ ### Breaking Changes
16
+ * As of the 2.8.0 release, the `rspec-puppet` project no longer guarantees compatibility
17
+ with Puppet 2.x or 3.x (running under Ruby 1.8.7) or Puppet 4.x (running under Ruby 1.9.3).
18
+ * This release adds support for the [`Sensitive`](https://puppet.com/docs/puppet/latest/lang_data_sensitive.html)
19
+ data type, however existing tests that were expecting `String` content may need to be updated
20
+ to wrap the expected value in the new `sensitive` helper:
21
+
22
+ ```ruby
23
+ # Old
24
+ it { is_expected.to contain_file('/etc/mysecret.conf').with_content("top secret\n") }
25
+
26
+ # New
27
+ it { is_expected.to contain_file('/etc/mysecret.conf').with_content(sensitive("top secret\n")) }
28
+ ```
29
+
30
+ ### Added
31
+ * Added support for [trusted external fact data](https://github.com/rodjek/rspec-puppet#specifying-trusted-external-data).
32
+ * Added the ability to exclude resources from the coverage report calculations using a regular expression.
33
+ (See [documentation](https://rspec-puppet.com/documentation/coverage/#excluded-resources) for an example.
34
+ * Added `have_unique_values_for_all` matcher to assert a specific resource parameter value is unique across
35
+ the entire catalogue.
36
+ (See [documentation](https://rspec-puppet.com/documentation/classes/#test-resource-parameter-values-for-uniqueness).)
37
+ * Added ability to customize module-layer Hiera configuration via new settings. See
38
+ [documentation](https://rspec-puppet.com/documentation/configuration/#disable_module_hiera) for details.
39
+
40
+ ### Changed
41
+ * `RSpec::Puppet::Cache` now evicts least recently used entries when it reaches max size.
42
+ * `rspec-puppet`'s implementation of `match_manifests` will no longer look in `init.pp` for class
43
+ declarations if a manifest file exactly matching the class name exists.
44
+
45
+ ### Fixed
46
+ * Resolved compatibility issues with Ruby 2.7.x and added Ruby 2.7.x to the test matrix.
47
+ * Resolved issues calculating coverage and reporting results when there are 0 tested resources.
48
+ * Resolved compatibility issue with `rspec-expectations` 3.10.0.
49
+
50
+ ## [2.7.10]
51
+
52
+ ### Fixed
53
+ * Fix issues with removal of `default_env` method in Puppet 6.17.0.
54
+
55
+ ## [2.7.9]
56
+
57
+ This release had unintended breaking changes and was withdrawn.
58
+
59
+ ## [2.7.8]
60
+
61
+ ### Fixed
62
+ * Fix cross-platform testing for Puppet >= 6.9.0 when there is no `ipaddress6`
63
+ fact defined.
64
+
65
+ ## [2.7.7]
66
+
67
+ ### Fixed
68
+ * Fix the support for rspec-expectations >= 3.8.5.
69
+
70
+ ### Changed
71
+ * Remove the rspec-expectations dependency limit introduced in 2.7.6.
72
+
5
73
  ## [2.7.6]
6
74
 
7
75
  ### Changed
@@ -486,7 +554,36 @@ Thanks to Adrien Thebo, Alex Harvey, Brian, Dan Bode, Dominic Cleal, Javier Pala
486
554
  ## 1.0.1 and earlier
487
555
  For changelog of versions 1.0.1 and earlier, see http://rspec-puppet.com/changelog/
488
556
 
489
- [2.x]: https://github.com/rodjek/rspec-puppet/compare/v2.5.0...master
557
+ [2.x]: https://github.com/rodjek/rspec-puppet/compare/v2.9.0...master
558
+ [2.9.0]: https://github.com/rodjek/rspec-puppet/compare/v2.8.0...v2.9.0
559
+ [2.8.0]: https://github.com/rodjek/rspec-puppet/compare/v2.7.10...v2.8.0
560
+ [2.7.10]: https://github.com/rodjek/rspec-puppet/compare/v2.7.9...v2.7.10
561
+ [2.7.9]: https://github.com/rodjek/rspec-puppet/compare/v2.7.8...v2.7.9
562
+ [2.7.8]: https://github.com/rodjek/rspec-puppet/compare/v2.7.7...v2.7.8
563
+ [2.7.7]: https://github.com/rodjek/rspec-puppet/compare/v2.7.6...v2.7.7
564
+ [2.7.6]: https://github.com/rodjek/rspec-puppet/compare/v2.7.5...v2.7.6
565
+ [2.7.5]: https://github.com/rodjek/rspec-puppet/compare/v2.7.4...v2.7.5
566
+ [2.7.4]: https://github.com/rodjek/rspec-puppet/compare/v2.7.3...v2.7.4
567
+ [2.7.3]: https://github.com/rodjek/rspec-puppet/compare/v2.7.2...v2.7.3
568
+ [2.7.2]: https://github.com/rodjek/rspec-puppet/compare/v2.7.1...v2.7.2
569
+ [2.7.1]: https://github.com/rodjek/rspec-puppet/compare/v2.7.0...v2.7.1
570
+ [2.7.0]: https://github.com/rodjek/rspec-puppet/compare/v2.6.15...v2.7.0
571
+ [2.6.15]: https://github.com/rodjek/rspec-puppet/compare/v2.6.14...v2.6.15
572
+ [2.6.14]: https://github.com/rodjek/rspec-puppet/compare/v2.6.13...v2.6.14
573
+ [2.6.13]: https://github.com/rodjek/rspec-puppet/compare/v2.6.12...v2.6.13
574
+ [2.6.12]: https://github.com/rodjek/rspec-puppet/compare/v2.6.11...v2.6.12
575
+ [2.6.11]: https://github.com/rodjek/rspec-puppet/compare/v2.6.10...v2.6.11
576
+ [2.6.10]: https://github.com/rodjek/rspec-puppet/compare/v2.6.9...v2.6.10
577
+ [2.6.9]: https://github.com/rodjek/rspec-puppet/compare/v2.6.8...v2.6.9
578
+ [2.6.8]: https://github.com/rodjek/rspec-puppet/compare/v2.6.7...v2.6.8
579
+ [2.6.7]: https://github.com/rodjek/rspec-puppet/compare/v2.6.6...v2.6.7
580
+ [2.6.6]: https://github.com/rodjek/rspec-puppet/compare/v2.6.5...v2.6.6
581
+ [2.6.5]: https://github.com/rodjek/rspec-puppet/compare/v2.6.4...v2.6.5
582
+ [2.6.4]: https://github.com/rodjek/rspec-puppet/compare/v2.6.3...v2.6.4
583
+ [2.6.3]: https://github.com/rodjek/rspec-puppet/compare/v2.6.2...v2.6.3
584
+ [2.6.2]: https://github.com/rodjek/rspec-puppet/compare/v2.6.1...v2.6.2
585
+ [2.6.1]: https://github.com/rodjek/rspec-puppet/compare/v2.6.0...v2.6.1
586
+ [2.6.0]: https://github.com/rodjek/rspec-puppet/compare/2.5.0...v2.6.0
490
587
  [2.5.0]: https://github.com/rodjek/rspec-puppet/compare/v2.4.0...v2.5.0
491
588
  [2.4.0]: https://github.com/rodjek/rspec-puppet/compare/v2.3.2...v2.4.0
492
589
  [2.3.2]: https://github.com/rodjek/rspec-puppet/compare/v2.3.1...v2.3.2
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
 
@@ -6,3 +6,5 @@ require 'rspec-puppet/matchers/count_generic'
6
6
  require 'rspec-puppet/matchers/dynamic_matchers'
7
7
  require 'rspec-puppet/matchers/type_matchers'
8
8
  require 'rspec-puppet/matchers/allow_value'
9
+ require 'rspec-puppet/matchers/raise_error'
10
+ require 'rspec-puppet/matchers/unique_values'
@@ -34,6 +34,14 @@ module RSpec::Puppet
34
34
  def failure_message_when_negated
35
35
  "expected that the type alias would not " + description + " but it does"
36
36
  end
37
+
38
+ def supports_block_expectations
39
+ true
40
+ end
41
+
42
+ def supports_value_expectations
43
+ true
44
+ end
37
45
  end
38
46
 
39
47
  def allow_value(*values)
@@ -78,6 +78,14 @@ module RSpec::Puppet
78
78
  end
79
79
  end
80
80
 
81
+ def supports_block_expectations
82
+ true
83
+ end
84
+
85
+ def supports_value_expectations
86
+ true
87
+ end
88
+
81
89
  private
82
90
  def missing_dependencies?
83
91
  retval = false
@@ -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
@@ -61,6 +63,14 @@ module RSpec::Puppet
61
63
  "expected that the catalogue would not " + description + " but it does"
62
64
  end
63
65
 
66
+ def supports_block_expectations
67
+ true
68
+ end
69
+
70
+ def supports_value_expectations
71
+ true
72
+ end
73
+
64
74
  private
65
75
 
66
76
  def referenced_type(type)
@@ -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
@@ -177,6 +182,14 @@ module RSpec::Puppet
177
182
  true
178
183
  end
179
184
 
185
+ def supports_block_expectations
186
+ true
187
+ end
188
+
189
+ def supports_value_expectations
190
+ true
191
+ end
192
+
180
193
  def expected
181
194
  @errors.map {|e| e.expected if e.respond_to?(:expected)}.compact.join("\n\n")
182
195
  end
@@ -294,14 +307,17 @@ module RSpec::Puppet
294
307
  end
295
308
  end
296
309
 
297
- # Add autorequires if any
298
- if type == :require and resource.resource_type.respond_to? :eachautorequire
299
- resource.resource_type.eachautorequire do |t, b|
300
- Array(resource.to_ral.instance_eval(&b)).each do |dep|
301
- res = "#{t.to_s.capitalize}[#{dep}]"
302
- if r = relationship_refs(res, type, visited)
303
- results << res
304
- 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
305
321
  end
306
322
  end
307
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
 
@@ -22,6 +22,13 @@ module RSpec::Puppet
22
22
  end
23
23
  end
24
24
 
25
+ def supports_block_expectations
26
+ true
27
+ end
28
+
29
+ def supports_value_expectations
30
+ true
31
+ end
25
32
  end
26
33
 
27
34
  end
@@ -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
@@ -0,0 +1,23 @@
1
+ module RSpec::Puppet
2
+ module GenericMatchers
3
+ # Due to significant code base depending on the
4
+ #
5
+ # is_expected.to raise_error Puppet::Error
6
+ #
7
+ # syntax, and removal of this syntax from RSpec, extend RSpec's built-in
8
+ # `raise_error` matcher to accept a value target, e.g. a subject defined
9
+ # as a lambda, e.g.:
10
+ #
11
+ # subject(:catalogue) { lambda { load_catalogue } }
12
+ #
13
+ class RaiseError < RSpec::Matchers::BuiltIn::RaiseError
14
+ def supports_value_expectations?
15
+ true
16
+ end
17
+ end
18
+
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
+ end
22
+ end
23
+ end
@@ -104,6 +104,14 @@ module RSpec::Puppet
104
104
  end
105
105
  end
106
106
 
107
+ def supports_block_expectations
108
+ true
109
+ end
110
+
111
+ def supports_value_expectations
112
+ true
113
+ end
114
+
107
115
  private
108
116
  def func_name
109
117
  @func_obj.func_name
@@ -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,10 +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
8
+ include GenericMatchers
9
+
7
10
  @@cache = RSpec::Puppet::Cache.new
11
+ @@fixture_hiera_configs = Hash.new { |h, k| h[k] = nil }
8
12
 
9
13
  def subject
10
14
  lambda { catalogue }
@@ -84,10 +88,29 @@ module RSpec::Puppet
84
88
  hiera_config_value = self.respond_to?(:hiera_config) ? hiera_config : nil
85
89
  hiera_data_value = self.respond_to?(:hiera_data) ? hiera_data : nil
86
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
+
87
99
  build_facts = facts_hash(node_name)
88
- catalogue = build_catalog(node_name, build_facts, trusted_facts_hash(node_name), hiera_config_value,
89
- build_code(type, manifest_opts), exported, node_params_hash, hiera_data_value,
90
- 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
+ )
91
114
 
92
115
  test_module = type == :host ? nil : class_name.split('::').first
93
116
  if type == :define
@@ -224,10 +247,11 @@ module RSpec::Puppet
224
247
  }
225
248
 
226
249
  node_facts = {
227
- 'hostname' => node.split('.').first,
228
- 'fqdn' => node,
229
- 'domain' => node.split('.', 2).last,
230
- 'clientcert' => node,
250
+ 'hostname' => node.split('.').first,
251
+ 'fqdn' => node,
252
+ 'domain' => node.split('.', 2).last,
253
+ 'clientcert' => node,
254
+ 'ipaddress6' => 'FE80:0000:0000:0000:AAAA:AAAA:AAAA',
231
255
  }
232
256
 
233
257
  networking_facts = {
@@ -290,6 +314,19 @@ module RSpec::Puppet
290
314
  extensions
291
315
  end
292
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
+
293
330
  def server_facts_hash
294
331
  server_facts = {}
295
332
 
@@ -355,7 +392,7 @@ module RSpec::Puppet
355
392
 
356
393
  # Enable app_management by default for Puppet versions that support it
357
394
  if Puppet::Util::Package.versioncmp(Puppet.version, '4.3.0') >= 0 && Puppet.version.to_i < 5
358
- Puppet[:app_management] = true
395
+ Puppet[:app_management] = ENV.include?('PUPPET_NOAPP_MANAGMENT') ? false : true
359
396
  end
360
397
 
361
398
  adapter.modulepath.map do |d|
@@ -377,6 +414,29 @@ module RSpec::Puppet
377
414
  end
378
415
 
379
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
+ )
380
440
 
381
441
  # If we're going to rebuild the catalog, we should clear the cached instance
382
442
  # of Hiera that Puppet is using. This opens the possibility of the catalog
@@ -398,10 +458,14 @@ module RSpec::Puppet
398
458
 
399
459
  node_obj = Puppet::Node.new(nodename, { :parameters => node_params, :facts => node_facts })
400
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
401
465
  if Puppet::Util::Package.versioncmp(Puppet.version, '4.3.0') >= 0
402
466
  Puppet.push_context(
403
467
  {
404
- :trusted_information => Puppet::Context::TrustedInformation.new('remote', nodename, trusted_facts_val)
468
+ :trusted_information => Puppet::Context::TrustedInformation.new(*trusted_info)
405
469
  },
406
470
  "Context for spec trusted hash"
407
471
  )
@@ -420,7 +484,11 @@ module RSpec::Puppet
420
484
 
421
485
  def build_catalog(*args)
422
486
  @@cache.get(*args) do |*args|
423
- 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
424
492
  end
425
493
  end
426
494
 
@@ -437,8 +505,7 @@ module RSpec::Puppet
437
505
  end
438
506
 
439
507
  def escape_special_chars(string)
440
- string.gsub!(/\$/, "\\$")
441
- string
508
+ string.gsub(/\$/, "\\$")
442
509
  end
443
510
 
444
511
  def rspec_compatibility
@@ -449,6 +516,23 @@ module RSpec::Puppet
449
516
  end
450
517
  end
451
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
+
452
536
  # Helper to return a resource/node reference, so it gets translated in params to a raw string
453
537
  # without quotes.
454
538
  #
@@ -459,6 +543,14 @@ module RSpec::Puppet
459
543
  return RSpec::Puppet::RawString.new("#{type}['#{title}']")
460
544
  end
461
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
+
462
554
  # @!attribute [r] adapter
463
555
  # @api private
464
556
  # @return [Class < RSpec::Puppet::Adapters::Base]
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rspec-puppet
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.7.6
4
+ version: 2.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tim Sharpe
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-10-04 00:00:00.000000000 Z
11
+ date: 2021-05-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -24,20 +24,6 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
- - !ruby/object:Gem::Dependency
28
- name: rspec-expectations
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "<"
32
- - !ruby/object:Gem::Version
33
- version: 3.8.5
34
- type: :runtime
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "<"
39
- - !ruby/object:Gem::Version
40
- version: 3.8.5
41
27
  description: RSpec tests for your Puppet manifests
42
28
  email: tim@sharpe.id.au
43
29
  executables:
@@ -71,14 +57,17 @@ files:
71
57
  - lib/rspec-puppet/matchers/dynamic_matchers.rb
72
58
  - lib/rspec-puppet/matchers/include_class.rb
73
59
  - lib/rspec-puppet/matchers/parameter_matcher.rb
60
+ - lib/rspec-puppet/matchers/raise_error.rb
74
61
  - lib/rspec-puppet/matchers/run.rb
75
62
  - lib/rspec-puppet/matchers/type_matchers.rb
63
+ - lib/rspec-puppet/matchers/unique_values.rb
76
64
  - lib/rspec-puppet/monkey_patches.rb
77
65
  - lib/rspec-puppet/monkey_patches/win32/registry.rb
78
66
  - lib/rspec-puppet/monkey_patches/win32/taskscheduler.rb
79
67
  - lib/rspec-puppet/monkey_patches/windows/taskschedulerconstants.rb
80
68
  - lib/rspec-puppet/rake_task.rb
81
69
  - lib/rspec-puppet/raw_string.rb
70
+ - lib/rspec-puppet/sensitive.rb
82
71
  - lib/rspec-puppet/setup.rb
83
72
  - lib/rspec-puppet/spec_helper.rb
84
73
  - lib/rspec-puppet/support.rb
@@ -102,8 +91,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
102
91
  - !ruby/object:Gem::Version
103
92
  version: '0'
104
93
  requirements: []
105
- rubyforge_project:
106
- rubygems_version: 2.6.14.4
94
+ rubygems_version: 3.2.5
107
95
  signing_key:
108
96
  specification_version: 4
109
97
  summary: RSpec tests for your Puppet manifests