Ralph Urban
Ralph Urban

Reputation: 45

Puppet unit test changing parameters between tests

I have a question concerning how to set up multiple tests for the same resource and changing parameters for different tests. The example is minimized to reflect just the problem.

TheGood: I got the first unit test running, where the parameter is a direct parameter of the resource: mymod/manifests/as/myressource3.pp:

define mymod::as::myressource3 (
  Optional[String] $maxheap = undef,
) {
  $effective_maxheap = ($maxheap =~ NotUndef) ? {
    true => $maxheap,
    false => "${::facts['memory']['system']['total_bytes'] * 3 / 4 / 1024 / 1024}M",
  }
  notice("effective_maxheap = ${effective_maxheap}")
  mymod::as::myressource2 {"myres3_myres2-${title}":
    maxheap => $effective_maxheap,
  }
}

mymod/spec/defines/as/myressource3_spec.rb:

require 'spec_helper'

describe 'mymod::as::myressource3' do
  let(:title) { 'as_myressource3_test' }
  on_supported_os.each do |os, os_facts|
    context "no maxheap on #{os}" do
      let(:facts) { os_facts }
      let(:params) { {
      } }
      it { is_expected.to compile }
      it { is_expected.to contain_mymod__as__myressource2("myres3_myres2-as_myressource3_test").with({
        :maxheap => /^[0-9]+M$/,
      })}

      context "with maxheap on #{os}" do
        let(:params) do
          super().merge('maxheap' => '3G')
        end
        it { is_expected.to compile }
        it { is_expected.to contain_mymod__as__myressource2("myres3_myres2-as_myressource3_test").with({
          :maxheap => '3G',
        })}
      end
    end
  end
end

As said, this works fine and I can change the value of the parameter maxheap for the second test.

TheBad: But in a different situation another resource is using a „global“ variable from an outer class. Using the same approach as in „TheGood“, I am not able the change the parameter in the second context.

mymod/manifests/as/myressource.pp:

define mymod::as::myressource (
) {
  $effective_maxheap = ($::mymod::maxheap =~ NotUndef) ? {
    true => $::mymod::maxheap,
    false => "${::facts['memory']['system']['total_bytes'] * 3 / 4 / 1024 / 1024}M",
  }
  notice("effective_maxheap = ${effective_maxheap}")
  mymod::as::myressource2 {"myres_myres2-${title}":
    maxheap => $effective_maxheap,
  }
}

notice the use of $::mymod::maxheap!

mymod/manifests/init.pp:

class mymod(
  Optional[String] $maxheap = undef,
) {
  notice("${title} start maxheap=${maxheap} ...")

  mymod::as::myressource {'whatever': }

  notice("${title} end ...")
}

mymod/spec/defines/as/myressource_spec.rb:

require 'spec_helper'

describe 'mymod::as::myressource' do
  let(:title) { 'as_myressource_test' }
  on_supported_os.each do |os, os_facts|
    context "no maxheap on #{os}" do
      let(:facts) { os_facts }
      let(:pre_condition) do
        "
          class { 'mymod':
          }
        "
      end
      it { is_expected.to compile }
      it { is_expected.to contain_mymod__as__myressource2("myres_myres2-as_myressource_test").with({
        :maxheap => /^[0-9]+M$/,
      })}

      context "with maxheap on #{os}" do
        let(:params) do
          super().merge('::mymod::maxheap' => '3G')
        end
        it { is_expected.to compile }
        it { is_expected.to contain_mymod__as__myressource2("myres_myres2-as_myressource_test").with({
          :maxheap => '3G'
        })}
      end
    end
  end
end

This is giving the following exeption:

  1) mymod::as::myressource no maxheap on sles-12-x86_64 with maxheap on sles-12-x86_64 is expected to compile into a catalogue without dependency cycles
     Failure/Error: super().merge('::mymod::maxheap' => '3G')

     NoMethodError:
       super: no superclass method `params' for #<RSpec::ExampleGroups::MymodAsMyressource::NoMaxheapOnSles12X8664::WithMaxheapOnSles12X8664:0x000000000781c5c0>
       Did you mean?  param_str
     # /opt/puppetlabs/pdk/share/cache/ruby/2.5.0/gems/rspec-puppet-2.7.8/lib/rspec-puppet/matchers/dynamic_matchers.rb:7:in `method_missing'
     # ./spec/defines/as/myressource_spec.rb:23:in `block (5 levels) in <top (required)>'
     # /opt/puppetlabs/pdk/share/cache/ruby/2.5.0/gems/rspec-puppet-2.7.8/lib/rspec-puppet/support.rb:149:in `test_manifest'
     # /opt/puppetlabs/pdk/share/cache/ruby/2.5.0/gems/rspec-puppet-2.7.8/lib/rspec-puppet/support.rb:21:in `build_code'
     # /opt/puppetlabs/pdk/share/cache/ruby/2.5.0/gems/rspec-puppet-2.7.8/lib/rspec-puppet/support.rb:91:in `block in load_catalogue'
     # /opt/puppetlabs/pdk/share/cache/ruby/2.5.0/gems/rspec-puppet-2.7.8/lib/rspec-puppet/support.rb:376:in `with_vardir'
     # /opt/puppetlabs/pdk/share/cache/ruby/2.5.0/gems/rspec-puppet-2.7.8/lib/rspec-puppet/support.rb:83:in `load_catalogue'
     # /opt/puppetlabs/pdk/share/cache/ruby/2.5.0/gems/rspec-puppet-2.7.8/lib/rspec-puppet/example/define_example_group.rb:7:in `catalogue'
     # /opt/puppetlabs/pdk/share/cache/ruby/2.5.0/gems/rspec-puppet-2.7.8/lib/rspec-puppet/support.rb:12:in `block in subject'
     # /opt/puppetlabs/pdk/share/cache/ruby/2.5.0/gems/rspec-puppet-2.7.8/lib/rspec-puppet/matchers/compile.rb:23:in `matches?'
     # ./spec/defines/as/myressource_spec.rb:25:in `block (5 levels) in <top (required)>'

How can I change ::mymod::maxheap for the second test? Or maybe this example is no good puppet style?

Upvotes: 0

Views: 424

Answers (1)

balder
balder

Reputation: 799

I think there are two ways to fix this. first in you have the following

define mymod::as::myressource (
) {
  $effective_maxheap = ($::mymod::maxheap =~ NotUndef) ? {}
}

As you make use of the mymod class i would explicitly include it e.g.

define mymod::as::myressource (
) {
  include mymod
  $effective_maxheap = ($::mymod::maxheap =~ NotUndef) ? {}
}

This means that when your rspec tests run mymod will automaticity be included, all code in it compiled, and you wont need to mock anything in rspec.

If this is not possible or desirable then you can use pre_condition to initiate the class for you. Again this will cause everything inside mymod to also get compiled when running the spec test

describe 'mymod::as::myressource' do
  let(:title) { 'as_myressource_test' }
  on_supported_os.each do |os, os_facts|
    context "no maxheap on #{os}" do
      let(:facts) { os_facts }
      let(:pre_condition) { "class {'mymod': $maxheap = undef" }
    end
  end
end

if compiling the code in mymod is undesirable and you really just want to mock the maxheap variable you can do the following

describe 'mymod::as::myressource' do
  let(:title) { 'as_myressource_test' }
  on_supported_os.each do |os, os_facts|
    context "no maxheap on #{os}" do
      let(:facts) { os_facts }
      let(:pre_condition) { "class mymod { $maxheap = undef }" }
    end
  end
end

Upvotes: 1

Related Questions