rspec-puppet-utils 1.0.2 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +72 -20
- data/lib/hieradata/validator.rb +33 -13
- data/lib/hieradata/yaml_validator.rb +27 -25
- data/lib/mock_function.rb +30 -21
- data/lib/rspec-puppet-utils.rb +1 -5
- data/lib/template_harness.rb +26 -22
- data/rspec-puppet-utils.gemspec +1 -1
- data/spec/classes/hieradata/validator_spec.rb +59 -12
- data/spec/classes/hieradata/yaml_validator_spec.rb +7 -0
- data/spec/classes/mock_function_spec.rb +69 -41
- data/spec/classes/template_harness_spec.rb +2 -0
- data/spec/classes/utils_spec.rb +2 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
SHA512:
|
3
|
-
metadata.gz: 635a0ce9c2b54988fb7ec410b75c4c77e435ae1e80fe1b66ce5b3d1c05c4cb3a8c97b79744060e8f2589607f0efca76372b53d9104e3dcc5673f087d87b2984f
|
4
|
-
data.tar.gz: 98963571a4a6102963fb1fc5435b01b3ee5783e70a58fbba4944e1e8de71307be6c92e5dd3bf5ee14d0aa25f7047678991d299a02bf812495680d5d8089180d8
|
5
2
|
SHA1:
|
6
|
-
|
7
|
-
|
3
|
+
data.tar.gz: a4dd63771ed01e8d6afa8f1e971ee5d34fd5422c
|
4
|
+
metadata.gz: c6a81e4e44b6d5e1198e5c4d27c4d9bf3d383cec
|
5
|
+
SHA512:
|
6
|
+
data.tar.gz: f0b85634b96353cee343e2238264a90b8a03aca441125c5fe7d08b048f803c8e38fd303e5a678d0641513d1fd64f14151d03b0366b3c4db53f94dbc949f32f27
|
7
|
+
metadata.gz: 39365b0ebfbfa4af02a41502d0f8bfa268648dee536082f871fe2cd8d7efbe5afa35ae6fc75e483185551d9fee6d644c3de7aa51b3e93b898747b0d65eb4c205
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# rspec-puppet-utils
|
2
2
|
|
3
|
-
This is
|
3
|
+
This is a more refined version of a previous project about [rspec-puppet unit testing](https://github.com/TomPoulton/rspec-puppet-unit-testing), it provides a class for mocking functions, a harness for testing templates, and a simple tool for testing hiera data files. The motivation for mocking functions etc is provided in that project so I won't go over it here.
|
4
4
|
|
5
5
|
## Usage
|
6
6
|
|
@@ -13,49 +13,49 @@ require 'spec_helper'
|
|
13
13
|
|
14
14
|
describe 'foo::bar' do
|
15
15
|
|
16
|
-
add_stuff
|
17
|
-
|
18
|
-
|
19
|
-
|
16
|
+
let!(:add_stuff) { MockFunction.new('add_stuff') { |f|
|
17
|
+
f.stubs(:call).with([1, 2]).returns(3)
|
18
|
+
}
|
19
|
+
}
|
20
20
|
|
21
21
|
it 'should do something with add_stuff' do
|
22
|
+
# Specific stub for this test
|
23
|
+
add_stuff.stubs(:call).with([]).returns(nil)
|
22
24
|
...
|
23
25
|
end
|
24
26
|
end
|
25
27
|
```
|
26
28
|
|
27
|
-
You can specify a default value:
|
28
|
-
```ruby
|
29
|
-
func = MockFunction.new(self, 'func', {:default_value => true})
|
30
|
-
```
|
31
|
-
|
32
29
|
You can mock a function that doesn't return a value (`:rvalue` is the default):
|
33
30
|
```ruby
|
34
|
-
|
31
|
+
MockFunction.new('func', {:type => :statement})
|
35
32
|
```
|
36
33
|
|
37
34
|
You can mock Hiera:
|
38
35
|
```ruby
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
end
|
36
|
+
MockFunction.new('hiera') { |f|
|
37
|
+
f.stubs(:call).with(['non-ex']).raises(Puppet::ParseError.new('Key not found'))
|
38
|
+
f.stubs(:call).with(['db-password']).returns('password1')
|
39
|
+
}
|
44
40
|
```
|
41
|
+
You handle when the functions are created yourself, e.g. you can assign it to a local variable `func = MockFunction...` create it in a before block `before(:each) do MockFunction... end` or use let `let!(:func) { MockFunction... }`
|
45
42
|
|
46
|
-
|
43
|
+
If you use let, **use `let!()` and not `let()`**, this is because lets are lazy-loaded, so unless you explicitly reference your function in each test, the function won't be created and puppet won't find it. Using `let!` means that the function will be created before every test regardless.
|
44
|
+
|
45
|
+
Also if you use `let` when mocking hiera, **you can't use `:hiera` as the name due to conflicts** so you have to do something like `let!(:mock_hiera) { MockFunction.new('hiera') }`
|
46
|
+
|
47
|
+
Notes:
|
47
48
|
- You always stub the `call` method as that gets called internally
|
48
49
|
- 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
50
|
|
51
51
|
### TemplateHarness
|
52
52
|
|
53
|
-
If your templates have some logic in them that you want to test,
|
53
|
+
If your templates have some logic in them that you want to test, you'd ideally like to get hold of the generated template so you can inspect it programmatically rather than just using a regex. In this case use `TemplateHarness`
|
54
54
|
|
55
55
|
Given a basic template:
|
56
56
|
|
57
57
|
|
58
|
-
```
|
58
|
+
```erb
|
59
59
|
<%
|
60
60
|
from_class = @class_var
|
61
61
|
from_fact = scope.lookupvar('fact-name')
|
@@ -91,6 +91,58 @@ end
|
|
91
91
|
|
92
92
|
Note:
|
93
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
|
+
### HieraData::Validator
|
96
|
+
|
97
|
+
The motivation behind this is to quickly check that your hiera data files have no syntax errors without having to run all of the possible combinations of your hiera hierarchy. At the moment this only supports yaml, but other file types can be added easily.
|
98
|
+
|
99
|
+
```ruby
|
100
|
+
require 'spec_helper'
|
101
|
+
|
102
|
+
describe 'YAML hieradata' do
|
103
|
+
|
104
|
+
# Files are loaded recursively
|
105
|
+
validator = HieraData::YamlValidator.new('spec/fixtures/hieradata')
|
106
|
+
|
107
|
+
it 'should not contain syntax errors' do
|
108
|
+
# Use true to ignore empty files (default false)
|
109
|
+
expect { validator.load true }.to_not raise_error
|
110
|
+
end
|
111
|
+
|
112
|
+
context 'with valid yaml' do
|
113
|
+
|
114
|
+
validator.load true
|
115
|
+
|
116
|
+
# Check types
|
117
|
+
it 'should use arrays for api host lists' do
|
118
|
+
validator.validate('my-api-hosts') { |v|
|
119
|
+
expect(v).to be_an Array
|
120
|
+
}
|
121
|
+
end
|
122
|
+
|
123
|
+
# Use regex to match keys
|
124
|
+
it 'ports should only contain digits' do
|
125
|
+
validator.validate(/-port$/) { |v|
|
126
|
+
expect(v).to match /^[0-9]+$/
|
127
|
+
}
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
133
|
+
```
|
134
|
+
|
135
|
+
In the examples above all keys in all yaml files are searched and checked
|
136
|
+
|
137
|
+
If there is an error, you'll see the inner RSpec error, as well as which key and which file is incorrect:
|
138
|
+
|
139
|
+
```
|
140
|
+
RSpecPuppetUtils::HieraData::ValidationError: mail-smtp-port is invalid in live: expected "TwoFive" to match /^[0-9]+$/
|
141
|
+
Diff:
|
142
|
+
@@ -1,2 +1,2 @@
|
143
|
+
-/^[0-9]+$/
|
144
|
+
+"TwoFive"
|
145
|
+
```
|
94
146
|
|
95
147
|
## Setup
|
96
148
|
- Add `rspec-puppet-utils` to your Gemfile (or use `gem install rspec-puppet-utils`)
|
data/lib/hieradata/validator.rb
CHANGED
@@ -1,24 +1,44 @@
|
|
1
|
+
module RSpecPuppetUtils
|
2
|
+
module HieraData
|
1
3
|
|
2
|
-
|
4
|
+
class Validator
|
3
5
|
|
4
|
-
|
6
|
+
attr_reader :data
|
5
7
|
|
6
|
-
|
8
|
+
def validate(key, &block)
|
9
|
+
raise ValidationError, 'No data available, try #load first' if @data.nil? || @data.empty?
|
7
10
|
|
8
|
-
|
11
|
+
found = false
|
12
|
+
@data.keys.each do |file|
|
13
|
+
keys = get_matching_keys(key, file)
|
14
|
+
keys.each do |matched_key|
|
15
|
+
found = true
|
16
|
+
begin
|
17
|
+
block.call(@data[file][matched_key])
|
18
|
+
rescue Exception => e
|
19
|
+
raise ValidationError, "#{matched_key} is invalid in #{file}: #{e.message}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
raise ValidationError, "No match for #{key.inspect} was not found in any files" unless found
|
24
|
+
end
|
9
25
|
|
10
|
-
|
11
|
-
raise StandardError, '@data is empty' if @data.empty?
|
26
|
+
private
|
12
27
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
28
|
+
def get_matching_keys(key, file)
|
29
|
+
if key.is_a?(String) || key.is_a?(Symbol)
|
30
|
+
keys = @data[file].has_key?(key) ? [key] : []
|
31
|
+
elsif key.is_a?(Regexp)
|
32
|
+
keys = @data[file].keys.select { |k| k.to_s =~ key }
|
33
|
+
else
|
34
|
+
raise ValidationError, 'Search key must be a String, Symbol or a Regexp'
|
19
35
|
end
|
36
|
+
keys
|
20
37
|
end
|
21
|
-
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
class ValidationError < StandardError
|
22
42
|
end
|
23
43
|
|
24
44
|
end
|
@@ -1,40 +1,42 @@
|
|
1
1
|
require 'hieradata/validator'
|
2
2
|
require 'yaml'
|
3
3
|
|
4
|
-
module
|
4
|
+
module RSpecPuppetUtils
|
5
|
+
module HieraData
|
5
6
|
|
6
|
-
|
7
|
+
class YamlValidator < HieraData::Validator
|
7
8
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
9
|
+
def initialize(directory, extensions = ['yaml', 'yml'])
|
10
|
+
raise ArgumentError, 'extensions should be an Array' unless extensions.is_a? Array
|
11
|
+
@directory = directory
|
12
|
+
@extensions = extensions.map {|ext| ext =~ /\..*/ ? ext : ".#{ext}" }
|
13
|
+
end
|
13
14
|
|
14
|
-
|
15
|
+
def load(ignore_empty = false)
|
15
16
|
|
16
|
-
|
17
|
-
|
18
|
-
|
17
|
+
files = Dir.glob(File.join(@directory, '**', '*')).reject { |path|
|
18
|
+
File.directory?(path) || !@extensions.include?(File.extname path )
|
19
|
+
}
|
19
20
|
|
20
|
-
|
21
|
-
|
21
|
+
@data = {}
|
22
|
+
files.each { |file|
|
22
23
|
|
23
|
-
|
24
|
-
|
24
|
+
# Assume all file names are unique i.e. thing.yaml and thing.yml don't both exist
|
25
|
+
file_name = File.basename(file).split('.').first
|
25
26
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
27
|
+
begin
|
28
|
+
yaml = File.open(file) { |yf|
|
29
|
+
YAML::load( yf )
|
30
|
+
}
|
31
|
+
rescue ArgumentError => e
|
32
|
+
raise StandardError, "Yaml Syntax error in file #{file}: #{e.message}"
|
33
|
+
end
|
34
|
+
raise StandardError, "Yaml file is empty: #{file}" unless yaml || ignore_empty
|
34
35
|
|
35
|
-
|
36
|
-
|
36
|
+
@data[file_name.to_sym] = yaml if yaml
|
37
|
+
}
|
37
38
|
|
39
|
+
end
|
38
40
|
end
|
39
41
|
end
|
40
42
|
end
|
data/lib/mock_function.rb
CHANGED
@@ -1,27 +1,36 @@
|
|
1
|
-
require '
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
1
|
+
require 'puppet'
|
2
|
+
|
3
|
+
module RSpecPuppetUtils
|
4
|
+
|
5
|
+
class MockFunction
|
6
|
+
|
7
|
+
def initialize(name, options = {})
|
8
|
+
parse_options! options
|
9
|
+
if options[:type] == :rvalue
|
10
|
+
this = self
|
11
|
+
Puppet::Parser::Functions.newfunction(name.to_sym, options) { |args| this.call args}
|
12
|
+
yield self if block_given?
|
13
|
+
else
|
14
|
+
# Even though the puppet function does not return a value,
|
15
|
+
# this mock still needs to do something, what it returns doesn't really matter.
|
16
|
+
Puppet::Parser::Functions.newfunction(name.to_sym, options) { |args| args }
|
17
|
+
end
|
18
|
+
end
|
13
19
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
20
|
+
private
|
21
|
+
|
22
|
+
def parse_options!(options)
|
23
|
+
unless options[:type]
|
24
|
+
options[:type] = :rvalue
|
25
|
+
end
|
26
|
+
unless [:rvalue, :statement].include? options[:type]
|
27
|
+
raise ArgumentError, "Type should be :rvalue or :statement, not #{options[:type]}"
|
28
|
+
end
|
29
|
+
unless options[:arity].nil? || options[:arity].is_a?(Integer)
|
30
|
+
raise ArgumentError, 'arity should be an integer'
|
31
|
+
end
|
18
32
|
end
|
19
33
|
|
20
|
-
this = self
|
21
|
-
example_group.before(:each) {
|
22
|
-
Puppet::Parser::Functions.newfunction(name.to_sym, {:type => this.function_type}) { |args| this.call(args) }
|
23
|
-
this.stubs(:call).returns(this.default_value) if this.has_default_value
|
24
|
-
}
|
25
34
|
end
|
26
35
|
|
27
36
|
end
|
data/lib/rspec-puppet-utils.rb
CHANGED
data/lib/template_harness.rb
CHANGED
@@ -1,33 +1,37 @@
|
|
1
1
|
require 'erb'
|
2
2
|
|
3
|
-
|
3
|
+
module RSpecPuppetUtils
|
4
4
|
|
5
|
-
|
6
|
-
@template = template
|
7
|
-
@isolator = Isolator.new(scope)
|
8
|
-
end
|
5
|
+
class TemplateHarness
|
9
6
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
7
|
+
def initialize(template, scope = nil)
|
8
|
+
@template = template
|
9
|
+
@isolator = Isolator.new(scope)
|
10
|
+
end
|
14
11
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
end
|
12
|
+
def set(name, value)
|
13
|
+
var_name = name.start_with?('@') ? name : "@#{name}"
|
14
|
+
@isolator.instance_variable_set(var_name, value)
|
15
|
+
end
|
20
16
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
@scope = scope
|
17
|
+
def run
|
18
|
+
b = @isolator.get_binding
|
19
|
+
template = File.exists?(@template) ? File.new(@template).read : @template
|
20
|
+
ERB.new(template, 0, '-').result b
|
26
21
|
end
|
27
|
-
|
28
|
-
|
29
|
-
binding
|
22
|
+
|
23
|
+
class Isolator
|
24
|
+
# Isolates the binding so that only the defined set
|
25
|
+
# of instance variables are available to erb
|
26
|
+
def initialize scope
|
27
|
+
@scope = scope
|
28
|
+
end
|
29
|
+
def get_binding
|
30
|
+
scope = @scope
|
31
|
+
binding
|
32
|
+
end
|
30
33
|
end
|
34
|
+
|
31
35
|
end
|
32
36
|
|
33
37
|
end
|
data/rspec-puppet-utils.gemspec
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
2
|
Gem::Specification.new do |gem|
|
3
3
|
gem.name = 'rspec-puppet-utils'
|
4
|
-
gem.version = '
|
4
|
+
gem.version = '2.0.0'
|
5
5
|
gem.description = 'Helper classes for mock/stub functions, templates and hierdata'
|
6
6
|
gem.summary = ''
|
7
7
|
gem.author = 'Tom Poulton'
|
@@ -1,6 +1,8 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'lib/hieradata/validator'
|
3
3
|
|
4
|
+
include RSpecPuppetUtils
|
5
|
+
|
4
6
|
module HieraData
|
5
7
|
class Test < Validator
|
6
8
|
def load
|
@@ -8,11 +10,13 @@ module HieraData
|
|
8
10
|
:file1 => {
|
9
11
|
'key' => 'value',
|
10
12
|
:other => 'other value',
|
11
|
-
'missmatch' => 'string'
|
13
|
+
'missmatch' => 'string',
|
14
|
+
'cat' => 'black',
|
12
15
|
},
|
13
16
|
:file2 => {
|
14
17
|
'hello' => 'world',
|
15
|
-
'missmatch' => ['array']
|
18
|
+
'missmatch' => ['array'],
|
19
|
+
'hat' => 'fedora',
|
16
20
|
}
|
17
21
|
}
|
18
22
|
end
|
@@ -33,39 +37,82 @@ describe HieraData::Validator do
|
|
33
37
|
|
34
38
|
it 'should use block to validate key' do
|
35
39
|
expect {
|
36
|
-
validator.validate
|
40
|
+
validator.validate('key') { |v| expect(v).to eq 'value' }
|
37
41
|
}.to_not raise_error
|
38
42
|
|
39
43
|
expect {
|
40
|
-
validator.validate
|
41
|
-
}.to raise_error
|
44
|
+
validator.validate('key') { |v| expect(v).to eq 'oooops' }
|
45
|
+
}.to raise_error HieraData::ValidationError
|
42
46
|
end
|
43
47
|
|
44
48
|
it 'should accept symbol as key' do
|
45
49
|
expect {
|
46
|
-
validator.validate
|
50
|
+
validator.validate(:other) { |v| v == 'other value' }
|
47
51
|
}.to_not raise_error
|
48
52
|
end
|
49
53
|
|
50
54
|
it 'should validate key in all files' do
|
51
55
|
expect {
|
52
|
-
validator.validate
|
53
|
-
}.to raise_error
|
56
|
+
validator.validate('missmatch') { |v| expect(v).to be_a String }
|
57
|
+
}.to raise_error HieraData::ValidationError
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'should return key and file in error messages' do
|
61
|
+
expect {
|
62
|
+
validator.validate('missmatch') { |v| expect(v).to be_a String }
|
63
|
+
}.to raise_error HieraData::ValidationError, /missmatch is invalid in file2/
|
64
|
+
end
|
65
|
+
|
66
|
+
context 'when matching with regex' do
|
67
|
+
|
68
|
+
it 'should raise error if no match is found' do
|
69
|
+
expect {
|
70
|
+
validator.validate(/nonex/) { }
|
71
|
+
}.to raise_error HieraData::ValidationError, /No match for \/nonex\/ was not found/
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'should not raise error if match is found' do
|
75
|
+
expect {
|
76
|
+
validator.validate(/at$/) { }
|
77
|
+
}.to_not raise_error
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'should validate block against all matches' do
|
81
|
+
parser = mock()
|
82
|
+
parser.expects(:parse).with('black').once
|
83
|
+
parser.expects(:parse).with('fedora').once
|
84
|
+
validator.validate(/at$/) { |v| parser.parse v }
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'should match symbols' do
|
88
|
+
expect {
|
89
|
+
validator.validate(/other/) { |v| expect(v).to eq 'other value' }
|
90
|
+
}.to_not raise_error
|
91
|
+
end
|
92
|
+
|
54
93
|
end
|
55
94
|
|
56
95
|
it 'should raise error if data is nil' do
|
57
96
|
nil_validator = HieraData::Test.new
|
58
97
|
expect {
|
59
|
-
nil_validator.validate
|
60
|
-
}.to raise_error
|
98
|
+
nil_validator.validate('meh') { }
|
99
|
+
}.to raise_error HieraData::ValidationError, /No data available/
|
61
100
|
end
|
62
101
|
|
63
102
|
it 'should raise error if data is empty' do
|
64
103
|
empty_validator = HieraData::Test.new
|
65
104
|
empty_validator.load_empty
|
66
105
|
expect {
|
67
|
-
empty_validator.validate
|
68
|
-
}.to raise_error
|
106
|
+
empty_validator.validate('meh') { }
|
107
|
+
}.to raise_error HieraData::ValidationError, /No data available/
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
|
112
|
+
describe HieraData::Validator do
|
113
|
+
|
114
|
+
it 'should inherit from StandardError' do
|
115
|
+
expect(HieraData::ValidationError.ancestors).to include StandardError
|
69
116
|
end
|
70
117
|
|
71
118
|
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
require 'lib/hieradata/yaml_validator'
|
2
2
|
|
3
|
+
include RSpecPuppetUtils
|
4
|
+
|
3
5
|
describe HieraData::YamlValidator do
|
4
6
|
|
5
7
|
it 'should be of type Validator' do
|
@@ -67,6 +69,11 @@ describe HieraData::YamlValidator do
|
|
67
69
|
expect { validator.load true }.to_not raise_error
|
68
70
|
end
|
69
71
|
|
72
|
+
it 'should not add empty files to @data' do
|
73
|
+
validator.load true
|
74
|
+
expect(validator.data.keys).to_not include :empty
|
75
|
+
end
|
76
|
+
|
70
77
|
end
|
71
78
|
|
72
79
|
end
|
@@ -1,83 +1,111 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'lib/mock_function'
|
3
3
|
|
4
|
+
include RSpecPuppetUtils
|
5
|
+
|
4
6
|
describe MockFunction do
|
5
7
|
|
6
8
|
let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
|
7
9
|
|
8
|
-
|
10
|
+
let(:values_from_let) { [1, 2, 3] }
|
11
|
+
|
12
|
+
describe '#initialize' do
|
9
13
|
|
10
|
-
|
14
|
+
func_name = 'my_func'
|
15
|
+
func_sym = func_name.to_sym
|
11
16
|
|
12
|
-
it 'should
|
13
|
-
|
17
|
+
it 'should add new function to puppet' do
|
18
|
+
name = 'mock_func'
|
19
|
+
func = MockFunction.new name
|
20
|
+
expect(Puppet::Parser::Functions.function(name.to_sym)).to eq "function_#{name}"
|
14
21
|
end
|
15
22
|
|
16
|
-
it 'should
|
17
|
-
|
23
|
+
it 'should default to :rvalue type' do
|
24
|
+
func = MockFunction.new func_name
|
25
|
+
expect(Puppet::Parser::Functions.rvalue?(func_sym)).to eq true
|
18
26
|
end
|
19
27
|
|
20
|
-
it 'should
|
21
|
-
|
28
|
+
it 'should default to :rvalue type if missing from options' do
|
29
|
+
func = MockFunction.new func_name, {}
|
30
|
+
expect(Puppet::Parser::Functions.rvalue?(func_sym)).to eq true
|
22
31
|
end
|
23
32
|
|
24
|
-
|
33
|
+
it 'should allow type to be set' do
|
34
|
+
func = MockFunction.new func_name, {:type => :statement}
|
35
|
+
expect(Puppet::Parser::Functions.rvalue?(func_sym)).to eq false
|
36
|
+
end
|
25
37
|
|
26
|
-
|
38
|
+
it 'should only allow :rvalue or :statement for type' do
|
39
|
+
expect {
|
40
|
+
MockFunction.new func_name, {:type => :error}
|
41
|
+
}.to raise_error ArgumentError, 'Type should be :rvalue or :statement, not error'
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'should allow arity to be set' do
|
45
|
+
func = MockFunction.new func_name, {:arity => 3}
|
46
|
+
expect(Puppet::Parser::Functions.arity(func_sym)).to eq 3
|
47
|
+
end
|
27
48
|
|
28
|
-
it 'should
|
29
|
-
expect {
|
49
|
+
it 'should only allow arity to be an integer' do
|
50
|
+
expect {
|
51
|
+
MockFunction.new func_name, {:arity => 'oops'}
|
52
|
+
}.to raise_error ArgumentError, 'arity should be an integer'
|
30
53
|
end
|
31
54
|
|
32
55
|
end
|
33
56
|
|
34
|
-
|
57
|
+
describe '#call' do
|
35
58
|
|
36
|
-
|
59
|
+
let(:func) { MockFunction.new('func') }
|
37
60
|
|
38
|
-
it '
|
39
|
-
expect(
|
61
|
+
it 'should not be defined by default' do
|
62
|
+
expect(func.respond_to?(:call)).to eq false
|
40
63
|
end
|
41
64
|
|
42
|
-
|
43
|
-
|
44
|
-
|
65
|
+
it 'should be stubable' do
|
66
|
+
func.stubs(:call)
|
67
|
+
expect(func.respond_to?(:call)).to eq true
|
68
|
+
end
|
45
69
|
|
46
|
-
|
70
|
+
it 'should be called by puppet function' do
|
71
|
+
func.stubs(:call).returns('penguin')
|
72
|
+
result = scope.function_func []
|
73
|
+
expect(result).to eq 'penguin'
|
74
|
+
end
|
47
75
|
|
48
|
-
it '
|
49
|
-
|
76
|
+
it 'should be passed puppet function args' do
|
77
|
+
func.expects(:call).with([1, 2, 3]).once
|
78
|
+
scope.function_func [1, 2, 3]
|
50
79
|
end
|
51
80
|
|
52
81
|
end
|
53
82
|
|
54
|
-
context '
|
55
|
-
|
56
|
-
statement = MockFunction.new(self, 'statement', {:type => :statement})
|
83
|
+
context 'when :type => :statement' do
|
57
84
|
|
58
|
-
it 'should
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
expect { statement.call }.to_not raise_error
|
85
|
+
it 'should not raise error' do
|
86
|
+
MockFunction.new 'statement', {:type => :statement}
|
87
|
+
expect {
|
88
|
+
scope.function_statement []
|
89
|
+
}.to_not raise_error
|
64
90
|
end
|
65
91
|
|
66
92
|
end
|
67
93
|
|
68
|
-
context 'when
|
69
|
-
|
70
|
-
func = MockFunction.new(self, 'func', {:default_value => true})
|
94
|
+
context 'when :type => :rvalue' do
|
71
95
|
|
72
|
-
it '
|
73
|
-
|
74
|
-
|
96
|
+
it 'should allow setup stubs' do
|
97
|
+
func = MockFunction.new('func') { |f| f.stubs(:call).returns('badger') }
|
98
|
+
result = func.call
|
99
|
+
expect(result).to eq 'badger'
|
75
100
|
end
|
76
101
|
|
77
|
-
it 'should
|
78
|
-
|
79
|
-
|
80
|
-
|
102
|
+
it 'should return values defined by a "let"' do
|
103
|
+
result = []
|
104
|
+
expect {
|
105
|
+
func = MockFunction.new('func') { |f| f.stubs(:call).returns(values_from_let) }
|
106
|
+
result = func.call
|
107
|
+
}.to_not raise_error
|
108
|
+
expect(result).to eq [1, 2, 3]
|
81
109
|
end
|
82
110
|
|
83
111
|
end
|
data/spec/classes/utils_spec.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rspec-puppet-utils
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tom Poulton
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2014-03-
|
12
|
+
date: 2014-03-19 00:00:00 Z
|
13
13
|
dependencies: []
|
14
14
|
|
15
15
|
description: Helper classes for mock/stub functions, templates and hierdata
|