Skip to content

Commit

Permalink
Add override_facts helper method
Browse files Browse the repository at this point in the history
  • Loading branch information
ekohl committed Apr 21, 2020
1 parent abe3ebb commit 87d851c
Show file tree
Hide file tree
Showing 4 changed files with 204 additions and 0 deletions.
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

0 comments on commit 87d851c

Please sign in to comment.