puppet 3.7.3 → 3.7.4

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of puppet might be problematic. Click here for more details.

Files changed (57) hide show
  1. data/Gemfile +4 -0
  2. data/ext/build_defaults.yaml +2 -2
  3. data/ext/project_data.yaml +2 -2
  4. data/lib/puppet.rb +1 -1
  5. data/lib/puppet/configurer.rb +7 -4
  6. data/lib/puppet/environments.rb +68 -51
  7. data/lib/puppet/functions/scanf.rb +46 -0
  8. data/lib/puppet/network/http/webrick/rest.rb +3 -0
  9. data/lib/puppet/parser/ast/pops_bridge.rb +2 -1
  10. data/lib/puppet/parser/compiler.rb +11 -3
  11. data/lib/puppet/parser/functions/realize.rb +7 -2
  12. data/lib/puppet/parser/functions/scanf.rb +35 -0
  13. data/lib/puppet/parser/relationship.rb +21 -6
  14. data/lib/puppet/parser/resource.rb +11 -4
  15. data/lib/puppet/pops.rb +7 -0
  16. data/lib/puppet/pops/evaluator/access_operator.rb +1 -6
  17. data/lib/puppet/pops/evaluator/collector_transformer.rb +219 -0
  18. data/lib/puppet/pops/evaluator/collectors/abstract_collector.rb +86 -0
  19. data/lib/puppet/pops/evaluator/collectors/catalog_collector.rb +25 -0
  20. data/lib/puppet/pops/evaluator/collectors/exported_collector.rb +66 -0
  21. data/lib/puppet/pops/evaluator/collectors/fixed_set_collector.rb +37 -0
  22. data/lib/puppet/pops/evaluator/compare_operator.rb +8 -28
  23. data/lib/puppet/pops/evaluator/evaluator_impl.rb +4 -18
  24. data/lib/puppet/pops/evaluator/relationship_operator.rb +4 -0
  25. data/lib/puppet/pops/evaluator/runtime3_support.rb +2 -2
  26. data/lib/puppet/pops/parser/egrammar.ra +3 -3
  27. data/lib/puppet/pops/parser/eparser.rb +3 -3
  28. data/lib/puppet/pops/parser/evaluating_parser.rb +4 -0
  29. data/lib/puppet/pops/types/type_calculator.rb +19 -8
  30. data/lib/puppet/pops/types/type_parser.rb +1 -4
  31. data/lib/puppet/provider/service/redhat.rb +6 -3
  32. data/lib/puppet/resource/catalog.rb +12 -1
  33. data/lib/puppet/settings/environment_conf.rb +7 -8
  34. data/lib/puppet/type/cron.rb +5 -1
  35. data/lib/puppet/type/file/content.rb +1 -1
  36. data/lib/puppet/util/tagging.rb +21 -2
  37. data/lib/puppet/version.rb +1 -1
  38. data/spec/integration/indirector/catalog/compiler_spec.rb +11 -0
  39. data/spec/integration/parser/collector_spec.rb +41 -0
  40. data/spec/integration/parser/compiler_spec.rb +16 -0
  41. data/spec/integration/parser/future_compiler_spec.rb +1 -1
  42. data/spec/unit/environments_spec.rb +238 -118
  43. data/spec/unit/functions/scanf_spec.rb +36 -0
  44. data/spec/unit/network/http/rack/rest_spec.rb +11 -8
  45. data/spec/unit/network/http/webrick/rest_spec.rb +19 -0
  46. data/spec/unit/parser/compiler_spec.rb +0 -27
  47. data/spec/unit/pops/evaluator/access_ops_spec.rb +9 -9
  48. data/spec/unit/pops/evaluator/comparison_ops_spec.rb +14 -8
  49. data/spec/unit/pops/evaluator/evaluating_parser_spec.rb +20 -8
  50. data/spec/unit/pops/parser/parse_basic_expressions_spec.rb +10 -0
  51. data/spec/unit/pops/parser/parse_heredoc_spec.rb +30 -0
  52. data/spec/unit/pops/types/type_calculator_spec.rb +18 -0
  53. data/spec/unit/pops/types/type_parser_spec.rb +2 -2
  54. data/spec/unit/provider/service/redhat_spec.rb +2 -1
  55. data/spec/unit/type/cron_spec.rb +24 -24
  56. data/spec/unit/util/tagging_spec.rb +7 -0
  57. metadata +11 -2
