rspec-puppet 2.2.0 → 2.3.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.
@@ -11,10 +11,18 @@ module RSpec::Puppet
11
11
  end
12
12
 
13
13
  def message
14
- if negative == true
15
- "#{param} not set to #{expected.inspect} but it is set to #{actual.inspect}"
14
+ if @param.to_s == 'content' and expected.is_a?( String )
15
+ if negative == true
16
+ "#{param} not set to supplied string"
17
+ else
18
+ "#{param} set to supplied string"
19
+ end
16
20
  else
17
- "#{param} set to #{expected.inspect} but it is set to #{actual.inspect}"
21
+ if negative == true
22
+ "#{param} not set to #{expected.inspect} but it is set to #{actual.inspect}"
23
+ else
24
+ "#{param} set to #{expected.inspect} but it is set to #{actual.inspect}"
25
+ end
18
26
  end
19
27
  end
20
28
 
@@ -6,5 +6,9 @@ module RSpec::Puppet
6
6
  def catalogue
7
7
  @catalogue ||= load_catalogue(:class)
8
8
  end
9
+
10
+ def rspec_puppet_cleanup
11
+ @catalogue = nil
12
+ end
9
13
  end
10
14
  end
@@ -6,5 +6,9 @@ module RSpec::Puppet
6
6
  def catalogue
7
7
  @catalogue ||= load_catalogue(:define)
8
8
  end
9
+
10
+ def rspec_puppet_cleanup
11
+ @catalogue = nil
12
+ end
9
13
  end
10
14
  end
@@ -10,7 +10,7 @@ module RSpec::Puppet
10
10
  vardir = setup_puppet
11
11
 
12
12
  if Puppet.version.to_f >= 4.0
13
- env = Puppet::Node::Environment.create(environment, [File.join(Puppet[:environmentpath],'fixtures','modules')], File.join(Puppet[:environmentpath],'fixtures','manifests'))
13
+ env = build_4x_environment(environment)
14
14
  loader = Puppet::Pops::Loaders.new(env)
15
15
  func = loader.private_environment_loader.load(:function,function_name)
16
16
  return func if func
@@ -35,6 +35,12 @@ module RSpec::Puppet
35
35
  @catalogue ||= compiler.catalog
36
36
  end
37
37
 
38
+ def rspec_puppet_cleanup
39
+ @catalogue = nil
40
+ @compiler = nil
41
+ @scope = nil
42
+ end
43
+
38
44
  private
39
45
 
40
46
  def compiler
@@ -63,5 +69,31 @@ module RSpec::Puppet
63
69
  compiler.compile
64
70
  compiler
65
71
  end
72
+
73
+ def build_scope(compiler, node_name)
74
+ if Puppet.version =~ /^2\.[67]/
75
+ # loadall should only be necessary prior to 3.x
76
+ # Please note, loadall needs to happen first when creating a scope, otherwise
77
+ # you might receive undefined method `function_*' errors
78
+ Puppet::Parser::Functions.autoloader.loadall
79
+ scope = Puppet::Parser::Scope.new(:compiler => compiler)
80
+ else
81
+ scope = Puppet::Parser::Scope.new(compiler)
82
+ end
83
+
84
+ scope.source = Puppet::Resource::Type.new(:node, node_name)
85
+ scope.parent = compiler.topscope
86
+ scope
87
+ end
88
+
89
+ def build_node(name, opts = {})
90
+ if Puppet.version.to_f >= 4.0
91
+ node_environment = build_4x_environment(environment)
92
+ else
93
+ node_environment = Puppet::Node::Environment.new(environment)
94
+ end
95
+ opts.merge!({:environment => node_environment})
96
+ Puppet::Node.new(name, opts)
97
+ end
66
98
  end
67
99
  end
@@ -6,5 +6,9 @@ module RSpec::Puppet
6
6
  def catalogue
7
7
  @catalogue ||= load_catalogue(:host)
8
8
  end
9
+
10
+ def rspec_puppet_cleanup
11
+ @catalogue = nil
12
+ end
9
13
  end
