-
Notifications
You must be signed in to change notification settings - Fork 203
/
monkey_patches.rb
352 lines (297 loc) · 9.99 KB
/
monkey_patches.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
require 'pathname'
# Load this library before enabling the monkey-patches to avoid HI-581
begin
require 'hiera/util/win32'
rescue LoadError
# ignore this on installs without hiera, e.g. puppet 3 gems
end
class RSpec::Puppet::EventListener
def self.example_started(example)
if rspec3?
@rspec_puppet_example = example.example.example_group.ancestors.include?(RSpec::Puppet::Support)
@current_example = example.example
if !@current_example.respond_to?(:environment) && @current_example.respond_to?(:example_group_instance)
@current_example = @current_example.example_group_instance
end
else
@rspec_puppet_example = example.example_group.ancestors.include?(RSpec::Puppet::Support)
@current_example = example
end
end
def self.example_passed(example)
@rspec_puppet_example = false
end
def self.example_pending(example)
@rspec_puppet_example = false
end
def self.example_failed(example)
@rspec_puppet_example = false
end
def self.rspec_puppet_example?
@rspec_puppet_example || false
end
def self.rspec3?
if @rspec3.nil?
@rspec3 = defined?(RSpec::Core::Notifications)
end
@rspec3
end
def self.current_example
@current_example
end
end
RSpec.configuration.reporter.register_listener(RSpec::Puppet::EventListener, :example_started, :example_pending, :example_passed, :example_failed)
require 'rspec-puppet/monkey_patches/win32/taskscheduler'
require 'rspec-puppet/monkey_patches/win32/registry'
require 'rspec-puppet/monkey_patches/windows/taskschedulerconstants'
module Puppet
# Allow rspec-puppet to prevent Puppet::Type from automatically picking
# a provider for a resource. We need to do this because in order to fully
# resolve the graph edges, we have to convert the Puppet::Resource objects
# into Puppet::Type objects so that their autorequires are evaluated. We need
# to prevent provider code from being called during this process as it's very
# platform specific.
class Type
old_set_default = instance_method(:set_default)
define_method(:set_default) do |attr|
if RSpec::Puppet.rspec_puppet_example?
old_posix = nil
old_microsoft_windows = nil
if attr == :provider
old_posix = Puppet.features.posix?
old_microsoft_windows = Puppet.features.microsoft_windows?
if Puppet::Util::Platform.pretend_windows?
Puppet.features.add(:posix) { false }
Puppet.features.add(:microsoft_windows) { true }
else
Puppet.features.add(:posix) { true }
Puppet.features.add(:microsoft_windows) { false }
end
end
retval = old_set_default.bind(self).call(attr)
unless old_posix.nil?
Puppet.features.add(:posix) { old_posix }
end
unless old_microsoft_windows.nil?
Puppet.features.add(:microsoft_windows) { old_microsoft_windows }
end
retval
else
old_set_default.bind(self).call(attr)
end
end
end
module Parser::Files
alias :old_find_manifests_in_modules :find_manifests_in_modules
module_function :old_find_manifests_in_modules
def find_manifests_in_modules(pattern, environment)
if RSpec::Puppet.rspec_puppet_example?
pretending = Puppet::Util::Platform.pretend_platform
unless pretending.nil?
Puppet::Util::Platform.pretend_to_be nil
RSpec::Puppet::Consts.stub_consts_for(RSpec.configuration.platform)
end
if pretending && pretending != Puppet::Util::Platform.actual_platform
environment.send(:value_cache).clear if environment.respond_to?(:value_cache, true)
end
output = old_find_manifests_in_modules(pattern, environment)
unless pretending.nil?
Puppet::Util::Platform.pretend_to_be pretending
RSpec::Puppet::Consts.stub_consts_for pretending
end
output
else
old_find_manifests_in_modules(pattern, environment)
end
end
module_function :find_manifests_in_modules
end
module Util
if respond_to?(:get_env)
alias :old_get_env :get_env
module_function :old_get_env
def get_env(name, mode = default_env)
if RSpec::Puppet.rspec_puppet_example?
# use the actual platform, not the pretended
old_get_env(name, Platform.actual_platform)
else
old_get_env(name, mode)
end
end
module_function :get_env
end
if respond_to?(:path_to_uri)
alias :old_path_to_uri :path_to_uri
module_function :old_path_to_uri
def path_to_uri(*args)
if RSpec::Puppet.rspec_puppet_example?
RSpec::Puppet::Consts.without_stubs do
old_path_to_uri(*args)
end
else
old_path_to_uri(*args)
end
end
module_function :path_to_uri
end
# Allow rspec-puppet to pretend to be different platforms.
module Platform
alias :old_windows? :windows?
module_function :old_windows?
def windows?
if RSpec::Puppet.rspec_puppet_example?
!pretending? ? (actual_platform == :windows) : pretend_windows?
else
old_windows?
end
end
module_function :windows?
def actual_platform
@actual_platform ||= !!File::ALT_SEPARATOR ? :windows : :posix
end
module_function :actual_platform
def actually_windows?
actual_platform == :windows
end
module_function :actually_windows?
def pretend_windows?
pretend_platform == :windows
end
module_function :pretend_windows?
def pretend_to_be(platform)
# Ensure that we cache the real platform before pretending to be
# a different one
actual_platform
@pretend_platform = platform
end
module_function :pretend_to_be
def pretend_platform
@pretend_platform ||= nil
end
module_function :pretend_platform
def pretending?
!pretend_platform.nil?
end
module_function :pretending?
end
class Autoload
if respond_to?(:load_file)
singleton_class.send(:alias_method, :old_load_file, :load_file)
def self.load_file(*args)
if RSpec::Puppet.rspec_puppet_example?
RSpec::Puppet::Consts.without_stubs do
old_load_file(*args)
end
else
old_load_file(*args)
end
end
end
end
end
begin
require 'puppet/confine/exists'
class Confine::Exists < Puppet::Confine
old_pass = instance_method(:pass?)
define_method(:pass?) do |value|
if RSpec::Puppet.rspec_puppet_example?
true
else
old_pass.bind(self).call(value)
end
end
end
rescue LoadError
require 'puppet/provider/confine/exists'
class Provider::Confine::Exists < Puppet::Provider::Confine
old_pass = instance_method(:pass?)
define_method(:pass?) do |value|
if RSpec::Puppet.rspec_puppet_example?
true
else
old_pass.bind(self).call(value)
end
end
end
end
end
class Pathname
def rspec_puppet_basename(path)
raise ArgumentError, 'pathname stubbing not enabled' unless RSpec.configuration.enable_pathname_stubbing
if path =~ /\A[a-zA-Z]:(#{SEPARATOR_PAT}.*)\z/
path = path[2..-1]
end
path.split(SEPARATOR_PAT).last || path[/(#{SEPARATOR_PAT})/, 1] || path
end
if instance_methods.include?("chop_basename")
old_chop_basename = instance_method(:chop_basename)
define_method(:chop_basename) do |path|
if RSpec::Puppet.rspec_puppet_example?
if RSpec.configuration.enable_pathname_stubbing
base = rspec_puppet_basename(path)
if /\A#{SEPARATOR_PAT}?\z/o =~ base
return nil
else
return path[0, path.rindex(base)], base
end
else
old_chop_basename.bind(self).call(path)
end
else
old_chop_basename.bind(self).call(path)
end
end
end
end
# Prevent the File type from munging paths (which uses File.expand_path to
# normalise paths, which does very bad things to *nix paths on Windows.
file_path_munge = Puppet::Type.type(:file).paramclass(:path).instance_method(:unsafe_munge)
Puppet::Type.type(:file).paramclass(:path).munge do |value|
if RSpec::Puppet.rspec_puppet_example?
value
else
file_path_munge.bind(self).call(value)
end
end
# Prevent the Exec type from validating the user. This parameter isn't
# supported under Windows at all and only under *nix when the current user is
# root.
exec_user_validate = Puppet::Type.type(:exec).paramclass(:user).instance_method(:unsafe_validate)
Puppet::Type.type(:exec).paramclass(:user).validate do |value|
if RSpec::Puppet.rspec_puppet_example?
true
else
exec_user_validate.bind(self).call(value)
end
end
# Stub out Puppet::Util::Windows::Security.supports_acl? if it has been
# defined. This check only makes sense when applying the catalogue to a host
# and so can be safely stubbed out for unit testing.
Puppet::Type.type(:file).provide(:windows).class_eval do
old_supports_acl = instance_method(:supports_acl?) if respond_to?(:supports_acl?)
def supports_acl?(path)
if RSpec::Puppet.rspec_puppet_example?
true
else
old_supports_acl.bind(self).call(value)
end
end
old_manages_symlinks = instance_method(:manages_symlinks?) if respond_to?(:manages_symlinks?)
def manages_symlinks?
if RSpec::Puppet.rspec_puppet_example?
true
else
old_manages_symlinks.bind(self).call(value)
end
end
end
# Prevent Puppet from requiring 'puppet/util/windows' if we're pretending to be
# windows, otherwise it will require other libraries that probably won't be
# available on non-windows hosts.
module Kernel
alias :old_require :require
def require(path)
return if (['puppet/util/windows', 'win32/registry'].include?(path)) && RSpec::Puppet.rspec_puppet_example? && Puppet::Util::Platform.pretend_windows?
old_require(path)
end
end