@@ -0,0 +1,37 @@
1
+ class Puppet::Pops::Evaluator::Collectors::FixedSetCollector < Puppet::Pops::Evaluator::Collectors::AbstractCollector
2
+
3
+ # Creates a FixedSetCollector using the AbstractCollector constructor
4
+ # to set the scope. It is not possible for a collection to have
5
+ # overrides in this case, since we have a fixed set of resources that
6
+ # can be different types.
7
+ #
8
+ # @param [Array] resources the fixed set of resources we want to realize
9
+ def initialize(scope, resources)
10
+ super(scope)
11
+ @resources = resources.is_a?(Array)? resources.dup : [resources]
12
+ end
13
+
14
+ # Collects a fixed set of resources and realizes them. Used
15
+ # by the realize function
16
+ def collect
17
+ resolved = []
18
+ result = @resources.reduce([]) do |memo, ref|
19
+ if res = @scope.findresource(ref.to_s)
20
+ res.virtual = false
21
+ memo << res
22
+ resolved << ref
23
+ end
24
+ memo
25
+ end
26
+
27
+ @resources = @resources - resolved
28
+
29
+ @scope.compiler.delete_collection(self) if @resources.empty?
30
+
31
+ result
32
+ end
33
+
34
+ def unresolved_resources
35
+ @resources
36
+ end
37
+ end
@@ -39,47 +39,27 @@ class Puppet::Pops::Evaluator::CompareOperator
39
39
  protected
40
40
 
41
41
  def cmp_String(a, b)
42
- # if both are numerics in string form, compare as number
43
- n1 = Puppet::Pops::Utils.to_n(a)
44
- n2 = Puppet::Pops::Utils.to_n(b)
45
-
46
- # Numeric is always lexically smaller than a string, even if the string is empty.
47
- return n1 <=> n2 if n1 && n2
48
- return -1 if n1 && b.is_a?(String)
49
- return 1 if n2
50
42
  return a.casecmp(b) if b.is_a?(String)
51
-
52
- raise ArgumentError.new("A String is not comparable to a non String or Number")
43
+ raise ArgumentError.new("A String is not comparable to a non String")
53
44
  end
54
45
 
55
46
  # Equality is case independent.
56
47
  def equals_String(a, b)
57
- if n1 = Puppet::Pops::Utils.to_n(a)
58
- if n2 = Puppet::Pops::Utils.to_n(b)
59
- n1 == n2
60
- else
61
- false
62
- end
63
- else
64
- return false unless b.is_a?(String)
65
- a.casecmp(b) == 0
66
- end
48
+ return false unless b.is_a?(String)
49
+ a.casecmp(b) == 0
67
50
  end
68
51
 
69
52
  def cmp_Numeric(a, b)
70
- if n2 = Puppet::Pops::Utils.to_n(b)
71
- a <=> n2
72
- elsif b.kind_of?(String)
73
- # Numeric is always lexiographically smaller than a string, even if the string is empty.
74
- -1
53
+ if b.is_a?(Numeric)
54
+ a <=> b
75
55
  else
76
- raise ArgumentError.new("A Numeric is not comparable to non Numeric or String")
56
+ raise ArgumentError.new("A Numeric is not comparable to non Numeric")
77
57
  end
78
58
  end
79
59
 
80
60
  def equals_Numeric(a, b)
81
- if n2 = Puppet::Pops::Utils.to_n(b)
82
- a == n2
61
+ if b.is_a?(Numeric)
62
+ a == b
83
63
  else
84
64
  false
85
65
  end
@@ -562,26 +562,12 @@ class Puppet::Pops::Evaluator::EvaluatorImpl
562
562
  end
563
563
  end
564
564
 
565
- # Evaluates a CollectExpression by transforming it into a 3x AST::Collection and then evaluating that.
566
- # This is done because of the complex API between compiler, indirector, backends, and difference between
567
- # collecting virtual resources and exported resources.
565
+ # Evaluates a CollectExpression by creating a collector transformer. The transformer
566
+ # will evaulate the collection, create the appropriate collector, and hand it off
567
+ # to the compiler to collect the resources specified by the query.
568
568
  #
569
569
  def eval_CollectExpression o, scope
