rspec-puppet-utils 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA512:
3
+ metadata.gz: 73d31647aca9a8ea92a51e91875d9428ddf36d65522e540205bd22fc056c577c025bac30e777479234c390977a1b13d815a64ebb5a33e742543e489b59493d80
4
+ data.tar.gz: 875c88ed3de884c3acdf8341e3dc675d011fba4f04b112ac3f9cb370580af86ba5ec9d256c0f82c62787b151035903bc1e5e40b11b3f8b1a1ac8cfab6026c2a6
5
+ SHA1:
6
+ metadata.gz: a44abeac9ab5e7f480bc8a9e0d1587cd41e8d596
7
+ data.tar.gz: 69010a95237c2e8c0c0e8777b266e98d7c00e3ae
@@ -0,0 +1,6 @@
1
+ .idea
2
+ *.iml
3
+ .ruby-version
4
+ .ruby-gemset
5
+ Gemfile.lock
6
+ pkg
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source 'https://rubygems.org/'
2
+
3
+ gem 'puppet'
4
+ gem 'mocha'
5
+ gem 'rspec'
6
+ gem 'rspec-puppet'
7
+ gem 'puppetlabs_spec_helper'
@@ -0,0 +1,97 @@
1
+ # rspec-puppet-utils
2
+
3
+ This is the continuation of a previous project about [rspec-puppet unit testing](https://github.com/TomPoulton/rspec-puppet-unit-testing), it provides a more refined version of the helper method for mocking functions, plus a harness for testing templates. The motivation for mocking functions etc is provided there so I won't go over it here.
4
+
5
+ ## Usage
6
+
7
+ ### MockFunction
8
+
9
+ The basic usage is to create your mock function with `MockFunction.new` and then use `mocha` to stub any particular calls that you need
10
+
11
+ ```ruby
12
+ require 'spec_helper'
13
+
14
+ describe 'foo::bar' do
15
+
16
+ add_stuff = MockFunction.new(self, 'add_stuff')
17
+ before(:each) do
18
+ add_stuff.stubs(:call).with([1, 2]).returns(3)
19
+ end
20
+
21
+ it 'should do something with add_stuff' do
22
+ ...
23
+ end
24
+ end
25
+ ```
26
+
27
+ You can specify a default value:
28
+ ```ruby
29
+ func = MockFunction.new(self, 'func', {:default_value => true})
30
+ ```
31
+
32
+ You can mock a function that doesn't return a value (`:rvalue` is the default):
33
+ ```ruby
34
+ func = MockFunction.new(self, 'func', {:type => :statement})
35
+ ```
36
+
37
+ You can mock Hiera:
38
+ ```ruby
39
+ hiera = MockFunction.new(self, 'hiera')
40
+ before(:each) do
41
+ hiera.stubs(:call).with(['non-ex']).raises(Puppet::ParseError.new('Key not found'))
42
+ hiera.stubs(:call).with(['db-password']).returns('password1')
43
+ end
44
+ ```
45
+
46
+ Note:
47
+ - You always stub the `call` method as that gets called internally
48
+ - The `call` method takes an array of arguments
49
+ - `self` is a way of getting hold of the current `RSpec::Core::ExampleGroup` instance. If anyone knows how to do this more cleanly let me know!
50
+
51
+ ### TemplateHarness
52
+
53
+ If your templates have some logic in them that you want to test, and you'd ideally like to get hold of the generated template so you can inspect it programatically rather than just using a regex then use `TemplateHarness`
54
+
55
+ Given a basic template:
56
+
57
+
58
+ ```ruby
59
+ <%
60
+ from_class = @class_var
61
+ from_fact = scope.lookupvar('fact-name')
62
+ from_hiera = scope.function_hiera('hiera-key')
63
+ -%>
64
+ <%= "#{from_class} #{from_fact} #{from_hiera}" %>
65
+
66
+ ```
67
+
68
+ A test could look like this:
69
+
70
+
71
+ ```ruby
72
+ require 'spec_helper'
73
+
74
+ describe 'my_template' do
75
+
76
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
77
+ before(:each) do
78
+ scope.stubs(:lookupvar).with('fact-name').returns('fact-value')
79
+ scope.stubs(:function_hiera).with('hiera-key').returns('hiera-value')
80
+ end
81
+
82
+ it 'should render template' do
83
+ harness = TemplateHarness.new('spec/.../.../my_template.erb', scope)
84
+ harness.set('@class_var', 'classy')
85
+ result = harness.run
86
+ expect(result).to eq 'classy fact-value hiera-value'
87
+ end
88
+
89
+ end
90
+ ```
91
+
92
+ Note:
93
+ - The path resolution is pretty simple, just pass it a normal relative path, **not** like the paths you pass into the `template` function in puppet (where you expect puppet to add the `templates` section to the path)
94
+
95
+ ## Setup
96
+ - Add `rspec-puppet-utils` to your Gemfile (or use `gem install rspec-puppet-utils`)
97
+ - Add `require 'rspec-puppet-utils'` to the top of your `spec_helper`
@@ -0,0 +1,6 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:rspec)
5
+
6
+ task :build => :rspec
@@ -0,0 +1,64 @@
1
+ require 'rspec-puppet'
2
+ require 'mocha'
3
+ require 'erb'
4
+
5
+ RSpec.configure do |c|
6
+ c.mock_with :mocha
7
+ end
8
+
9
+ class MockFunction
10
+
11
+ attr_accessor :function_type, :has_default_value, :default_value
12
+
13
+ def initialize(example_group, name, options = {})
14
+ opts = options.nil? ? {} : options
15
+
16
+ @function_type = opts.has_key?(:type) ? opts[:type] : :rvalue
17
+
18
+ opts[:default_value] = nil if @function_type == :statement
19
+
20
+ @has_default_value = false
21
+ if opts.has_key?(:default_value)
22
+ @has_default_value = true
23
+ @default_value = opts[:default_value]
24
+ end
25
+
26
+ this = self
27
+ example_group.before(:each) {
28
+ Puppet::Parser::Functions.newfunction(name.to_sym, {:type => this.function_type}) { |args| this.call(args) }
29
+ this.stubs(:call).returns(this.default_value) if this.has_default_value
30
+ }
31
+ end
32
+ end
33
+
34
+ class TemplateHarness
35
+
36
+ def initialize(template, scope = nil)
37
+ @template = template
38
+ @isolator = Isolator.new(scope)
39
+ end
40
+
41
+ def set(name, value)
42
+ var_name = name.start_with?('@') ? name : "@#{name}"
43
+ @isolator.instance_variable_set(var_name, value)
44
+ end
45
+
46
+ def run
47
+ b = @isolator.get_binding
48
+ template = File.exists?(@template) ? File.new(@template).read : @template
49
+ ERB.new(template, 0, '-').result b
50
+ end
51
+
52
+ class Isolator
53
+ # Isolates the binding so that only the defined set
54
+ # of instance variables are available to erb
55
+ def initialize scope
56
+ @scope = scope
57
+ end
58
+ def get_binding
59
+ scope = @scope
60
+ binding
61
+ end
62
+ end
63
+
64
+ end
@@ -0,0 +1,14 @@
1
+ # -*- encoding: utf-8 -*-
2
+ Gem::Specification.new do |gem|
3
+ gem.name = 'rspec-puppet-utils'
4
+ gem.version = '1.0.0'
5
+ gem.description = 'Helper classes for mock functions and templates'
6
+ gem.summary = ''
7
+ gem.author = 'Tom Poulton'
8
+ #gem.license = ''
9
+
10
+ gem.homepage = 'https://github.com/Accuity/rspec-puppet-utils'
11
+ gem.files = `git ls-files`.split($/)
12
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
13
+ gem.require_paths = ['lib']
14
+ end
@@ -0,0 +1,85 @@
1
+ require 'spec_helper'
2
+ require 'rspec-puppet-utils'
3
+
4
+ describe MockFunction do
5
+
6
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
7
+
8
+ context 'with no options' do
9
+
10
+ func = MockFunction.new(self, 'func')
11
+
12
+ it 'should return an object' do
13
+ expect(func).to_not eq nil
14
+ end
15
+
16
+ it 'should not attach stub method to object' do
17
+ expect { func.call 'a' }.to raise_error NoMethodError
18
+ end
19
+
20
+ it 'should set function_type to :rvalue' do
21
+ expect(func.function_type).to eq :rvalue
22
+ end
23
+
24
+ end
25
+
26
+ context 'with options set to nil' do
27
+
28
+ it 'should not throw error creating function' do
29
+ expect { MockFunction.new(example.example_group, 'nil_options', nil) }.to_not raise_error
30
+ end
31
+
32
+ end
33
+
34
+ context 'with a default value of true' do
35
+
36
+ default_of_true = MockFunction.new(self, 'default_of_true', {:default_value => true})
37
+
38
+ it 'function should return true' do
39
+ expect(default_of_true.call 'a').to eq true
40
+ end
41
+
42
+ end
43
+
44
+ context 'with a default value of nil' do
45
+
46
+ default_of_nil = MockFunction.new(self, 'default_of_nil', {:default_value => nil})
47
+
48
+ it 'function should return true' do
49
+ expect(default_of_nil.call 'a').to eq nil
50
+ end
51
+
52
+ end
53
+
54
+ context 'with a type of :statement' do
55
+
56
+ statement = MockFunction.new(self, 'statement', {:type => :statement})
57
+
58
+ it 'should set function_type to :statement' do
59
+ expect(statement.function_type).to eq :statement
60
+ end
61
+
62
+ it 'should wire up a stub call method' do
63
+ expect { statement.call }.to_not raise_error
64
+ end
65
+
66
+ end
67
+
68
+ context 'when using a puppet scope' do
69
+
70
+ func = MockFunction.new(self, 'func', {:default_value => true})
71
+
72
+ it 'puppet should be able to call function' do
73
+ result = scope.function_func ['a']
74
+ expect(result).to eq true
75
+ end
76
+
77
+ it 'should be able to stub calls' do
78
+ func.stubs(:call).with([1, 2]).returns(3)
79
+ result = scope.function_func [1, 2]
80
+ expect(result).to eq 3
81
+ end
82
+
83
+ end
84
+
85
+ end
@@ -0,0 +1,46 @@
1
+ require 'spec_helper'
2
+ require 'rspec-puppet-utils'
3
+
4
+ describe TemplateHarness do
5
+
6
+ it 'should render template' do
7
+ harness = TemplateHarness.new('<%= "inside template" %>')
8
+ expect(harness.run).to eq 'inside template'
9
+ end
10
+
11
+ it 'should handle -%> syntax' do
12
+ harness = TemplateHarness.new('<% animal = "penguin" -%><%= animal %>')
13
+ expect { harness.run }.to_not raise_error
14
+ end
15
+
16
+ it 'should provide access to scope' do
17
+ scope = PuppetlabsSpec::PuppetInternals.scope
18
+ scope.stubs(:lookupvar).with('honey').returns('badger')
19
+ harness = TemplateHarness.new('<%= scope.lookupvar("honey") %>', scope)
20
+ expect(harness.run).to eq 'badger'
21
+ end
22
+
23
+ it 'should provide access to instance vars' do
24
+ harness = TemplateHarness.new('<%= @foo %>')
25
+ harness.set('@foo', 'bar')
26
+ expect(harness.run).to eq 'bar'
27
+ end
28
+
29
+ it 'should add @ to instance vars when missing' do
30
+ harness = TemplateHarness.new('<%= @alice %>')
31
+ harness.set('alice', 'bob')
32
+ expect(harness.run).to eq 'bob'
33
+ end
34
+
35
+ it 'should isolate instance vars' do
36
+ harness = TemplateHarness.new('<%= @not_exist %>')
37
+ harness.instance_variable_set('@not_exist', 'pixies')
38
+ expect(harness.run).to eq ''
39
+ end
40
+
41
+ it 'should read file if it exists' do
42
+ harness = TemplateHarness.new('spec/fixtures/templates/returns_elephant.erb')
43
+ expect(harness.run).to eq 'elephant'
44
+ end
45
+
46
+ end
@@ -0,0 +1 @@
1
+ <%= 'elephant' %>
@@ -0,0 +1,6 @@
1
+ require 'rspec-puppet'
2
+ require 'puppetlabs_spec_helper/module_spec_helper'
3
+
4
+ RSpec.configure do |c|
5
+ c.color = true
6
+ end
metadata ADDED
@@ -0,0 +1,64 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rspec-puppet-utils
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Tom Poulton
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2014-03-04 00:00:00 Z
13
+ dependencies: []
14
+
15
+ description: Helper classes for mock functions and templates
16
+ email:
17
+ executables: []
18
+
19
+ extensions: []
20
+
21
+ extra_rdoc_files: []
22
+
23
+ files:
24
+ - .gitignore
25
+ - Gemfile
26
+ - README.md
27
+ - Rakefile
28
+ - lib/rspec-puppet-utils.rb
29
+ - rspec-puppet-utils.gemspec
30
+ - spec/classes/mock_function_spec.rb
31
+ - spec/classes/template_harness_spec.rb
32
+ - spec/fixtures/templates/returns_elephant.erb
33
+ - spec/spec_helper.rb
34
+ homepage: https://github.com/Accuity/rspec-puppet-utils
35
+ licenses: []
36
+
37
+ metadata: {}
38
+
39
+ post_install_message:
40
+ rdoc_options: []
41
+
42
+ require_paths:
43
+ - lib
44
+ required_ruby_version: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - &id001
47
+ - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: "0"
50
+ required_rubygems_version: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - *id001
53
+ requirements: []
54
+
55
+ rubyforge_project:
56
+ rubygems_version: 2.0.14
57
+ signing_key:
58
+ specification_version: 4
59
+ summary: ""
60
+ test_files:
61
+ - spec/classes/mock_function_spec.rb
62
+ - spec/classes/template_harness_spec.rb
63
+ - spec/fixtures/templates/returns_elephant.erb
64
+ - spec/spec_helper.rb