10
14
  end
@@ -0,0 +1,4 @@
1
+ module RSpec::Puppet
2
+ module ProviderExampleGroup
3
+ end
4
+ end
@@ -0,0 +1,26 @@
1
+ module RSpec::Puppet
2
+ module TypeExampleGroup
3
+ include RSpec::Puppet::TypeMatchers
4
+ include RSpec::Puppet::Support
5
+
6
+ def subject
7
+ @type_and_resource ||= begin
8
+ setup_puppet
9
+ type_name = self.class.top_level_description.downcase
10
+ my_params = self.respond_to?(:params) ? params : {}
11
+ [
12
+ Puppet::Type.type(type_name),
13
+ # I don't want to create the resource here, so I have
14
+ # to pass all of the bits form the current scope
15
+ # required to create it
16
+ title,
17
+ my_params
18
+ ]
19
+ end
20
+ end
21
+
22
+ def rspec_puppet_cleanup
23
+ @type_and_resource = nil
24
+ end
25
+ end
26
+ end
@@ -3,8 +3,11 @@ require 'rspec-puppet/example/define_example_group'
3
3
  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
+ require 'rspec-puppet/example/type_example_group'
7
+ require 'rspec-puppet/example/provider_example_group'
6
8
 
7
9
  RSpec::configure do |c|
10
+
8
11
  def c.escaped_path(*parts)
9
12
  Regexp.compile(parts.join('[\\\/]'))
10
13
  end
@@ -21,11 +24,23 @@ RSpec::configure do |c|
21
24
  }
22
25
  c.include RSpec::Puppet::HostExampleGroup, :type => :host, :example_group => {
23
26
  :file_path => c.escaped_path(%w[spec hosts])
24
- }
27
+ }
28
+ c.include RSpec::Puppet::TypeExampleGroup, :type => :type, :example_group => {
29
+ :file_path => c.escaped_path(%w[spec types])
30
+ }
31
+ c.include RSpec::Puppet::ProviderExampleGroup, :type => :provider, :example_group => {
32
+ :file_path => c.escaped_path(%w[spec providers])
33
+ }
25
34
  else
26
35
  c.include RSpec::Puppet::DefineExampleGroup, :type => :define, :file_path => c.escaped_path(%w[spec defines])
27
36
  c.include RSpec::Puppet::ClassExampleGroup, :type => :class, :file_path => c.escaped_path(%w[spec classes])
28
37
  c.include RSpec::Puppet::FunctionExampleGroup, :type => :puppet_function, :file_path => c.escaped_path(%w[spec functions])
29
38
  c.include RSpec::Puppet::HostExampleGroup, :type => :host, :file_path => c.escaped_path(%w[spec hosts])
39
+ c.include RSpec::Puppet::TypeExampleGroup, :type => :type, :file_path => c.escaped_path(%w[spec types])
40
+ c.include RSpec::Puppet::ProviderExampleGroup, :type => :provider, :file_path => c.escaped_path(%w[spec providers])
30
41
  end
42
+
43
+ # Hook for each example group type to remove any caches or instance variables, since they will remain
44
+ # and cause a memory leak. Can't be assigned per type by :file_path, so check for its presence.
45
+ c.after(:each) { rspec_puppet_cleanup if respond_to?(:rspec_puppet_cleanup) }
31
46
  end
@@ -27,7 +27,7 @@ module RSpec::Puppet
27
27
  elsif @check_deps == true && missing_dependencies?
28
28
  false
29
29
  else
30
- true
30
+ @expected_error.nil?
31
31
  end
32
32
  rescue Puppet::Error => e
33
33
  @error_msg = e.message
@@ -58,13 +58,24 @@ module RSpec::Puppet
58
58
  unless @error_msg.empty?
59
59
  "error during compilation: #{@error_msg}"
60
60
  else
