0

Consider the following recipe:

  recipe_name = 'mongodb'
  service_name = if node['szdigi'][recipe_name]['version'].to_f < 2.6
                   'mongodb'
                 else
                   'mongod'
                 end

  conffile = "/etc/#{service_name}.conf"

  # Add configuration
  template conffile do
    source 'mongodb/mongodb-conf.erb'
    owner 'root'
    group 'root'
    mode 0o644
  end

  # Remove old config file
  file '/etc/mongodb.conf' do
    action :delete
    only_if { node['szdigi'][recipe_name]['version'].to_f >= 2.6 }
  end

... and the following chefspec tests:

require_relative 'spec_helper'

describe 'szdigi::mongo_test' do
  before(:all) do
    @conf_file = '/etc/mongodb.conf'
  end

  context 'Mongo 2.4' do
    let(:chef_run) do
      runner = ChefSpec::SoloRunner.new
      runner.node.normal['szdigi']['mongodb']['version'] = '2.4.14'
      runner.converge(described_recipe)
    end

    it 'creates mongo conf file' do
      expect(chef_run).to create_template(@conf_file)
        .with_mode(0o644)
        .with_owner('root')
        .with_group('root')
    end

    it 'does not remove /etc/mongodb.conf' do
      expect(chef_run).not_to delete_file(@conf_file)
    end

    it 'defines authentication options' do
      expect(chef_run).to render_file(@conf_file).with_content { |content|
        expect(content).to match(/^\s*auth\s*=\s*true\s*$/)
      }
    end
  end

  context 'Mongo 2.6' do
    before :all do
      @conf_file = '/etc/mongod.conf'
    end

    let(:chef_run) do
      runner = ChefSpec::SoloRunner.new
      runner.node.normal['szdigi']['mongodb']['version'] = '2.6.12'
      runner.converge(described_recipe)
    end

    it 'creates mongo conf file' do
      expect(chef_run).to create_template(@conf_file)
        .with_mode(0o644)
        .with_owner('root')
        .with_group('root')
    end

    it 'defines authentication options' do
      expect(chef_run).to render_file(@conf_file).with_content { |content|
        expect(content).to match(/^\s*auth\s*=\s*true\s*$/)
      }
    end

    it 'removes 2.4 configuration file /etc/mongodb.conf' do
      expect(chef_run).to delete_file('/etc/mongodb.conf')
    end
  end
end

The recipe does exactly what I want: It creates /etc/mongodb.conf when the version attribute is set to 2.4.x and /etc/mongod.conf otherwise, both with auth = true. In the latter case it also removes the now obsolete /etc/mongodb.conf.

However, as long as the recipe contains the file '/etc/mongodb.conf' resource, chefspec fails on the it 'defines authentication options' within the Mongo 2.4 context:

Failure/Error:
   expect(chef_run).to render_file(@conf_file).with_content { |content|
     expect(content).to match(/^\s*auth\s*=\s*true\s*$/)
   }

   expected Chef run to render "/etc/mongodb.conf" matching:

   (the result of a proc)

   but got:

Any idea how I should rewrite the render_file test in 2.6 context in order to succeed?

Thanks

Patricia

trish
  • 1
  • 3

1 Answers1

0

I would use a single top-level if node['szdigi'][recipe_name]['version'].to_f >= 2.6 and then restructure the recipe into the two branches on that. The use of clever flow-y bits is nice, but don't.

coderanger
  • 52,400
  • 4
  • 52
  • 75
  • Thanks, this works. But aren't guards recommended best practice? – trish Jul 25 '17 at 12:54
  • Not always. It depends on the structure of your code, in this case you have two very different branches so making that explicit is probably more readable. – coderanger Jul 25 '17 at 17:01