puppetlabs-spec-helper-0.4.1/0000755000175000017500000000000012246125657014272 5ustar tomtompuppetlabs-spec-helper-0.4.1/metadata.yml0000644000175000017500000000571312246125657016603 0ustar tomtom--- !ruby/object:Gem::Specification name: puppetlabs_spec_helper version: !ruby/object:Gem::Version hash: 13 prerelease: segments: - 0 - 4 - 1 version: 0.4.1 platform: ruby authors: - Puppet Labs autorequire: bindir: bin cert_chain: [] date: 2013-02-08 00:00:00 Z dependencies: - !ruby/object:Gem::Dependency name: rake prerelease: false requirement: &id001 !ruby/object:Gem::Requirement none: false requirements: - - ">=" - !ruby/object:Gem::Version hash: 3 segments: - 0 version: "0" type: :runtime version_requirements: *id001 - !ruby/object:Gem::Dependency name: rspec prerelease: false requirement: &id002 !ruby/object:Gem::Requirement none: false requirements: - - ">=" - !ruby/object:Gem::Version hash: 43 segments: - 2 - 9 - 0 version: 2.9.0 type: :runtime version_requirements: *id002 - !ruby/object:Gem::Dependency name: mocha prerelease: false requirement: &id003 !ruby/object:Gem::Requirement none: false requirements: - - ">=" - !ruby/object:Gem::Version hash: 61 segments: - 0 - 10 - 5 version: 0.10.5 type: :runtime version_requirements: *id003 - !ruby/object:Gem::Dependency name: rspec-puppet prerelease: false requirement: &id004 !ruby/object:Gem::Requirement none: false requirements: - - ">=" - !ruby/object:Gem::Version hash: 25 segments: - 0 - 1 - 1 version: 0.1.1 type: :runtime version_requirements: *id004 description: Contains rake tasks and a standard spec_helper for running spec tests on puppet modules email: - puppet-dev@puppetlabs.com executables: [] extensions: [] extra_rdoc_files: [] files: - lib/puppetlabs_spec_helper/module_spec_helper.rb - lib/puppetlabs_spec_helper/puppet_spec_helper.rb - lib/puppetlabs_spec_helper/puppetlabs_spec/files.rb - lib/puppetlabs_spec_helper/puppetlabs_spec/fixtures.rb - lib/puppetlabs_spec_helper/puppetlabs_spec/matchers.rb - lib/puppetlabs_spec_helper/puppetlabs_spec/puppet_internals.rb - lib/puppetlabs_spec_helper/puppetlabs_spec_helper.rb - lib/puppetlabs_spec_helper/rake_tasks.rb - LICENSE - CHANGELOG homepage: http://github.com/puppetlabs/puppetlabs_spec_helper licenses: [] post_install_message: rdoc_options: [] require_paths: - lib required_ruby_version: !ruby/object:Gem::Requirement none: false requirements: - - ">=" - !ruby/object:Gem::Version hash: 3 segments: - 0 version: "0" required_rubygems_version: !ruby/object:Gem::Requirement none: false requirements: - - ">=" - !ruby/object:Gem::Version hash: 3 segments: - 0 version: "0" requirements: [] rubyforge_project: rubygems_version: 1.8.24 signing_key: specification_version: 3 summary: Standard tasks and configuration for module spec tests test_files: [] puppetlabs-spec-helper-0.4.1/lib/0000755000175000017500000000000012246125657015040 5ustar tomtompuppetlabs-spec-helper-0.4.1/lib/puppetlabs_spec_helper/0000755000175000017500000000000012246125657021570 5ustar tomtompuppetlabs-spec-helper-0.4.1/lib/puppetlabs_spec_helper/rake_tasks.rb0000644000175000017500000000635412246125657024254 0ustar tomtomrequire 'rake' require 'rspec/core/rake_task' require 'yaml' task :default => [:help] desc "Run spec tests on an existing fixtures directory" RSpec::Core::RakeTask.new(:spec_standalone) do |t| t.rspec_opts = ['--color'] t.pattern = 'spec/{classes,defines,unit,functions,hosts}/**/*_spec.rb' end desc "Generate code coverage information" RSpec::Core::RakeTask.new(:coverage) do |t| t.rcov = true t.rcov_opts = ['--exclude', 'spec'] end # This is a helper for the self-symlink entry of fixtures.yml def source_dir Dir.pwd end def fixtures(category) begin fixtures = YAML.load_file(".fixtures.yml")["fixtures"] rescue Errno::ENOENT return {} end if not fixtures abort("malformed fixtures.yml") end result = {} if fixtures.include? category fixtures[category].each do |fixture, opts| if opts.instance_of?(String) source = opts target = "spec/fixtures/modules/#{fixture}" real_source = eval('"'+source+'"') result[real_source] = target elsif opts.instance_of?(Hash) target = "spec/fixtures/modules/#{fixture}" real_source = eval('"'+opts["repo"]+'"') result[real_source] = { "target" => target, "ref" => opts["ref"] } end end end return result end desc "Create the fixtures directory" task :spec_prep do fixtures("repositories").each do |remote, opts| if opts.instance_of?(String) target = opts ref = "refs/remotes/origin/master" elsif opts.instance_of?(Hash) target = opts["target"] ref = opts["ref"] end unless File::exists?(target) || system("git clone #{remote} #{target}") fail "Failed to clone #{remote} into #{target}" end system("cd #{target}; git reset --hard #{ref}") if ref end FileUtils::mkdir_p("spec/fixtures/modules") fixtures("symlinks").each do |source, target| File::exists?(target) || FileUtils::ln_s(source, target) end FileUtils::mkdir_p("spec/fixtures/manifests") FileUtils::touch("spec/fixtures/manifests/site.pp") end desc "Clean up the fixtures directory" task :spec_clean do fixtures("repositories").each do |remote, opts| if opts.instance_of?(String) target = opts elsif opts.instance_of?(Hash) target = opts["target"] end FileUtils::rm_rf(target) end fixtures("symlinks").each do |source, target| FileUtils::rm(target) end site = "spec/fixtures/manifests/site.pp" if File::exists?(site) and ! File.size?(site) FileUtils::rm("spec/fixtures/manifests/site.pp") end end desc "Run spec tests in a clean fixtures directory" task :spec do Rake::Task[:spec_prep].invoke Rake::Task[:spec_standalone].invoke Rake::Task[:spec_clean].invoke end desc "Build puppet module package" task :build do # This will be deprecated once puppet-module is a face. begin Gem::Specification.find_by_name('puppet-module') rescue Gem::LoadError, NoMethodError require 'puppet/face' pmod = Puppet::Face['module', :current] pmod.build('./') end end desc "Clean a built module package" task :clean do FileUtils.rm_rf("pkg/") end desc "Check puppet manifests with puppet-lint" task :lint do require 'puppet-lint/tasks/puppet-lint' end desc "Display the list of available rake tasks" task :help do system("rake -T") end puppetlabs-spec-helper-0.4.1/lib/puppetlabs_spec_helper/puppet_spec_helper.rb0000644000175000017500000001511212246125657026003 0ustar tomtomrequire 'puppetlabs_spec_helper/puppetlabs_spec_helper' # Don't want puppet getting the command line arguments for rake or autotest ARGV.clear # This is needed because we're using mocha with rspec instead of Test::Unit or MiniTest ENV['MOCHA_OPTIONS']='skip_integration' require 'puppet' gem 'rspec', '>=2.0.0' require 'rspec/expectations' require 'mocha/api' require 'pathname' require 'tmpdir' require 'puppetlabs_spec_helper/puppetlabs_spec/files' ###################################################################################### # WARNING # ###################################################################################### # # You should probably be frightened by this file. :) # # The goal of this file is to try to maximize spec-testing compatibility between # multiple versions of various external projects (which depend on puppet core) and # multiple versions of puppet core itself. This is accomplished via a series # of hacks and magical incantations that I am not particularly proud of. However, # after discussion it was decided that the goal of achieving compatibility was # a very worthy one, and that isolating the hacks to one place in a non-production # project was as good a solution as we could hope for. # # You may want to hold your nose before you proceed. :) # # This is just a utility class to allow us to isolate the various version-specific # branches of initialization logic into methods without polluting the global namespace.# module Puppet class PuppetSpecInitializer # This method uses the "new"/preferred approach of delegating all of the test # state initialization to puppet itself, via Puppet::Test::TestHelper API. This # should be fairly future-proof as long as that API doesn't change, which it # hopefully will not need to. def self.initialize_via_testhelper(config) begin Puppet::Test::TestHelper.initialize rescue NoMethodError Puppet::Test::TestHelper.before_each_test end # connect rspec hooks to TestHelper methods. config.before :all do Puppet::Test::TestHelper.before_all_tests end config.after :all do Puppet::Test::TestHelper.after_all_tests end config.before :each do Puppet::Test::TestHelper.before_each_test end config.after :each do Puppet::Test::TestHelper.after_each_test end end # This method is for initializing puppet state for testing for older versions # of puppet that do not support the new TestHelper API. As you can see, # this involves explicitly modifying global variables, directly manipulating # Puppet's Settings singleton object, and other fun implementation details # that code external to puppet should really never know about. def self.initialize_via_fallback_compatibility(config) config.before :all do # nothing to do for now end config.after :all do # nothing to do for now end config.before :each do # these globals are set by Application $puppet_application_mode = nil $puppet_application_name = nil # REVISIT: I think this conceals other bad tests, but I don't have time to # fully diagnose those right now. When you read this, please come tell me # I suck for letting this float. --daniel 2011-04-21 Signal.stubs(:trap) # Set the confdir and vardir to gibberish so that tests # have to be correctly mocked. Puppet[:confdir] = "/dev/null" Puppet[:vardir] = "/dev/null" # Avoid opening ports to the outside world Puppet.settings[:bindaddress] = "127.0.0.1" end config.after :each do Puppet.settings.clear Puppet::Node::Environment.clear Puppet::Util::Storage.clear Puppet::Util::ExecutionStub.reset if Puppet::Util.constants.include? "ExecutionStub" PuppetlabsSpec::Files.cleanup end end end end # Here we attempt to load the new TestHelper API, and print a warning if we are falling back # to compatibility mode for older versions of puppet. begin require 'puppet/test/test_helper' rescue LoadError => err $stderr.puts("Warning: you appear to be using an older version of puppet; spec_helper will use fallback compatibility mode.") end # JJM Hack to make the stdlib tests run in Puppet 2.6 (See puppet commit cf183534) if not Puppet.constants.include? "Test" then module Puppet::Test class LogCollector def initialize(logs) @logs = logs end def <<(value) @logs << value end end end Puppet::Util::Log.newdesttype :log_collector do match "Puppet::Test::LogCollector" def initialize(messages) @messages = messages end def handle(msg) @messages << msg end end end # And here is where we do the main rspec configuration / setup. RSpec.configure do |config| config.mock_with :mocha # determine whether we can use the new API or not, and call the appropriate initializer method. if (defined?(Puppet::Test::TestHelper)) Puppet::PuppetSpecInitializer.initialize_via_testhelper(config) else Puppet::PuppetSpecInitializer.initialize_via_fallback_compatibility(config) end # Here we do some general setup that is relevant to all initialization modes, regardless # of the availability of the TestHelper API. config.before :each do # Here we redirect logging away from console, because otherwise the test output will be # obscured by all of the log output. # # TODO: in a more sane world, we'd move this logging redirection into our TestHelper # class, so that it was not coupled with a specific testing framework (rspec in this # case). Further, it would be nicer and more portable to encapsulate the log messages # into an object somewhere, rather than slapping them on an instance variable of the # actual test class--which is what we are effectively doing here. # # However, because there are over 1300 tests that are written to expect # this instance variable to be available--we can't easily solve this problem right now. @logs = [] Puppet::Util::Log.newdestination(Puppet::Test::LogCollector.new(@logs)) @log_level = Puppet::Util::Log.level end config.after :each do # clean up after the logging changes that we made before each test. # TODO: this should be abstracted in the future--see comments above the '@logs' block in the # "before" code above. @logs.clear Puppet::Util::Log.close_all Puppet::Util::Log.level = @log_level end end puppetlabs-spec-helper-0.4.1/lib/puppetlabs_spec_helper/module_spec_helper.rb0000644000175000017500000000145412246125657025757 0ustar tomtomrequire 'rspec-puppet' require 'puppetlabs_spec_helper/puppet_spec_helper' require 'puppetlabs_spec_helper/puppetlabs_spec/puppet_internals' def param_value(subject, type, title, param) subject.resource(type, title).send(:parameters)[param.to_sym] end def verify_contents(subject, title, expected_lines) content = subject.resource('file', title).send(:parameters)[:content] (content.split("\n") & expected_lines).should == expected_lines end fixture_path = File.expand_path(File.join(Dir.pwd, 'spec/fixtures')) env_module_path = ENV['MODULEPATH'] module_path = File.join(fixture_path, 'modules') module_path = [module_path, env_module_path].join(File::PATH_SEPARATOR) if env_module_path RSpec.configure do |c| c.module_path = module_path c.manifest_dir = File.join(fixture_path, 'manifests') end puppetlabs-spec-helper-0.4.1/lib/puppetlabs_spec_helper/puppetlabs_spec/0000755000175000017500000000000012246125657024761 5ustar tomtompuppetlabs-spec-helper-0.4.1/lib/puppetlabs_spec_helper/puppetlabs_spec/puppet_internals.rb0000644000175000017500000000473112246125657030707 0ustar tomtom# Initialize puppet for testing by loading the # 'puppetlabs_spec_helper/puppet_spec_helper' library require 'puppetlabs_spec_helper/puppet_spec_helper' module PuppetlabsSpec module PuppetInternals # parser_scope is intended to return a Puppet::Parser::Scope # instance suitable for placing in a test harness with the intent of # testing parser functions from modules. def scope(parts = {}) if Puppet.version =~ /^2\.[67]/ # loadall should only be necessary prior to 3.x # Please note, loadall needs to happen first when creating a scope, otherwise # you might receive undefined method `function_*' errors Puppet::Parser::Functions.autoloader.loadall end scope_compiler = parts[:compiler] || compiler scope_parent = parts[:parent] || scope_compiler.topscope scope_resource = parts[:resource] || resource(:type => :node, :title => scope_compiler.node.name) if Puppet.version =~ /^2\.[67]/ scope = Puppet::Parser::Scope.new(:compiler => scope_compiler) else scope = Puppet::Parser::Scope.new(scope_compiler) end scope.source = Puppet::Resource::Type.new(:node, "foo") scope.parent = scope_parent scope end module_function :scope def resource(parts = {}) resource_type = parts[:type] || :hostclass resource_name = parts[:name] || "testing" Puppet::Resource::Type.new(resource_type, resource_name) end module_function :resource def compiler(parts = {}) compiler_node = parts[:node] || node() Puppet::Parser::Compiler.new(compiler_node) end module_function :compiler def node(parts = {}) node_name = parts[:name] || 'testinghost' options = parts[:options] || {} node_environment = Puppet::Node::Environment.new(parts[:environment] || 'test') options.merge!({:environment => node_environment}) Puppet::Node.new(node_name, options) end module_function :node # Return a method instance for a given function. This is primarily useful # for rspec-puppet def function_method(name, parts = {}) scope = parts[:scope] || scope() # Ensure the method instance is defined by side-effect of checking if it # exists. This is a hack, but at least it's a hidden hack and not an # exposed hack. return nil unless Puppet::Parser::Functions.function(name) scope.method("function_#{name}".intern) end module_function :function_method end end puppetlabs-spec-helper-0.4.1/lib/puppetlabs_spec_helper/puppetlabs_spec/files.rb0000755000175000017500000000240012246125657026407 0ustar tomtomrequire 'fileutils' require 'tempfile' require 'pathname' # A support module for testing files. module PuppetlabsSpec::Files # This code exists only to support tests that run as root, pretty much. # Once they have finally been eliminated this can all go... --daniel 2011-04-08 def self.in_tmp(path) tempdir = Dir.tmpdir Pathname.new(path).ascend do |dir| return true if File.identical?(tempdir, dir) end false end def self.cleanup $global_tempfiles ||= [] while path = $global_tempfiles.pop do fail "Not deleting tmpfile #{path} outside regular tmpdir" unless in_tmp(path) begin FileUtils.rm_r path, :secure => true rescue Errno::ENOENT # nothing to do end end end def make_absolute(path) path = File.expand_path(path) path[0] = 'c' if Puppet.features.microsoft_windows? path end def tmpfilename(name) # Generate a temporary file, just for the name... source = Tempfile.new(name) path = source.path source.close! # ...record it for cleanup, $global_tempfiles ||= [] $global_tempfiles << File.expand_path(path) # ...and bam. path end def tmpdir(name) path = tmpfilename(name) FileUtils.mkdir_p(path) path end end puppetlabs-spec-helper-0.4.1/lib/puppetlabs_spec_helper/puppetlabs_spec/fixtures.rb0000755000175000017500000000324112246125657027162 0ustar tomtom# This module provides some helper methods to assist with fixtures. It's # methods are designed to help when you have a conforming fixture layout so we # get project consistency. module PuppetlabsSpec::Fixtures # Returns the joined path of the global FIXTURE_DIR plus any path given to it def fixtures(*rest) File.join(PuppetlabsSpec::FIXTURE_DIR, *rest) end # Returns the path to your relative fixture dir. So if your spec test is # /spec/unit/facter/foo_spec.rb then your relative dir will be # /spec/fixture/unit/facter/foo def my_fixture_dir callers = caller while line = callers.shift do next unless found = line.match(%r{/spec/(.*)_spec\.rb:}) return fixtures(found[1]) end fail "sorry, I couldn't work out your path from the caller stack!" end # Given a name, returns the full path of a file from your relative fixture # dir as returned by my_fixture_dir. def my_fixture(name) file = File.join(my_fixture_dir, name) unless File.readable? file then fail "fixture '#{name}' for #{my_fixture_dir} is not readable" end return file end # Return the contents of the file using read when given a name. Uses # my_fixture to work out the relative path. def my_fixture_read(name) File.read(my_fixture(name)) end # Provides a block mechanism for iterating across the files in your fixture # area. def my_fixtures(glob = '*', flags = 0) files = Dir.glob(File.join(my_fixture_dir, glob), flags) unless files.length > 0 then fail "fixture '#{glob}' for #{my_fixture_dir} had no files!" end block_given? and files.each do |file| yield file end files end end puppetlabs-spec-helper-0.4.1/lib/puppetlabs_spec_helper/puppetlabs_spec/matchers.rb0000644000175000017500000000377012246125657027123 0ustar tomtomrequire 'stringio' ######################################################################## # Backward compatibility for Jenkins outdated environment. module RSpec module Matchers module BlockAliases alias_method :to, :should unless method_defined? :to alias_method :to_not, :should_not unless method_defined? :to_not alias_method :not_to, :should_not unless method_defined? :not_to end end end ######################################################################## # Custom matchers... RSpec::Matchers.define :have_matching_element do |expected| match do |actual| actual.any? { |item| item =~ expected } end end RSpec::Matchers.define :exit_with do |expected| actual = nil match do |block| begin block.call rescue SystemExit => e actual = e.status end actual and actual == expected end failure_message_for_should do |block| "expected exit with code #{expected} but " + (actual.nil? ? " exit was not called" : "we exited with #{actual} instead") end failure_message_for_should_not do |block| "expected that exit would not be called with #{expected}" end description do "expect exit with #{expected}" end end RSpec::Matchers.define :have_printed do |expected| match do |block| $stderr = $stdout = StringIO.new begin block.call ensure $stdout.rewind @actual = $stdout.read $stdout = STDOUT $stderr = STDERR end if @actual then case expected when String @actual.include? expected when Regexp expected.match @actual else raise ArgumentError, "No idea how to match a #{@actual.class.name}" end end end failure_message_for_should do |actual| if actual.nil? then "expected #{expected.inspect}, but nothing was printed" else "expected #{expected.inspect} to be printed; got:\n#{actual}" end end description do "expect #{expected.inspect} to be printed" end diffable end puppetlabs-spec-helper-0.4.1/lib/puppetlabs_spec_helper/puppetlabs_spec_helper.rb0000644000175000017500000000201512246125657026643 0ustar tomtom# Define the main module namespace for use by the helper modules module PuppetlabsSpec # FIXTURE_DIR represents the standard locations of all fixture data. Normally # this represents /spec/fixtures. This will be used by the fixtures # library to find relative fixture data. FIXTURE_DIR = File.join("spec", "fixtures") unless defined?(FIXTURE_DIR) end # Require all necessary helper libraries so they can be used later require 'puppetlabs_spec_helper/puppetlabs_spec/files' require 'puppetlabs_spec_helper/puppetlabs_spec/fixtures' require 'puppetlabs_spec_helper/puppetlabs_spec/puppet_internals' require 'puppetlabs_spec_helper/puppetlabs_spec/matchers' RSpec.configure do |config| # Include PuppetlabsSpec helpers so they can be called at convenience config.extend PuppetlabsSpec::Files config.extend PuppetlabsSpec::Fixtures config.include PuppetlabsSpec::Fixtures # This will cleanup any files that were created with tmpdir or tmpfile config.after :each do PuppetlabsSpec::Files.cleanup end end puppetlabs-spec-helper-0.4.1/LICENSE0000644000175000017500000000114612246125657015301 0ustar tomtomCopyright (C) 2012 Puppet Labs Inc Puppet Labs can be contacted at: info@puppetlabs.com Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.puppetlabs-spec-helper-0.4.1/CHANGELOG0000644000175000017500000000206612246125657015510 0ustar tomtom2013-02-08 Puppet Labs - 0.4.1 * (#18165) Mark tests pending on broken puppet versions * (#18165) Initialize TestHelper as soon as possible * Maint: Change formatting and handle windows path separator 2012-12-14 Puppet Labs - 0.4.0 * Rake should fail if git can't clone repository * Add readme for fixtures * Fix Mocha deprecations * add opts logic to rake spec_clean * add backwards-compatible support for arbitrary git refs in .fixtures.yml * Only remove the site.pp if it is empty * (#15464) Make contributing easy via bundle Gemfile * (#15464) Add gemspec from 0.3.0 published gem 2012-08-14 Puppet Labs - 0.3.0 * Add PuppetInternals compatibility module for scope, node, compiler, and functions * Add rspec-puppet convention directories to rake tasks 2012-07-05 Puppet Labs - 0.2.0 * Fix integration with mocha-0.12.0 * Fix coverage rake task * Fix an issue creating the fixtures directory 2012-06-08 Puppet Labs - 0.1.0 * Initial release