From 1e8ac1288507e05f6cd20d64e2db0e9019d5d8d9 Mon Sep 17 00:00:00 2001 From: Anthony Vitacco Date: Fri, 17 Jan 2025 13:20:19 -0500 Subject: [PATCH] Fixing up unit tests The only unit test that existed did not work, so I fixed that and added tests for most other resources in this module. I did not add tests for the anchors as the anchor pattern is not considered good practice and is something that `pdk validate` complains about. I also added an integration acceptance test. This test actually applies the graylog::server class per the documentation to test that the module behaves as expected. This test could be expanded upon, but this serves as a good starting point. --- .fixtures.yml | 11 ++- provision.yaml | 28 +++++++ spec/acceptance/integration_spec.rb | 77 ++++++++++++++++++ spec/classes/allinone_spec.rb | 37 +++++++++ spec/classes/init_spec.rb | 13 ++- spec/classes/params_spec.rb | 13 +++ spec/classes/repository_spec.rb | 80 +++++++++++++++++++ spec/classes/server_spec.rb | 120 ++++++++++++++++++++++++++++ spec/default_facts.yml | 7 +- spec/spec_helper.rb | 5 +- spec/spec_helper_acceptance.rb | 6 ++ 11 files changed, 389 insertions(+), 8 deletions(-) create mode 100644 provision.yaml create mode 100644 spec/acceptance/integration_spec.rb create mode 100644 spec/classes/allinone_spec.rb create mode 100644 spec/classes/params_spec.rb create mode 100644 spec/classes/repository_spec.rb create mode 100644 spec/classes/server_spec.rb create mode 100644 spec/spec_helper_acceptance.rb diff --git a/.fixtures.yml b/.fixtures.yml index 2296adb..ec662c3 100644 --- a/.fixtures.yml +++ b/.fixtures.yml @@ -3,4 +3,13 @@ --- fixtures: forge_modules: -# stdlib: "puppetlabs/stdlib" + stdlib: "puppetlabs/stdlib" + apt: puppetlabs/apt + yumrepo_core: puppetlabs/yumrepo_core + mongodb: puppet/mongodb + opensearch: puppet/opensearch + archive: puppet/archive + repositories: + facts: 'https://github.com/puppetlabs/puppetlabs-facts.git' + puppet_agent: 'https://github.com/puppetlabs/puppetlabs-puppet_agent.git' + provision: 'https://github.com/puppetlabs/provision.git' diff --git a/provision.yaml b/provision.yaml new file mode 100644 index 0000000..016ae95 --- /dev/null +++ b/provision.yaml @@ -0,0 +1,28 @@ +--- +default: + provisioner: docker + images: + - litmusimage/ubuntu:22.04 + - litmusimage/debian:11 + - litmusimage/debian:12 + - litmusimage/rockylinux:8 + - litmusimage/rockylinux:9 + - litmusimage/almalinux:8 + - litmusimage/almalinux:9 +debian: + provisioner: docker + images: + - litmusimage/ubuntu:22.04 + - litmusimage/debian:11 + - litmusimage/debian:12 +redhat: + provisioner: docker + images: + - litmusimage/rockylinux:8 + - litmusimage/rockylinux:9 + - litmusimage/almalinux:8 + - litmusimage/almalinux:9 +single: + provisioner: docker + images: + - litmusimage/ubuntu:22.04 diff --git a/spec/acceptance/integration_spec.rb b/spec/acceptance/integration_spec.rb new file mode 100644 index 0000000..575e55e --- /dev/null +++ b/spec/acceptance/integration_spec.rb @@ -0,0 +1,77 @@ +# frozen_string_literal: true + +require 'spec_helper_acceptance' + +describe 'init class' do + context 'applying graylog server class works' do + let(:pp) do + <<-CODE + class { 'graylog::repository': + version => '6.1' + } + -> class { 'graylog::server': + config => { + 'password_secret' => 'super secret secret', + 'root_password_sha2' => '9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08', + } + } + CODE + end + + it 'behaves idempotently' do + idempotent_apply(pp) + end + + if os[:family] == 'redhat' + + # Ensure the yum repo exists and is enabled + describe yumrepo('graylog') do + it { is_expected.to exist } + it { is_expected.to be_enabled } + end + + # Ensure the package is found + describe command('dnf -q search graylog-server') do + its(:stdout) { is_expected.to match(%r{Name Exactly Matched: graylog\-server}) } + its(:exit_status) { is_expected.to eq 0 } + end + + describe file('/etc/sysconfig/graylog-server') do + it { is_expected.to be_file } + its(:content) { is_expected.to match(%r{\-Xms1g}) } + its(:content) { is_expected.to match(%r{\-Xmx1g}) } + its(:content) { is_expected.to match(%r{GRAYLOG_SERVER_ARGS=""}) } + end + elsif ['debian', 'ubuntu'].include?(os[:family]) + + # Ensure the repo exists on the filesystem + describe file('/etc/apt/sources.list.d/graylog.list') do + it { is_expected.to be_file } + its(:content) { is_expected.to match(%r{https://downloads.graylog.org/repo/debian}) } + end + + # Ensure the package is found + describe command('apt-cache search graylog-server') do + its(:stdout) { is_expected.to match(%r{graylog-server - Graylog server}) } + its(:exit_status) { is_expected.to eq 0 } + end + + # Ensure the environment vars file is present on disk and looks correct + describe file('/etc/default/graylog-server') do + it { is_expected.to be_file } + its(:content) { is_expected.to match(%r{\-Xms1g}) } + its(:content) { is_expected.to match(%r{\-Xmx1g}) } + its(:content) { is_expected.to match(%r{GRAYLOG_SERVER_ARGS=""}) } + end + end + + describe package('graylog-server') do + it { is_expected.to be_installed } + end + + describe file('/etc/graylog/server/server.conf') do + it { is_expected.to be_file } + its(:content) { is_expected.to match(%r{root_password_sha2\s\=\s[a-f0-9]{64}}) } + end + end +end diff --git a/spec/classes/allinone_spec.rb b/spec/classes/allinone_spec.rb new file mode 100644 index 0000000..67685c1 --- /dev/null +++ b/spec/classes/allinone_spec.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'graylog::allinone' do + on_supported_os.each do |os, os_facts| + context "on #{os}" do + let(:facts) { os_facts } + let(:params) do + { + 'opensearch' => { + 'version' => '2.15.0', + 'settings' => { + 'setting_a' => 'value_b' + } + }, + 'graylog' => { + 'major_version' => '6.1', + 'config' => { + 'password_secret' => 'super secret secret', + 'root_password_sha2' => '9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08', + } + } + } + end + + # Because of an issue with the opensearch module,the allinone class will + # always fail an RedHat family operating systems using modern facts. + case os_facts[:os]['family'] + when 'Debian' + it { is_expected.to compile.with_all_deps } + when 'RedHat' + it { is_expected.to compile.and_raise_error(%r{Could not find class ::yum.*}) } + end + end + end +end diff --git a/spec/classes/init_spec.rb b/spec/classes/init_spec.rb index 264eba5..1085068 100644 --- a/spec/classes/init_spec.rb +++ b/spec/classes/init_spec.rb @@ -1,6 +1,15 @@ +# frozen_string_literal: true + require 'spec_helper' + describe 'graylog' do - context 'with default values for all parameters' do - it { is_expected.to contain_class('graylog') } + on_supported_os.each do |os, os_facts| + context "on #{os}" do + let(:facts) { os_facts } + + it { + is_expected.to compile.and_raise_error(%r{use the \"graylog::server\" class}) + } + end end end diff --git a/spec/classes/params_spec.rb b/spec/classes/params_spec.rb new file mode 100644 index 0000000..d99f888 --- /dev/null +++ b/spec/classes/params_spec.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'graylog::params' do + on_supported_os.each do |os, os_facts| + context "on #{os}" do + let(:facts) { os_facts } + + it { is_expected.to compile.with_all_deps } + end + end +end diff --git a/spec/classes/repository_spec.rb b/spec/classes/repository_spec.rb new file mode 100644 index 0000000..5e9406d --- /dev/null +++ b/spec/classes/repository_spec.rb @@ -0,0 +1,80 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'graylog::repository' do + on_supported_os.each do |os, os_facts| + context "on #{os}" do + let(:facts) { os_facts } + + it { is_expected.to compile.with_all_deps } + + case os_facts[:os]['family'] + when 'Debian' + it { + is_expected.to contain_class('graylog::repository::apt') + } + it { + is_expected.to contain_package('apt-transport-https') + } + it { + is_expected.to contain_file('/etc/apt/trusted.gpg.d/graylog-keyring.gpg') + .with_ensure('file') + .with_owner('root') + .with_group('root') + .with_mode('0444') + .with_source('puppet:///modules/graylog/graylog-keyring.gpg') + .that_notifies('Exec[apt_update]') + } + it { + is_expected.to contain_apt__source('graylog') + .with_ensure('present') + .with_comment('The official Graylog package repository') + .with_location('https://downloads.graylog.org/repo/debian/') + .with_release('stable') + .with_repos('6.1') + .with_include({ 'deb' => true, 'src' => false }) + .that_requires( + [ + 'File[/etc/apt/trusted.gpg.d/graylog-keyring.gpg]', + 'Package[apt-transport-https]', + ], + ) + .that_notifies('Exec[apt_update]') + } + it { + is_expected.to contain_file('/etc/apt/apt.conf.d/01_graylog_proxy') + .with_ensure('file') + } + it { + is_expected.to contain_file_line('Remove graylog config from apt proxy file') + .with_ensure('absent') + .with_path('/etc/apt/apt.conf.d/01_graylog_proxy') + .with_match('graylog') + .with_match_for_absence(true) + .with_multiple(true) + } + when 'RedHat' + it { + is_expected.to contain_class('graylog::repository::yum') + } + it { + is_expected.to contain_file('/etc/pki/rpm-gpg/RPM-GPG-KEY-graylog') + .with_ensure('file') + .with_owner('root') + .with_group('root') + .with_mode('0444') + .with_source('puppet:///modules/graylog/RPM-GPG-KEY-graylog') + } + it { + is_expected.to contain_yumrepo('graylog') + .with_descr('The official Graylog package repository') + .with_baseurl('https://downloads.graylog.org/repo/el/stable/6.1/$basearch/') + .with_enabled(true) + .with_gpgcheck(true) + .that_requires(['File[/etc/pki/rpm-gpg/RPM-GPG-KEY-graylog]']) + } + end + end + end +end diff --git a/spec/classes/server_spec.rb b/spec/classes/server_spec.rb new file mode 100644 index 0000000..e09e00e --- /dev/null +++ b/spec/classes/server_spec.rb @@ -0,0 +1,120 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'graylog::server' do + on_supported_os.each do |os, os_facts| + context "on #{os}" do + let(:facts) { os_facts } + let(:params) do + { + 'config' => { + 'password_secret' => 'super secret secret', + 'root_password_sha2' => '9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08', + } + } + end + + # Test that the class doesn't error when given expected params + it { is_expected.to compile.with_all_deps } + + # Ensure that the class has the graylog-server package and that it is + # installed + it { + is_expected.to contain_package('graylog-server') + .with_ensure('installed') + } + + # Tests that the server config is managed and has expected content + it { + is_expected.to contain_file('/etc/graylog/server/server.conf') + .with_ensure('file') + .with_owner('graylog') + .with_group('graylog') + .with_mode('0640') + .with_content(%r{password_secret = super secret secret}) + .with_content(%r{root_password_sha2\s\=\s[a-f0-9]{64}}) + } + + # Ensure that the java params are being managed and contain expected + # content + case os_facts[:os]['family'] + when 'Debian' + it { + is_expected.to contain_file('/etc/default/graylog-server') + .with_ensure('file') + .with_owner('graylog') + .with_group('graylog') + .with_mode('0640') + .with_content(%r{-Xms1g}) + .with_content(%r{-Xmx1g}) + } + when 'RedHat' + it { + is_expected.to contain_file('/etc/sysconfig/graylog-server') + .with_ensure('file') + .with_owner('graylog') + .with_group('graylog') + .with_mode('0640') + .with_content(%r{-Xms1g}) + .with_content(%r{-Xmx1g}) + } + end + + # Ensure that the service is being managed + it { + is_expected.to contain_service('graylog-server') + .with_ensure('running') + .with_enable(true) + .with_hasstatus(true) + .with_hasrestart(true) + } + end + + context "on #{os} without password_secret" do + let(:facts) { os_facts } + let(:params) do + { + 'config' => { + 'root_password_sha2' => '9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08', + } + } + end + + it { + is_expected.to compile.and_raise_error(%r{Missing .*?password_secret}) + } + end + + context "on #{os} without root_password_sha2" do + let(:facts) { os_facts } + let(:params) do + { + 'config' => { + 'password_secret' => 'super secret secret', + } + } + end + + it { + is_expected.to compile.and_raise_error(%r{Missing .*root_password_sha2}) + } + end + + context "on #{os} with invalid root_password_sha2" do + let(:facts) { os_facts } + let(:params) do + { + 'config' => { + 'password_secret' => 'super secret secret', + 'root_password_sha2' => 'this is an invalid hash', + } + } + end + + it { + is_expected.to compile.and_raise_error(%r{root_password_sha2 parameter does not look like a SHA256 checksum}) + } + end + end +end diff --git a/spec/default_facts.yml b/spec/default_facts.yml index f777abf..3346c39 100644 --- a/spec/default_facts.yml +++ b/spec/default_facts.yml @@ -2,7 +2,8 @@ # # Facts specified here will override the values provided by rspec-puppet-facts. --- -ipaddress: "172.16.254.254" -ipaddress6: "FE80:0000:0000:0000:AAAA:AAAA:AAAA" +networking: + ip: "172.16.254.254" + ip6: "FE80:0000:0000:0000:AAAA:AAAA:AAAA" + mac: "AA:AA:AA:AA:AA:AA" is_pe: false -macaddress: "AA:AA:AA:AA:AA:AA" diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 6820ceb..ae7c1f6 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -25,7 +25,8 @@ next unless File.exist?(f) && File.readable?(f) && File.size?(f) begin - default_facts.merge!(YAML.safe_load(File.read(f), permitted_classes: [], permitted_symbols: [], aliases: true)) + require 'deep_merge' + default_facts.deep_merge!(YAML.safe_load(File.read(f), permitted_classes: [], permitted_symbols: [], aliases: true)) rescue StandardError => e RSpec.configuration.reporter.message "WARNING: Unable to load #{f}: #{e}" end @@ -33,7 +34,7 @@ # read default_facts and merge them over what is provided by facterdb default_facts.each do |fact, value| - add_custom_fact fact, value + add_custom_fact fact, value, merge_facts: true end RSpec.configure do |c| diff --git a/spec/spec_helper_acceptance.rb b/spec/spec_helper_acceptance.rb new file mode 100644 index 0000000..4ac8d7e --- /dev/null +++ b/spec/spec_helper_acceptance.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +require 'puppet_litmus' +require 'spec_helper_acceptance_local' if File.file?(File.join(File.dirname(__FILE__), 'spec_helper_acceptance_local.rb')) + +PuppetLitmus.configure!