61
- "expected that the catalogue would include #{@failed_resource}"
61
+ case @expected_error
62
+ when nil
63
+ "expected that the catalogue would include #{@failed_resource}"
64
+ when Regexp
65
+ "expected that the catalogue would fail to compile and raise an error matching #{@expected_error.inspect}"
66
+ else
67
+ "expected that the catalogue would fail to compile and raise the error #{@expected_error.inspect}"
68
+ end
62
69
  end
63
70
  end
64
71
  end
65
72
 
66
73
  def failure_message_when_negated
67
- "expected that the catalogue would not compile but it does"
74
+ if @expected_error.nil?
75
+ "expected that the catalogue would not compile but it does"
76
+ else
77
+ "expected that the catalogue would compile but it does not"
78
+ end
68
79
  end
69
80
 
70
81
  private
@@ -189,7 +189,11 @@ module RSpec::Puppet
189
189
  else
190
190
  a = type == :not ? '!' : '='
191
191
  b = value.is_a?(Regexp) ? '~' : '>'
192
- output << "#{param.to_s} #{a}#{b} #{value.inspect}"
192
+ if param.to_s == 'content' and value.is_a?( String )
193
+ output << "#{param.to_s} #{type == :not ? 'not ' : ''} supplied string"
194
+ else
195
+ output << "#{param.to_s} #{a}#{b} #{value.inspect}"
196
+ end
193
197
  end
194
198
  end
195
199
  output
@@ -227,32 +231,84 @@ module RSpec::Puppet
227
231
  end
228
232
  end
229
233
 
230
- def relationship_refs(array)
231
- Array[array].flatten.map do |resource|
232
- resource.respond_to?(:to_ref) ? resource.to_ref : resource
234
+ def resource_ref(resource)
235
+ resource.respond_to?(:to_ref) ? resource.to_ref : resource
236
+ end
237
+
238
+ def resource_from_ref(ref)
239
+ ref.is_a?(Puppet::Resource) ? ref : @catalogue.resource(ref)
240
+ end
241
+
242
+ def canonicalize_resource(resource)
243
+ resource_from_ref(resource_ref(resource))
244
+ end
245
+
246
+ def canonicalize_resource_ref(ref)
247
+ resource_ref(resource_from_ref(ref))
248
+ end
249
+
250
+ def relationship_refs(resource, type)
251
+ resource = canonicalize_resource(resource)
252
+ results = []
253
+ return results unless resource
254
+ Array[resource[type]].flatten.compact.each do |r|
255
+ results << canonicalize_resource_ref(r)
256
+ results << relationship_refs(r, type)
233
257
  end
258
+
259
+ # Add autorequires if any
260
+ if type == :require and resource.resource_type.respond_to? :eachautorequire
261
+ resource.resource_type.eachautorequire do |t, b|
262
+ Array(resource.to_ral.instance_eval(&b)).each do |dep|
263
+ res = "#{t.to_s.capitalize}[#{dep}]"
264
+ if r = relationship_refs(res, type)
265
+ results << res
266
+ results << r
267
+ end
268
+ end
269
+ end
270
+ end
271
+ results.flatten
272
+ end
273
+
274
+ def self_or_upstream(vertex)
275
+ [vertex] + @catalogue.upstream_from_vertex(vertex).keys
234
276
  end
235
277
 
236
278
  def precedes?(first, second)
237
- if first.nil? || second.nil?
238
- false
239
- else
240
- before_refs = relationship_refs(first[:before])
241
- require_refs = relationship_refs(second[:require])
279
+ return false if first.nil? || second.nil?
280
+
281
+ self_or_upstream(first).each do |u|
282
+ self_or_upstream(second).each do |v|
283
+ before_refs = relationship_refs(u, :before)
284
+ require_refs = relationship_refs(v, :require)
242
285
 
243
- before_refs.include?(second.to_ref) || require_refs.include?(first.to_ref)
286
+ if before_refs.include?(v.to_ref) || require_refs.include?(u.to_ref) || (before_refs & require_refs).any?
287
+ return true
288
+ end
289
+ end
244
290
  end
291
+
292
+ # Nothing found
293
+ return false
245
294
  end
