Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add override_facts helper method #15

Merged
merged 2 commits into from
Apr 21, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ source 'https://rubygems.org'

gemspec

gem 'rspec'

group :release do
gem 'github_changelog_generator', :require => false, :git => 'https://github.com/voxpupuli/github-changelog-generator', :branch => 'voxpupuli_essential_fixes'
end
76 changes: 76 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,79 @@ In your `spec/spec_helper.rb`
```ruby
require 'voxpupuli/test/spec_helper'
```

# Fact handling

The recommended method is using [rspec-puppet-facts](https://github.com/mcanevet/rspec-puppet-facts) and is set up by default. This means the tests are writting as follows:

```ruby
require 'spec_helper'

describe 'myclass' 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
```

Now a common case is to override facts in tests. Let's take the example of SELinux with legacy facts.

```ruby
require 'spec_helper'

describe 'mytool' 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 }

describe 'with SELinux enabled' do
let(:facts) { super().merge(selinux: true) }

it { is_expected.to contain_package('mytool-selinux') }
end

describe 'with SELinux disabled' do
let(:facts) { super().merge(selinux: false) }

it { is_expected.not_to contain_package('mytool-selinux') }
end
end
end
end
```

This is all fairly straight forward, but it gets more complex when using modern facts. Modern facts are nested which means you need to do deep merging. There is [deep_merge](https://rubygems.org/gems/deep_merge) but its results are not at all useful for spec testing. That's why voxpupuli-test has an `override_facts` helper.

```ruby
require 'spec_helper'

describe 'mytool' 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 }

describe 'with SELinux enabled' do
let(:facts) { override_facts(super(), os: {selinux: {enabled: true}}) }

it { is_expected.to contain_package('mytool-selinux') }
end

describe 'with SELinux disabled' do
let(:facts) { override_facts(super(), os: {selinux: {enabled: false}}) }

it { is_expected.not_to contain_package('mytool-selinux') }
end
end
end
end
```

Note that this helper deals with symbols/strings for you as well.
34 changes: 34 additions & 0 deletions lib/voxpupuli/test/facts.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Override facts
#
# This doesn't use deep_merge because that's highly unpredictable. It can merge
# nested hashes in place, modifying the original. It's also unable to override
# true to false.
#
# A deep copy is obtained by using Marshal so it can be modified in place. Then
# it recursively overrides values. If the result is a hash, it's recursed into.
#
# A typical example:
#
# let(:facts) do
# override_facts(super(), os: {'selinux' => {'enabled' => false}})
# end
def override_facts(base_facts, **overrides)
facts = Marshal.load(Marshal.dump(base_facts))
apply_overrides!(facts, overrides, false)
facts
end

# A private helper to override_facts
def apply_overrides!(facts, overrides, enforce_strings)
overrides.each do |key, value|
# Nested facts are strings
key = key.to_s if enforce_strings

if value.is_a?(Hash)
facts[key] = {} unless facts.key?(key)
apply_overrides!(facts[key], value, true)
else
facts[key] = value
end
end
end
1 change: 1 addition & 0 deletions lib/voxpupuli/test/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ def suggest_facter_version
end
end

require 'voxpupuli/test/facts'
require 'puppetlabs_spec_helper/module_spec_helper'
require 'rspec-puppet-facts'
include RspecPuppetFacts
Expand Down
93 changes: 93 additions & 0 deletions spec/facts_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
require 'spec_helper'
require 'voxpupuli/test/facts'

describe 'override_facts' do
let(:base_facts) do
{
os: {
'family' => 'RedHat',
'name' => 'CentOS',
'release' => {
'full' => '7.7.1908',
'major' => '7',
'minor' => '7'
},
}
}
end

describe 'no overrides' do
let(:expected) do
{
os: {
'family' => 'RedHat',
'name' => 'CentOS',
'release' => {
'full' => '7.7.1908',
'major' => '7',
'minor' => '7'
},
}
}
end

it { expect(override_facts(base_facts)).to eq(expected) }
end

describe 'with addition at the top level' do
let(:expected) do
{
os: {
'family' => 'RedHat',
'name' => 'CentOS',
'release' => {
'full' => '7.7.1908',
'major' => '7',
'minor' => '7'
},
},
ruby: {
'sitedir' => '/usr/local/share/ruby/site_ruby',
}
}
end

it { expect(override_facts(base_facts, ruby: {sitedir: '/usr/local/share/ruby/site_ruby'})).to eq(expected) }
end

describe 'with deep merging' do
let(:expected) do
{
os: {
'family' => 'RedHat',
'name' => 'CentOS',
'release' => {
'full' => '7.7.1908',
'major' => '7',
'minor' => '8'
},
}
}
end

it { expect(override_facts(base_facts, os: {release: {minor: '8'}})).to eq(expected) }
end

describe 'with strings' do
let(:expected) do
{
os: {
'family' => 'RedHat',
'name' => 'CentOS',
'release' => {
'full' => '7.7.1908',
'major' => '7',
'minor' => '8'
},
}
}
end

it { expect(override_facts(base_facts, os: {'release' => {minor: '8'}})).to eq(expected) }
end
end
1 change: 1 addition & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require 'rspec/core'
3 changes: 3 additions & 0 deletions voxpupuli-test.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,7 @@ Gem::Specification.new do |s|
s.add_runtime_dependency 'puppet-lint-variable_contains_upcase'
s.add_runtime_dependency 'puppet-lint-version_comparison-check'
s.add_runtime_dependency 'puppet-lint-resource_reference_syntax'

# development
s.add_development_dependency 'rspec'
end