rspec-puppet-maestrodev 0.1.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Tim Sharpe
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,292 @@
1
+ # RSpec tests for your Puppet manifests & modules
2
+
3
+ ## Installation
4
+
5
+ gem install rspec-puppet
6
+
7
+ ## Naming conventions
8
+
9
+ For clarity and consistency, I recommend that you use the following directory
10
+ structure and naming convention.
11
+
12
+ module
13
+ |
14
+ +-- manifests
15
+ |
16
+ +-- lib
17
+ |
18
+ +-- spec
19
+ |
20
+ +-- spec_helper.rb
21
+ |
22
+ +-- classes
23
+ | |
24
+ | +-- <class_name>_spec.rb
25
+ |
26
+ +-- defines
27
+ | |
28
+ | +-- <define_name>_spec.rb
29
+ |
30
+ +-- functions
31
+ | |
32
+ | +-- <function_name>_spec.rb
33
+ |
34
+ +-- hosts
35
+ |
36
+ +-- <host_name>_spec.rb
37
+
38
+ ## Example groups
39
+
40
+ If you use the above directory structure, your examples will automatically be
41
+ placed in the correct groups and have access to the custom matchers. *If you
42
+ choose not to*, you can force the examples into the required groups as follows.
43
+
44
+ ```ruby
45
+ describe 'myclass', :type => :class do
46
+ ...
47
+ end
48
+
49
+ describe 'mydefine', :type => :define do
50
+ ...
51
+ end
52
+
53
+ describe 'myfunction', :type => :puppet_function do
54
+ ...
55
+ end
56
+
57
+ describe 'myhost.example.com', :type => :host do
58
+ ...
59
+ end
60
+ ```
61
+
62
+ ## Defined Types & Classes
63
+
64
+ ### Matchers
65
+
66
+ #### Checking if a class has been included
67
+
68
+ You can test if a class has been included in the catalogue with the
69
+ `include_class` matcher. It takes the class name as a string as its only
70
+ argument
71
+
72
+ ```ruby
73
+ it { should include_class('foo') }
74
+ ```
75
+
76
+ #### Checking if a resource exists
77
+
78
+ You can test if a resource exists in the catalogue with the generic
79
+ `contain_<resource type>` matcher.
80
+
81
+ ```ruby
82
+ it { should contain_augeas('bleh') }
83
+ ```
84
+
85
+ If your resource type includes :: (e.g.
86
+ `foo::bar` simply replace the :: with __ (two underscores).
87
+
88
+ ```ruby
89
+ it { should contain_foo__bar('baz') }
90
+ ```
91
+
92
+ You can further test the parameters that have been passed to the resources with
93
+ the generic `with_<parameter>` chains.
94
+
95
+ ```ruby
96
+ it { should contain_package('mysql-server').with_ensure('present') }
97
+ ```
98
+
99
+ You can use the `with` method to verify the value of multiple parameters.
100
+
101
+ ```ruby
102
+ it do should contain_service('keystone').with(
103
+ 'ensure' => 'running',
104
+ 'enable' => 'true',
105
+ 'hasstatus' => 'true',
106
+ 'hasrestart' => 'true'
107
+ ) end
108
+ ```
109
+
110
+ You can also test that specific parameters have been left undefined with the
111
+ generic `without_<parameter>` chains.
112
+
113
+ ```ruby
114
+ it { should contain_file('/foo/bar').without_mode }
115
+ ```
116
+
117
+ You can use the without method to verify that a list of parameters have not been
118
+ defined
119
+
120
+ ```ruby
121
+ it { should contain_service('keystone').without(
122
+ ['restart', 'status']
123
+ )}
124
+ ```
125
+
126
+ ### Writing tests
127
+
128
+ #### Basic test structure
129
+
130
+ To test that
131
+
132
+ sysctl { 'baz'
133
+ value => 'foo',
134
+ }
135
+
136
+ Will cause the following resource to be in included in catalogue for a host
137
+
138
+ exec { 'sysctl/reload':
139
+ command => '/sbin/sysctl -p /etc/sysctl.conf',
140
+ }
141
+
142
+ We can write the following testcase (in `spec/defines/sysctl_spec.rb`)
143
+
144
+ ```ruby
145
+ describe 'sysctl' do
146
+ let(:title) { 'baz' }
147
+ let(:params) { { :value => 'foo' } }
148
+
149
+ it { should contain_exec('sysctl/reload').with_command("/sbin/sysctl -p /etc/sysctl.conf") }
150
+ end
151
+ ```
152
+
153
+ #### Specifying the title of a resource
154
+
155
+ ```ruby
156
+ let(:title) { 'foo' }
157
+ ```
158
+
159
+ #### Specifying the parameters to pass to a resources or parametised class
160
+
161
+ ```ruby
162
+ let(:params) { {:ensure => 'present', ...} }
163
+ ```
164
+
165
+ #### Specifying the FQDN of the test node
166
+
167
+ If the manifest you're testing expects to run on host with a particular name,
168
+ you can specify this as follows
169
+
170
+ ```ruby
171
+ let(:node) { 'testhost.example.com' }
172
+ ```
173
+
174
+ #### Specifying the facts that should be available to your manifest
175
+
176
+ By default, the test environment contains no facts for your manifest to use.
177
+ You can set them with a hash
178
+
179
+ ```ruby
180
+ let(:facts) { {:operatingsystem => 'Debian', :kernel => 'Linux', ...} }
181
+ ```
182
+
183
+ #### Specifying the path to find your modules
184
+
185
+ I recommend setting a default module path by adding the following code to your
186
+ `spec_helper.rb`
187
+
188
+ ```ruby
189
+ RSpec.configure do |c|
190
+ c.module_path = '/path/to/your/module/dir'
191
+ end
192
+ ```
193
+
194
+ However, if you want to specify it in each example, you can do so
195
+
196
+ ```ruby
197
+ let(:module_path) { '/path/to/your/module/dir' }
198
+ ```
199
+
200
+ ## Functions
201
+
202
+ ### Matchers
203
+
204
+ All of the standard RSpec matchers are available for you to use when testing
205
+ Puppet functions.
206
+
207
+ ```ruby
208
+ it 'should be able to do something' do
209
+ subject.call('foo') == 'bar'
210
+ end
211
+ ```
212
+
213
+ For your convenience though, a `run` matcher exists to provide easier to
214
+ understand test cases.
215
+
216
+ ```ruby
217
+ it { should run.with_params('foo').and_return('bar') }
218
+ ```
219
+
220
+ ### Writing tests
221
+
222
+ #### Basic test structure
223
+
224
+ ```ruby
225
+ require 'spec_helper'
226
+
227
+ describe '<function name>' do
228
+ ...
229
+ end
230
+ ```
231
+
232
+ #### Specifying the name of the function to test
233
+
234
+ The name of the function must be provided in the top level description, e.g.
235
+
236
+ ```ruby
237
+ describe 'split' do
238
+ ```
239
+
240
+ #### Specifying the arguments to pass to the function
241
+
242
+ You can specify the arguments to pass to your function during the test(s) using
243
+ either the `with_params` chain method in the `run` matcher
244
+
245
+ ```ruby
246
+ it { should run.with_params('foo', 'bar', ['baz']) }
247
+ ```
248
+
249
+ Or by using the `call` method on the subject directly
250
+
251
+ ```ruby
252
+ it 'something' do
253
+ subject.call('foo', 'bar', ['baz'])
254
+ end
255
+ ```
256
+
257
+ #### Testing the results of the function
258
+
259
+ You can test the result of a function (if it produces one) using either the
260
+ `and_returns` chain method in the `run` matcher
261
+
262
+ ```ruby
263
+ it { should run.with_params('foo').and_return('bar') }
264
+ ```
265
+
266
+ Or by using any of the existing RSpec matchers on the subject directly
267
+
268
+ ```ruby
269
+ it 'something' do
270
+ subject.call('foo') == 'bar'
271
+ subject.call('baz').should be_an Array
272
+ end
273
+ ```
274
+
275
+ #### Testing the errors thrown by the function
276
+
277
+ You can test whether the function throws an exception using either the
278
+ `and_raises_error` chain method in the `run` matcher
279
+
280
+ ```ruby
281
+ it { should run.with_params('a', 'b').and_raise_error(Puppet::ParseError) }
282
+ it { should_not run.with_params('a').and_raise_error(Puppet::ParseError) }
283
+ ```
284
+
285
+ Or by using the existing `raises_error` RSpec matcher
286
+
287
+ ```ruby
288
+ it 'something' do
289
+ expect { subject.call('a', 'b') }.should raise_error(Puppet::ParseError)
290
+ expect { subject.call('a') }.should_not raise_error(Puppet::ParseError)
291
+ end
292
+ ```
@@ -0,0 +1,7 @@
1
+ require 'rake'
2
+ require 'rspec/core/rake_task'
3
+
4
+ task :default => :test
5
+ task :spec => :test
6
+
7
+ RSpec::Core::RakeTask.new(:test)
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
4
+
5
+ require 'rspec-puppet'
6
+ require 'optparse'
7
+
8
+ options = {
9
+ :module_name => nil,
10
+ }
11
+
12
+ OptionParser.new do |opts|
13
+ opts.banner = "Usage: rspec-puppet-init [options]"
14
+
15
+ opts.on('-n', '--name NAME', 'The name of the module (override autodetection)') do |v|
16
+ options[:module_name] = v
17
+ end
18
+ end.parse!
19
+
20
+ RSpec::Puppet::Setup.run(options[:module_name])
@@ -0,0 +1,15 @@
1
+ require 'puppet'
2
+ require 'rspec'
3
+ require 'fileutils'
4
+ require 'tmpdir'
5
+ require 'rspec-puppet/matchers'
6
+ require 'rspec-puppet/example'
7
+ require 'rspec-puppet/setup'
8
+
9
+ RSpec.configure do |c|
10
+ c.add_setting :module_path, :default => '/etc/puppet/modules'
11
+ c.add_setting :manifest_dir, :default => nil
12
+ c.add_setting :manifest, :default => nil
13
+ c.add_setting :template_dir, :default => nil
14
+ c.add_setting :config, :default => nil
15
+ end
@@ -0,0 +1,27 @@
1
+ require 'rspec-puppet/support'
2
+ require 'rspec-puppet/example/define_example_group'
3
+ require 'rspec-puppet/example/class_example_group'
4
+ require 'rspec-puppet/example/function_example_group'
5
+ require 'rspec-puppet/example/host_example_group'
6
+
7
+ RSpec::configure do |c|
8
+ def c.escaped_path(*parts)
9
+ Regexp.compile(parts.join('[\\\/]'))
10
+ end
11
+
12
+ c.include RSpec::Puppet::DefineExampleGroup, :type => :define, :example_group => {
13
+ :file_path => c.escaped_path(%w[spec defines])
14
+ }
15
+
16
+ c.include RSpec::Puppet::ClassExampleGroup, :type => :class, :example_group => {
17
+ :file_path => c.escaped_path(%w[spec classes])
18
+ }
19
+
20
+ c.include RSpec::Puppet::FunctionExampleGroup, :type => :puppet_function, :example_group => {
21
+ :file_path => c.escaped_path(%w[spec functions])
22
+ }
23
+
24
+ c.include RSpec::Puppet::HostExampleGroup, :type => :host, :example_group => {
25
+ :file_path => c.escaped_path(%w[spec hosts])
26
+ }
27
+ end
@@ -0,0 +1,60 @@
1
+ module RSpec::Puppet
2
+ module ClassExampleGroup
3
+ include RSpec::Puppet::ManifestMatchers
4
+ include RSpec::Puppet::Support
5
+
6
+ def subject
7
+ @catalogue ||= catalogue
8
+ end
9
+
10
+ def catalogue
11
+ vardir = Dir.mktmpdir
12
+ Puppet[:vardir] = vardir
13
+ Puppet[:hiera_config] = File.join(vardir, "hiera.yaml") if Puppet[:hiera_config] == File.expand_path("/dev/null")
14
+ Puppet[:modulepath] = self.respond_to?(:module_path) ? module_path : RSpec.configuration.module_path
15
+ Puppet[:manifestdir] = self.respond_to?(:manifest_dir) ? manifest_dir : RSpec.configuration.manifest_dir
16
+ Puppet[:manifest] = self.respond_to?(:manifest) ? manifest : RSpec.configuration.manifest
17
+ Puppet[:templatedir] = self.respond_to?(:template_dir) ? template_dir : RSpec.configuration.template_dir
18
+ Puppet[:config] = self.respond_to?(:config) ? config : RSpec.configuration.config
19
+
20
+ klass_name = self.class.top_level_description.downcase
21
+
22
+ # If we're testing a standalone module (i.e. one that's outside of a
23
+ # puppet tree), the autoloader won't work, so we need to fudge it a bit.
24
+ if File.exists?(File.join(Puppet[:modulepath], 'manifests', 'init.pp'))
25
+ path_to_manifest = File.join([Puppet[:modulepath], 'manifests', klass_name.split('::')[1..-1]].flatten)
26
+ import_str = "import '#{Puppet[:modulepath]}/manifests/init.pp'\nimport '#{path_to_manifest}.pp'\n"
27
+ elsif File.exists?(Puppet[:modulepath])
28
+ import_str = "import '#{Puppet[:manifest]}'\n"
29
+ else
30
+ import_str = ""
31
+ end
32
+
33
+ if self.respond_to? :pre_condition
34
+ pre_cond = pre_condition
35
+ else
36
+ pre_cond = ''
37
+ end
38
+
39
+ if !self.respond_to?(:params) || params == {}
40
+ code = import_str + "include #{klass_name}"
41
+ else
42
+ code = import_str + 'class' + " { \"" + klass_name + "\": " + params.keys.map { |r| "#{r.to_s} => #{params[r].inspect}"
43
+ }.join(',' ) + " }"
44
+ end
45
+ code = pre_cond + "\n" + code
46
+
47
+ nodename = self.respond_to?(:node) ? node : Puppet[:certname]
48
+ facts_val = {
49
+ 'hostname' => nodename.split('.').first,
50
+ 'fqdn' => nodename,
51
+ 'domain' => nodename.split('.').last,
52
+ }
53
+ facts_val.merge!(munge_facts(facts)) if self.respond_to?(:facts)
54
+
55
+ catalogue = build_catalog(nodename, facts_val, code)
56
+ FileUtils.rm_rf(vardir) if File.directory?(vardir)
57
+ catalogue
58
+ end
59
+ end
60
+ end