570
- # The Collect Expression and its contained query expressions are implemented in such a way in
571
- # 3x that it is almost impossible to do anything about them (the AST objects are lazily evaluated,
572
- # and the built structure consists of both higher order functions and arrays with query expressions
573
- # that are either used as a predicate filter, or given to an indirection terminus (such as the Puppet DB
574
- # resource terminus). Unfortunately, the 3x implementation has many inconsistencies that the implementation
575
- # below carries forward.
576
- #
577
- collect_3x = Puppet::Pops::Model::AstTransformer.new().transform(o)
578
- collected = collect_3x.evaluate(scope)
579
- # the 3x returns an instance of Parser::Collector (but it is only registered with the compiler at this
580
- # point and does not contain any valuable information (like the result)
581
- # Dilemma: If this object is returned, it is a first class value in the Puppet Language and we
582
- # need to be able to perform operations on it. We can forbid it from leaking by making CollectExpression
583
- # a non R-value. This makes it possible for the evaluator logic to make use of the Collector.
584
- collected
570
+ Puppet::Pops::Evaluator::CollectorTransformer.new().transform(o,scope)
585
571
  end
586
572
 
587
573
  def eval_ParenthesizedExpression(o, scope)
@@ -76,6 +76,10 @@ class Puppet::Pops::Evaluator::RelationshipOperator
76
76
  o
77
77
  end
78
78
 
79
+ def transform_AbstractCollector(o, scope)
80
+ o
81
+ end
82
+
79
83
  # Array content needs to be transformed
80
84
  def transform_Array(o, scope)
81
85
  o.map{|x| transform(x, scope) }
@@ -194,7 +194,7 @@ module Puppet::Pops::Evaluator::Runtime3Support
194
194
  # And if that is not enough, a source/target may be a Collector (a baked query that will be evaluated by the
195
195
  # compiler - it is simply passed through here for processing by the compiler at the right time).
196
196
  #
197
- if source.is_a?(Puppet::Parser::Collector)
197
+ if source.is_a?(Puppet::Parser::Collector) || source.is_a?(Puppet::Pops::Evaluator::Collectors::AbstractCollector)
198
198
  # use verbatim - behavior defined by 3x
199
199
  source_resource = source
200
200
  else
@@ -202,7 +202,7 @@ module Puppet::Pops::Evaluator::Runtime3Support
202
202
  type, title = catalog_type_to_split_type_title(source)
203
203
  source_resource = Puppet::Resource.new(type, title)
204
204
  end
205
- if target.is_a?(Puppet::Parser::Collector)
205
+ if target.is_a?(Puppet::Parser::Collector) || target.is_a?(Puppet::Pops::Evaluator::Collectors::AbstractCollector)
206
206
  # use verbatim - behavior defined by 3x
207
207
  target_resource = target
208
208
  else
@@ -635,14 +635,14 @@ reserved_word
635
635
 
636
636
  array
637
637
  : LISTSTART assignments endcomma RBRACK { result = Factory.LIST(val[1]); loc result, val[0], val[3] }
638
- | LISTSTART RBRACK { result = Factory.literal([]) ; loc result, val[0] }
638
+ | LISTSTART RBRACK { result = Factory.literal([]) ; loc result, val[0], val[1] }
639
639
  | LBRACK assignments endcomma RBRACK { result = Factory.LIST(val[1]); loc result, val[0], val[3] }
640
- | LBRACK RBRACK { result = Factory.literal([]) ; loc result, val[0] }
640
+ | LBRACK RBRACK { result = Factory.literal([]) ; loc result, val[0], val[1] }
641
641
 
642
642
  hash
643
643
  : LBRACE hashpairs RBRACE { result = Factory.HASH(val[1]); loc result, val[0], val[2] }
644
644
  | LBRACE hashpairs COMMA RBRACE { result = Factory.HASH(val[1]); loc result, val[0], val[3] }
645
- | LBRACE RBRACE { result = Factory.literal({}) ; loc result, val[0], val[3] }
645
+ | LBRACE RBRACE { result = Factory.literal({}) ; loc result, val[0], val[1] }
646
646
 
647
647
  hashpairs
648
648
  : hashpair { result = [val[0]] }
@@ -2360,7 +2360,7 @@ module_eval(<<'.,.,', 'egrammar.ra', 636)
2360
2360
 
2361
2361
  module_eval(<<'.,.,', 'egrammar.ra', 637)
