puppetlabs_spec_helper 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,16 @@
1
+ Copyright (C) 2012 Puppet Labs Inc
2
+
3
+ Puppet Labs can be contacted at: info@puppetlabs.com
4
+
5
+ Licensed under the Apache License, Version 2.0 (the "License");
6
+ you may not use this file except in compliance with the License.
7
+ You may obtain a copy of the License at
8
+
9
+ http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ Unless required by applicable law or agreed to in writing, software
12
+ distributed under the License is distributed on an "AS IS" BASIS,
13
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+
15
+ See the License for the specific language governing permissions and
16
+ limitations under the License.
@@ -0,0 +1,23 @@
1
+ require 'puppetlabs_spec_helper/puppet_spec_helper'
2
+ require 'rspec-puppet'
3
+
4
+ def param_value(subject, type, title, param)
5
+ subject.resource(type, title).send(:parameters)[param.to_sym]
6
+ end
7
+
8
+ def verify_contents(subject, title, expected_lines)
9
+ content = subject.resource('file', title).send(:parameters)[:content]
10
+ (content.split("\n") & expected_lines).should == expected_lines
11
+ end
12
+
13
+ fixture_path = File.expand_path(File.join(Dir.pwd, 'spec/fixtures'))
14
+
15
+ env_module_path = ENV['MODULEPATH']
16
+ module_path = File.join(fixture_path, 'modules')
17
+
18
+ module_path = [module_path, env_module_path].join(':') if env_module_path
19
+
20
+ RSpec.configure do |c|
21
+ c.module_path = module_path
22
+ c.manifest_dir = File.join(fixture_path, 'manifests')
23
+ end
@@ -0,0 +1,187 @@
1
+ require 'puppetlabs_spec_helper/puppetlabs_spec_helper'
2
+
3
+ # Don't want puppet getting the command line arguments for rake or autotest
4
+ ARGV.clear
5
+
6
+ require 'puppet'
7
+ require 'mocha'
8
+ gem 'rspec', '>=2.0.0'
9
+ require 'rspec/expectations'
10
+
11
+ require 'pathname'
12
+ require 'tmpdir'
13
+
14
+ require 'puppetlabs_spec_helper/puppetlabs_spec/files'
15
+
16
+ ######################################################################################
17
+ # WARNING #
18
+ ######################################################################################
19
+ #
20
+ # You should probably be frightened by this file. :)
21
+ #
22
+ # The goal of this file is to try to maximize spec-testing compatibility between
23
+ # multiple versions of various external projects (which depend on puppet core) and
24
+ # multiple versions of puppet core itself. This is accomplished via a series
25
+ # of hacks and magical incantations that I am not particularly proud of. However,
26
+ # after discussion it was decided that the goal of achieving compatibility was
27
+ # a very worthy one, and that isolating the hacks to one place in a non-production
28
+ # project was as good a solution as we could hope for.
29
+ #
30
+ # You may want to hold your nose before you proceed. :)
31
+ #
32
+
33
+
34
+ # This is just a utility class to allow us to isolate the various version-specific
35
+ # branches of initialization logic into methods without polluting the global namespace.#
36
+ module Puppet
37
+ class PuppetSpecInitializer
38
+ # This method uses the "new"/preferred approach of delegating all of the test
39
+ # state initialization to puppet itself, via Puppet::Test::TestHelper API. This
40
+ # should be fairly future-proof as long as that API doesn't change, which it
41
+ # hopefully will not need to.
42
+ def self.initialize_via_testhelper(config)
43
+ # connect rspec hooks to TestHelper methods.
44
+ config.before :all do
45
+ Puppet::Test::TestHelper.before_all_tests()
46
+ end
47
+
48
+ config.after :all do
49
+ Puppet::Test::TestHelper.after_all_tests()
50
+ end
51
+
52
+ config.before :each do
53
+ Puppet::Test::TestHelper.before_each_test()
54
+ end
55
+
56
+ config.after :each do
57
+ Puppet::Test::TestHelper.after_each_test()
58
+ end
59
+ end
60
+
61
+ # This method is for initializing puppet state for testing for older versions
62
+ # of puppet that do not support the new TestHelper API. As you can see,
63
+ # this involves explicitly modifying global variables, directly manipulating
64
+ # Puppet's Settings singleton object, and other fun implementation details
65
+ # that code external to puppet should really never know about.
66
+ def self.initialize_via_fallback_compatibility(config)
67
+ config.before :all do
68
+ # nothing to do for now
69
+ end
70
+
71
+ config.after :all do
72
+ # nothing to do for now
73
+ end
74
+
75
+ config.before :each do
76
+ # these globals are set by Application
77
+ $puppet_application_mode = nil
78
+ $puppet_application_name = nil
79
+
80
+ # REVISIT: I think this conceals other bad tests, but I don't have time to
81
+ # fully diagnose those right now. When you read this, please come tell me
82
+ # I suck for letting this float. --daniel 2011-04-21
83
+ Signal.stubs(:trap)
84
+
85
+ # Set the confdir and vardir to gibberish so that tests
86
+ # have to be correctly mocked.
87
+ Puppet[:confdir] = "/dev/null"
88
+ Puppet[:vardir] = "/dev/null"
89
+
90
+ # Avoid opening ports to the outside world
91
+ Puppet.settings[:bindaddress] = "127.0.0.1"
92
+ end
93
+
94
+ config.after :each do
95
+ Puppet.settings.clear
96
+
97
+ Puppet::Node::Environment.clear
98
+ Puppet::Util::Storage.clear
99
+ Puppet::Util::ExecutionStub.reset if Puppet::Util.constants.include? "ExecutionStub"
100
+
101
+ PuppetlabsSpec::Files.cleanup
102
+ end
103
+ end
104
+ end
105
+ end
106
+
107
+
108
+
109
+ # Here we attempt to load the new TestHelper API, and print a warning if we are falling back
110
+ # to compatibility mode for older versions of puppet.
111
+ begin
112
+ require 'puppet/test/test_helper'
113
+ rescue LoadError => err
114
+ $stderr.puts("Warning: you appear to be using an older version of puppet; spec_helper will use fallback compatibility mode.")
115
+ end
116
+
117
+
118
+ # JJM Hack to make the stdlib tests run in Puppet 2.6 (See puppet commit cf183534)
119
+ if not Puppet.constants.include? "Test" then
120
+ module Puppet::Test
121
+ class LogCollector
122
+ def initialize(logs)
123
+ @logs = logs
124
+ end
125
+
126
+ def <<(value)
127
+ @logs << value
128
+ end
129
+ end
130
+ end
131
+ Puppet::Util::Log.newdesttype :log_collector do
132
+ match "Puppet::Test::LogCollector"
133
+
134
+ def initialize(messages)
135
+ @messages = messages
136
+ end
137
+
138
+ def handle(msg)
139
+ @messages << msg
140
+ end
141
+ end
142
+ end
143
+
144
+
145
+ # And here is where we do the main rspec configuration / setup.
146
+ RSpec.configure do |config|
147
+ config.mock_with :mocha
148
+
149
+ # determine whether we can use the new API or not, and call the appropriate initializer method.
150
+ if (defined?(Puppet::Test::TestHelper))
151
+ Puppet::PuppetSpecInitializer.initialize_via_testhelper(config)
152
+ else
153
+ Puppet::PuppetSpecInitializer.initialize_via_fallback_compatibility(config)
154
+ end
155
+
156
+ # Here we do some general setup that is relevant to all initialization modes, regardless
157
+ # of the availability of the TestHelper API.
158
+
159
+ config.before :each do
160
+ # Here we redirect logging away from console, because otherwise the test output will be
161
+ # obscured by all of the log output.
162
+ #
163
+ # TODO: in a more sane world, we'd move this logging redirection into our TestHelper
164
+ # class, so that it was not coupled with a specific testing framework (rspec in this
165
+ # case). Further, it would be nicer and more portable to encapsulate the log messages
166
+ # into an object somewhere, rather than slapping them on an instance variable of the
167
+ # actual test class--which is what we are effectively doing here.
168
+ #
169
+ # However, because there are over 1300 tests that are written to expect
170
+ # this instance variable to be available--we can't easily solve this problem right now.
171
+ @logs = []
172
+ Puppet::Util::Log.newdestination(Puppet::Test::LogCollector.new(@logs))
173
+
174
+ @log_level = Puppet::Util::Log.level
175
+ end
176
+
177
+ config.after :each do
178
+ # clean up after the logging changes that we made before each test.
179
+
180
+ # TODO: this should be abstracted in the future--see comments above the '@logs' block in the
181
+ # "before" code above.
182
+ @logs.clear
183
+ Puppet::Util::Log.close_all
184
+ Puppet::Util::Log.level = @log_level
185
+ end
186
+
187
+ end
@@ -0,0 +1,57 @@
1
+ require 'fileutils'
2
+ require 'tempfile'
3
+ require 'pathname'
4
+
5
+ # A support module for testing files.
6
+ module PuppetlabsSpec::Files
7
+ # This code exists only to support tests that run as root, pretty much.
8
+ # Once they have finally been eliminated this can all go... --daniel 2011-04-08
9
+ def self.in_tmp(path)
10
+ tempdir = Dir.tmpdir
11
+
12
+ Pathname.new(path).ascend do |dir|
13
+ return true if File.identical?(tempdir, dir)
14
+ end
15
+
16
+ false
17
+ end
18
+
19
+ def self.cleanup
20
+ $global_tempfiles ||= []
21
+ while path = $global_tempfiles.pop do
22
+ fail "Not deleting tmpfile #{path} outside regular tmpdir" unless in_tmp(path)
23
+
24
+ begin
25
+ FileUtils.rm_r path, :secure => true
26
+ rescue Errno::ENOENT
27
+ # nothing to do
28
+ end
29
+ end
30
+ end
31
+
32
+ def make_absolute(path)
33
+ path = File.expand_path(path)
34
+ path[0] = 'c' if Puppet.features.microsoft_windows?
35
+ path
36
+ end
37
+
38
+ def tmpfilename(name)
39
+ # Generate a temporary file, just for the name...
40
+ source = Tempfile.new(name)
41
+ path = source.path
42
+ source.close!
43
+
44
+ # ...record it for cleanup,
45
+ $global_tempfiles ||= []
46
+ $global_tempfiles << File.expand_path(path)
47
+
48
+ # ...and bam.
49
+ path
50
+ end
51
+
52
+ def tmpdir(name)
53
+ path = tmpfilename(name)
54
+ FileUtils.mkdir_p(path)
55
+ path
56
+ end
57
+ end
@@ -0,0 +1,49 @@
1
+ # This module provides some helper methods to assist with fixtures. It's
2
+ # methods are designed to help when you have a conforming fixture layout so we
3
+ # get project consistency.
4
+ module PuppetlabsSpec::Fixtures
5
+
6
+ # Returns the joined path of the global FIXTURE_DIR plus any path given to it
7
+ def fixtures(*rest)
8
+ File.join(PuppetlabsSpec::FIXTURE_DIR, *rest)
9
+ end
10
+
11
+ # Returns the path to your relative fixture dir. So if your spec test is
12
+ # <project>/spec/unit/facter/foo_spec.rb then your relative dir will be
13
+ # <project>/spec/fixture/unit/facter/foo
14
+ def my_fixture_dir
15
+ callers = caller
16
+ while line = callers.shift do
17
+ next unless found = line.match(%r{/spec/(.*)_spec\.rb:})
18
+ return fixtures(found[1])
19
+ end
20
+ fail "sorry, I couldn't work out your path from the caller stack!"
21
+ end
22
+
23
+ # Given a name, returns the full path of a file from your relative fixture
24
+ # dir as returned by my_fixture_dir.
25
+ def my_fixture(name)
26
+ file = File.join(my_fixture_dir, name)
27
+ unless File.readable? file then
28
+ fail "fixture '#{name}' for #{my_fixture_dir} is not readable"
29
+ end
30
+ return file
31
+ end
32
+
33
+ # Return the contents of the file using read when given a name. Uses
34
+ # my_fixture to work out the relative path.
35
+ def my_fixture_read(name)
36
+ File.read(my_fixture(name))
37
+ end
38
+
39
+ # Provides a block mechanism for iterating across the files in your fixture
40
+ # area.
41
+ def my_fixtures(glob = '*', flags = 0)
42
+ files = Dir.glob(File.join(my_fixture_dir, glob), flags)
43
+ unless files.length > 0 then
44
+ fail "fixture '#{glob}' for #{my_fixture_dir} had no files!"
45
+ end
46
+ block_given? and files.each do |file| yield file end
47
+ files
48
+ end
49
+ end
@@ -0,0 +1,87 @@
1
+ require 'stringio'
2
+
3
+ ########################################################################
4
+ # Backward compatibility for Jenkins outdated environment.
5
+ module RSpec
6
+ module Matchers
7
+ module BlockAliases
8
+ alias_method :to, :should unless method_defined? :to
9
+ alias_method :to_not, :should_not unless method_defined? :to_not
10
+ alias_method :not_to, :should_not unless method_defined? :not_to
11
+ end
12
+ end
13
+ end
14
+
15
+
16
+ ########################################################################
17
+ # Custom matchers...
18
+ RSpec::Matchers.define :have_matching_element do |expected|
19
+ match do |actual|
20
+ actual.any? { |item| item =~ expected }
21
+ end
22
+ end
23
+
24
+
25
+ RSpec::Matchers.define :exit_with do |expected|
26
+ actual = nil
27
+ match do |block|
28
+ begin
29
+ block.call
30
+ rescue SystemExit => e
31
+ actual = e.status
32
+ end
33
+ actual and actual == expected
34
+ end
35
+ failure_message_for_should do |block|
36
+ "expected exit with code #{expected} but " +
37
+ (actual.nil? ? " exit was not called" : "we exited with #{actual} instead")
38
+ end
39
+ failure_message_for_should_not do |block|
40
+ "expected that exit would not be called with #{expected}"
41
+ end
42
+ description do
43
+ "expect exit with #{expected}"
44
+ end
45
+ end
46
+
47
+
48
+ RSpec::Matchers.define :have_printed do |expected|
49
+ match do |block|
50
+ $stderr = $stdout = StringIO.new
51
+
52
+ begin
53
+ block.call
54
+ ensure
55
+ $stdout.rewind
56
+ @actual = $stdout.read
57
+
58
+ $stdout = STDOUT
59
+ $stderr = STDERR
60
+ end
61
+
62
+ if @actual then
63
+ case expected
64
+ when String
65
+ @actual.include? expected
66
+ when Regexp
67
+ expected.match @actual
68
+ else
69
+ raise ArgumentError, "No idea how to match a #{@actual.class.name}"
70
+ end
71
+ end
72
+ end
73
+
74
+ failure_message_for_should do |actual|
75
+ if actual.nil? then
76
+ "expected #{expected.inspect}, but nothing was printed"
77
+ else
78
+ "expected #{expected.inspect} to be printed; got:\n#{actual}"
79
+ end
80
+ end
81
+
82
+ description do
83
+ "expect #{expected.inspect} to be printed"
84
+ end
85
+
86
+ diffable
87
+ end
@@ -0,0 +1,24 @@
1
+ # Define the main module namespace for use by the helper modules
2
+ module PuppetlabsSpec
3
+ # FIXTURE_DIR represents the standard locations of all fixture data. Normally
4
+ # this represents <project>/spec/fixtures. This will be used by the fixtures
5
+ # library to find relative fixture data.
6
+ FIXTURE_DIR = File.join("spec", "fixtures") unless defined?(FIXTURE_DIR)
7
+ end
8
+
9
+ # Require all necessary helper libraries so they can be used later
10
+ require 'puppetlabs_spec_helper/puppetlabs_spec/files'
11
+ require 'puppetlabs_spec_helper/puppetlabs_spec/fixtures'
12
+ require 'puppetlabs_spec_helper/puppetlabs_spec/matchers'
13
+
14
+ RSpec.configure do |config|
15
+ # Include PuppetlabsSpec helpers so they can be called at convenience
16
+ config.extend PuppetlabsSpec::Files
17
+ config.extend PuppetlabsSpec::Fixtures
18
+ config.include PuppetlabsSpec::Fixtures
19
+
20
+ # This will cleanup any files that were created with tmpdir or tmpfile
21
+ config.after :each do
22
+ PuppetlabsSpec::Files.cleanup
23
+ end
24
+ end
@@ -0,0 +1,107 @@
1
+ require 'rake'
2
+ require 'rspec/core/rake_task'
3
+ require 'yaml'
4
+
5
+ task :default => [:help]
6
+
7
+ desc "Run spec tests on an existing fixtures directory"
8
+ RSpec::Core::RakeTask.new(:spec_standalone) do |t|
9
+ t.rspec_opts = ['--color']
10
+ t.pattern = 'spec/{classes,defines,unit}/**/*_spec.rb'
11
+ end
12
+
13
+ desc "Generate code coverage information"
14
+ RSpec::Core::RakeTask.new(:coverage) do |t|
15
+ t.rcov = true
16
+ t.rcov_opts = ['--exclude', 'spec']
17
+ end
18
+
19
+ # This is a helper for the self-symlink entry of fixtures.yml
20
+ def source_dir
21
+ Dir.pwd
22
+ end
23
+
24
+ def fixtures(category)
25
+ begin
26
+ fixtures = YAML.load_file(".fixtures.yml")["fixtures"]
27
+ rescue Errno::ENOENT
28
+ return {}
29
+ end
30
+
31
+ if not fixtures
32
+ abort("malformed fixtures.yml")
33
+ end
34
+
35
+ result = {}
36
+ if fixtures.include? category
37
+ fixtures[category].each do |fixture, source|
38
+ target = "spec/fixtures/modules/#{fixture}"
39
+ real_source = eval('"'+source+'"')
40
+ result[real_source] = target
41
+ end
42
+ end
43
+ return result
44
+ end
45
+
46
+ desc "Create the fixtures directory"
47
+ task :spec_prep do
48
+ fixtures("repositories").each do |repo, target|
49
+ File::exists?(target) || system("git clone #{repo} #{target}")
50
+ end
51
+
52
+ FileUtils::mkdir_p("spec/fixtures/modules")
53
+ fixtures("symlinks").each do |source, target|
54
+ File::exists?(target) || FileUtils::ln_s(source, target)
55
+ end
56
+
57
+ FileUtils::touch("spec/fixtures/manifests/site.pp")
58
+ end
59
+
60
+ desc "Clean up the fixtures directory"
61
+ task :spec_clean do
62
+ fixtures("repositories").each do |repo, target|
63
+ FileUtils::rm_rf(target)
64
+ end
65
+
66
+ fixtures("symlinks").each do |source, target|
67
+ FileUtils::rm(target)
68
+ end
69
+
70
+ FileUtils::rm("spec/fixtures/manifests/site.pp")
71
+ end
72
+
73
+ desc "Run spec tests in a clean fixtures directory"
74
+ task :spec do
75
+ Rake::Task[:spec_prep].invoke
76
+ Rake::Task[:spec_standalone].invoke
77
+ Rake::Task[:spec_clean].invoke
78
+ end
79
+
80
+ desc "Build puppet module package"
81
+ task :build do
82
+ # This will be deprecated once puppet-module is a face.
83
+ begin
84
+ Gem::Specification.find_by_name('puppet-module')
85
+ rescue Gem::LoadError, NoMethodError
86
+ require 'puppet/face'
87
+ pmod = Puppet::Face['module', :current]
88
+ pmod.build('./')
89
+ end
90
+ end
91
+
92
+ desc "Clean a built module package"
93
+ task :clean do
94
+ FileUtils.rm_rf("pkg/")
95
+ end
96
+
97
+ desc "Check puppet manifests with puppet-lint"
98
+ task :lint do
99
+ # This requires pull request: https://github.com/rodjek/puppet-lint/pull/81
100
+ system("puppet-lint manifests")
101
+ system("puppet-lint tests")
102
+ end
103
+
104
+ desc "Display the list of available rake tasks"
105
+ task :help do
106
+ system("rake -T")
107
+ end
metadata ADDED
@@ -0,0 +1,134 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: puppetlabs_spec_helper
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - Puppet Labs
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2012-06-08 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: rake
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ hash: 3
29
+ segments:
30
+ - 0
31
+ version: "0"
32
+ type: :runtime
33
+ version_requirements: *id001
34
+ - !ruby/object:Gem::Dependency
35
+ name: rspec
36
+ prerelease: false
37
+ requirement: &id002 !ruby/object:Gem::Requirement
38
+ none: false
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ hash: 43
43
+ segments:
44
+ - 2
45
+ - 9
46
+ - 0
47
+ version: 2.9.0
48
+ type: :runtime
49
+ version_requirements: *id002
50
+ - !ruby/object:Gem::Dependency
51
+ name: mocha
52
+ prerelease: false
53
+ requirement: &id003 !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ hash: 61
59
+ segments:
60
+ - 0
61
+ - 10
62
+ - 5
63
+ version: 0.10.5
64
+ type: :runtime
65
+ version_requirements: *id003
66
+ - !ruby/object:Gem::Dependency
67
+ name: rspec-puppet
68
+ prerelease: false
69
+ requirement: &id004 !ruby/object:Gem::Requirement
70
+ none: false
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ hash: 25
75
+ segments:
76
+ - 0
77
+ - 1
78
+ - 1
79
+ version: 0.1.1
80
+ type: :runtime
81
+ version_requirements: *id004
82
+ description: Contains rake tasks and a standard spec_helper for running spec tests on puppet modules
83
+ email:
84
+ - puppet-dev@puppetlabs.com
85
+ executables: []
86
+
87
+ extensions: []
88
+
89
+ extra_rdoc_files: []
90
+
91
+ files:
92
+ - lib/puppetlabs_spec_helper/module_spec_helper.rb
93
+ - lib/puppetlabs_spec_helper/puppet_spec_helper.rb
94
+ - lib/puppetlabs_spec_helper/puppetlabs_spec/files.rb
95
+ - lib/puppetlabs_spec_helper/puppetlabs_spec/fixtures.rb
96
+ - lib/puppetlabs_spec_helper/puppetlabs_spec/matchers.rb
97
+ - lib/puppetlabs_spec_helper/puppetlabs_spec_helper.rb
98
+ - lib/puppetlabs_spec_helper/rake_tasks.rb
99
+ - LICENSE
100
+ homepage: http://github.com/puppetlabs/puppetlabs_spec_helper
101
+ licenses: []
102
+
103
+ post_install_message:
104
+ rdoc_options: []
105
+
106
+ require_paths:
107
+ - lib
108
+ required_ruby_version: !ruby/object:Gem::Requirement
109
+ none: false
110
+ requirements:
111
+ - - ">="
112
+ - !ruby/object:Gem::Version
113
+ hash: 3
114
+ segments:
115
+ - 0
116
+ version: "0"
117
+ required_rubygems_version: !ruby/object:Gem::Requirement
118
+ none: false
119
+ requirements:
120
+ - - ">="
121
+ - !ruby/object:Gem::Version
122
+ hash: 3
123
+ segments:
124
+ - 0
125
+ version: "0"
126
+ requirements: []
127
+
128
+ rubyforge_project:
129
+ rubygems_version: 1.8.24
130
+ signing_key:
131
+ specification_version: 3
132
+ summary: Standard tasks and configuration for module spec tests
133
+ test_files: []
134
+