bolt icon indicating copy to clipboard operation
bolt copied to clipboard

BoltSpec should be able to mock Puppet functions

Open op-ct opened this issue 4 years ago • 3 comments

Use Case

I have plans that use Puppet functions.

I want to test these plans with BoltSpec, but I can't because BoltSpec doesn't mock functions yet.

Describe the Solution You Would Like

A new method in BoltSpec that can mock Puppet functions.

Additional Context

  • The "normal" rspec-puppet approaches to mocking Puppet 4+ functions don't work, because Bolt compiles plans using its own separate Puppet compiler (accessed via Bolt::PAL).
  • In the #bolt slack, @nicklewis pointed out Puppet::Parser::EnvironmentCompiler#add_function_override as an example of the kind of functionality that we'd have to add to the Bolt compiler for it to support a function-mocking BoltSpec function. (slack discussion)

Describe Alternatives You've Considered

We discussed other approaches in the #bolt slack that ranged from "impossible" to "effectively impossible":

  1. Adding a function stub with pal.evaluate_string before example.run. This would override the mocked function with a pure Puppet language stub just before compiling the example, like the rspec-puppet let(:pre_condition) { "function foo::bar{ return 'blah' }" } technique for mocking Puppet 4+ functions. (slack discussion).

    :no_entry_sign: This approach won't work in BoltSpec. The life cycle of the relevant PAL object is bound to the BoltSpec::Plans module's run_plan method, and there's no opportunity to get at the compiler to before the example runs.

    It would also limit the stubbed function's definition to the Puppet language. (slack discussion)

  2. Substituting the compiler object with a (wrapped) mock + expectation for the function Since we can't get at anything inside run_plan, intercept the Puppet compiler object before run_plan gets hold of it: set an RSpec expectation for the compiler object's constructor, use .and_wrap_original to mock it, and stub out the mocked function call by setting another expectation on the mocked compiler object (returning a suitable object with .and_return). @hlindberg originally suggested this approach to mock complex Puppet 4 functions in rspec-puppet. (https://gist.github.com/hlindberg/8c250c54f5adb76679576ae5cffff868).

    :no_entry_sign: Mocking Bolt's compiler like this might not be impossible, but the process would be so difficult and fragile, it pretty much is. (slack discusson)

  3. Adding a stub version of the function to the front of the modulepath @nicklewis suggested this as a workaround to the other approaches.

    :no_entry_sign::question: Placing any path before the one that contains the plan under test makes BoltSpec/respc-puppet/PAL/something unable to find the plan, resulting in a Bolt::Error: Could not find a plan named <plan_name> failure. It's not clear why this happens. (slack discussion)

op-ct avatar May 11 '20 19:05 op-ct

My team was about to file a new issue (text below), looks like this is the same as our request.


When writing a unit test for a plan, we need to be able to allow or expect custom function calls as well as task and plan runs. At this moment, this is unfortunately not possible using BoltSpec. This makes unit tests of plans less useful since a unit test for a plan currently basically consists of just allowing or expecting task or plan runs in a specified order.

The module https://github.com/puppetlabs/puppetlabs-peadm contains many plans which we would like to simplify testing for by mocking functions. As an example, in this unit test we would ideally just mock the peadm::file_content_upload() function. Because that isn't possible, we are left to dig deep into the function's innards as a workaround.


Thought: could we rig this up by injecting a new/custom function loader, which loads any mock functions first? https://www.rubydoc.info/gems/puppet/Puppet/Pops/Loader/BaseLoader

reidmv avatar Jun 29 '21 17:06 reidmv

This issue has not had activity for 60 days and will be marked as stale. If this issue continues to have no activity for 7 days, it will be closed.

github-actions[bot] avatar Jul 29 '22 01:07 github-actions[bot]

I am currently struggling with this exact issue, so just wanted to add a note saying I think this would be super helpful in maintaining clean tests.

glangloi avatar Aug 05 '22 21:08 glangloi

This issue has not had activity for 60 days and will be marked as stale. If this issue continues to have no activity for 7 days, it will be closed.

github-actions[bot] avatar Oct 05 '22 00:10 github-actions[bot]

This issue is stale and has been closed. If you believe this is in error, or would like the Bolt team to reconsider it, please reopen the issue.

github-actions[bot] avatar Oct 12 '22 00:10 github-actions[bot]