Skip to content

Commit

Permalink
(PDK-508) implement autorequire and friends
Browse files Browse the repository at this point in the history
The spec/classes/autorequire_cycle_spec.rb test shows that the
autorelations implementation of the Resource API does build relations.
Since rspec-puppet doesn't provide matching on compile errors, this
builds a test case that compiles when make_cycle is false, thereby
proving that there is no error in the manifest, but fails with a
dependency cycle error when make_cycle is set to true.
  • Loading branch information
DavidS committed Mar 12, 2018
1 parent e699da1 commit bc43895
Show file tree
Hide file tree
Showing 6 changed files with 112 additions and 10 deletions.
18 changes: 18 additions & 0 deletions lib/puppet/resource_api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,24 @@ def my_provider
def context
self.class.context
end

[:autorequire, :autobefore, :autosubscribe, :autonotify].each do |auto|
next unless definition[auto]

definition[auto].each do |type, values|
Puppet.debug("Registering #{auto} for #{type}: #{values.inspect}")
send(auto, type.downcase.to_sym) do
[values].flatten.map do |v|
match = %r{\A\$(.*)\Z}.match(v) if v.is_a? String
if match.nil?
v
else
self[match[1].to_sym]
end
end
end
end
end
end
end
module_function :register_type
Expand Down
11 changes: 10 additions & 1 deletion spec/classes/autorequire_cycle_spec.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
require 'spec_helper'

RSpec.describe 'test_module::autorequire_cycle' do
it { is_expected.to compile }
context 'with make_cycle => false' do
let(:params) { { make_cycle: false } }

it { is_expected.to compile }
end
context 'with make_cycle => true' do
let(:params) { { make_cycle: true } }

it { is_expected.not_to compile }
end
end
8 changes: 8 additions & 0 deletions spec/fixtures/test_module/lib/puppet/type/test_autorequire.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,13 @@
desc: 'The name of the resource you want to manage.',
behaviour: :namevar,
},
target: {
type: 'String',
desc: 'The resource to autorequire.',
behaviour: :parameter,
},
},
autorequire: {
test_autorequire: '$target',
},
)
19 changes: 16 additions & 3 deletions spec/fixtures/test_module/manifests/autorequire_cycle.pp
Original file line number Diff line number Diff line change
@@ -1,10 +1,23 @@
# test_module::autorequire_cycle
#
# A description of what this class does
# This class is used to test autorequires.
# With make_cycle set to false, this should compile without errors or cycles. When make_cycle is set to true, autorequires will be used to
# construct a dependency cycle. This makes it possible to test exactly the function of the autorequires implementation.
#
# @summary A short summary of the purpose of this class
# @summary This class is used to test autorequires.
#
# @example
# include test_module::autorequire_cycle
class test_module::autorequire_cycle {
class test_module::autorequire_cycle (
Boolean $make_cycle
) {
test_autorequire { "a":
target => "b",
}
test_autorequire { "b":
target => "c",
}
test_autorequire { "c":
target => $make_cycle ? { true => "a", false => undef },
}
}
15 changes: 9 additions & 6 deletions spec/fixtures/test_module/spec/classes/autorequire_cycle_spec.rb
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
require 'spec_helper'

describe 'test_module::autorequire_cycle' do
on_supported_os.each do |os, os_facts|
context "on #{os}" do
let(:facts) { os_facts }
RSpec.describe 'test_module::autorequire_cycle' do
context 'with make_cycle => false' do
let(:params) { { make_cycle: false } }

it { is_expected.to compile }
end
it { is_expected.to compile }
end
context 'with make_cycle => true' do
let(:params) { { make_cycle: true } }

it { is_expected.not_to compile }
end
end
51 changes: 51 additions & 0 deletions spec/puppet/resource_api_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,18 @@
desc: 'a optional string value',
},
},
autorequire: {
var: '$test_string',
},
autobefore: {
const: 'value',
},
autosubscribe: {
list: %w[foo bar],
},
autonotify: {
mixed: [10, '$test_integer'],
},
}
end

Expand All @@ -84,6 +96,45 @@
it { is_expected.not_to be_nil }
it { expect(type.properties.first.doc).to match %r{the description} }
it { expect(type.properties.first.name).to eq :test_string }

def extract_values(function)
result = []
type.send(function) do |_type, values|
# rely on the fact that the resource api is doing `self[]` internally to find the value
# see https://github.com/puppetlabs/puppet/blob/9f2c143962803a72c68f35be3462944e851bcdce/lib/puppet/type.rb#L2143
# for details
result += { test_string: 'foo', test_integer: 100 }.instance_eval(&values)
end
result
end

describe 'autorequire' do
it('yields the block for `var`') { expect { |b| type.eachautorequire(&b) }.to yield_with_args(:var, be_a(Proc)) }
it 'the yielded block returns the `test_string` value' do
expect(extract_values(:eachautorequire)).to eq ['foo']
end
end

describe 'autobefore' do
it('yields the block for `const`') { expect { |b| type.eachautobefore(&b) }.to yield_with_args(:const, be_a(Proc)) }
it('the yielded block returns the constant "value"') do
expect(extract_values(:eachautobefore)).to eq ['value']
end
end

describe 'autosubscribe' do
it('yields the block for `list`') { expect { |b| type.eachautosubscribe(&b) }.to yield_with_args(:list, be_a(Proc)) }
it('the yielded block returns the multiple values') do
expect(extract_values(:eachautosubscribe)).to eq %w[foo bar]
end
end

describe 'autonotify' do
it('yields the block for `mixed`') { expect { |b| type.eachautonotify(&b) }.to yield_with_args(:mixed, be_a(Proc)) }
it('the yielded block returns multiple integer values') do
expect(extract_values(:eachautonotify)).to eq [10, 100]
end
end
end

describe 'an instance of this type' do
Expand Down

0 comments on commit bc43895

Please sign in to comment.