246
295
 
247
296
  def notifies?(first, second)
248
- if first.nil? || second.nil?
249
- false
250
- else
251
- notify_refs = relationship_refs(first[:notify])
252
- subscribe_refs = relationship_refs(second[:subscribe])
297
+ return false if first.nil? || second.nil?
298
+
299
+ self_or_upstream(first).each do |u|
300
+ self_or_upstream(second).each do |v|
301
+ notify_refs = relationship_refs(u, :notify)
302
+ subscribe_refs = relationship_refs(v, :subscribe)
253
303
 
254
- notify_refs.include?(second.to_ref) || subscribe_refs.include?(first.to_ref)
304
+ if notify_refs.include?(v.to_ref) || subscribe_refs.include?(u.to_ref)
305
+ return true
306
+ end
307
+ end
255
308
  end
309
+
310
+ # Nothing found
311
+ return false
256
312
  end
257
313
 
258
314
  # @param resource [Hash<Symbol, Object>] The resource in the catalog
@@ -14,4 +14,11 @@ module RSpec::Puppet
14
14
  super
15
15
  end
16
16
  end
17
+
18
+ module TypeMatchers
19
+ def method_missing(method, *args, &block)
20
+ return RSpec::Puppet::TypeMatchers::CreateGeneric.new(method, *args, &block) if method == :be_valid_type
21
+ super
22
+ end
23
+ end
17
24
  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, :contain_class)
7
+ RSpec.deprecate(:include_class, :replacement => :contain_class)
8
8
  catalogue.call.classes.include?(expected_class)
9
9
  end
10
10
 
@@ -17,6 +17,7 @@ module RSpec::Puppet
17
17
  end
18
18
  end
19
19
 
20
+ @has_returned = false
20
21
  begin
21
22
  @actual_return = @func.call
22
23
  @has_returned = true
@@ -32,7 +33,7 @@ module RSpec::Puppet
32
33
  when nil
33
34
  return true
34
35
  when Regexp
35
- return @actual_error.message =~ @expected_error_message
36
+ return !!(@actual_error.message =~ @expected_error_message)
36
37
  else
37
38
  return @actual_error.message == @expected_error_message
38
39
  end
@@ -45,7 +46,7 @@ module RSpec::Puppet
45
46
  else
46
47
  case @expected_return
47
48
  when Regexp
48
- return @actual_return =~ @expected_return
49
+ return !!(@actual_return =~ @expected_return)
49
50
  else
50
51
  return @actual_return == @expected_return
51
52
  end
