rspec-puppet 2.7.10 → 2.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +37 -0
- data/README.md +38 -0
- data/lib/rspec-puppet.rb +5 -0
- data/lib/rspec-puppet/cache.rb +11 -6
- data/lib/rspec-puppet/coverage.rb +79 -13
- data/lib/rspec-puppet/matchers.rb +1 -0
- data/lib/rspec-puppet/matchers/create_generic.rb +5 -0
- data/lib/rspec-puppet/matchers/parameter_matcher.rb +3 -4
- data/lib/rspec-puppet/matchers/raise_error.rb +2 -2
- data/lib/rspec-puppet/matchers/unique_values.rb +31 -0
- data/lib/rspec-puppet/monkey_patches.rb +52 -0
- data/lib/rspec-puppet/sensitive.rb +47 -0
- data/lib/rspec-puppet/support.rb +96 -7
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 375cf91b75c36ee1bc0bbade72608205a7b85fce94a49d0fcfafb02fa6f8eddc
|
4
|
+
data.tar.gz: 732ce59e27a5fd9d15052262d21b2de6df85b090fb56152aca88da4480133ac1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3f1b0bb5c052df4ff70981384ad81bdc2e75ec1f23f9a890f101a933a4f7f50d569acef001524c7c3a9f37f0cfffd2eeaf0a26a7d67f8a3abd80b7147005e758
|
7
|
+
data.tar.gz: 65f0fbe718948c13b1866bb8d71c6b03fe741927ed86e97d6eeefb39526e98671e3ac5ae98e14e939654988fa8c272b3e72f66c5b61e9c6321fac11d5b66e276
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,43 @@
|
|
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.8.0]
|
6
|
+
|
7
|
+
### Breaking Changes
|
8
|
+
* As of the 2.8.0 release, the `rspec-puppet` project no longer guarantees compatibility
|
9
|
+
with Puppet 2.x or 3.x (running under Ruby 1.8.7) or Puppet 4.x (running under Ruby 1.9.3).
|
10
|
+
* This release adds support for the [`Sensitive`](https://puppet.com/docs/puppet/latest/lang_data_sensitive.html)
|
11
|
+
data type, however existing tests that were expecting `String` content may need to be updated
|
12
|
+
to wrap the expected value in the new `sensitive` helper:
|
13
|
+
|
14
|
+
```ruby
|
15
|
+
# Old
|
16
|
+
it { is_expected.to contain_file('/etc/mysecret.conf').with_content("top secret\n") }
|
17
|
+
|
18
|
+
# New
|
19
|
+
it { is_expected.to contain_file('/etc/mysecret.conf').with_content(sensitive("top secret\n")) }
|
20
|
+
```
|
21
|
+
|
22
|
+
### Added
|
23
|
+
* Added support for [trusted external fact data](https://github.com/rodjek/rspec-puppet#specifying-trusted-external-data).
|
24
|
+
* Added the ability to exclude resources from the coverage report calculations using a regular expression.
|
25
|
+
(See [documentation](https://rspec-puppet.com/documentation/coverage/#excluded-resources) for an example.
|
26
|
+
* Added `have_unique_values_for_all` matcher to assert a specific resource parameter value is unique across
|
27
|
+
the entire catalogue.
|
28
|
+
(See [documentation](https://rspec-puppet.com/documentation/classes/#test-resource-parameter-values-for-uniqueness).)
|
29
|
+
* Added ability to customize module-layer Hiera configuration via new settings. See
|
30
|
+
[documentation](https://rspec-puppet.com/documentation/configuration/#disable_module_hiera) for details.
|
31
|
+
|
32
|
+
### Changed
|
33
|
+
* `RSpec::Puppet::Cache` now evicts least recently used entries when it reaches max size.
|
34
|
+
* `rspec-puppet`'s implementation of `match_manifests` will no longer look in `init.pp` for class
|
35
|
+
declarations if a manifest file exactly matching the class name exists.
|
36
|
+
|
37
|
+
### Fixed
|
38
|
+
* Resolved compatibility issues with Ruby 2.7.x and added Ruby 2.7.x to the test matrix.
|
39
|
+
* Resolved issues calculating coverage and reporting results when there are 0 tested resources.
|
40
|
+
* Resolved compatibility issue with `rspec-expectations` 3.10.0.
|
41
|
+
|
5
42
|
## [2.7.10]
|
6
43
|
|
7
44
|
### Fixed
|
data/README.md
CHANGED
@@ -2,6 +2,20 @@
|
|
2
2
|
[](https://travis-ci.org/rodjek/rspec-puppet)
|
3
3
|
[](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
|
data/lib/rspec-puppet/cache.rb
CHANGED
@@ -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
|
17
|
-
|
18
|
-
|
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
|
-
|
29
|
-
|
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
|
-
|
25
|
-
|
26
|
-
|
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
|
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
|
-
|
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
|
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
|
|
@@ -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
|
@@ -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(
|
20
|
-
RaiseError.new(
|
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
|
@@ -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
|
@@ -268,6 +268,40 @@ module Puppet
|
|
268
268
|
end
|
269
269
|
end
|
270
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
|
271
305
|
end
|
272
306
|
|
273
307
|
class Pathname
|
@@ -302,6 +336,24 @@ class Pathname
|
|
302
336
|
end
|
303
337
|
end
|
304
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
|
+
|
305
357
|
# Prevent the File type from munging paths (which uses File.expand_path to
|
306
358
|
# normalise paths, which does very bad things to *nix paths on Windows.
|
307
359
|
file_path_munge = Puppet::Type.type(:file).paramclass(:path).instance_method(:unsafe_munge)
|
@@ -0,0 +1,47 @@
|
|
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
|
+
return unwrap == other.unwrap
|
33
|
+
else
|
34
|
+
super
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
else
|
39
|
+
#:nocov:
|
40
|
+
class Sensitive
|
41
|
+
def initialize(value)
|
42
|
+
raise 'The use of the Sensitive data type is not supported by this Puppet version'
|
43
|
+
end
|
44
|
+
end
|
45
|
+
#:nocov:
|
46
|
+
end
|
47
|
+
end
|
data/lib/rspec-puppet/support.rb
CHANGED
@@ -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(
|
91
|
-
|
92
|
-
|
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
|
|
@@ -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(
|
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
|
-
|
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,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rspec-puppet
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.8.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: 2020-
|
11
|
+
date: 2020-11-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -60,12 +60,14 @@ files:
|
|
60
60
|
- lib/rspec-puppet/matchers/raise_error.rb
|
61
61
|
- lib/rspec-puppet/matchers/run.rb
|
62
62
|
- lib/rspec-puppet/matchers/type_matchers.rb
|
63
|
+
- lib/rspec-puppet/matchers/unique_values.rb
|
63
64
|
- lib/rspec-puppet/monkey_patches.rb
|
64
65
|
- lib/rspec-puppet/monkey_patches/win32/registry.rb
|
65
66
|
- lib/rspec-puppet/monkey_patches/win32/taskscheduler.rb
|
66
67
|
- lib/rspec-puppet/monkey_patches/windows/taskschedulerconstants.rb
|
67
68
|
- lib/rspec-puppet/rake_task.rb
|
68
69
|
- lib/rspec-puppet/raw_string.rb
|
70
|
+
- lib/rspec-puppet/sensitive.rb
|
69
71
|
- lib/rspec-puppet/setup.rb
|
70
72
|
- lib/rspec-puppet/spec_helper.rb
|
71
73
|
- lib/rspec-puppet/support.rb
|
@@ -89,7 +91,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
89
91
|
- !ruby/object:Gem::Version
|
90
92
|
version: '0'
|
91
93
|
requirements: []
|
92
|
-
rubygems_version: 3.0.
|
94
|
+
rubygems_version: 3.0.8
|
93
95
|
signing_key:
|
94
96
|
specification_version: 4
|
95
97
|
summary: RSpec tests for your Puppet manifests
|