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
         |