2362
2362
  def _reduce_180(val, _values, result)
2363
- result = Factory.literal([]) ; loc result, val[0]
2363
+ result = Factory.literal([]) ; loc result, val[0], val[1]
2364
2364
  result
2365
2365
  end
2366
2366
  .,.,
@@ -2374,7 +2374,7 @@ module_eval(<<'.,.,', 'egrammar.ra', 638)
2374
2374
 
2375
2375
  module_eval(<<'.,.,', 'egrammar.ra', 639)
2376
2376
  def _reduce_182(val, _values, result)
2377
- result = Factory.literal([]) ; loc result, val[0]
2377
+ result = Factory.literal([]) ; loc result, val[0], val[1]
2378
2378
  result
2379
2379
  end
2380
2380
  .,.,
@@ -2395,7 +2395,7 @@ module_eval(<<'.,.,', 'egrammar.ra', 643)
2395
2395
 
2396
2396
  module_eval(<<'.,.,', 'egrammar.ra', 644)
2397
2397
  def _reduce_185(val, _values, result)
2398
- result = Factory.literal({}) ; loc result, val[0], val[3]
2398
+ result = Factory.literal({}) ; loc result, val[0], val[1]
2399
2399
  result
2400
2400
  end
2401
2401
  .,.,
@@ -60,6 +60,10 @@ class Puppet::Pops::Parser::EvaluatingParser
60
60
  @@evaluator
61
61
  end
62
62
 
63
+ def convert_to_3x(object, scope)
64
+ val = @@evaluator.convert(object, scope, nil)
65
+ end
66
+
63
67
  def validate(parse_result)
64
68
  resulting_acceptor = acceptor()
65
69
  validator(resulting_acceptor).validate(parse_result)
@@ -272,7 +272,12 @@ class Puppet::Pops::Types::TypeCalculator
272
272
  # Unit can be assigned to anything
273
273
  return true if t2.class == Types::PUnitType
274
274
 
275
- @@assignable_visitor.visit_this_1(self, t, t2)
275
+ if t2.class == Types::PVariantType
276
+ # Assignable if all contained types are assignable
277
+ t2.types.all? { |vt| @@assignable_visitor.visit_this_1(self, t, vt) }
278
+ else
279
+ @@assignable_visitor.visit_this_1(self, t, t2)
280
+ end
276
281
  end
277
282
 
278
283
  # Returns an enumerable if the t represents something that can be iterated
@@ -411,9 +416,18 @@ class Puppet::Pops::Types::TypeCalculator
411
416
  return false unless o.is_a?(Array)
412
417
  return false unless o.all? {|element| instance_of(t.element_type, element) }
413
418
  size_t = t.size_type || @collection_default_size_t
414
- size_t2 = size_as_type(o)
415
419
  # optimize by calling directly
416
- assignable_PIntegerType(size_t, size_t2)
420
+ return instance_of_PIntegerType(size_t, o.size)
421
+ end
422
+
423
+ # @api private
424
+ def instance_of_PIntegerType(t, o)
425
+ return false unless o.is_a?(Integer)
426
+ x = t.from
427
+ x = -Float::INFINITY if x.nil? || x == :default
428
+ y = t.to
429
+ y = Float::INFINITY if y.nil? || y == :default
430
+ return x < y ? x <= o && y >= o : y <= o && x >= o
417
431
  end
418
432
 
419
433
  def instance_of_PTupleType(t, o)
@@ -421,9 +435,7 @@ class Puppet::Pops::Types::TypeCalculator
421
435
  # compute the tuple's min/max size, and check if that size matches
422
436
  size_t = t.size_type || Puppet::Pops::Types::TypeFactory.range(*t.size_range)
423
437
 
424
- # compute the array's size as type
425
- size_t2 = size_as_type(o)
426
- return false unless assignable?(size_t, size_t2)
438
+ return false unless instance_of_PIntegerType(size_t, o.size)
427
439
  o.each_with_index do |element, index|
428
440
  return false unless instance_of(t.types[index] || t.types[-1], element)
429
441
  end
@@ -443,9 +455,8 @@ class Puppet::Pops::Types::TypeCalculator
443
455
  element_t = t.element_type
444
456
  return false unless o.keys.all? {|key| instance_of(key_t, key) } && o.values.all? {|value| instance_of(element_t, value) }
