Skip to content

Instantly share code, notes, and snippets.

@hlindberg
Last active October 4, 2021 07:17
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save hlindberg/8c250c54f5adb76679576ae5cffff868 to your computer and use it in GitHub Desktop.
Save hlindberg/8c250c54f5adb76679576ae5cffff868 to your computer and use it in GitHub Desktop.
An rspec sample showing some override and mocking of 4.x functions/function loading
require 'spec_helper'
# Example rspec_puppet function rspec test (i.e. subject is the function 'min')
# This works for other rspec subjects as well as a compiler is always involved.
# This kind of mocking can be required when it is not enough to simply override
# a function with another implementation (which can be done with a `let(:pre_condition) { 'function min($x, $y) { ... }'}`
#
# The main difficulty that this overcomes is the need to let the compiler initialize and
# create the context in which it will operate before making any mocks.
#
describe 'min' do
before(:each) {
# An instance of compiler is always used - this adds a wrapper around its creation
# - the wrapper creates the instance (as if the wrapper did not exists (m.call(*args))
# - the wrapper loads a function (in this case the subject, but could load some other function
# the subject function is calling.
# - the loaded function is mocked to accept a call, and return absolute smallest possible number
# - the created compiler is returned
#
expect(Puppet::Parser::Compiler).to receive(:new).and_wrap_original do |m,*args|
the_compiler = m.call(*args)
the_function = the_compiler.loaders.private_environment_loader.load(:function, 'min')
expect(the_function).to receive(:call).and_return(-Float::INFINITY)
the_compiler
end
}
it { is_expected.to run.with_params(1, 2).and_return(-Float::INFINITY) }
end
require 'spec_helper'
require 'puppet/pops'
require 'puppet/loaders'
require 'puppet_spec/compiler'
describe 'a sample function test with override and mocks' do
after(:each) { Puppet::Pops::Loaders.clear }
let(:loaders) { Puppet::Pops::Loaders.new(Puppet::Node::Environment.create(:testing, [])) }
let(:loaded_func) {
loaders.private_environment_loader.load(:function, 'assert_type')
}
let(:dynamic_func) {
f = Puppet::Functions.create_function('test_echo') do
def test_echo(x)
x
end
end
f.new({}, loaders.private_environment_loader)
}
let(:dynamic_func2) {
f = Puppet::Functions.create_function('test_echo') do
def test_echo(x)
[x, x]
end
end
f.new({}, loaders.private_environment_loader)
}
it 'can mock an existing function' do
loaded_func.expects(:call).returns("I am mocked")
expect(loaded_func.call({}, Puppet::Pops::Types::PIntegerType::DEFAULT, 42)).to eq('I am mocked')
end
it 'can call a dynamically created function' do
expect(dynamic_func.call({}, 42)).to eq(42)
end
it 'can add a dynamically loaded function to the loaders and load it' do
loaders.private_environment_loader.add_entry(:function, 'test_echo', dynamic_func, nil)
f = loaders.private_environment_loader.load(:function, 'test_echo')
expect(f.call({}, 42)).to eq(42)
end
it 'can add a dynamically loaded function to the loaders, call it, replace it with another and call that' do
typed_name = Puppet::Pops::Loader::TypedName.new(:function, 'test_echo')
loaders.private_environment_loader.set_entry(typed_name, dynamic_func, nil)
f = loaders.private_environment_loader.load_typed(typed_name).value # load_typed returns a wrapper that contains meta data
expect(f.call({}, 42)).to eq(42)
# drop the loaded
loaders.private_environment_loader.remove_entry(typed_name)
# add/set new definition of the function
loaders.private_environment_loader.set_entry(typed_name, dynamic_func2)
f = loaders.private_environment_loader.load_typed(typed_name).value
expect(f.call({}, 42)).to eq([42, 42])
end
end
require 'spec_helper'
# Example use of rspec_puppet's `pre_condition` feature. This will define the function `myfunction` before
# there is an attempt to load that function from disk. Thus, the function definition in the pre_condition
# will win over the otherwise autoloaded function.
# This is a simple method of overriding - but requires that what is returned can be expressed in the Puppet
# language.
describe 'something' do
let(:pre_condition) { 'function myfunction() { return "the mocked return" }' }
it { # some test
}
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment