diff --git a/lib/simp-spec-helpers.rb b/lib/simp-spec-helpers.rb new file mode 100644 index 0000000..d33f3b5 --- /dev/null +++ b/lib/simp-spec-helpers.rb @@ -0,0 +1 @@ +require 'simp/spec_helpers' diff --git a/lib/simp/spec_helpers.rb b/lib/simp/spec_helpers.rb index 8be9460..6600f9d 100644 --- a/lib/simp/spec_helpers.rb +++ b/lib/simp/spec_helpers.rb @@ -1,14 +1,200 @@ -require 'bundler' -require 'rspec' module Simp; end module Simp::SpecHelpers - # Stealing this from the Ruby 2.5 Dir::Tmpname workaround from Rails - def self.tmpname - t = Time.new.strftime("%Y%m%d") - "simp-spec-helpers-#{t}-#{$$}-#{rand(0x100000000).to_s(36)}.tmp" +def global_spec_helper(fixture_path, module_name) + + + if ENV['PUPPET_DEBUG'] + Puppet::Util::Log.level = :debug + Puppet::Util::Log.newdestination(:console) + end + + + default_hiera_config =<<-EOM +--- +version: 5 +hierarchy: + - name: SIMP Compliance Engine + lookup_key: compliance_markup::enforcement + options: + enabled_sce_versions: [2] + - name: Custom Test Hiera + path: "%{custom_hiera}.yaml" + - name: "%{module_name}" + path: "%{module_name}.yaml" + - name: Common + path: default.yaml +defaults: + data_hash: yaml_data + datadir: "stub" +EOM + + if not File.directory?(File.join(fixture_path,'hieradata')) then + FileUtils.mkdir_p(File.join(fixture_path,'hieradata')) + end + + if not File.directory?(File.join(fixture_path,'modules',module_name)) then + FileUtils.mkdir_p(File.join(fixture_path,'modules',module_name)) end + RSpec.configure do |c| + # If nothing else... + c.default_facts = { + :production => { + #:fqdn => 'production.rspec.test.localdomain', + :path => '/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin', + :concat_basedir => '/tmp' + } + } + + c.mock_framework = :rspec + c.mock_with :mocha + + c.module_path = File.join(fixture_path, 'modules') + c.manifest_dir = File.join(fixture_path, 'manifests') + + c.hiera_config = File.join(fixture_path,'hieradata','hiera.yaml') + + # Useless backtrace noise + backtrace_exclusion_patterns = [ + /spec_helper/, + /gems/ + ] + + if c.respond_to?(:backtrace_exclusion_patterns) + c.backtrace_exclusion_patterns = backtrace_exclusion_patterns + elsif c.respond_to?(:backtrace_clean_patterns) + c.backtrace_clean_patterns = backtrace_exclusion_patterns + end + + c.before(:all) do + data = YAML.load(default_hiera_config) + data.keys.each do |key| + next unless data[key].is_a?(Hash) + + if data[key][:datadir] == 'stub' + data[key][:datadir] = File.join(fixture_path, 'hieradata') + elsif data[key]['datadir'] == 'stub' + data[key]['datadir'] = File.join(fixture_path, 'hieradata') + end + end + + File.open(c.hiera_config, 'w') do |f| + f.write data.to_yaml + end + end + + c.before(:each) do + @spec_global_env_temp = Dir.mktmpdir('simpspec') + + if defined?(environment) + set_environment(environment) + FileUtils.mkdir_p(File.join(@spec_global_env_temp,environment.to_s)) + end + + # ensure the user running these tests has an accessible environmentpath + Puppet[:environmentpath] = @spec_global_env_temp + Puppet[:user] = Etc.getpwuid(Process.uid).name + Puppet[:group] = Etc.getgrgid(Process.gid).name + Puppet[:digest_algorithm] = 'sha256' + + # sanitize hieradata + if defined?(hieradata) + set_hieradata(hieradata.gsub(':','_')) + elsif defined?(class_name) + set_hieradata(class_name.gsub(':','_')) + end + end + + c.after(:each) do + # clean up the mocked environmentpath + FileUtils.rm_rf(@spec_global_env_temp) + @spec_global_env_temp = nil + end + end + + Dir.glob("#{RSpec.configuration.module_path}/*").each do |dir| + begin + Pathname.new(dir).realpath + rescue + fail "ERROR: The module '#{dir}' is not installed. Tests cannot continue." + end + end +end + +# This can be used from inside your spec tests to set the testable environment. +# You can use this to stub out an ENC. +# + +# Example: +# +# context 'in the :foo environment' do +# let(:environment){:foo} +# ... +# end +# +def set_environment(environment = :production) + RSpec.configure { |c| c.default_facts['environment'] = environment.to_s } +end + +# This can be used from inside your spec tests to load custom hieradata within +# any context. +# +# Example: +# +# describe 'some::class' do +# context 'with version 10' do +# let(:hieradata){ "#{class_name}_v10" } +# ... +# end +# end +# +# Then, create a YAML file at spec/fixtures/hieradata/some__class_v10.yaml. +# +# Hiera will use this file as it's base of information stacked on top of +# 'default.yaml' and .yaml per the defaults above. +# +# Note: Any colons (:) are replaced with underscores (_) in the class name. + +def set_hieradata(hieradata) + RSpec.configure { |c| c.default_facts['custom_hiera'] = hieradata } end + +def normalize_compliance_results(compliance_profile_data, section, exceptions) + normalized = Marshal.load(Marshal.dump(compliance_profile_data)) + if section == 'non_compliant' + exceptions['non_compliant'].each do |resource,params| + params.each do |param| + if normalized['non_compliant'].key?(resource) && + normalized['non_compliant'][resource]['parameters'].key?(param) + normalized['non_compliant'][resource]['parameters'].delete(param) + if normalized['non_compliant'][resource]['parameters'].empty? + normalized['non_compliant'].delete(resource) + end + end + end + end + else + normalized[section].delete_if do |item| + rm = false + Array(exceptions[section]).each do |allowed| + if allowed.is_a?(Regexp) + if allowed.match?(item) + rm = true + break + end + else + rm = (allowed == item) + end + end + rm + end + end + + normalized +end + +end + diff --git a/lib/simp/spec_helpers/helpers.rb b/lib/simp/spec_helpers/helpers.rb new file mode 100644 index 0000000..230ed78 --- /dev/null +++ b/lib/simp/spec_helpers/helpers.rb @@ -0,0 +1,77 @@ +module Simp; end + +module Simp::SpecHelpers::Helpers + +# This can be used from inside your spec tests to set the testable environment. +# You can use this to stub out an ENC. +# + +# Example: +# +# context 'in the :foo environment' do +# let(:environment){:foo} +# ... +# end +# +def set_environment(environment = :production) + RSpec.configure { |c| c.default_facts['environment'] = environment.to_s } +end + +# This can be used from inside your spec tests to load custom hieradata within +# any context. +# +# Example: +# +# describe 'some::class' do +# context 'with version 10' do +# let(:hieradata){ "#{class_name}_v10" } +# ... +# end +# end +# +# Then, create a YAML file at spec/fixtures/hieradata/some__class_v10.yaml. +# +# Hiera will use this file as it's base of information stacked on top of +# 'default.yaml' and .yaml per the defaults above. +# +# Note: Any colons (:) are replaced with underscores (_) in the class name. + +def set_hieradata(hieradata) + RSpec.configure { |c| c.default_facts['custom_hiera'] = hieradata } +end + +def normalize_compliance_results(compliance_profile_data, section, exceptions) + normalized = Marshal.load(Marshal.dump(compliance_profile_data)) + if section == 'non_compliant' + exceptions['non_compliant'].each do |resource,params| + params.each do |param| + if normalized['non_compliant'].key?(resource) && + normalized['non_compliant'][resource]['parameters'].key?(param) + normalized['non_compliant'][resource]['parameters'].delete(param) + if normalized['non_compliant'][resource]['parameters'].empty? + normalized['non_compliant'].delete(resource) + end + end + end + end + else + normalized[section].delete_if do |item| + rm = false + Array(exceptions[section]).each do |allowed| + if allowed.is_a?(Regexp) + if allowed.match?(item) + rm = true + break + end + else + rm = (allowed == item) + end + end + rm + end + end + + normalized +end + +end