How to make stubs in Rspec tests for Elasticsearch Puppet modules

I need help making stubs in order to write Rspec-puppet unit tests for the Elasticsearch Puppet module. Right now, I am stuck on a bit of the code that declares an elasticsearch::template.

elasticsearch::template { 'logstash':
  source => 'puppet:///modules/profile/logstash/logstash.json', 
}

I have code that compiles the role that includes this template that looks like this:

require 'spec_helper'

describe 'role::elk_stack' do
  it { is_expected.to compile.with_all_deps }
end

If I attempt to compile, this fails here, because the Elasticsearch template type has its own custom provider which interacts with Puppet's internals:

From: /Users/alexharvey/git/elk/spec/fixtures/modules/elasticsearch/lib/puppet/type/elasticsearch_template.rb @ line 93 elasticsearch_template#validate:

    88:     end
    89: 
    90:     # If a source was passed, retrieve the source content from Puppet's
    91:     # FileServing indirection and set the content property
    92:     unless self[:source].nil?
 => 93:       unless Puppet::FileServing::Metadata.indirection.find(self[:source])
    94:         fail(format('Could not retrieve source %s', self[:source]))
    95:       end
    96: 
    97:       tmp = if !catalog.nil? \
    98:                 and catalog.respond_to?(:environment_instance)

In the past, I got past problems like this by using Rspec-mocks and stubbing out bits of Puppet's internals.

Thus, I can actually get past this first problem as follows:

require 'spec_helper'
require 'puppet/file_serving'

describe 'role::elk_stack' do
  before(:each) do
    allow(Puppet::FileServing::Metadata.indirection).to receive(:find).and_call_original
    allow(Puppet::FileServing::Metadata.indirection).to receive(:find).with("puppet:///modules/profile/logstash/logstash.json").and_return('foo')
  end
  it { is_expected.to compile.with_all_deps }
end

Then I get stuck here:

 94:         fail(format('Could not retrieve source %s', self[:source]))
 95:       end
 96: 
 97:       tmp = if !catalog.nil? \
 98:                 and catalog.respond_to?(:environment_instance)
 =>  99:               Puppet::FileServing::Content.indirection.find(
100:                 self[:source],
101:                 :environment => catalog.environment_instance
102:               )
103:             else
104:               Puppet::FileServing::Content.indirection.find(self[:source])

The trouble is I can't see how I can then stub out the second parameter, because it's an instance of a class, that is based on my local setup:

[1] pry(#<Puppet::Type::Elasticsearch_template>)> catalog.environment_instance
=> <Puppet::Node::Environment:70189414399600 @name="rp_env" @manifest="/Users/alexharvey/git/elk/spec/fixtures/manifests" @modulepath="/Users/alexharvey/git/elk/spec/fixtures/modules" >

Any advice on how I can get these Elastic Puppet modules to compile in Rspec most appreciated. The code will be published online here

I asked a related Rspec question on Stack Overflow and received an answer here https://stackoverflow.com/questions/50832951/how-to-allow-a-class-to-receive-an-instance-of-a-class-in-rspec-mocks#50832951

Hi @Alex_Harvey, thank you for reporting back with the ultimate solution. I was out of the office when your question came up, so I apologize for not getting to it earlier.

If you run into any other bumps writing specs for the module, do let us know. To be honest, I'm not an rspec expert, so asking something rspec-specific on Stack Overflow for some rspec expert input seems like a better approach in this case, at least. :smile:

This topic was automatically closed 28 days after the last reply. New replies are no longer allowed.