445
457
  size_t = t.size_type || @collection_default_size_t
446
- size_t2 = size_as_type(o)
447
458
  # optimize by calling directly
448
- assignable_PIntegerType(size_t, size_t2)
459
+ return instance_of_PIntegerType(size_t, o.size)
449
460
  end
450
461
 
451
462
  def instance_of_PDataType(t, o)
@@ -230,9 +230,6 @@ class Puppet::Pops::Types::TypeParser
230
230
 
231
231
  when "hash"
232
232
  result = case parameters.size
233
- when 1
234
- assert_type(parameters[0])
235
- TYPES.hash_of(parameters[0])
236
233
  when 2
237
234
  assert_type(parameters[0])
238
235
  assert_type(parameters[1])
@@ -256,7 +253,7 @@ class Puppet::Pops::Types::TypeParser
256
253
  assert_type(parameters[1])
257
254
  TYPES.hash_of(parameters[1], parameters[0])
258
255
  else
259
- raise_invalid_parameters_error("Hash", "1 to 4", parameters.size)
256
+ raise_invalid_parameters_error("Hash", "2 to 4", parameters.size)
260
257
  end
261
258
  result.size_type = size_type if size_type
262
259
  result
@@ -15,9 +15,11 @@ Puppet::Type.type(:service).provide :redhat, :parent => :init, :source => :init
15
15
  # The off method operates on run levels 2,3,4 and 5 by default We ensure
16
16
  # all run levels are turned off because the reset method may turn on the
17
17
  # service in run levels 0, 1 and/or 6
18
- output = chkconfig("--level", "0123456", @resource[:name], :off)
19
- rescue Puppet::ExecutionFailure
20
- raise Puppet::Error, "Could not disable #{self.name}: #{output}", $!.backtrace
18
+ # We're not using --del here because we want to disable the service only,
19
+ # and --del removes the service from chkconfig management
20
+ chkconfig("--level", "0123456", @resource[:name], :off)
21
+ rescue Puppet::ExecutionFailure => detail
22
+ raise Puppet::Error, "Could not disable #{self.name}: #{detail}", detail.backtrace
21
23
  end
22
24
 
23
25
  def enabled?
@@ -39,6 +41,7 @@ Puppet::Type.type(:service).provide :redhat, :parent => :init, :source => :init
39
41
  # Don't support them specifying runlevels; always use the runlevels
40
42
  # in the init scripts.
41
43
  def enable
44
+ chkconfig("--add", @resource[:name])
42
45
  chkconfig(@resource[:name], :on)
43
46
  rescue Puppet::ExecutionFailure => detail
44
47
  raise Puppet::Error, "Could not enable #{self.name}: #{detail}", detail.backtrace
@@ -416,7 +416,18 @@ class Puppet::Resource::Catalog < Puppet::Graph::SimpleGraph
416
416
  # If the block result is false, the resource will
417
417
  # be kept otherwise it will be skipped
418
418
  def filter(&block)
419
- to_catalog :to_resource, &block
419
+ # to_catalog must take place in a context where current_environment is set to the same env as the
420
+ # environment set in the catalog (if it is set)
421
+ # See PUP-3755
422
+ if environment_instance
423
+ Puppet.override({:current_environment => environment_instance}) do
424
+ to_catalog :to_resource, &block
425
+ end
426
+ else
427
+ # If catalog has no environment_instance, hope that the caller has made sure the context has the
428
+ # correct current_environment
429
+ to_catalog :to_resource, &block
430
+ end
420
431
  end
421
432
 
422
433
  # Store the classes in the classfile.
@@ -37,11 +37,11 @@ class Puppet::Settings::EnvironmentConf
37
37
  # Configuration values are exactly those returned by the environment object,
38
38
  # without interpolation. This is a special case for the default configured
39
39
  # environment returned by the Puppet::Environments::StaticPrivate loader.
40
- def self.static_for(environment)
41
- Static.new(environment)
40
+ def self.static_for(environment, environment_timeout = 0)
41
+ Static.new(environment, environment_timeout)
42
42
  end
43
43
 
44
- attr_reader :section
44
+ attr_reader :section, :path_to_env, :global_modulepath
45
45
 
46
46
  # Create through EnvironmentConf.load_from()
47
47
  def initialize(path_to_env, section, global_module_path)
