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.
@@ -0,0 +1,62 @@
1
+ module RSpec::Puppet
2
+ module DefineExampleGroup
3
+ include RSpec::Puppet::ManifestMatchers
4
+ include RSpec::Puppet::Support
5
+
6
+ def subject
7
+ @catalogue ||= catalogue
8
+ end
9
+
10
+ def catalogue
11
+ define_name = self.class.top_level_description.downcase
12
+
13
+ vardir = Dir.mktmpdir
14
+ Puppet[:vardir] = vardir
15
+ Puppet[:hiera_config] = File.join(vardir, "hiera.yaml") if Puppet[:hiera_config] == File.expand_path("/dev/null")
16
+ Puppet[:modulepath] = self.respond_to?(:module_path) ? module_path : RSpec.configuration.module_path
17
+ Puppet[:manifestdir] = self.respond_to?(:manifest_dir) ? manifest_dir : RSpec.configuration.manifest_dir
18
+ Puppet[:manifest] = self.respond_to?(:manifest) ? manifest : RSpec.configuration.manifest
19
+ Puppet[:templatedir] = self.respond_to?(:template_dir) ? template_dir : RSpec.configuration.template_dir
20
+ Puppet[:config] = self.respond_to?(:config) ? config : RSpec.configuration.config
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', define_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? :params
34
+ param_str = params.keys.map { |r|
35
+ "#{r.to_s} => #{params[r].inspect}"
36
+ }.join(', ')
37
+ else
38
+ param_str = ""
39
+ end
40
+
41
+ if self.respond_to? :pre_condition
42
+ pre_cond = pre_condition
43
+ else
44
+ pre_cond = ""
45
+ end
46
+
47
+ code = pre_cond + "\n" + import_str + define_name + " { \"" + title + "\": " + param_str + " }"
48
+
49
+ nodename = self.respond_to?(:node) ? node : Puppet[:certname]
50
+ facts_val = {
51
+ 'hostname' => nodename.split('.').first,
52
+ 'fqdn' => nodename,
53
+ 'domain' => nodename.split('.', 2).last,
54
+ }
55
+ facts_val.merge!(munge_facts(facts)) if self.respond_to?(:facts)
56
+
57
+ catalogue = build_catalog(nodename, facts_val, code)
58
+ FileUtils.rm_rf(vardir) if File.directory?(vardir)
59
+ catalogue
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,54 @@
1
+ require 'puppetlabs_spec_helper/puppetlabs_spec/puppet_internals'
2
+
3
+ module RSpec::Puppet
4
+ module FunctionExampleGroup
5
+ include RSpec::Puppet::FunctionMatchers
6
+ PuppetInternals = PuppetlabsSpec::PuppetInternals
7
+
8
+ def subject
9
+ function_name = self.class.top_level_description.downcase
10
+
11
+ Puppet[:modulepath] = self.respond_to?(:module_path) ? module_path : RSpec.configuration.module_path
12
+ Puppet[:libdir] = Dir["#{Puppet[:modulepath]}/*/lib"].entries.join(File::PATH_SEPARATOR)
13
+
14
+ # if we specify a pre_condition, we should ensure that we compile that code
15
+ # into a catalog that is accessible from the scope where the function is called
16
+ if self.respond_to? :pre_condition
17
+ Puppet[:code] = pre_condition
18
+ nodename = self.respond_to?(:node) ? node : Puppet[:certname]
19
+ facts_val = {
20
+ 'hostname' => nodename.split('.').first,
21
+ 'fqdn' => nodename,
22
+ 'domain' => nodename.split('.').last,
23
+ }
24
+ facts_val.merge!(munge_facts(facts)) if self.respond_to?(:facts)
25
+ # we need to get a compiler, b/c we can attach that to a scope
26
+ @compiler = build_compiler(nodename, facts_val)
27
+ else
28
+ @compiler = PuppetInternals.compiler
29
+ end
30
+
31
+ scope = PuppetInternals.scope(:compiler => @compiler)
32
+
33
+ # Return the method instance for the function. This can be used with
34
+ # method.call
35
+ method = PuppetInternals.function_method(function_name, :scope => scope)
36
+ end
37
+
38
+ def compiler
39
+ @compiler
40
+ end
41
+
42
+ # get a compiler with an attached compiled catalog
43
+ def build_compiler(node_name, fact_values)
44
+ node_options = {
45
+ :name => node_name,
46
+ :options => { :parameters => fact_values },
47
+ }
48
+ node = PuppetInternals.node(node_options)
49
+ compiler = PuppetInternals.compiler(:node => node)
50
+ compiler.compile
51
+ compiler
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,35 @@
1
+ module RSpec::Puppet
2
+ module HostExampleGroup
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
+ code = ""
20
+
21
+ nodename = self.class.top_level_description.downcase
22
+
23
+ facts_val = {
24
+ 'hostname' => nodename.split('.').first,
25
+ 'fqdn' => nodename,
26
+ 'domain' => nodename.split('.').last,
27
+ }
28
+ facts_val.merge!(munge_facts(facts)) if self.respond_to?(:facts)
29
+
30
+ catalogue = build_catalog(nodename, facts_val, code)
31
+ FileUtils.rm_rf(vardir) if File.directory?(vardir)
32
+ catalogue
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,4 @@
1
+ require 'rspec-puppet/matchers/create_generic'
2
+ require 'rspec-puppet/matchers/create_resource'
3
+ require 'rspec-puppet/matchers/include_class'
4
+ require 'rspec-puppet/matchers/run'
@@ -0,0 +1,133 @@
1
+ module RSpec::Puppet
2
+ module ManifestMatchers
3
+ class CreateGeneric
4
+ def initialize(*args, &block)
5
+ @exp_resource_type = args.shift.to_s.gsub(/^(create|contain)_/, '')
6
+ @args = args
7
+ @block = block
8
+ @referenced_type = referenced_type(@exp_resource_type)
9
+ @title = args[0]
10
+ end
11
+
12
+ def with(*args, &block)
13
+ params = args.shift
14
+ @expected_params = (@expected_params || []) | params.to_a
15
+ self
16
+ end
17
+
18
+ def without(*args, &block)
19
+ params = args.shift
20
+ @expected_undef_params = (@expected_undef_params || []) | Array(params)
21
+ self
22
+ end
23
+
24
+ def method_missing(method, *args, &block)
25
+ if method.to_s =~ /^with_/
26
+ param = method.to_s.gsub(/^with_/, '')
27
+ (@expected_params ||= []) << [param, args[0]]
28
+ self
29
+ elsif method.to_s =~ /^without_/
30
+ param = method.to_s.gsub(/^without_/, '')
31
+ (@expected_undef_params ||= []) << param
32
+ self
33
+ else
34
+ super
35
+ end
36
+ end
37
+
38
+ def matches?(catalogue)
39
+ ret = true
40
+ resource = catalogue.resource(@referenced_type, @title)
41
+
42
+ if resource.nil?
43
+ ret = false
44
+ else
45
+ rsrc_hsh = resource.to_hash
46
+ if @expected_params
47
+ @expected_params.each do |name, value|
48
+ if value.kind_of?(Regexp) then
49
+ unless rsrc_hsh[name.to_sym].to_s =~ value
50
+ ret = false
51
+ (@errors ||= []) << "#{name.to_s} matching `#{value.inspect}` but its value of `#{rsrc_hsh[name.to_sym].inspect}` does not"
52
+ end
53
+ elsif value.kind_of?(Array) then
54
+ unless Array(rsrc_hsh[name.to_sym]).flatten.join == value.flatten.join
55
+ ret = false
56
+ (@errors ||= []) << "#{name.to_s} set to `#{value.inspect}` but it is set to `#{rsrc_hsh[name.to_sym].inspect}` in the catalogue"
57
+ end
58
+ else
59
+ unless rsrc_hsh[name.to_sym].to_s == value.to_s
60
+ ret = false
61
+ (@errors ||= []) << "#{name.to_s} set to `#{value.inspect}` but it is set to `#{rsrc_hsh[name.to_sym].inspect}` in the catalogue"
62
+ end
63
+ end
64
+ end
65
+ end
66
+
67
+ if @expected_undef_params
68
+ @expected_undef_params.each do |name|
69
+ unless resource.send(:parameters)[name.to_sym].nil?
70
+ ret = false
71
+ (@errors ||= []) << "#{name.to_s} undefined"
72
+ end
73
+ end
74
+ end
75
+ end
76
+
77
+ ret
78
+ end
79
+
80
+ def failure_message_for_should
81
+ "expected that the catalogue would contain #{@referenced_type}[#{@title}]#{errors}"
82
+ end
83
+
84
+ def failure_message_for_should_not
85
+ "expected that the catalogue would not contain #{@referenced_type}[#{@title}]#{errors}"
86
+ end
87
+
88
+ def description
89
+ values = []
90
+ if @expected_params
91
+ @expected_params.each do |name, value|
92
+ if value.kind_of?(Regexp)
93
+ values << "#{name.to_s} matching #{value.inspect}"
94
+ else
95
+ values << "#{name.to_s} => #{value.inspect}"
96
+ end
97
+ end
98
+ end
99
+
100
+ if @expected_undef_params
101
+ @expected_undef_params.each do |name, value|
102
+ values << "#{name.to_s} undefined"
103
+ end
104
+ end
105
+
106
+ unless values.empty?
107
+ if values.length == 1
108
+ value_str = " with #{values.first}"
109
+ else
110
+ value_str = " with #{values[0..-2].join(", ")} and #{values[-1]}"
111
+ end
112
+ end
113
+
114
+ "contain #{@referenced_type}[#{@title}]#{value_str}"
115
+ end
116
+
117
+ private
118
+
119
+ def referenced_type(type)
120
+ type.split('__').map { |r| r.capitalize }.join('::')
121
+ end
122
+
123
+ def errors
124
+ @errors.nil? ? "" : " with #{@errors.join(', and parameter ')}"
125
+ end
126
+ end
127
+
128
+ def method_missing(method, *args, &block)
129
+ return RSpec::Puppet::ManifestMatchers::CreateGeneric.new(method, *args, &block) if method.to_s =~ /^(create|contain)_/
130
+ super
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,53 @@
1
+ module RSpec::Puppet
2
+ module ManifestMatchers
3
+ extend RSpec::Matchers::DSL
4
+
5
+ matcher :create_resource do |expected_type, expected_title|
6
+ match do |catalogue|
7
+ ret = true
8
+ resources = catalogue.resources.select { |r|
9
+ r.type == referenced_type(expected_type)
10
+ }.select { |r|
11
+ r.title == expected_title if r.respond_to? :title
12
+ }
13
+
14
+ unless resources.length == 1
15
+ ret = false
16
+ end
17
+
18
+ if @expected_params and resources.length != 0
19
+ @expected_params.each do |name, value|
20
+ unless resources.first.send(:parameters)[name.to_sym] == value
21
+ ret = false
22
+ (@errors ||= []) << "the parameter #{name.to_s} set to `#{value}`"
23
+ end
24
+ end
25
+ end
26
+
27
+ ret
28
+ end
29
+
30
+ def errors
31
+ @errors.nil? ? "" : " with #{@errors.join(', ')}"
32
+ end
33
+
34
+ def referenced_type(type)
35
+ type.split('::').map { |r| r.capitalize }.join('::')
36
+ end
37
+
38
+ chain :with_param do |param_name,param_value|
39
+ (@expected_params ||= []) << [param_name, param_value]
40
+ end
41
+
42
+ description do
43
+ type = referenced_type(expected_type)
44
+ "create #{type}['#{expected_title}']"
45
+ end
46
+
47
+ failure_message_for_should do |actual|
48
+ type = referenced_type(expected_type)
49
+ "expected that the catalogue would contain #{type}['#{expected_title}']#{errors}"
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,19 @@
1
+ module RSpec::Puppet
2
+ module ManifestMatchers
3
+ extend RSpec::Matchers::DSL
4
+
5
+ matcher :include_class do |expected_class|
6
+ match do |catalogue|
7
+ catalogue.classes.include? expected_class
8
+ end
9
+
10
+ description do
11
+ "include Class[#{expected_class}]"
12
+ end
13
+
14
+ failure_message_for_should do |actual|
15
+ "expected that the catalogue would include Class[#{expected_class}]"
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,76 @@
1
+ module RSpec::Puppet
2
+ module FunctionMatchers
3
+ extend RSpec::Matchers::DSL
4
+
5
+ matcher :run do
6
+ match do |func_obj|
7
+ if @params
8
+ @func = lambda { func_obj.call(@params) }
9
+ else
10
+ @func = lambda { func_obj.call }
11
+ end
12
+
13
+ if @expected_error
14
+ begin
15
+ @func.call
16
+ rescue @expected_error
17
+ #XXX check error string here
18
+ true
19
+ rescue
20
+ false
21
+ end
22
+ else
23
+ if @expected_return
24
+ @func.call == @expected_return
25
+ else
26
+ begin
27
+ @func.call
28
+ rescue
29
+ false
30
+ end
31
+ true
32
+ end
33
+ end
34
+ end
35
+
36
+ chain :with_params do |*params|
37
+ @params = params
38
+ end
39
+
40
+ chain :and_return do |value|
41
+ @expected_return = value
42
+ end
43
+
44
+ # XXX support error string and regexp
45
+ chain :and_raise_error do |value|
46
+ @expected_error = value
47
+ end
48
+
49
+ failure_message_for_should do |func_obj|
50
+ func_name = func_obj.name.gsub(/^function_/, '')
51
+ func_params = @params.inspect[1..-2]
52
+
53
+ if @expected_return
54
+ "expected #{func_name}(#{func_params}) to have returned #{@expected_return.inspect} instead of #{@func.call.inspect}"
55
+ elsif @expected_error
56
+ "expected #{func_name}(#{func_params}) to have raised #{@expected_error.inspect}"
57
+ else
58
+ "expected #{func_name}(#{func_params}) to have run successfully"
59
+ end
60
+ end
61
+
62
+ failure_message_for_should_not do |func_obj|
63
+ func_name = func_obj.name.gsub(/^function_/, '')
64
+ func_params = @params.inspect[1..-2]
65
+
66
+ if @expected_return
67
+ "expected #{func_name}(#{func_params}) to not have returned #{@expected_return.inspect}"
68
+ elsif @expected_error
69
+ "expected #{func_name}(#{func_params}) to not have raised #{@expected_error.inspect}"
70
+ else
71
+ "expected #{func_name}(#{func_params}) to not have run successfully"
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,144 @@
1
+ require 'puppet'
2
+ require 'fileutils'
3
+
4
+ module RSpec::Puppet
5
+ class Setup
6
+ def self.run(module_name=nil)
7
+ unless is_module_dir?
8
+ $stderr.puts "Does not appear to be a Puppet module. Aborting"
9
+ return false
10
+ end
11
+
12
+ if module_name.nil?
13
+ module_name = get_module_name
14
+ if module_name.nil?
15
+ $stderr.puts "Unable to determine module name. Aborting"
16
+ return false
17
+ end
18
+ end
19
+
20
+ [
21
+ 'spec',
22
+ 'spec/classes',
23
+ 'spec/defines',
24
+ 'spec/functions',
25
+ 'spec/hosts',
26
+ 'spec/fixtures',
27
+ 'spec/fixtures/manifests',
28
+ 'spec/fixtures/modules',
29
+ "spec/fixtures/modules/#{module_name}",
30
+ ].each { |dir| safe_mkdir(dir) }
31
+
32
+ safe_touch('spec/fixtures/manifests/site.pp')
33
+
34
+ ['manifests','lib','files','templates'].each do |dir|
35
+ if File.exist? dir
36
+ safe_make_symlink("../../../../#{dir}", "spec/fixtures/modules/#{module_name}/#{dir}")
37
+ end
38
+ end
39
+
40
+ safe_create_spec_helper
41
+ safe_create_rakefile
42
+ end
43
+
44
+ protected
45
+ def self.get_module_name
46
+ p = Puppet::Parser::Lexer.new
47
+ module_name = nil
48
+ Dir["manifests/*.pp"].entries.each do |manifest|
49
+ p.string = File.read(manifest)
50
+ tokens = p.fullscan
51
+ i = tokens.index { |token| [:CLASS, :DEFINE].include? token.first }
52
+ unless i.nil?
53
+ module_name = tokens[i + 1].last[:value].split('::').first
54
+ break
55
+ end
56
+ end
57
+ module_name
58
+ end
59
+
60
+ def self.is_module_dir?
61
+ Dir["*"].entries.include? "manifests"
62
+ end
63
+
64
+ def self.safe_mkdir(dir)
65
+ if File.exists? dir
66
+ unless File.directory? dir
67
+ $stderr.puts "!! #{dir} already exists and is not a directory"
68
+ end
69
+ else
70
+ FileUtils.mkdir dir
71
+ puts " + #{dir}/"
72
+ end
73
+ end
74
+
75
+ def self.safe_touch(file)
76
+ if File.exists? file
77
+ unless File.file? file
78
+ $stderr.puts "!! #{file} already exists and is not a regular file"
79
+ end
80
+ else
81
+ FileUtils.touch file
82
+ puts " + #{file}"
83
+ end
84
+ end
85
+
86
+ def self.safe_create_spec_helper
87
+ content = <<-EOF
88
+ require 'rspec-puppet'
89
+
90
+ fixture_path = File.expand_path(File.join(__FILE__, '..', 'fixtures'))
91
+
92
+ RSpec.configure do |c|
93
+ c.module_path = File.join(fixture_path, 'modules')
94
+ c.manifest_dir = File.join(fixture_path, 'manifests')
95
+ end
96
+ EOF
97
+ if File.exists? 'spec/spec_helper.rb'
98
+ old_content = File.read('spec/spec_helper.rb')
99
+ if old_content != content
100
+ $stderr.puts "!! spec/spec_helper.rb already exists and differs from template"
101
+ end
102
+ else
103
+ File.open('spec/spec_helper.rb', 'w') do |f|
104
+ f.puts content
105
+ end
106
+ puts ' + spec/spec_helper.rb'
107
+ end
108
+ end
109
+
110
+ def self.safe_make_symlink(source, target)
111
+ if File.exists? target
112
+ unless File.symlink? target
113
+ $stderr.puts "!! #{file} already exists and is not a symlink"
114
+ end
115
+ else
116
+ FileUtils.ln_s(source, target)
117
+ puts " + #{target}"
118
+ end
119
+ end
120
+
121
+ def self.safe_create_rakefile
122
+ content = <<-EOF
123
+ require 'rake'
124
+
125
+ require 'rspec/core/rake_task'
126
+
127
+ RSpec::Core::RakeTask.new(:spec) do |t|
128
+ t.pattern = 'spec/*/*_spec.rb'
129
+ end
130
+ EOF
131
+ if File.exists? 'Rakefile'
132
+ old_content = File.read('Rakefile')
133
+ if old_content != content
134
+ $stderr.puts "!! Rakefile already exists and differs from template"
135
+ end
136
+ else
137
+ File.open('Rakefile', 'w') do |f|
138
+ f.puts content
139
+ end
140
+ puts ' + Rakefile'
141
+ end
142
+ end
143
+ end
144
+ end