puppetlabs / rspec-puppet

RSpec tests for your Puppet manifests
https://puppetlabs.github.io/rspec-puppet/
MIT License
11 stars 18 forks source link

Question on mocking v4 api functions #103

Open gerases opened 5 months ago

gerases commented 5 months ago

Hi,

I've structured my code base so that all rspec setup stuff and mocks are done in one ruby include (default_spec.rb in my case) that all rspec files include. It also included v3 api function mocks (for example the file function). But now I need to mock binary_file, which is a v4 api function.

I've learned that one of the ways to mock those functions is to use a pre_condition block defining the mock code. That works but I would like to do this mock once in a central place like the default_spec.file. That seems problematic as soon as one of the tests defines its own pre_condition block, which overrides the one defined in default_spec.rb.

Is there an elegant way to define a "global" pre_condition block that is immune to being overwritten in one of the tests and that is in effect additive with the ones defined elsewhere?

nabertrand commented 5 months ago

I had run into the same issue and the only thing I could come up with was wrapping the code that instantiates the function and replacing the original function code with a stub. Here's an example of overriding a v4 API function called ssl_certificate within my spec_helper.rb:

RSpec.configure do |c|
  c.before :each do
    allow(Puppet::Pops::Loader::RubyFunctionInstantiator).to receive(:create).and_wrap_original do |original, loader, typed_name, source_ref, ruby_code_string, &_block|
      if typed_name.name == 'ssl_certificate'
        ruby_code_string = 'Puppet::Functions.create_function(:ssl_certificate) do
          def ssl_certificate(*args)
            { "cert" => "#{args}", "chain" => "chain", "fullchain" => "fullchain", "privkey" => "key" }
          end
        end'
      end
      original.call(loader, typed_name, source_ref, ruby_code_string)
    end
  end
end

Out of curiosity, where did you find the hint to mock v4 API functions in a pre_condition block? Is that in the rspec-puppet documentation somewhere?

gerases commented 5 months ago

I found the pre_condition here: https://github.com/rodjek/rspec-puppet/issues/102#issuecomment-372658544.

What you have there is pretty cool though I would never have come up with that myself :) Is that a well-known/recommended approach?

nabertrand commented 5 months ago

I wouldn't say it's well-known or recommended, but it got the job done for me 😁. Ideally there would be a supported method within rspec-puppet that would account for possible argument changes to Puppet::Pops::Loader::RubyFunctionInstantiator.create in new versions of Puppet, but this at least works in Puppet 7 (could work in 8 but I haven't tested).

gerases commented 5 months ago

Your solution works for me as well. Thanks for posting that -- you saved me a ton of research!