puppetlabs_spec_helper 0.1.0

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,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
+