@@ -151,8 +151,11 @@ class Puppet::Settings::EnvironmentConf
151
151
  #
152
152
  # @api private
153
153
  class Static
154
- def initialize(environment)
154
+ attr_reader :environment_timeout
155
+
156
+ def initialize(environment, environment_timeout)
155
157
  @environment = environment
158
+ @environment_timeout = environment_timeout
156
159
  end
157
160
 
158
161
  def manifest
@@ -166,10 +169,6 @@ class Puppet::Settings::EnvironmentConf
166
169
  def config_version
167
170
  @environment.config_version
168
171
  end
169
-
170
- def environment_timeout
171
- 0
172
- end
173
172
  end
174
173
 
175
174
  end
@@ -290,7 +290,11 @@ Puppet::Type.newtype(:cron) do
290
290
 
291
291
  newproperty(:month, :parent => CronParam) do
292
292
  def alpha
293
- %w{january february march april may june july
293
+ # The ___placeholder accounts for the fact that month is unique among
294
+ # "nameable" crontab entries in that it does not use 0-based indexing.
295
+ # Padding the array with a placeholder introduces the appropriate shift
296
+ # in indices.
297
+ %w{___placeholder january february march april may june july
294
298
  august september october november december}
295
299
  end
296
300
  self.boundaries = [1, 12]
@@ -135,7 +135,7 @@ module Puppet
135
135
  def should=(value)
136
136
  # treat the value as a bytestring, in Ruby versions that support it, regardless of the encoding
137
137
  # in which it has been supplied
138
- value = value.clone.force_encoding(Encoding::ASCII_8BIT) if value.respond_to?(:force_encoding)
138
+ value = value.dup.force_encoding(Encoding::ASCII_8BIT) if value.respond_to?(:force_encoding)
139
139
  @resource.newattr(:checksum) unless @resource.parameter(:checksum)
140
140
  super
141
141
  end
@@ -23,9 +23,28 @@ module Puppet::Util::Tagging
23
23
  end
24
24
  end
25
25
 
26
- # Is the receiver tagged with the given tags?
26
+ # Answers if this resource is tagged with at least one of the given tags.
27
+ #
28
+ # The given tags are converted to downcased strings before the match is performed.
29
+ #
30
+ # @param *tags [String] splat of tags to look for
31
+ # @return [Boolean] true if this instance is tagged with at least one of the provided tags
32
+ #
27
33
  def tagged?(*tags)
28
- not ( self.tags & tags.flatten.collect { |t| t.to_s } ).empty?
34
+ raw_tagged?(tags.collect {|t| t.to_s.downcase})
35
+ end
36
+
37
+ # Answers if this resource is tagged with at least one of the tags given in downcased string form.
38
+ #
39
+ # The method is a faster variant of the tagged? method that does no conversion of its
40
+ # arguments.
41
+ #
42
+ # @param tag_array [Array[String]] array of tags to look for
43
+ # @return [Boolean] true if this instance is tagged with at least one of the provided tags
44
+ #
45
+ def raw_tagged?(tag_array)
46
+ my_tags = self.tags
47
+ !tag_array.index { |t| my_tags.include?(t) }.nil?
29
48
  end
30
49
 
31
50
  # Return a copy of the tag list, so someone can't ask for our tags
@@ -7,7 +7,7 @@
7
7
 
8
8
 
9
9
  module Puppet
10
- PUPPETVERSION = '3.7.3'
10
+ PUPPETVERSION = '3.7.4'
11
11
 
12
12
  ##
13
13
  # version is a public API method intended to always provide a fast and
@@ -62,4 +62,15 @@ describe Puppet::Resource::Catalog::Compiler do
62
62
 
63
63
  Puppet::Resource::Catalog.indirection.find("mynode").resource_refs.should == [ @two.ref ]
64
64
  end
65
+
66
+ it "filters out virtual exported resources using the agent's production environment" do
67
+ Puppet[:node_terminus] = :memory
68
+ Puppet::Node.indirection.save(Puppet::Node.new("mynode"))
69
+
70
+ Puppet::Parser::Resource::Catalog.any_instance.expects(:to_resource).with do |catalog|
71
+ expect(Puppet.lookup(:current_environment).name).to eq(:production)
72
+ end
73
+
74
+ Puppet::Resource::Catalog.indirection.find("mynode")
75
+ end
65
76
  end