@@ -0,0 +1,161 @@
1
+ module RSpec::Puppet
2
+ module TypeMatchers
3
+
4
+ class CreateGeneric
5
+
6
+ def initialize(*args, &block)
7
+
8
+ @exp_provider = nil
9
+ @exp_parameters = []
10
+ @exp_properties = []
11
+ @exp_features = []
12
+ @exp_defaults = {}
13
+ @params_with_values = {}
14
+ @errors = []
15
+ end
16
+
17
+ # specifies a provider to validate
18
+ def with_provider(name)
19
+ @exp_provider = name
20
+ self
21
+ end
22
+
23
+ # ensures the listed properties are valid
24
+ def with_properties(props)
25
+ @exp_properties = @exp_properties | Array(props)
26
+ self
27
+ end
28
+
29
+ # ensures the listed parameters are valid
30
+ def with_parameters(params)
31
+ @exp_parameters = @exp_parameters | Array(params)
32
+ self
33
+ end
34
+
35
+ # ensure the type has the list of features
36
+ def with_features(features)
37
+ @exp_features = @exp_features | Array(features)
38
+ self
39
+ end
40
+
41
+ #
42
+ # ensures that the specified parameters with their values
43
+ # results in a valid resource
44
+ #
45
+ def with_set_attributes(params)
46
+ @params_with_values.merge!(params)
47
+ self
48
+ end
49
+
50
+ def with_defaults(defaults_hash)
51
+ @exp_defaults.merge!(defaults_hash)
52
+ self
53
+ end
54
+
55
+ #def with_autorequires(autorequires))
56
+ #end
57
+
58
+ #
59
+ # this is the method that drives all of the validation
60
+ #
61
+ def matches?(type_title_and_params)
62
+ type = type_title_and_params[0]
63
+ title = type_title_and_params[1]
64
+ params = type_title_and_params[2]
65
+ unless match_params(type) && match_props(type) && match_features(type)
66
+ return false
67
+ end
68
+ if @params_with_values != {} || @exp_provider
69
+ # only build a resource if we are validating provider or setting
70
+ # additional parameters
71
+ resource = be_valid_resource(type, title, params.merge(@params_with_values))
72
+ match_default_provider(resource) and match_default_values(resource)
73
+ else
74
+ true
75
+ end
76
+ end
77
+
78
+ # checks that the specified params exist
79
+ def match_params(type)
80
+ match_attrs(type, @exp_parameters, :parameter)
81
+ end
82
+
83
+ # checks that the specified properties exist
84
+ def match_props(type)
85
+ match_attrs(type, @exp_properties, :property)
86
+ end
87
+
88
+ # checks that the specified features exist
89
+ def match_features(type)
90
+ match_attrs(type, @exp_features, :feature)
91
+ end
92
+
93
+ # builds the resource with the specified param values
94
+ def be_valid_resource(type, title, params)
95
+ params[:name] ||= title
96
+ type.new(params)
97
+ end
98
+
99
+ #
100
+ # checks that the expected provider is set
101
+ #
102
+ def match_default_provider(resource)
103
+ if @exp_provider
104
+ if resource[:provider] == @exp_provider
105
+ return true
106
+ else
107
+ @errors.push("Expected provider: #{@exp_provider} does not match: #{resource[:provider]}")
108
+ return false
109
+ end
110
+ else
111
+ return true
112
+ end
113
+ end
114
+
115
+ def match_default_values(resource)
116
+ # TODO FINISH
117
+ true
118
+ end
119
+
120
+ def description
121
+ "be a valid type"
122
+ end
123
+
124
+ def failure_message
125
+ "Not a valid type #{@errors.inspect}"
126
+ end
127
+
128
+ private
129
+
130
+ def match_attrs(type, attrs, attr_type)
131
+ baddies = []
132
+ attrs.each do |param|
133
+ param = param.to_sym
134
+ if attr_type == :feature
135
+ unless type.provider_feature(param)
136
+ baddies.push(param)
137
+ end
138
+ elsif ! type.send("valid#{attr_type}?".to_sym, param)
139
+ baddies.push(param)
140
+ end
141
+ end
142
+ if baddies.size > 0
143
+ @errors.push("Invalid #{pluralize(attr_type)}: #{baddies.join(',')}")
144
+ false
145
+ else
146
+ true
147
+ end
148
+ end
149
+
150
+ def pluralize(name)
151
+ if name == :property
152
+ "properties"
153
+ else
154
+ "#{name}s"
155
+ end
156
+ end
157
+
158
+ end
159
+
160
+ end
161
+ end
@@ -4,3 +4,4 @@ require 'rspec-puppet/matchers/compile'
4
4
  require 'rspec-puppet/matchers/run'
5
5
  require 'rspec-puppet/matchers/count_generic'
6
6
  require 'rspec-puppet/matchers/dynamic_matchers'
7
+ require 'rspec-puppet/matchers/type_matchers'
@@ -0,0 +1,20 @@
1
+ require 'rake'
2
+ require 'rspec/core/rake_task'
3
+
4
+ desc "Run all RSpec code examples"
5
+ RSpec::Core::RakeTask.new(:rspec) do |t|
6
+ File.exist?('spec/spec.opts') ? opts = File.read("spec/spec.opts").chomp : opts = ""
7
+ t.rspec_opts = opts
8
+ end
9
+
10
+ SPEC_SUITES = (Dir.entries('spec') - ['.', '..','fixtures']).select {|e| File.directory? "spec/#{e}" }
11
+ namespace :rspec do
12
+ SPEC_SUITES.each do |suite|
13
+ desc "Run #{suite} RSpec code examples"
14
+ RSpec::Core::RakeTask.new(suite) do |t|
15
+ t.pattern = "spec/#{suite}/**/*_spec.rb"
16
+ File.exist?('spec/spec.opts') ? opts = File.read("spec/spec.opts").chomp : opts = ""
17
+ t.rspec_opts = opts
18
+ end
19
+ end
20
+ end
@@ -55,6 +55,8 @@ module RSpec::Puppet
55
55
  end
