rspec-puppet 2.5.0 → 2.6.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.
- data/CHANGELOG.md +86 -0
- data/README.md +317 -34
- data/lib/rspec-puppet/adapters.rb +38 -30
- data/lib/rspec-puppet/coverage.rb +31 -6
- data/lib/rspec-puppet/example/function_example_group.rb +53 -8
- data/lib/rspec-puppet/example/type_alias_example_group.rb +14 -0
- data/lib/rspec-puppet/example.rb +16 -33
- data/lib/rspec-puppet/matchers/allow_value.rb +45 -0
- data/lib/rspec-puppet/matchers/compile.rb +7 -0
- data/lib/rspec-puppet/matchers/create_generic.rb +54 -13
- data/lib/rspec-puppet/matchers/parameter_matcher.rb +2 -2
- data/lib/rspec-puppet/matchers/run.rb +6 -1
- data/lib/rspec-puppet/matchers.rb +1 -0
- data/lib/rspec-puppet/monkey_patches.rb +162 -0
- data/lib/rspec-puppet/setup.rb +47 -26
- data/lib/rspec-puppet/spec_helper.rb +4 -3
- data/lib/rspec-puppet/support.rb +183 -34
- data/lib/rspec-puppet.rb +18 -0
- metadata +35 -28
- checksums.yaml +0 -7
@@ -14,9 +14,9 @@ module RSpec::Puppet
|
|
14
14
|
end
|
15
15
|
|
16
16
|
# This method is used by the `run` matcher to trigger the function execution, and provides a uniform interface across all puppet versions.
|
17
|
-
def execute(*args)
|
17
|
+
def execute(*args, &block)
|
18
18
|
Puppet.override(@overrides, "rspec-test scope") do
|
19
|
-
@func.call(@overrides[:global_scope], *args)
|
19
|
+
@func.call(@overrides[:global_scope], *freeze_arg(args), &block)
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
@@ -25,6 +25,24 @@ module RSpec::Puppet
|
|
25
25
|
RSpec.deprecate("subject.call", :replacement => "is_expected.to run.with().and_raise_error(), or execute()")
|
26
26
|
execute(*args)
|
27
27
|
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
# Facts, keywords, single-quoted strings etc. are usually frozen in Puppet manifests, so freeze arguments to ensure functions are tested
|
32
|
+
# under worst-case conditions.
|
33
|
+
def freeze_arg(arg)
|
34
|
+
case arg
|
35
|
+
when Array
|
36
|
+
arg.each { |a| freeze_arg(a) }
|
37
|
+
arg.freeze
|
38
|
+
when Hash
|
39
|
+
arg.each { |k,v| freeze_arg(k); freeze_arg(v) }
|
40
|
+
arg.freeze
|
41
|
+
when String
|
42
|
+
arg.freeze
|
43
|
+
end
|
44
|
+
arg
|
45
|
+
end
|
28
46
|
end
|
29
47
|
|
30
48
|
class V3FunctionWrapper
|
@@ -61,18 +79,16 @@ module RSpec::Puppet
|
|
61
79
|
@subject ||= find_function
|
62
80
|
end
|
63
81
|
|
64
|
-
def find_function
|
65
|
-
function_name = self.class.top_level_description.downcase
|
66
|
-
|
82
|
+
def find_function(function_name = self.class.top_level_description)
|
67
83
|
with_vardir do
|
68
84
|
env = adapter.current_environment
|
69
85
|
|
70
86
|
if Puppet.version.to_f >= 4.0
|
71
87
|
context_overrides = compiler.context_overrides
|
72
88
|
func = nil
|
89
|
+
loaders = Puppet.lookup(:loaders)
|
73
90
|
Puppet.override(context_overrides, "rspec-test scope") do
|
74
|
-
|
75
|
-
func = V4FunctionWrapper.new(function_name, loader.private_environment_loader.load(:function, function_name), context_overrides)
|
91
|
+
func = V4FunctionWrapper.new(function_name, loaders.private_environment_loader.load(:function, function_name), context_overrides)
|
76
92
|
@scope = context_overrides[:global_scope]
|
77
93
|
end
|
78
94
|
|
@@ -86,7 +102,11 @@ module RSpec::Puppet
|
|
86
102
|
end
|
87
103
|
end
|
88
104
|
end
|
89
|
-
|
105
|
+
def call_function(function_name, *args)
|
106
|
+
# function = find_function(function_name)
|
107
|
+
# function.execute(*args)
|
108
|
+
scope.call_function(function_name, args)
|
109
|
+
end
|
90
110
|
def scope
|
91
111
|
@scope ||= build_scope(compiler, nodename(:function))
|
92
112
|
end
|
@@ -112,22 +132,47 @@ module RSpec::Puppet
|
|
112
132
|
def build_compiler
|
113
133
|
node_name = nodename(:function)
|
114
134
|
fact_values = facts_hash(node_name)
|
135
|
+
trusted_values = trusted_facts_hash(node_name)
|
136
|
+
|
137
|
+
# Allow different Hiera configurations:
|
138
|
+
HieraPuppet.instance_variable_set('@hiera', nil) if defined? HieraPuppet
|
115
139
|
|
116
140
|
# if we specify a pre_condition, we should ensure that we compile that
|
117
141
|
# code into a catalog that is accessible from the scope where the
|
118
142
|
# function is called
|
119
143
|
Puppet[:code] = pre_cond
|
120
144
|
|
145
|
+
node_facts = Puppet::Node::Facts.new(node_name, fact_values.dup)
|
146
|
+
|
121
147
|
node_options = {
|
122
148
|
:parameters => fact_values,
|
149
|
+
:facts => node_facts
|
123
150
|
}
|
124
151
|
|
125
152
|
stub_facts! fact_values
|
126
153
|
|
127
154
|
node = build_node(node_name, node_options)
|
128
155
|
|
156
|
+
if Puppet::Util::Package.versioncmp(Puppet.version, '4.3.0') >= 0
|
157
|
+
Puppet.push_context(
|
158
|
+
{
|
159
|
+
:trusted_information => Puppet::Context::TrustedInformation.new('remote', node_name, trusted_values)
|
160
|
+
},
|
161
|
+
"Context for spec trusted hash"
|
162
|
+
)
|
163
|
+
end
|
164
|
+
|
129
165
|
compiler = Puppet::Parser::Compiler.new(node)
|
130
166
|
compiler.compile
|
167
|
+
if Puppet::Util::Package.versioncmp(Puppet.version, '4.0.0') >= 0
|
168
|
+
loaders = Puppet::Pops::Loaders.new(adapter.current_environment)
|
169
|
+
Puppet.push_context(
|
170
|
+
{
|
171
|
+
:loaders => loaders,
|
172
|
+
:global_scope => compiler.context_overrides[:global_scope]
|
173
|
+
},
|
174
|
+
"set globals")
|
175
|
+
end
|
131
176
|
compiler
|
132
177
|
end
|
133
178
|
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module RSpec::Puppet
|
2
|
+
module TypeAliasExampleGroup
|
3
|
+
include RSpec::Puppet::TypeAliasMatchers
|
4
|
+
include RSpec::Puppet::Support
|
5
|
+
|
6
|
+
def catalogue(test_value)
|
7
|
+
load_catalogue(:type_alias, false, :test_value => test_value)
|
8
|
+
end
|
9
|
+
|
10
|
+
def subject
|
11
|
+
lambda { |test_value| catalogue(test_value) }
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
data/lib/rspec-puppet/example.rb
CHANGED
@@ -4,46 +4,29 @@ require 'rspec-puppet/example/class_example_group'
|
|
4
4
|
require 'rspec-puppet/example/function_example_group'
|
5
5
|
require 'rspec-puppet/example/host_example_group'
|
6
6
|
require 'rspec-puppet/example/type_example_group'
|
7
|
+
require 'rspec-puppet/example/type_alias_example_group'
|
7
8
|
require 'rspec-puppet/example/provider_example_group'
|
8
9
|
require 'rspec-puppet/example/application_example_group'
|
9
10
|
|
10
11
|
RSpec::configure do |c|
|
11
12
|
|
12
|
-
def c.
|
13
|
-
Regexp.compile(
|
13
|
+
def c.rspec_puppet_include(group, type, file_path)
|
14
|
+
escaped_file_path = Regexp.compile(file_path.join('[\\\/]'))
|
15
|
+
if RSpec::Version::STRING < '3'
|
16
|
+
self.include group, :type => type, :example_group => { :file_path => escaped_file_path }, :spec_type => type
|
17
|
+
else
|
18
|
+
self.include group, :type => type, :file_path => lambda { |file_path, metadata| metadata[:type].nil? && escaped_file_path =~ file_path }
|
19
|
+
end
|
14
20
|
end
|
15
21
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
:file_path => c.escaped_path(%w[spec functions])
|
25
|
-
}
|
26
|
-
c.include RSpec::Puppet::HostExampleGroup, :type => :host, :example_group => {
|
27
|
-
:file_path => c.escaped_path(%w[spec hosts])
|
28
|
-
}
|
29
|
-
c.include RSpec::Puppet::TypeExampleGroup, :type => :type, :example_group => {
|
30
|
-
:file_path => c.escaped_path(%w[spec types])
|
31
|
-
}
|
32
|
-
c.include RSpec::Puppet::ProviderExampleGroup, :type => :provider, :example_group => {
|
33
|
-
:file_path => c.escaped_path(%w[spec providers])
|
34
|
-
}
|
35
|
-
c.include RSpec::Puppet::ApplicationExampleGroup, :type => :application, :example_group => {
|
36
|
-
:file_path => c.escaped_path(%w[spec applications])
|
37
|
-
}
|
38
|
-
else
|
39
|
-
c.include RSpec::Puppet::DefineExampleGroup, :type => :define, :file_path => c.escaped_path(%w[spec defines])
|
40
|
-
c.include RSpec::Puppet::ClassExampleGroup, :type => :class, :file_path => c.escaped_path(%w[spec classes])
|
41
|
-
c.include RSpec::Puppet::FunctionExampleGroup, :type => :puppet_function, :file_path => c.escaped_path(%w[spec functions])
|
42
|
-
c.include RSpec::Puppet::HostExampleGroup, :type => :host, :file_path => c.escaped_path(%w[spec hosts])
|
43
|
-
c.include RSpec::Puppet::TypeExampleGroup, :type => :type, :file_path => c.escaped_path(%w[spec types])
|
44
|
-
c.include RSpec::Puppet::ProviderExampleGroup, :type => :provider, :file_path => c.escaped_path(%w[spec providers])
|
45
|
-
c.include RSpec::Puppet::ApplicationExampleGroup, :type => :application, :file_path => c.escaped_path(%w[spec applications])
|
46
|
-
end
|
22
|
+
c.rspec_puppet_include RSpec::Puppet::DefineExampleGroup, :define, %w[spec defines]
|
23
|
+
c.rspec_puppet_include RSpec::Puppet::ClassExampleGroup, :class, %w[spec classes]
|
24
|
+
c.rspec_puppet_include RSpec::Puppet::FunctionExampleGroup, :puppet_function, %w[spec functions]
|
25
|
+
c.rspec_puppet_include RSpec::Puppet::HostExampleGroup, :host, %w[spec hosts]
|
26
|
+
c.rspec_puppet_include RSpec::Puppet::TypeExampleGroup, :type, %w[spec types]
|
27
|
+
c.rspec_puppet_include RSpec::Puppet::TypeAliasExampleGroup, :type_alias, %w[spec type_aliases]
|
28
|
+
c.rspec_puppet_include RSpec::Puppet::ProviderExampleGroup, :provider, %w[spec providers]
|
29
|
+
c.rspec_puppet_include RSpec::Puppet::ApplicationExampleGroup, :application, %w[spec applications]
|
47
30
|
|
48
31
|
# Hook for each example group type to remove any caches or instance variables, since they will remain
|
49
32
|
# and cause a memory leak. Can't be assigned per type by :file_path, so check for its presence.
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module RSpec::Puppet
|
2
|
+
module TypeAliasMatchers
|
3
|
+
class AllowValue
|
4
|
+
def initialize(values)
|
5
|
+
@values = values
|
6
|
+
@error_msgs = []
|
7
|
+
end
|
8
|
+
|
9
|
+
def matches?(catalogue)
|
10
|
+
matches = @values.map do |test_value|
|
11
|
+
begin
|
12
|
+
catalogue.call(test_value)
|
13
|
+
true
|
14
|
+
rescue Puppet::Error => e
|
15
|
+
@error_msgs << e.message
|
16
|
+
false
|
17
|
+
end
|
18
|
+
end
|
19
|
+
matches.all?
|
20
|
+
end
|
21
|
+
|
22
|
+
def description
|
23
|
+
if @values.length == 1
|
24
|
+
"match value #{@values.first.inspect}"
|
25
|
+
else
|
26
|
+
"match values #{@values.map(&:inspect).join(', ')}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def failure_message
|
31
|
+
"expected that the type alias would " + description + " but it raised the #{@error_msgs.length == 1 ? 'error' : 'errors'} #{@error_msgs.join(', ')}"
|
32
|
+
end
|
33
|
+
|
34
|
+
def failure_message_when_negated
|
35
|
+
"expected that the type alias would not " + description + " but it does"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def allow_value(*values)
|
40
|
+
RSpec::Puppet::TypeAliasMatchers::AllowValue.new(values)
|
41
|
+
end
|
42
|
+
|
43
|
+
alias_method :allow_values, :allow_value
|
44
|
+
end
|
45
|
+
end
|
@@ -108,6 +108,10 @@ module RSpec::Puppet
|
|
108
108
|
if vertex[:alias]
|
109
109
|
res_hash["#{vertex.type.to_s}[#{vertex[:alias]}]"] = 1
|
110
110
|
end
|
111
|
+
|
112
|
+
if vertex.uniqueness_key != [vertex.title]
|
113
|
+
res_hash["#{vertex.type.to_s}[#{vertex.uniqueness_key.first}]"] = 1
|
114
|
+
end
|
111
115
|
end
|
112
116
|
end
|
113
117
|
res_hash
|
@@ -134,6 +138,7 @@ module RSpec::Puppet
|
|
134
138
|
end
|
135
139
|
|
136
140
|
def cycles_found?
|
141
|
+
Puppet::Type.suppress_provider
|
137
142
|
cat = @catalogue.to_ral.relationship_graph
|
138
143
|
cat.write_graph(:resources)
|
139
144
|
if cat.respond_to? :find_cycles_in_graph
|
@@ -141,6 +146,8 @@ module RSpec::Puppet
|
|
141
146
|
else
|
142
147
|
find_cycles_legacy(cat)
|
143
148
|
end
|
149
|
+
Puppet::Type.unsuppress_provider
|
150
|
+
|
144
151
|
!@cycles.empty?
|
145
152
|
end
|
146
153
|
|
@@ -1,4 +1,6 @@
|
|
1
|
+
require 'set'
|
1
2
|
require 'rspec-puppet/matchers/parameter_matcher'
|
3
|
+
|
2
4
|
module RSpec::Puppet
|
3
5
|
module ManifestMatchers
|
4
6
|
class CreateGeneric
|
@@ -79,7 +81,7 @@ module RSpec::Puppet
|
|
79
81
|
|
80
82
|
def matches?(catalogue)
|
81
83
|
ret = true
|
82
|
-
@catalogue = catalogue.call
|
84
|
+
@catalogue = catalogue.is_a?(Puppet::Resource::Catalog) ? catalogue : catalogue.call
|
83
85
|
resource = @catalogue.resource(@referenced_type, @title)
|
84
86
|
|
85
87
|
if resource.nil?
|
@@ -87,6 +89,17 @@ module RSpec::Puppet
|
|
87
89
|
else
|
88
90
|
RSpec::Puppet::Coverage.cover!(resource)
|
89
91
|
rsrc_hsh = resource.to_hash
|
92
|
+
|
93
|
+
if resource.builtin_type?
|
94
|
+
namevar = resource.resource_type.key_attributes.first.to_s
|
95
|
+
else
|
96
|
+
namevar = 'name'
|
97
|
+
end
|
98
|
+
|
99
|
+
unless @expected_params.any? { |param| param.first.to_s == namevar }
|
100
|
+
rsrc_hsh.delete(namevar.to_sym) if rsrc_hsh.has_key?(namevar.to_sym)
|
101
|
+
end
|
102
|
+
|
90
103
|
if @expected_params_count
|
91
104
|
unless rsrc_hsh.size == @expected_params_count
|
92
105
|
ret = false
|
@@ -201,7 +214,7 @@ module RSpec::Puppet
|
|
201
214
|
|
202
215
|
def check_befores(catalogue, resource)
|
203
216
|
@befores.each do |ref|
|
204
|
-
unless precedes?(resource,
|
217
|
+
unless precedes?(resource, canonicalize_resource(ref))
|
205
218
|
@errors << BeforeRelationshipError.new(resource.to_ref, ref)
|
206
219
|
end
|
207
220
|
end
|
@@ -209,7 +222,7 @@ module RSpec::Puppet
|
|
209
222
|
|
210
223
|
def check_requires(catalogue, resource)
|
211
224
|
@requires.each do |ref|
|
212
|
-
unless precedes?(
|
225
|
+
unless precedes?(canonicalize_resource(ref), resource)
|
213
226
|
@errors << RequireRelationshipError.new(resource.to_ref, ref)
|
214
227
|
end
|
215
228
|
end
|
@@ -217,7 +230,7 @@ module RSpec::Puppet
|
|
217
230
|
|
218
231
|
def check_notifies(catalogue, resource)
|
219
232
|
@notifies.each do |ref|
|
220
|
-
unless notifies?(resource,
|
233
|
+
unless notifies?(resource, canonicalize_resource(ref))
|
221
234
|
@errors << NotifyRelationshipError.new(resource.to_ref, ref)
|
222
235
|
end
|
223
236
|
end
|
@@ -225,7 +238,7 @@ module RSpec::Puppet
|
|
225
238
|
|
226
239
|
def check_subscribes(catalogue, resource)
|
227
240
|
@subscribes.each do |ref|
|
228
|
-
unless notifies?(
|
241
|
+
unless notifies?(canonicalize_resource(ref), resource)
|
229
242
|
@errors << SubscribeRelationshipError.new(resource.to_ref, ref)
|
230
243
|
end
|
231
244
|
end
|
@@ -240,34 +253,62 @@ module RSpec::Puppet
|
|
240
253
|
end
|
241
254
|
|
242
255
|
def canonicalize_resource(resource)
|
243
|
-
resource_from_ref(resource_ref(resource))
|
256
|
+
res = resource_from_ref(resource_ref(resource))
|
257
|
+
if res.nil?
|
258
|
+
resource = Struct.new(:type, :title).new(*@catalogue.title_key_for_ref(resource)) if resource.is_a?(String)
|
259
|
+
res = @catalogue.resource_keys.select { |type, name|
|
260
|
+
type == resource.type
|
261
|
+
}.map { |type, name|
|
262
|
+
@catalogue.resource(type, name)
|
263
|
+
}.compact.find { |cat_res|
|
264
|
+
cat_res.builtin_type? && cat_res.uniqueness_key.first == resource.title
|
265
|
+
}
|
266
|
+
end
|
267
|
+
res
|
244
268
|
end
|
245
269
|
|
246
270
|
def canonicalize_resource_ref(ref)
|
247
271
|
resource_ref(resource_from_ref(ref))
|
248
272
|
end
|
249
273
|
|
250
|
-
def relationship_refs(resource, type)
|
274
|
+
def relationship_refs(resource, type, visited = Set.new)
|
251
275
|
resource = canonicalize_resource(resource)
|
252
|
-
results =
|
276
|
+
results = Set.new
|
253
277
|
return results unless resource
|
278
|
+
|
279
|
+
# guard to prevent infinite recursion
|
280
|
+
if visited.include?(resource.object_id)
|
281
|
+
return [canonicalize_resource_ref(resource)]
|
282
|
+
else
|
283
|
+
visited << resource.object_id
|
284
|
+
end
|
285
|
+
|
254
286
|
Array[resource[type]].flatten.compact.each do |r|
|
255
287
|
results << canonicalize_resource_ref(r)
|
256
|
-
results << relationship_refs(r, type)
|
288
|
+
results << relationship_refs(r, type, visited)
|
289
|
+
|
290
|
+
res = canonicalize_resource(r)
|
291
|
+
if res && res.builtin_type?
|
292
|
+
results << res.to_ref
|
293
|
+
results << "#{res.type.to_s.capitalize}[#{res.uniqueness_key.first}]"
|
294
|
+
end
|
257
295
|
end
|
258
296
|
|
297
|
+
Puppet::Type.suppress_provider
|
259
298
|
# Add autorequires if any
|
260
299
|
if type == :require and resource.resource_type.respond_to? :eachautorequire
|
261
300
|
resource.resource_type.eachautorequire do |t, b|
|
262
301
|
Array(resource.to_ral.instance_eval(&b)).each do |dep|
|
263
302
|
res = "#{t.to_s.capitalize}[#{dep}]"
|
264
|
-
if r = relationship_refs(res, type)
|
303
|
+
if r = relationship_refs(res, type, visited)
|
265
304
|
results << res
|
266
305
|
results << r
|
267
306
|
end
|
268
307
|
end
|
269
308
|
end
|
270
309
|
end
|
310
|
+
Puppet::Type.unsuppress_provider
|
311
|
+
|
271
312
|
results.flatten
|
272
313
|
end
|
273
314
|
|
@@ -280,8 +321,8 @@ module RSpec::Puppet
|
|
280
321
|
|
281
322
|
self_or_upstream(first).each do |u|
|
282
323
|
self_or_upstream(second).each do |v|
|
283
|
-
before_refs = relationship_refs(u, :before)
|
284
|
-
require_refs = relationship_refs(v, :require)
|
324
|
+
before_refs = relationship_refs(u, :before) + relationship_refs(u, :notify)
|
325
|
+
require_refs = relationship_refs(v, :require) + relationship_refs(u, :subscribe)
|
285
326
|
|
286
327
|
if before_refs.include?(v.to_ref) || require_refs.include?(u.to_ref) || (before_refs & require_refs).any?
|
287
328
|
return true
|
@@ -320,7 +361,7 @@ module RSpec::Puppet
|
|
320
361
|
|
321
362
|
if value.nil? then
|
322
363
|
unless resource[param].nil?
|
323
|
-
@errors << "#{param} undefined"
|
364
|
+
@errors << "#{param} undefined but it is set to #{resource[param].inspect}"
|
324
365
|
end
|
325
366
|
else
|
326
367
|
m = ParameterMatcher.new(param, value, type)
|
@@ -30,7 +30,7 @@ module RSpec::Puppet
|
|
30
30
|
# Puppet flattens an array with a single value into just the value and
|
31
31
|
# this can cause confusion when testing as people expect when you put
|
32
32
|
# an array in, you'll get an array out.
|
33
|
-
actual = [
|
33
|
+
actual = [actual] if expected.is_a?(Array) && !actual.is_a?(Array)
|
34
34
|
|
35
35
|
retval = check(expected, actual)
|
36
36
|
|
@@ -55,7 +55,7 @@ module RSpec::Puppet
|
|
55
55
|
#
|
56
56
|
# @return [true, false] If the resource matched
|
57
57
|
def check(expected, actual)
|
58
|
-
return false if actual.nil? && !expected.nil?
|
58
|
+
return false if !expected.is_a?(Proc) && actual.nil? && !expected.nil?
|
59
59
|
case expected
|
60
60
|
when Proc
|
61
61
|
check_proc(expected, actual)
|
@@ -7,7 +7,7 @@ module RSpec::Puppet
|
|
7
7
|
@has_returned = false
|
8
8
|
begin
|
9
9
|
# `*nil` does not evaluate to "no params" on ruby 1.8 :-(
|
10
|
-
@actual_return = @params.nil? ? @func_obj.execute : @func_obj.execute(*@params)
|
10
|
+
@actual_return = @params.nil? ? @func_obj.execute(&@block) : @func_obj.execute(*@params, &@block)
|
11
11
|
@has_returned = true
|
12
12
|
rescue Exception => e
|
13
13
|
@actual_error = e
|
@@ -52,6 +52,11 @@ module RSpec::Puppet
|
|
52
52
|
self
|
53
53
|
end
|
54
54
|
|
55
|
+
def with_lambda(&block)
|
56
|
+
@block = block
|
57
|
+
self
|
58
|
+
end
|
59
|
+
|
55
60
|
def and_return(value)
|
56
61
|
@has_expected_return = true
|
57
62
|
@expected_return = value
|
@@ -0,0 +1,162 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
|
3
|
+
module Puppet
|
4
|
+
# Allow rspec-puppet to prevent Puppet::Type from automatically picking
|
5
|
+
# a provider for a resource. We need to do this because in order to fully
|
6
|
+
# resolve the graph edges, we have to convert the Puppet::Resource objects
|
7
|
+
# into Puppet::Type objects so that their autorequires are evaluated. We need
|
8
|
+
# to prevent provider code from being called during this process as it's very
|
9
|
+
# platform specific.
|
10
|
+
class Type
|
11
|
+
old_set_default = instance_method(:set_default)
|
12
|
+
|
13
|
+
define_method(:set_default) do |attr|
|
14
|
+
old_posix = nil
|
15
|
+
old_microsoft_windows = nil
|
16
|
+
|
17
|
+
if attr == :provider
|
18
|
+
old_posix = Puppet.features.posix?
|
19
|
+
old_microsoft_windows = Puppet.features.microsoft_windows?
|
20
|
+
|
21
|
+
if Puppet::Util::Platform.pretend_windows?
|
22
|
+
Puppet.features.add(:posix) { false }
|
23
|
+
Puppet.features.add(:microsoft_windows) { true }
|
24
|
+
else
|
25
|
+
Puppet.features.add(:posix) { true }
|
26
|
+
Puppet.features.add(:microsoft_windows) { false }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
retval = old_set_default.bind(self).call(attr)
|
31
|
+
|
32
|
+
unless old_posix.nil?
|
33
|
+
Puppet.features.add(:posix) { old_posix }
|
34
|
+
end
|
35
|
+
unless old_microsoft_windows.nil?
|
36
|
+
Puppet.features.add(:microsoft_windows) { old_microsoft_windows }
|
37
|
+
end
|
38
|
+
|
39
|
+
retval
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.suppress_provider?
|
43
|
+
@suppress_provider ||= false
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.suppress_provider
|
47
|
+
@suppress_provider = true
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.unsuppress_provider
|
51
|
+
@suppress_provider = false
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# If Puppet::Node::Environment has a validate_dirs instance method (i.e.
|
56
|
+
# Puppet < 3.x), wrap the method to check if rspec-puppet is pretending to be
|
57
|
+
# running under windows. The original method uses Puppet::Util.absolute_path?
|
58
|
+
# (which in turn calls Puppet::Util::Platform.windows?) to validate the path
|
59
|
+
# to the manifests on disk during compilation, so we have to temporarily
|
60
|
+
# disable the pretending when running it.
|
61
|
+
class Node::Environment
|
62
|
+
if instance_methods.include?("validate_dirs")
|
63
|
+
old_validate_dirs = instance_method(:validate_dirs)
|
64
|
+
|
65
|
+
define_method(:validate_dirs) do |dirs|
|
66
|
+
pretending = Puppet::Util::Platform.pretend_platform
|
67
|
+
|
68
|
+
if pretending
|
69
|
+
Puppet::Util::Platform.pretend_to_be nil
|
70
|
+
end
|
71
|
+
|
72
|
+
output = old_validate_dirs.bind(self).call(dirs)
|
73
|
+
|
74
|
+
Puppet::Util::Platform.pretend_to_be pretending
|
75
|
+
|
76
|
+
output
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
module Util
|
82
|
+
# Allow rspec-puppet to pretend to be different platforms.
|
83
|
+
module Platform
|
84
|
+
def windows?
|
85
|
+
pretend_platform.nil? ? (actual_platform == :windows) : pretend_windows?
|
86
|
+
end
|
87
|
+
module_function :windows?
|
88
|
+
|
89
|
+
def actual_platform
|
90
|
+
@actual_platform ||= !!File::ALT_SEPARATOR ? :windows : :posix
|
91
|
+
end
|
92
|
+
module_function :actual_platform
|
93
|
+
|
94
|
+
def pretend_windows?
|
95
|
+
pretend_platform == :windows
|
96
|
+
end
|
97
|
+
module_function :pretend_windows?
|
98
|
+
|
99
|
+
def pretend_to_be(platform)
|
100
|
+
# Ensure that we cache the real platform before pretending to be
|
101
|
+
# a different one
|
102
|
+
actual_platform
|
103
|
+
|
104
|
+
@pretend_platform = platform
|
105
|
+
end
|
106
|
+
module_function :pretend_to_be
|
107
|
+
|
108
|
+
def pretend_platform
|
109
|
+
@pretend_platform ||= nil
|
110
|
+
end
|
111
|
+
module_function :pretend_platform
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
class Pathname
|
117
|
+
def rspec_puppet_basename(path)
|
118
|
+
raise ArgumentError, 'pathname stubbing not enabled' unless RSpec.configuration.enable_pathname_stubbing
|
119
|
+
|
120
|
+
if path =~ /\A[a-zA-Z]:(#{SEPARATOR_PAT}.*)\z/
|
121
|
+
path = path[2..-1]
|
122
|
+
end
|
123
|
+
path.split(SEPARATOR_PAT).last || path[/(#{SEPARATOR_PAT})/, 1] || path
|
124
|
+
end
|
125
|
+
|
126
|
+
if instance_methods.include?("chop_basename")
|
127
|
+
old_chop_basename = instance_method(:chop_basename)
|
128
|
+
|
129
|
+
define_method(:chop_basename) do |path|
|
130
|
+
if RSpec.configuration.enable_pathname_stubbing
|
131
|
+
base = rspec_puppet_basename(path)
|
132
|
+
if /\A#{SEPARATOR_PAT}?\z/o =~ base
|
133
|
+
return nil
|
134
|
+
else
|
135
|
+
return path[0, path.rindex(base)], base
|
136
|
+
end
|
137
|
+
else
|
138
|
+
old_chop_basename.bind(self).call(path)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
# Prevent the File type from munging paths (which uses File.expand_path to
|
145
|
+
# normalise paths, which does very bad things to *nix paths on Windows.
|
146
|
+
Puppet::Type.type(:file).paramclass(:path).munge { |value| value }
|
147
|
+
|
148
|
+
# Prevent the Exec type from validating the user. This parameter isn't
|
149
|
+
# supported under Windows at all and only under *nix when the current user is
|
150
|
+
# root.
|
151
|
+
Puppet::Type.type(:exec).paramclass(:user).validate { |value| true }
|
152
|
+
|
153
|
+
# Prevent Puppet from requiring 'puppet/util/windows' if we're pretending to be
|
154
|
+
# windows, otherwise it will require other libraries that probably won't be
|
155
|
+
# available on non-windows hosts.
|
156
|
+
module Kernel
|
157
|
+
alias :old_require :require
|
158
|
+
def require(path)
|
159
|
+
return if path == 'puppet/util/windows' && Puppet::Util::Platform.pretend_windows?
|
160
|
+
old_require(path)
|
161
|
+
end
|
162
|
+
end
|