From 37b805e676cf294d65b4383732449a16226e6b94 Mon Sep 17 00:00:00 2001 From: Ewoud Kohl van Wijngaarden Date: Tue, 1 Nov 2022 00:00:26 +0100 Subject: [PATCH] Add infrastructure for testing custom facts This adds testing of custom facts by placing them in spec/facts, similar to how classes have spec/classes and defines have spec/defines. The subject is also set in the same way. It is possible to stub other facts using a facts block and facts are properly cleared before and after a run. --- lib/rspec-puppet/example.rb | 2 + .../example/fact_example_group.rb | 51 +++++++++++++++++++ lib/rspec-puppet/matchers.rb | 1 + lib/rspec-puppet/matchers/fact_matchers.rb | 11 ++++ spec/facts/custom_spec.rb | 28 ++++++++++ .../modules/custom_fact/lib/facter/custom.rb | 3 ++ 6 files changed, 96 insertions(+) create mode 100644 lib/rspec-puppet/example/fact_example_group.rb create mode 100644 lib/rspec-puppet/matchers/fact_matchers.rb create mode 100644 spec/facts/custom_spec.rb create mode 100644 spec/fixtures/modules/custom_fact/lib/facter/custom.rb diff --git a/lib/rspec-puppet/example.rb b/lib/rspec-puppet/example.rb index 2bed2ca70..ca883efc0 100644 --- a/lib/rspec-puppet/example.rb +++ b/lib/rspec-puppet/example.rb @@ -3,6 +3,7 @@ require 'rspec-puppet/support' require 'rspec-puppet/example/define_example_group' require 'rspec-puppet/example/class_example_group' +require 'rspec-puppet/example/fact_example_group' require 'rspec-puppet/example/function_example_group' require 'rspec-puppet/example/host_example_group' require 'rspec-puppet/example/type_example_group' @@ -19,6 +20,7 @@ def c.rspec_puppet_include(group, type, file_path) c.rspec_puppet_include RSpec::Puppet::DefineExampleGroup, :define, %w[spec defines] c.rspec_puppet_include RSpec::Puppet::ClassExampleGroup, :class, %w[spec classes] + c.rspec_puppet_include RSpec::Puppet::FactExampleGroup, :define, %w[spec facts] c.rspec_puppet_include RSpec::Puppet::FunctionExampleGroup, :puppet_function, %w[spec functions] c.rspec_puppet_include RSpec::Puppet::HostExampleGroup, :host, %w[spec hosts] c.rspec_puppet_include RSpec::Puppet::TypeExampleGroup, :type, %w[spec types] diff --git a/lib/rspec-puppet/example/fact_example_group.rb b/lib/rspec-puppet/example/fact_example_group.rb new file mode 100644 index 000000000..c2ad989c1 --- /dev/null +++ b/lib/rspec-puppet/example/fact_example_group.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true + +module RSpec::Puppet + # This module provides support for custom facts + module FactExampleGroup + include RSpec::Puppet::FactMatchers + + def subject + setup_facter + Facter.fact(self.class.top_level_description) + end + + def rspec_puppet_cleanup + Facter.clear + # TODO: clean LOAD_PATH again? + end + + private + + # TODO: duplicates adapter + def modulepath + if (rspec_modulepath = RSpec.configuration.module_path) + rspec_modulepath.split(File::PATH_SEPARATOR) + else + Puppet[:environmentpath].split(File::PATH_SEPARATOR).map do |path| + File.join(path, 'fixtures', 'modules') + end + end + end + + def setup_facter + # TODO: duplicates RSpec::Puppet::Support.setup_puppet + modulepath.map do |d| + Dir["#{d}/*/lib/facter"].entries.each do |entry| + $LOAD_PATH << File.expand_path(File.dirname(entry)) + end + end + + Facter.clear + + return unless respond_to?(:facts) + + allow(Facter).to receive(:value).and_call_original + + facts.each do |fact, value| + # TODO: Facter.fact(fact).value? + allow(Facter).to receive(:value).with(fact.to_sym).and_return(value) + end + end + end +end diff --git a/lib/rspec-puppet/matchers.rb b/lib/rspec-puppet/matchers.rb index 172086f32..cf201a8b0 100644 --- a/lib/rspec-puppet/matchers.rb +++ b/lib/rspec-puppet/matchers.rb @@ -6,6 +6,7 @@ require 'rspec-puppet/matchers/run' require 'rspec-puppet/matchers/count_generic' require 'rspec-puppet/matchers/dynamic_matchers' +require 'rspec-puppet/matchers/fact_matchers' require 'rspec-puppet/matchers/type_matchers' require 'rspec-puppet/matchers/allow_value' require 'rspec-puppet/matchers/raise_error' diff --git a/lib/rspec-puppet/matchers/fact_matchers.rb b/lib/rspec-puppet/matchers/fact_matchers.rb new file mode 100644 index 000000000..25ce49786 --- /dev/null +++ b/lib/rspec-puppet/matchers/fact_matchers.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +module RSpec::Puppet + module FactMatchers + extend RSpec::Matchers::DSL + + matcher :have_value do |expected| + match { |actual| actual.value == expected } + end + end +end diff --git a/spec/facts/custom_spec.rb b/spec/facts/custom_spec.rb new file mode 100644 index 000000000..5e6649440 --- /dev/null +++ b/spec/facts/custom_spec.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'custom' do + it { is_expected.not_to be_nil } + it { is_expected.to have_value('bar') } + + context 'with overridden' do + let(:facts) do + { + myfact: 'set' + } + end + + it { is_expected.to have_value('foo') } + end + + context 'with unrelated fact overridden' do + let(:facts) do + { + kernel: 'unix' + } + end + + it { is_expected.to have_value('bar') } + end +end diff --git a/spec/fixtures/modules/custom_fact/lib/facter/custom.rb b/spec/fixtures/modules/custom_fact/lib/facter/custom.rb new file mode 100644 index 000000000..87d27e781 --- /dev/null +++ b/spec/fixtures/modules/custom_fact/lib/facter/custom.rb @@ -0,0 +1,3 @@ +Facter.add(:custom) do + setcode { Facter.value(:myfact) ? 'foo' : 'bar' } +end