Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Add support for pre_condition with functions #36

Merged
merged 1 commit into from

3 participants

Dan Bode Jeff McCune Tim Sharpe
Dan Bode
Collaborator

This commit adds support for using the pre_condition
hook to specify the source code that should be used to
compile a catalog that can be introspected by functions for
testing purposes.

This allows users to test functions that need access to
catalog contents.

This allows the following snippet to test a function that
needs access to the catalog generated by pre_condition:

describe 'defined_with_params' do
#describe 'when resource is passed as a string' do
let :pre_condition do
'user { "dan": }'
end
it { should run.with_params('User[dan]', {}).and_return('true') }
end

Dan Bode bodepd Add support for pre_condition with functions
This commit adds support for using the pre_condition
hook to specify the source code that should be used to
compile a catalog that can be introspected by functions for
testing purposes.

This allows users to test functions that need access to
catalog contents.

This allows the following snippet to test a function that
needs access to the catalog generated by pre_condition:

  describe 'defined_with_params' do
    #describe 'when resource is passed as a string' do
    let :pre_condition do
      'user { "dan": }'
    end
    it { should run.with_params('User[dan]', {}).and_return('true') }
  end
41a2fc8
Tim Sharpe rodjek merged commit e3495af into from
Jeff McCune jeffmccune commented on the diff
lib/rspec-puppet/example/function_example_group.rb
((7 lines not shown))
+ if self.respond_to? :pre_condition
+ Puppet[:code] = pre_condition
+ nodename = self.respond_to?(:node) ? node : Puppet[:certname]
+ facts_val = {
+ 'hostname' => nodename.split('.').first,
+ 'fqdn' => nodename,
+ 'domain' => nodename.split('.').last,
+ }
+ facts_val.merge!(munge_facts(facts)) if self.respond_to?(:facts)
+ # we need to get a compiler, b/c we can attach that to a scope
+ @compiler = build_compiler(nodename, facts_val)
+ else
+ @compiler = nil
+ end
+
+ scope = Puppet::Parser::Scope.new(:compiler => @compiler)
Jeff McCune Collaborator

Today, rspec-puppet should not reach directly into Puppet to obtain a scope instance. Instead, it should use the puppetlabs_spec_helper to obtain a scope instance in Puppet version-agnostic manner. As a concrete example, this line:

scope = Puppet::Parser::Scope.new(:compiler => @compiler)

should be:

scope = PuppetlabsSpec::PuppetInternals.scope

This is important because if we change the behavior of the scope object again we will also change PuppetlabsSpec::PuppetInternals.scope to work correctly. rspec-puppet will then "just work" instead of breaking again.

It's very likely that the method signature of the scope object will change as we inject more dependencies through the initializer rather than relying on global process state.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Jeff McCune jeffmccune commented on the diff
lib/rspec-puppet/example/function_example_group.rb
((23 lines not shown))
scope.method "function_#{function_name}".to_sym
end
+
+ def compiler
+ @compiler
+ end
+ # get a compiler with an attached compiled catalog
+ def build_compiler(node_name, fact_values)
+ compiler = Puppet::Parser::Compiler.new(Puppet::Node.new(node_name, :parameters => fact_values))
+ compiler.compile
+ compiler
+ end
Jeff McCune Collaborator

The same logic applies here. rspec-puppet should not reach deep into Puppet to build a compiler instance. Instead, it should use puppetlabs_spec_helper to obtain a compiler instance in a Puppet version agnostic way.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Dan Bode
Collaborator

@rodjek Hi Tim, it is probably worth reading through Jeff's comments here. It has implications beyond the single pull request referenced here. It looks like rspec-puppet puppet is going through a few unsupported APIs and the recommended approach is to add an extra dependency on the puppetlabs spec helper gem and refactor calls that call puppet directly to instead make calls through the supported APIs made available by this gem.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Aug 2, 2012
  1. Dan Bode

    Add support for pre_condition with functions

    bodepd authored
    This commit adds support for using the pre_condition
    hook to specify the source code that should be used to
    compile a catalog that can be introspected by functions for
    testing purposes.
    
    This allows users to test functions that need access to
    catalog contents.
    
    This allows the following snippet to test a function that
    needs access to the catalog generated by pre_condition:
    
      describe 'defined_with_params' do
        #describe 'when resource is passed as a string' do
        let :pre_condition do
          'user { "dan": }'
        end
        it { should run.with_params('User[dan]', {}).and_return('true') }
      end
This page is out of date. Refresh to see the latest.
Showing with 28 additions and 1 deletion.
  1. +28 −1 lib/rspec-puppet/example/function_example_group.rb
29 lib/rspec-puppet/example/function_example_group.rb
View
@@ -9,9 +9,36 @@ def subject
Puppet[:libdir] = Dir["#{Puppet[:modulepath]}/*/lib"].entries.join(File::PATH_SEPARATOR)
Puppet::Parser::Functions.autoloader.loadall
- scope = Puppet::Parser::Scope.new
+ # if we specify a pre_condition, we should ensure that we compile that code
+ # into a catalog that is accessible from the scope where the function is called
+ if self.respond_to? :pre_condition
+ Puppet[:code] = pre_condition
+ nodename = self.respond_to?(:node) ? node : Puppet[:certname]
+ facts_val = {
+ 'hostname' => nodename.split('.').first,
+ 'fqdn' => nodename,
+ 'domain' => nodename.split('.').last,
+ }
+ facts_val.merge!(munge_facts(facts)) if self.respond_to?(:facts)
+ # we need to get a compiler, b/c we can attach that to a scope
+ @compiler = build_compiler(nodename, facts_val)
+ else
+ @compiler = nil
+ end
+
+ scope = Puppet::Parser::Scope.new(:compiler => @compiler)
Jeff McCune Collaborator

Today, rspec-puppet should not reach directly into Puppet to obtain a scope instance. Instead, it should use the puppetlabs_spec_helper to obtain a scope instance in Puppet version-agnostic manner. As a concrete example, this line:

scope = Puppet::Parser::Scope.new(:compiler => @compiler)

should be:

scope = PuppetlabsSpec::PuppetInternals.scope

This is important because if we change the behavior of the scope object again we will also change PuppetlabsSpec::PuppetInternals.scope to work correctly. rspec-puppet will then "just work" instead of breaking again.

It's very likely that the method signature of the scope object will change as we inject more dependencies through the initializer rather than relying on global process state.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
scope.method "function_#{function_name}".to_sym
end
+
+ def compiler
+ @compiler
+ end
+ # get a compiler with an attached compiled catalog
+ def build_compiler(node_name, fact_values)
+ compiler = Puppet::Parser::Compiler.new(Puppet::Node.new(node_name, :parameters => fact_values))
+ compiler.compile
+ compiler
+ end
Jeff McCune Collaborator

The same logic applies here. rspec-puppet should not reach deep into Puppet to build a compiler instance. Instead, it should use puppetlabs_spec_helper to obtain a compiler instance in a Puppet version agnostic way.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
end
end
Something went wrong with that request. Please try again.