56
56
 
57
57
  def self.get_module_name_from_file(file)
58
+ # FIXME: see discussion at
59
+ # https://github.com/rodjek/rspec-puppet/issues/290
58
60
  if Puppet.version.to_f >= 4.0
59
61
  p = Puppet::Pops::Parser::Lexer2.new
60
62
  else
@@ -113,18 +115,8 @@ module RSpec::Puppet
113
115
  end
114
116
 
115
117
  def self.safe_create_spec_helper
116
- content = <<-EOF
117
- require 'rspec-puppet'
118
-
119
- fixture_path = File.expand_path(File.join(__FILE__, '..', 'fixtures'))
120
-
121
- RSpec.configure do |c|
122
- c.module_path = File.join(fixture_path, 'modules')
123
- c.manifest_dir = File.join(fixture_path, 'manifests')
124
- c.environmentpath = File.join(Dir.pwd, 'spec')
125
- end
126
- EOF
127
- safe_create_file('spec/spec_helper.rb', content)
118
+ content = "require 'rspec-puppet/spec_helper'\n"
119
+ safe_create_file('spec/spec_helper.rb', content)
128
120
  end
129
121
 
130
122
  def self.safe_make_symlink(source, target)
@@ -140,27 +132,7 @@ EOF
140
132
 
141
133
  def self.safe_create_rakefile
142
134
  content = <<-'EOF'
143
- require 'rake'
144
- require 'rspec/core/rake_task'
145
-
146
- desc "Run all RSpec code examples"
147
- RSpec::Core::RakeTask.new(:rspec) do |t|
148
- File.exist?('spec/spec.opts') ? opts = File.read("spec/spec.opts").chomp : opts = ""
149
- t.rspec_opts = opts
150
- end
151
-
152
- SPEC_SUITES = (Dir.entries('spec') - ['.', '..','fixtures']).select {|e| File.directory? "spec/#{e}" }
153
- namespace :rspec do
154
- SPEC_SUITES.each do |suite|
155
- desc "Run #{suite} RSpec code examples"
156
- RSpec::Core::RakeTask.new(suite) do |t|
157
- t.pattern = "spec/#{suite}/**/*_spec.rb"
158
- File.exist?('spec/spec.opts') ? opts = File.read("spec/spec.opts").chomp : opts = ""
159
- t.rspec_opts = opts
160
- end
161
- end
162
- end
163
- task :default => :rspec
135
+ require 'rspec-puppet/rake_task'
164
136
 
165
137
  begin
166
138
  if Gem::Specification::find_by_name('puppet-lint')
@@ -169,9 +141,10 @@ begin
169
141
  task :default => [:rspec, :lint]
170
142
  end
171
143
  rescue Gem::LoadError
144
+ task :default => :rspec
172
145
  end
173
146
  EOF
174
- safe_create_file('Rakefile', content)
147
+ safe_create_file('Rakefile', content)
175
148
  end
176
149
  end
177
150
  end
@@ -0,0 +1,9 @@
1
+ require 'rspec-puppet'
2
+
3
+ fixture_path = File.expand_path(File.join(__FILE__, '..', 'fixtures'))
4
+
5
+ RSpec.configure do |c|
6
+ c.module_path = File.join(fixture_path, 'modules')
7
+ c.manifest_dir = File.join(fixture_path, 'manifests')
8
+ c.environmentpath = File.join(Dir.pwd, 'spec')
9
+ end