diff --git a/lib/puppet/application/config.rb b/lib/puppet/application/config.rb index 41a46c339..a94441e7f 100644 --- a/lib/puppet/application/config.rb +++ b/lib/puppet/application/config.rb @@ -1,4 +1,4 @@ -require 'puppet/application/faces_base' +require 'puppet/application/face_base' -class Puppet::Application::Config < Puppet::Application::FacesBase +class Puppet::Application::Config < Puppet::Application::FaceBase end diff --git a/lib/puppet/application/configurer.rb b/lib/puppet/application/configurer.rb index 751e6b4d7..6e86cd2d4 100644 --- a/lib/puppet/application/configurer.rb +++ b/lib/puppet/application/configurer.rb @@ -1,23 +1,23 @@ require 'puppet/application' -require 'puppet/faces' +require 'puppet/face' class Puppet::Application::Configurer < Puppet::Application should_parse_config run_mode :agent option("--debug", "-d") option("--verbose", "-v") def setup if options[:debug] or options[:verbose] Puppet::Util::Log.level = options[:debug] ? :debug : :info end Puppet::Util::Log.newdestination(:console) end def run_command - report = Puppet::Faces[:configurer, '0.0.1'].synchronize(Puppet[:certname]) - Puppet::Faces[:report, '0.0.1'].submit(report) + report = Puppet::Face[:configurer, '0.0.1'].synchronize(Puppet[:certname]) + Puppet::Face[:report, '0.0.1'].submit(report) end end diff --git a/lib/puppet/application/faces_base.rb b/lib/puppet/application/face_base.rb similarity index 97% rename from lib/puppet/application/faces_base.rb rename to lib/puppet/application/face_base.rb index f1b77f285..2a048a532 100644 --- a/lib/puppet/application/faces_base.rb +++ b/lib/puppet/application/face_base.rb @@ -1,158 +1,158 @@ require 'puppet/application' -require 'puppet/faces' +require 'puppet/face' require 'optparse' -class Puppet::Application::FacesBase < Puppet::Application +class Puppet::Application::FaceBase < Puppet::Application should_parse_config run_mode :agent option("--debug", "-d") do |arg| Puppet::Util::Log.level = :debug end option("--verbose", "-v") do Puppet::Util::Log.level = :info end option("--format FORMAT") do |arg| @format = arg.to_sym end option("--mode RUNMODE", "-r") do |arg| raise "Invalid run mode #{arg}; supported modes are user, agent, master" unless %w{user agent master}.include?(arg) self.class.run_mode(arg.to_sym) set_run_mode self.class.run_mode end attr_accessor :face, :action, :type, :arguments, :format attr_writer :exit_code # This allows you to set the exit code if you don't want to just exit # immediately but you need to indicate a failure. def exit_code @exit_code || 0 end # Override this if you need custom rendering. def render(result) render_method = Puppet::Network::FormatHandler.format(format).render_method if render_method == "to_pson" jj result exit(0) else result.send(render_method) end end def preinit super Signal.trap(:INT) do $stderr.puts "Cancelling Face" exit(0) end end def parse_options # We need to parse enough of the command line out early, to identify what # the action is, so that we can obtain the full set of options to parse. # REVISIT: These should be configurable versions, through a global # '--version' option, but we don't implement that yet... --daniel 2011-03-29 @type = self.class.name.to_s.sub(/.+:/, '').downcase.to_sym - @face = Puppet::Faces[@type, :current] + @face = Puppet::Face[@type, :current] @format = @face.default_format # Now, walk the command line and identify the action. We skip over # arguments based on introspecting the action and all, and find the first # non-option word to use as the action. action = nil index = -1 until @action or (index += 1) >= command_line.args.length do item = command_line.args[index] if item =~ /^-/ then option = @face.options.find do |name| item =~ /^-+#{name.to_s.gsub(/[-_]/, '[-_]')}(?:[ =].*)?$/ end if option then option = @face.get_option(option) # If we have an inline argument, just carry on. We don't need to # care about optional vs mandatory in that case because we do a real # parse later, and that will totally take care of raising the error # when we get there. --daniel 2011-04-04 if option.takes_argument? and !item.index('=') then index += 1 unless (option.optional_argument? and command_line.args[index + 1] =~ /^-/) end elsif option = find_global_settings_argument(item) then unless Puppet.settings.boolean? option.name then # As far as I can tell, we treat non-bool options as always having # a mandatory argument. --daniel 2011-04-05 index += 1 # ...so skip the argument. end else raise OptionParser::InvalidOption.new(item.sub(/=.*$/, '')) end else action = @face.get_action(item.to_sym) if action.nil? then raise OptionParser::InvalidArgument.new("#{@face} does not have an #{item} action") end @action = action end end unless @action raise OptionParser::MissingArgument.new("No action given on the command line") end # Now we can interact with the default option code to build behaviour # around the full set of options we now know we support. @action.options.each do |option| option = @action.get_option(option) # make it the object. self.class.option(*option.optparse) # ...and make the CLI parse it. end # ...and invoke our parent to parse all the command line options. super end def find_global_settings_argument(item) Puppet.settings.each do |name, object| object.optparse_args.each do |arg| next unless arg =~ /^-/ # sadly, we have to emulate some of optparse here... pattern = /^#{arg.sub('[no-]', '').sub(/[ =].*$/, '')}(?:[ =].*)?$/ pattern.match item and return object end end return nil # nothing found. end def setup Puppet::Util::Log.newdestination :console @arguments = command_line.args # Note: because of our definition of where the action is set, we end up # with it *always* being the first word of the remaining set of command # line arguments. So, strip that off when we construct the arguments to # pass down to the face action. --daniel 2011-04-04 @arguments.delete_at(0) # We copy all of the app options to the end of the call; This allows each # action to read in the options. This replaces the older model where we # would invoke the action with options set as global state in the # interface object. --daniel 2011-03-28 @arguments << options end def main # Call the method associated with the provided action (e.g., 'find'). if result = @face.send(@action.name, *arguments) puts render(result) end exit(exit_code) end end diff --git a/lib/puppet/application/faces.rb b/lib/puppet/application/faces.rb index a7b227e23..3dd3f0312 100644 --- a/lib/puppet/application/faces.rb +++ b/lib/puppet/application/faces.rb @@ -1,88 +1,88 @@ require 'puppet/application' -require 'puppet/faces' +require 'puppet/face' class Puppet::Application::Faces < Puppet::Application should_parse_config run_mode :agent option("--debug", "-d") do |arg| Puppet::Util::Log.level = :debug end option("--help", "-h") do |arg| puts "Usage: puppet faces [actions|terminuses] -Lists all available interfaces, and by default includes all available terminuses and actions. +Lists all available faces, and by default includes all available terminuses and actions. " end option("--verbose", "-v") do Puppet::Util::Log.level = :info end def list(*arguments) if arguments.empty? arguments = %w{terminuses actions} end faces.each do |name| str = "#{name}:\n" if arguments.include?("terminuses") begin terms = terminus_classes(name.to_sym) str << "\tTerminuses: #{terms.join(", ")}\n" rescue => detail puts detail.backtrace if Puppet[:trace] $stderr.puts "Could not load terminuses for #{name}: #{detail}" end end if arguments.include?("actions") begin actions = actions(name.to_sym) str << "\tActions: #{actions.join(", ")}\n" rescue => detail puts detail.backtrace if Puppet[:trace] $stderr.puts "Could not load actions for #{name}: #{detail}" end end print str end end attr_accessor :name, :arguments def main list(*arguments) end def setup Puppet::Util::Log.newdestination :console load_applications # Call this to load all of the apps @arguments = command_line.args @arguments ||= [] end def faces - Puppet::Faces.faces + Puppet::Face.faces end def terminus_classes(indirection) Puppet::Indirector::Terminus.terminus_classes(indirection).collect { |t| t.to_s }.sort end def actions(indirection) - return [] unless faces = Puppet::Faces[indirection, '0.0.1'] - faces.load_actions - return faces.actions.sort { |a, b| a.to_s <=> b.to_s } + return [] unless face = Puppet::Face[indirection, '0.0.1'] + face.load_actions + return face.actions.sort { |a, b| a.to_s <=> b.to_s } end def load_applications command_line.available_subcommands.each do |app| command_line.require_application app end end end diff --git a/lib/puppet/application/help.rb b/lib/puppet/application/help.rb index fd8818db0..0d7767632 100644 --- a/lib/puppet/application/help.rb +++ b/lib/puppet/application/help.rb @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- -require 'puppet/application/faces_base' +require 'puppet/application/face_base' -class Puppet::Application::Help < Puppet::Application::FacesBase +class Puppet::Application::Help < Puppet::Application::FaceBase # Meh. Disable the default behaviour, which is to inspect the # string and return that – not so helpful. --daniel 2011-04-11 def render(result) result end end diff --git a/lib/puppet/application/indirection_base.rb b/lib/puppet/application/indirection_base.rb index 7455ebedf..580a0999a 100644 --- a/lib/puppet/application/indirection_base.rb +++ b/lib/puppet/application/indirection_base.rb @@ -1,4 +1,4 @@ -require 'puppet/application/faces_base' +require 'puppet/application/face_base' -class Puppet::Application::IndirectionBase < Puppet::Application::FacesBase +class Puppet::Application::IndirectionBase < Puppet::Application::FaceBase end diff --git a/lib/puppet/faces.rb b/lib/puppet/face.rb similarity index 82% rename from lib/puppet/faces.rb rename to lib/puppet/face.rb index 947eecf24..f73b2fc3b 100644 --- a/lib/puppet/faces.rb +++ b/lib/puppet/face.rb @@ -1,12 +1,12 @@ -# The public name of this feature is 'faces', but we have hidden all the +# The public name of this feature is 'face', but we have hidden all the # plumbing over in the 'interfaces' namespace to make clear the distinction # between the two. # # This file exists to ensure that the public name is usable without revealing # the details of the implementation; you really only need go look at anything # under Interfaces if you are looking to extend the implementation. # # It isn't hidden to gratuitously hide things, just to make it easier to # separate out the interests people will have. --daniel 2011-04-07 require 'puppet/interface' -Puppet::Faces = Puppet::Interface +Puppet::Face = Puppet::Interface diff --git a/lib/puppet/faces/catalog.rb b/lib/puppet/face/catalog.rb similarity index 85% rename from lib/puppet/faces/catalog.rb rename to lib/puppet/face/catalog.rb index 3353d5d04..0dcde3591 100644 --- a/lib/puppet/faces/catalog.rb +++ b/lib/puppet/face/catalog.rb @@ -1,40 +1,40 @@ -require 'puppet/faces/indirector' +require 'puppet/face/indirector' -Puppet::Faces::Indirector.define(:catalog, '0.0.1') do +Puppet::Face::Indirector.define(:catalog, '0.0.1') do action(:apply) do when_invoked do |catalog, options| report = Puppet::Transaction::Report.new("apply") report.configuration_version = catalog.version Puppet::Util::Log.newdestination(report) begin benchmark(:notice, "Finished catalog run") do catalog.apply(:report => report) end rescue => detail puts detail.backtrace if Puppet[:trace] Puppet.err "Failed to apply catalog: #{detail}" end report.finalize_report report end end action(:download) do when_invoked do |certname, facts, options| Puppet::Resource::Catalog.indirection.terminus_class = :rest facts_to_upload = {:facts_format => :b64_zlib_yaml, :facts => CGI.escape(facts.render(:b64_zlib_yaml))} catalog = nil retrieval_duration = thinmark do - catalog = Puppet::Faces[:catalog, '0.0.1'].find(certname, facts_to_upload) + catalog = Puppet::Face[:catalog, '0.0.1'].find(certname, facts_to_upload) end catalog = catalog.to_ral catalog.finalize catalog.retrieval_duration = retrieval_duration catalog.write_class_file catalog end end end diff --git a/lib/puppet/faces/catalog/select.rb b/lib/puppet/face/catalog/select.rb similarity index 86% rename from lib/puppet/faces/catalog/select.rb rename to lib/puppet/face/catalog/select.rb index e29d19970..ba27117bc 100644 --- a/lib/puppet/faces/catalog/select.rb +++ b/lib/puppet/face/catalog/select.rb @@ -1,10 +1,10 @@ # Select and show a list of resources of a given type. -Puppet::Faces.define(:catalog, '0.0.1') do +Puppet::Face.define(:catalog, '0.0.1') do action :select do when_invoked do |host, type, options| catalog = Puppet::Resource::Catalog.indirection.find(host) catalog.resources.reject { |res| res.type != type }.each { |res| puts res } end end end diff --git a/lib/puppet/faces/certificate.rb b/lib/puppet/face/certificate.rb similarity index 93% rename from lib/puppet/faces/certificate.rb rename to lib/puppet/face/certificate.rb index b10bee579..77e80f099 100644 --- a/lib/puppet/faces/certificate.rb +++ b/lib/puppet/face/certificate.rb @@ -1,46 +1,46 @@ -require 'puppet/faces/indirector' +require 'puppet/face/indirector' require 'puppet/ssl/host' -Puppet::Faces::Indirector.define(:certificate, '0.0.1') do +Puppet::Face::Indirector.define(:certificate, '0.0.1') do # REVISIT: This should use a pre-invoke hook to run the common code that # needs to happen before we invoke any action; that would be much nicer than # the "please repeat yourself" stuff found in here right now. # # option "--ca-location LOCATION" do # type [:whatever, :location, :symbols] # hook :before do |value| # Puppet::SSL::Host.ca_location = value # end # end # # ...but should I pass the arguments as well? # --daniel 2011-04-05 option "--ca-location LOCATION" action :generate do when_invoked do |name, options| Puppet::SSL::Host.ca_location = options[:ca_location].to_sym host = Puppet::SSL::Host.new(name) host.generate_certificate_request host.certificate_request.class.indirection.save(host.certificate_request) end end action :list do when_invoked do |options| Puppet::SSL::Host.ca_location = options[:ca_location].to_sym Puppet::SSL::Host.indirection.search("*", { :for => :certificate_request, }).map { |h| h.inspect } end end action :sign do when_invoked do |name, options| Puppet::SSL::Host.ca_location = options[:ca_location].to_sym host = Puppet::SSL::Host.new(name) host.desired_state = 'signed' Puppet::SSL::Host.indirection.save(host) end end end diff --git a/lib/puppet/face/certificate_request.rb b/lib/puppet/face/certificate_request.rb new file mode 100644 index 000000000..1feba25ab --- /dev/null +++ b/lib/puppet/face/certificate_request.rb @@ -0,0 +1,4 @@ +require 'puppet/face/indirector' + +Puppet::Face::Indirector.define(:certificate_request, '0.0.1') do +end diff --git a/lib/puppet/face/certificate_revocation_list.rb b/lib/puppet/face/certificate_revocation_list.rb new file mode 100644 index 000000000..6a75aa578 --- /dev/null +++ b/lib/puppet/face/certificate_revocation_list.rb @@ -0,0 +1,4 @@ +require 'puppet/face/indirector' + +Puppet::Face::Indirector.define(:certificate_revocation_list, '0.0.1') do +end diff --git a/lib/puppet/faces/config.rb b/lib/puppet/face/config.rb similarity index 75% rename from lib/puppet/faces/config.rb rename to lib/puppet/face/config.rb index 647bf5052..45cb6b156 100644 --- a/lib/puppet/faces/config.rb +++ b/lib/puppet/face/config.rb @@ -1,12 +1,12 @@ -require 'puppet/faces' +require 'puppet/face' -Puppet::Faces.define(:config, '0.0.1') do +Puppet::Face.define(:config, '0.0.1') do action(:print) do when_invoked do |*args| options = args.pop Puppet.settings[:configprint] = args.join(",") Puppet.settings.print_config_options nil end end end diff --git a/lib/puppet/face/configurer.rb b/lib/puppet/face/configurer.rb new file mode 100644 index 000000000..74dfb854e --- /dev/null +++ b/lib/puppet/face/configurer.rb @@ -0,0 +1,12 @@ +require 'puppet/face' + +Puppet::Face.define(:configurer, '0.0.1') do + action(:synchronize) do + when_invoked do |certname, options| + facts = Puppet::Face[:facts, '0.0.1'].find(certname) + catalog = Puppet::Face[:catalog, '0.0.1'].download(certname, facts) + report = Puppet::Face[:catalog, '0.0.1'].apply(catalog) + report + end + end +end diff --git a/lib/puppet/faces/facts.rb b/lib/puppet/face/facts.rb similarity index 84% rename from lib/puppet/faces/facts.rb rename to lib/puppet/face/facts.rb index 33eacef38..8668b2531 100644 --- a/lib/puppet/faces/facts.rb +++ b/lib/puppet/face/facts.rb @@ -1,18 +1,18 @@ -require 'puppet/faces/indirector' +require 'puppet/face/indirector' require 'puppet/node/facts' -Puppet::Faces::Indirector.define(:facts, '0.0.1') do +Puppet::Face::Indirector.define(:facts, '0.0.1') do set_default_format :yaml # Upload our facts to the server action(:upload) do when_invoked do |options| Puppet::Node::Facts.indirection.terminus_class = :facter facts = Puppet::Node::Facts.indirection.find(Puppet[:certname]) Puppet::Node::Facts.indirection.terminus_class = :rest Puppet::Node::Facts.indirection.save(facts) Puppet.notice "Uploaded facts for '#{Puppet[:certname]}'" nil end end end diff --git a/lib/puppet/face/file.rb b/lib/puppet/face/file.rb new file mode 100644 index 000000000..1aa9462dd --- /dev/null +++ b/lib/puppet/face/file.rb @@ -0,0 +1,5 @@ +require 'puppet/face/indirector' + +Puppet::Face::Indirector.define(:file, '0.0.1') do + set_indirection_name :file_bucket_file +end diff --git a/lib/puppet/faces/help.rb b/lib/puppet/face/help.rb similarity index 93% rename from lib/puppet/faces/help.rb rename to lib/puppet/face/help.rb index 1d8abe20e..1c2da9e83 100644 --- a/lib/puppet/faces/help.rb +++ b/lib/puppet/face/help.rb @@ -1,104 +1,104 @@ -require 'puppet/faces' +require 'puppet/face' require 'puppet/util/command_line' require 'pathname' require 'erb' -Puppet::Faces.define(:help, '0.0.1') do +Puppet::Face.define(:help, '0.0.1') do summary "Displays help about puppet subcommands" action(:help) do summary "Display help about faces and their actions." option "--version VERSION" do desc "Which version of the interface to show help for" end when_invoked do |*args| # Check our invocation, because we want varargs and can't do defaults # yet. REVISIT: when we do option defaults, and positional options, we # should rewrite this to use those. --daniel 2011-04-04 options = args.pop if options.nil? or args.length > 2 then raise ArgumentError, "help only takes two (optional) arguments, a face name, and an action" end version = :current if options.has_key? :version then if options[:version].to_s !~ /^current$/i then version = options[:version] else if args.length == 0 then raise ArgumentError, "version only makes sense when a face is given" end end end # Name those parameters... facename, actionname = args if facename then if legacy_applications.include? facename then actionname and raise ArgumentError, "Legacy subcommands don't take actions" return Puppet::Application[facename].help else - face = Puppet::Faces[facename.to_sym, version] + face = Puppet::Face[facename.to_sym, version] actionname and action = face.get_action(actionname.to_sym) end end case args.length when 0 then template = erb 'global.erb' when 1 then face or fail ArgumentError, "Unable to load face #{facename}" template = erb 'face.erb' when 2 then face or fail ArgumentError, "Unable to load face #{facename}" action or fail ArgumentError, "Unable to load action #{actionname} from #{face}" template = erb 'action.erb' else fail ArgumentError, "Too many arguments to help action" end # Run the ERB template in our current binding, including all the local # variables we established just above. --daniel 2011-04-11 return template.result(binding) end end def erb(name) template = (Pathname(__FILE__).dirname + "help" + name) erb = ERB.new(template.read, nil, '%') erb.filename = template.to_s return erb end def legacy_applications # The list of applications, less those that are duplicated as a face. Puppet::Util::CommandLine.available_subcommands.reject do |appname| - Puppet::Faces.face? appname.to_sym, :current or + Puppet::Face.face? appname.to_sym, :current or # ...this is a nasty way to exclude non-applications. :( - %w{faces_base indirection_base}.include? appname + %w{face_base indirection_base}.include? appname end.sort end def horribly_extract_summary_from(appname) begin require "puppet/application/#{appname}" help = Puppet::Application[appname].help.split("\n") # Now we find the line with our summary, extract it, and return it. This # depends on the implementation coincidence of how our pages are # formatted. If we can't match the pattern we expect we return the empty # string to ensure we don't blow up in the summary. --daniel 2011-04-11 while line = help.shift do if md = /^puppet-#{appname}\([^\)]+\) -- (.*)$/.match(line) then return md[1] end end rescue Exception # Damn, but I hate this: we just ignore errors here, no matter what # class they are. Meh. end return '' end end diff --git a/lib/puppet/faces/help/action.erb b/lib/puppet/face/help/action.erb similarity index 100% rename from lib/puppet/faces/help/action.erb rename to lib/puppet/face/help/action.erb diff --git a/lib/puppet/faces/help/face.erb b/lib/puppet/face/help/face.erb similarity index 100% rename from lib/puppet/faces/help/face.erb rename to lib/puppet/face/help/face.erb diff --git a/lib/puppet/faces/help/global.erb b/lib/puppet/face/help/global.erb similarity index 89% rename from lib/puppet/faces/help/global.erb rename to lib/puppet/face/help/global.erb index e123367a2..f4c761b2b 100644 --- a/lib/puppet/faces/help/global.erb +++ b/lib/puppet/face/help/global.erb @@ -1,20 +1,20 @@ puppet [options] [options] Available subcommands, from Puppet Faces: -% Puppet::Faces.faces.sort.each do |name| -% face = Puppet::Faces[name, :current] +% Puppet::Face.faces.sort.each do |name| +% face = Puppet::Face[name, :current] <%= face.name.to_s.ljust(16) %> <%= face.summary %> % end % unless legacy_applications.empty? then # great victory when this is true! Available applications, soon to be ported to Faces: % legacy_applications.each do |appname| % summary = horribly_extract_summary_from appname <%= appname.to_s.ljust(16) %> <%= summary %> % end % end See 'puppet help ' for help on a specific subcommand action. See 'puppet help ' for help on a specific subcommand. See 'puppet man ' for the full man page. Puppet v<%= Puppet::PUPPETVERSION %> diff --git a/lib/puppet/faces/indirector.rb b/lib/puppet/face/indirector.rb similarity index 97% rename from lib/puppet/faces/indirector.rb rename to lib/puppet/face/indirector.rb index 7e4e0f00f..f48611e4b 100644 --- a/lib/puppet/faces/indirector.rb +++ b/lib/puppet/face/indirector.rb @@ -1,94 +1,94 @@ require 'puppet' -require 'puppet/faces' +require 'puppet/face' -class Puppet::Faces::Indirector < Puppet::Faces +class Puppet::Face::Indirector < Puppet::Face option "--terminus TERMINUS" do desc "REVISIT: You can select a terminus, which has some bigger effect that we should describe in this file somehow." end def self.indirections Puppet::Indirector::Indirection.instances.collect { |t| t.to_s }.sort end def self.terminus_classes(indirection) Puppet::Indirector::Terminus.terminus_classes(indirection.to_sym).collect { |t| t.to_s }.sort end def call_indirection_method(method, *args) options = args.last options.has_key?(:terminus) and set_terminus(options[:terminus]) begin result = indirection.__send__(method, *args) rescue => detail puts detail.backtrace if Puppet[:trace] raise "Could not call '#{method}' on '#{indirection_name}': #{detail}" end indirection.reset_terminus_class return result end action :destroy do when_invoked { |*args| call_indirection_method(:destroy, *args) } end action :find do when_invoked { |*args| call_indirection_method(:find, *args) } end action :save do when_invoked { |*args| call_indirection_method(:save, *args) } end action :search do when_invoked { |*args| call_indirection_method(:search, *args) } end # Print the configuration for the current terminus class action :info do when_invoked do |*args| options = args.pop options.has_key?(:terminus) and set_terminus(options[:terminus]) if t = indirection.terminus_class puts "Run mode '#{Puppet.run_mode.name}': #{t}" else $stderr.puts "No default terminus class for run mode '#{Puppet.run_mode.name}'" end indirection.reset_terminus_class end end attr_accessor :from def indirection_name @indirection_name || name.to_sym end # Here's your opportunity to override the indirection name. By default it # will be the same name as the face. def set_indirection_name(name) @indirection_name = name end # Return an indirection associated with a face, if one exists; # One usually does. def indirection unless @indirection @indirection = Puppet::Indirector::Indirection.instance(indirection_name) @indirection or raise "Could not find terminus for #{indirection_name}" end @indirection end def set_terminus(from) begin indirection.terminus_class = from rescue => detail raise "Could not set '#{indirection.name}' terminus to '#{from}' (#{detail}); valid terminus types are #{self.class.terminus_classes(indirection.name).join(", ") }" end end end diff --git a/lib/puppet/face/key.rb b/lib/puppet/face/key.rb new file mode 100644 index 000000000..3a11ddb03 --- /dev/null +++ b/lib/puppet/face/key.rb @@ -0,0 +1,4 @@ +require 'puppet/face/indirector' + +Puppet::Face::Indirector.define(:key, '0.0.1') do +end diff --git a/lib/puppet/face/node.rb b/lib/puppet/face/node.rb new file mode 100644 index 000000000..fd1a548d6 --- /dev/null +++ b/lib/puppet/face/node.rb @@ -0,0 +1,5 @@ +require 'puppet/face/indirector' + +Puppet::Face::Indirector.define(:node, '0.0.1') do + set_default_format :yaml +end diff --git a/lib/puppet/faces/report.rb b/lib/puppet/face/report.rb similarity index 77% rename from lib/puppet/faces/report.rb rename to lib/puppet/face/report.rb index 23a518981..6e6f0b335 100644 --- a/lib/puppet/faces/report.rb +++ b/lib/puppet/face/report.rb @@ -1,15 +1,15 @@ -require 'puppet/faces/indirector' +require 'puppet/face/indirector' -Puppet::Faces::Indirector.define(:report, '0.0.1') do +Puppet::Face::Indirector.define(:report, '0.0.1') do action(:submit) do when_invoked do |report, options| begin Puppet::Transaction::Report.terminus_class = :rest report.save rescue => detail puts detail.backtrace if Puppet[:trace] Puppet.err "Could not send report: #{detail}" end end end end diff --git a/lib/puppet/face/resource.rb b/lib/puppet/face/resource.rb new file mode 100644 index 000000000..d162f728a --- /dev/null +++ b/lib/puppet/face/resource.rb @@ -0,0 +1,4 @@ +require 'puppet/face/indirector' + +Puppet::Face::Indirector.define(:resource, '0.0.1') do +end diff --git a/lib/puppet/face/resource_type.rb b/lib/puppet/face/resource_type.rb new file mode 100644 index 000000000..0cdbd719f --- /dev/null +++ b/lib/puppet/face/resource_type.rb @@ -0,0 +1,4 @@ +require 'puppet/face/indirector' + +Puppet::Face::Indirector.define(:resource_type, '0.0.1') do +end diff --git a/lib/puppet/face/status.rb b/lib/puppet/face/status.rb new file mode 100644 index 000000000..7085e7cd7 --- /dev/null +++ b/lib/puppet/face/status.rb @@ -0,0 +1,4 @@ +require 'puppet/face/indirector' + +Puppet::Face::Indirector.define(:status, '0.0.1') do +end diff --git a/lib/puppet/faces/certificate_request.rb b/lib/puppet/faces/certificate_request.rb deleted file mode 100644 index 5e91bdb7f..000000000 --- a/lib/puppet/faces/certificate_request.rb +++ /dev/null @@ -1,4 +0,0 @@ -require 'puppet/faces/indirector' - -Puppet::Faces::Indirector.define(:certificate_request, '0.0.1') do -end diff --git a/lib/puppet/faces/certificate_revocation_list.rb b/lib/puppet/faces/certificate_revocation_list.rb deleted file mode 100644 index 2f2d72874..000000000 --- a/lib/puppet/faces/certificate_revocation_list.rb +++ /dev/null @@ -1,4 +0,0 @@ -require 'puppet/faces/indirector' - -Puppet::Faces::Indirector.define(:certificate_revocation_list, '0.0.1') do -end diff --git a/lib/puppet/faces/configurer.rb b/lib/puppet/faces/configurer.rb deleted file mode 100644 index d40987697..000000000 --- a/lib/puppet/faces/configurer.rb +++ /dev/null @@ -1,12 +0,0 @@ -require 'puppet/faces' - -Puppet::Faces.define(:configurer, '0.0.1') do - action(:synchronize) do - when_invoked do |certname, options| - facts = Puppet::Faces[:facts, '0.0.1'].find(certname) - catalog = Puppet::Faces[:catalog, '0.0.1'].download(certname, facts) - report = Puppet::Faces[:catalog, '0.0.1'].apply(catalog) - report - end - end -end diff --git a/lib/puppet/faces/file.rb b/lib/puppet/faces/file.rb deleted file mode 100644 index e8ad18c17..000000000 --- a/lib/puppet/faces/file.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'puppet/faces/indirector' - -Puppet::Faces::Indirector.define(:file, '0.0.1') do - set_indirection_name :file_bucket_file -end diff --git a/lib/puppet/faces/key.rb b/lib/puppet/faces/key.rb deleted file mode 100644 index 7b6ad52ac..000000000 --- a/lib/puppet/faces/key.rb +++ /dev/null @@ -1,4 +0,0 @@ -require 'puppet/faces/indirector' - -Puppet::Faces::Indirector.define(:key, '0.0.1') do -end diff --git a/lib/puppet/faces/node.rb b/lib/puppet/faces/node.rb deleted file mode 100644 index 7eed0df91..000000000 --- a/lib/puppet/faces/node.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'puppet/faces/indirector' - -Puppet::Faces::Indirector.define(:node, '0.0.1') do - set_default_format :yaml -end diff --git a/lib/puppet/faces/resource.rb b/lib/puppet/faces/resource.rb deleted file mode 100644 index 60b0d94db..000000000 --- a/lib/puppet/faces/resource.rb +++ /dev/null @@ -1,4 +0,0 @@ -require 'puppet/faces/indirector' - -Puppet::Faces::Indirector.define(:resource, '0.0.1') do -end diff --git a/lib/puppet/faces/resource_type.rb b/lib/puppet/faces/resource_type.rb deleted file mode 100644 index 4321d65e7..000000000 --- a/lib/puppet/faces/resource_type.rb +++ /dev/null @@ -1,4 +0,0 @@ -require 'puppet/faces/indirector' - -Puppet::Faces::Indirector.define(:resource_type, '0.0.1') do -end diff --git a/lib/puppet/faces/status.rb b/lib/puppet/faces/status.rb deleted file mode 100644 index e035f281f..000000000 --- a/lib/puppet/faces/status.rb +++ /dev/null @@ -1,4 +0,0 @@ -require 'puppet/faces/indirector' - -Puppet::Faces::Indirector.define(:status, '0.0.1') do -end diff --git a/lib/puppet/interface.rb b/lib/puppet/interface.rb index 27b3584b9..6570ebe46 100644 --- a/lib/puppet/interface.rb +++ b/lib/puppet/interface.rb @@ -1,120 +1,120 @@ require 'puppet' require 'puppet/util/autoload' class Puppet::Interface require 'puppet/interface/face_collection' require 'puppet/interface/action_manager' include Puppet::Interface::ActionManager extend Puppet::Interface::ActionManager require 'puppet/interface/option_manager' include Puppet::Interface::OptionManager extend Puppet::Interface::OptionManager include Puppet::Util class << self # This is just so we can search for actions. We only use its # list of directories to search. # Can't we utilize an external autoloader, or simply use the $LOAD_PATH? -pvb def autoloader - @autoloader ||= Puppet::Util::Autoload.new(:application, "puppet/faces") + @autoloader ||= Puppet::Util::Autoload.new(:application, "puppet/face") end def faces Puppet::Interface::FaceCollection.faces end def face?(name, version) Puppet::Interface::FaceCollection.face?(name, version) end def register(instance) Puppet::Interface::FaceCollection.register(instance) end def define(name, version, &block) if face?(name, version) face = Puppet::Interface::FaceCollection[name, version] else face = self.new(name, version) Puppet::Interface::FaceCollection.register(face) # REVISIT: Shouldn't this be delayed until *after* we evaluate the # current block, not done before? --daniel 2011-04-07 face.load_actions end face.instance_eval(&block) if block_given? return face end def [](name, version) unless face = Puppet::Interface::FaceCollection[name, version] if current = Puppet::Interface::FaceCollection[name, :current] raise Puppet::Error, "Could not find version #{version} of #{current}" else raise Puppet::Error, "Could not find Puppet Face #{name.inspect}" end end face end end attr_accessor :default_format def set_default_format(format) self.default_format = format.to_sym end attr_accessor :summary def summary(value = nil) @summary = value unless value.nil? @summary end attr_reader :name, :version def initialize(name, version, &block) unless Puppet::Interface::FaceCollection.validate_version(version) raise ArgumentError, "Cannot create face #{name.inspect} with invalid version number '#{version}'!" end @name = Puppet::Interface::FaceCollection.underscorize(name) @version = version @default_format = :pson instance_eval(&block) if block_given? end # Try to find actions defined in other files. def load_actions - path = "puppet/faces/#{name}" + path = "puppet/face/#{name}" loaded = [] [path, "#{name}@#{version}/#{path}"].each do |path| Puppet::Interface.autoloader.search_directories.each do |dir| fdir = ::File.join(dir, path) next unless FileTest.directory?(fdir) Dir.chdir(fdir) do Dir.glob("*.rb").each do |file| aname = file.sub(/\.rb/, '') if loaded.include?(aname) Puppet.debug "Not loading duplicate action '#{aname}' for '#{name}' from '#{fdir}/#{file}'" next end loaded << aname Puppet.debug "Loading action '#{aname}' for '#{name}' from '#{fdir}/#{file}'" require "#{Dir.pwd}/#{aname}" end end end end end def to_s - "Puppet::Faces[#{name.inspect}, #{version.inspect}]" + "Puppet::Face[#{name.inspect}, #{version.inspect}]" end end diff --git a/lib/puppet/interface/face_collection.rb b/lib/puppet/interface/face_collection.rb index e4eb22fa3..591471d4b 100644 --- a/lib/puppet/interface/face_collection.rb +++ b/lib/puppet/interface/face_collection.rb @@ -1,131 +1,131 @@ # -*- coding: utf-8 -*- require 'puppet/interface' module Puppet::Interface::FaceCollection SEMVER_VERSION = /^(\d+)\.(\d+)\.(\d+)([A-Za-z][0-9A-Za-z-]*|)$/ @faces = Hash.new { |hash, key| hash[key] = {} } def self.faces unless @loaded @loaded = true $LOAD_PATH.each do |dir| next unless FileTest.directory?(dir) Dir.chdir(dir) do - Dir.glob("puppet/faces/*.rb").collect { |f| f.sub(/\.rb/, '') }.each do |file| + Dir.glob("puppet/face/*.rb").collect { |f| f.sub(/\.rb/, '') }.each do |file| iname = file.sub(/\.rb/, '') begin require iname rescue Exception => detail puts detail.backtrace if Puppet[:trace] raise "Could not load #{iname} from #{dir}/#{file}: #{detail}" end end end end end return @faces.keys end def self.validate_version(version) !!(SEMVER_VERSION =~ version.to_s) end def self.cmp_semver(a, b) a, b = [a, b].map do |x| parts = SEMVER_VERSION.match(x).to_a[1..4] parts[0..2] = parts[0..2].map { |e| e.to_i } parts end cmp = a[0..2] <=> b[0..2] if cmp == 0 cmp = a[3] <=> b[3] cmp = +1 if a[3].empty? && !b[3].empty? cmp = -1 if b[3].empty? && !a[3].empty? end cmp end def self.[](name, version) @faces[underscorize(name)][version] if face?(name, version) end def self.face?(name, version) name = underscorize(name) # Note: be careful not to accidentally create the top level key, either, # because it will result in confusion when people try to enumerate the # list of valid faces later. --daniel 2011-04-11 return true if @faces.has_key?(name) and @faces[name].has_key?(version) # We always load the current version file; the common case is that we have # the expected version and any compatibility versions in the same file, # the default. Which means that this is almost always the case. # # We use require to avoid executing the code multiple times, like any # other Ruby library that we might want to use. --daniel 2011-04-06 begin - require "puppet/faces/#{name}" + require "puppet/face/#{name}" # If we wanted :current, we need to index to find that; direct version # requests just work™ as they go. --daniel 2011-04-06 if version == :current then # We need to find current out of this. This is the largest version # number that doesn't have a dedicated on-disk file present; those # represent "experimental" versions of faces, which we don't fully # support yet. # # We walk the versions from highest to lowest and take the first version # that is not defined in an explicitly versioned file on disk as the # current version. # # This constrains us to only ship experimental versions with *one* # version in the file, not multiple, but given you can't reliably load # them except by side-effect when you ignore that rule this seems safe # enough... # # Given those constraints, and that we are not going to ship a versioned # interface that is not :current in this release, we are going to leave # these thoughts in place, and just punt on the actual versioning. # # When we upgrade the core to support multiple versions we can solve the # problems then; as lazy as possible. # # We do support multiple versions in the same file, though, so we sort # versions here and return the last item in that set. # # --daniel 2011-04-06 latest_ver = @faces[name].keys.sort {|a, b| cmp_semver(a, b) }.last @faces[name][:current] = @faces[name][latest_ver] end rescue LoadError => e - raise unless e.message =~ %r{-- puppet/faces/#{name}$} + raise unless e.message =~ %r{-- puppet/face/#{name}$} # ...guess we didn't find the file; return a much better problem. end # Now, either we have the version in our set of faces, or we didn't find # the version they were looking for. In the future we will support # loading versioned stuff from some look-aside part of the Ruby load path, # but we don't need that right now. # # So, this comment is a place-holder for that. --daniel 2011-04-06 # # Note: be careful not to accidentally create the top level key, either, # because it will result in confusion when people try to enumerate the # list of valid faces later. --daniel 2011-04-11 return !! (@faces.has_key?(name) and @faces[name].has_key?(version)) end def self.register(face) @faces[underscorize(face.name)][face.version] = face end def self.underscorize(name) unless name.to_s =~ /^[-_a-z]+$/i then raise ArgumentError, "#{name.inspect} (#{name.class}) is not a valid face name" end name.to_s.downcase.split(/[-_]/).join('_').to_sym end end diff --git a/lib/puppet/util/command_line.rb b/lib/puppet/util/command_line.rb index fa462ee2d..a884b8658 100644 --- a/lib/puppet/util/command_line.rb +++ b/lib/puppet/util/command_line.rb @@ -1,112 +1,112 @@ require "puppet/util/plugins" module Puppet module Util class CommandLine LegacyName = Hash.new{|h,k| k}.update( 'agent' => 'puppetd', 'cert' => 'puppetca', 'doc' => 'puppetdoc', 'filebucket' => 'filebucket', 'apply' => 'puppet', 'describe' => 'pi', 'queue' => 'puppetqd', 'resource' => 'ralsh', 'kick' => 'puppetrun', 'master' => 'puppetmasterd' ) def initialize(zero = $0, argv = ARGV, stdin = STDIN) @zero = zero @argv = argv.dup @stdin = stdin @subcommand_name, @args = subcommand_and_args(@zero, @argv, @stdin) Puppet::Plugins.on_commandline_initialization(:command_line_object => self) end attr :subcommand_name attr :args def appdir File.join('puppet', 'application') end def self.available_subcommands absolute_appdirs = $LOAD_PATH.collect do |x| File.join(x,'puppet','application') end.select{ |x| File.directory?(x) } absolute_appdirs.inject([]) do |commands, dir| commands + Dir[File.join(dir, '*.rb')].map{|fn| File.basename(fn, '.rb')} end.uniq end # available_subcommands was previously an instance method, not a class # method, and we have an unknown number of user-implemented applications # that depend on that behaviour. Forwarding allows us to preserve a # backward compatible API. --daniel 2011-04-11 def available_subcommands self.class.available_subcommands end def require_application(application) require File.join(appdir, application) end def execute if subcommand_name and available_subcommands.include?(subcommand_name) then require_application subcommand_name app = Puppet::Application.find(subcommand_name).new(self) Puppet::Plugins.on_application_initialization(:appliation_object => self) app.run elsif execute_external_subcommand then # Logically, we shouldn't get here, but we do, so whatever. We just # return to the caller. How strange we are. --daniel 2011-04-11 else unless subcommand_name.nil? then puts "Error: Unknown Puppet subcommand #{subcommand_name}.\n" end # Doing this at the top of the file is natural, but causes puppet.rb # to load too early, which causes things to break. This is a nasty # thing, found in #7065. --daniel 2011-04-11 - require 'puppet/faces/help' - puts Puppet::Faces[:help, :current].help + require 'puppet/face' + puts Puppet::Face[:help, :current].help end end def execute_external_subcommand external_command = "puppet-#{subcommand_name}" require 'puppet/util' path_to_subcommand = Puppet::Util.which(external_command) return false unless path_to_subcommand system(path_to_subcommand, *args) true end def legacy_executable_name LegacyName[ subcommand_name ] end private def subcommand_and_args(zero, argv, stdin) zero = File.basename(zero, '.rb') if zero == 'puppet' case argv.first when nil; [ stdin.tty? ? nil : "apply", argv] # ttys get usage info when "--help", "-h"; [nil, argv] # help should give you usage, not the help for `puppet apply` when /^-|\.pp$|\.rb$/; ["apply", argv] else [ argv.first, argv[1..-1] ] end else [ zero, argv ] end end end end end diff --git a/lib/puppet/util/selinux.rb b/lib/puppet/util/selinux.rb index 9d0e0a715..cec8a57d9 100644 --- a/lib/puppet/util/selinux.rb +++ b/lib/puppet/util/selinux.rb @@ -1,216 +1,216 @@ -# Provides utility functions to help interfaces Puppet to SELinux. +# Provides utility functions to help interface Puppet to SELinux. # # This requires the very new SELinux Ruby bindings. These bindings closely # mirror the SELinux C library interface. # # Support for the command line tools is not provided because the performance # was abysmal. At this time (2008-11-02) the only distribution providing # these Ruby SELinux bindings which I am aware of is Fedora (in libselinux-ruby). Puppet.features.selinux? # check, but continue even if it's not require 'pathname' module Puppet::Util::SELinux def selinux_support? return false unless defined?(Selinux) if Selinux.is_selinux_enabled == 1 return true end false end # Retrieve and return the full context of the file. If we don't have # SELinux support or if the SELinux call fails then return nil. def get_selinux_current_context(file) return nil unless selinux_support? retval = Selinux.lgetfilecon(file) if retval == -1 return nil end retval[1] end # Retrieve and return the default context of the file. If we don't have # SELinux support or if the SELinux call fails to file a default then return nil. def get_selinux_default_context(file) return nil unless selinux_support? # If the filesystem has no support for SELinux labels, return a default of nil # instead of what matchpathcon would return return nil unless selinux_label_support?(file) # If the file exists we should pass the mode to matchpathcon for the most specific # matching. If not, we can pass a mode of 0. begin filestat = File.lstat(file) mode = filestat.mode rescue Errno::ENOENT mode = 0 end retval = Selinux.matchpathcon(file, mode) if retval == -1 return nil end retval[1] end # Take the full SELinux context returned from the tools and parse it # out to the three (or four) component parts. Supports :seluser, :selrole, # :seltype, and on systems with range support, :selrange. def parse_selinux_context(component, context) if context.nil? or context == "unlabeled" return nil end unless context =~ /^([a-z0-9_]+):([a-z0-9_]+):([a-zA-Z0-9_]+)(?::([a-zA-Z0-9:,._-]+))?/ raise Puppet::Error, "Invalid context to parse: #{context}" end ret = { :seluser => $1, :selrole => $2, :seltype => $3, :selrange => $4, } ret[component] end # This updates the actual SELinux label on the file. You can update # only a single component or update the entire context. # The caveat is that since setting a partial context makes no sense the # file has to already exist. Puppet (via the File resource) will always # just try to set components, even if all values are specified by the manifest. # I believe that the OS should always provide at least a fall-through context # though on any well-running system. def set_selinux_context(file, value, component = false) return nil unless selinux_support? && selinux_label_support?(file) if component # Must first get existing context to replace a single component context = Selinux.lgetfilecon(file)[1] if context == -1 # We can't set partial context components when no context exists # unless/until we can find a way to make Puppet call this method # once for all selinux file label attributes. Puppet.warning "Can't set SELinux context on file unless the file already has some kind of context" return nil end context = context.split(':') case component when :seluser context[0] = value when :selrole context[1] = value when :seltype context[2] = value when :selrange context[3] = value else raise ArguementError, "set_selinux_context component must be one of :seluser, :selrole, :seltype, or :selrange" end context = context.join(':') else context = value end retval = Selinux.lsetfilecon(file, context) if retval == 0 return true else Puppet.warning "Failed to set SELinux context #{context} on #{file}" return false end end # Since this call relies on get_selinux_default_context it also needs a # full non-relative path to the file. Fortunately, that seems to be all # Puppet uses. This will set the file's SELinux context to the policy's # default context (if any) if it differs from the context currently on # the file. def set_selinux_default_context(file) new_context = get_selinux_default_context(file) return nil unless new_context cur_context = get_selinux_current_context(file) if new_context != cur_context set_selinux_context(file, new_context) return new_context end nil end # Internal helper function to read and parse /proc/mounts def read_mounts mounts = "" begin if File.instance_methods.include? "read_nonblock" # If possible we use read_nonblock in a loop rather than read to work- # a linux kernel bug. See ticket #1963 for details. mountfh = File.open("/proc/mounts") mounts += mountfh.read_nonblock(1024) while true else # Otherwise we shell out and let cat do it for us mountfh = IO.popen("/bin/cat /proc/mounts") mounts = mountfh.read end rescue EOFError # that's expected rescue return nil ensure mountfh.close if mountfh end mntpoint = {} # Read all entries in /proc/mounts. The second column is the # mountpoint and the third column is the filesystem type. # We skip rootfs because it is always mounted at / mounts.collect do |line| params = line.split(' ') next if params[2] == 'rootfs' mntpoint[params[1]] = params[2] end mntpoint end def realpath(path) path, rest = Pathname.new(path), [] path, rest = path.dirname, [path.basename] + rest while ! path.exist? File.join( path.realpath, *rest ) end def parent_directory(path) Pathname.new(path).dirname.to_s end # Internal helper function to return which type of filesystem a # given file path resides on def find_fs(path) unless mnts = read_mounts return nil end # For a given file: # Check if the filename is in the data structure; # return the fstype if it is. # Just in case: return something if you're down to "/" or "" # Remove the last slash and everything after it, # and repeat with that as the file for the next loop through. path = realpath(path) while not path.empty? return mnts[path] if mnts.has_key?(path) path = parent_directory(path) end mnts['/'] end # Check filesystem a path resides on for SELinux support against # whitelist of known-good filesystems. # Returns true if the filesystem can support SELinux labels and # false if not. def selinux_label_support?(file) fstype = find_fs(file) return false if fstype.nil? filesystems = ['ext2', 'ext3', 'ext4', 'gfs', 'gfs2', 'xfs', 'jfs'] filesystems.include?(fstype) end end diff --git a/spec/integration/application/apply_spec.rb b/spec/integration/application/apply_spec.rb index 33b00a1f6..84acc28b2 100755 --- a/spec/integration/application/apply_spec.rb +++ b/spec/integration/application/apply_spec.rb @@ -1,30 +1,29 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet_spec/files' require 'puppet/application/apply' describe "apply" do include PuppetSpec::Files describe "when applying provided catalogs", :if => Puppet.features.pson? do it "should be able to apply catalogs provided in a file in pson" do file_to_create = tmpfile("pson_catalog") catalog = Puppet::Resource::Catalog.new resource = Puppet::Resource.new(:file, file_to_create, :parameters => {:content => "my stuff"}) catalog.add_resource resource manifest = tmpfile("manifest") File.open(manifest, "w") { |f| f.print catalog.to_pson } puppet = Puppet::Application[:apply] puppet.options[:catalog] = manifest puppet.apply File.should be_exist(file_to_create) File.read(file_to_create).should == "my stuff" end end end diff --git a/spec/integration/application/doc_spec.rb b/spec/integration/application/doc_spec.rb index bcff8f756..df9b91608 100755 --- a/spec/integration/application/doc_spec.rb +++ b/spec/integration/application/doc_spec.rb @@ -1,55 +1,54 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet_spec/files' describe Puppet::Application::Doc do include PuppetSpec::Files it "should not generate an error when module dir overlaps parent of site.pp (#4798)" do begin # Note: the directory structure below is more complex than it # needs to be, but it's representative of the directory structure # used in bug #4798. old_dir = Dir.getwd # Note: can't use chdir with a block because it will generate bogus warnings tmpdir = tmpfile('doc_spec') Dir.mkdir(tmpdir) Dir.chdir(tmpdir) site_file = 'site.pp' File.open(site_file, 'w') do |f| f.puts '# A comment' end modules_dir = 'modules' Dir.mkdir(modules_dir) rt_dir = File.join(modules_dir, 'rt') Dir.mkdir(rt_dir) manifests_dir = File.join(rt_dir, 'manifests') Dir.mkdir(manifests_dir) rt_file = File.join(manifests_dir, 'rt.pp') File.open(rt_file, 'w') do |f| f.puts '# A class' f.puts 'class foo { }' f.puts '# A definition' f.puts 'define bar { }' end puppet = Puppet::Application[:doc] Puppet[:modulepath] = modules_dir Puppet[:manifest] = site_file puppet.options[:mode] = :rdoc puppet.expects(:exit).with(0) puppet.run_command File.should be_exist('doc') ensure Dir.chdir(old_dir) end end it "should respect the -o option" do puppetdoc = Puppet::Application[:doc] puppetdoc.command_line.stubs(:args).returns(['foo', '-o', 'bar']) puppetdoc.parse_options puppetdoc.options[:outputdir].should == 'bar' end end diff --git a/spec/integration/configurer_spec.rb b/spec/integration/configurer_spec.rb index f826b0f5d..f5d8bceb2 100755 --- a/spec/integration/configurer_spec.rb +++ b/spec/integration/configurer_spec.rb @@ -1,73 +1,72 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/configurer' describe Puppet::Configurer do include PuppetSpec::Files describe "when downloading plugins" do it "should use the :pluginsignore setting, split on whitespace, for ignoring remote files" do resource = Puppet::Type.type(:notify).new :name => "yay" Puppet::Type.type(:file).expects(:new).with { |args| args[:ignore] == Puppet[:pluginsignore].split(/\s+/) }.returns resource configurer = Puppet::Configurer.new configurer.stubs(:download_plugins?).returns true configurer.download_plugins end end describe "when running" do before(:each) do @catalog = Puppet::Resource::Catalog.new @catalog.add_resource(Puppet::Type.type(:notify).new(:title => "testing")) # Make sure we don't try to persist the local state after the transaction ran, # because it will fail during test (the state file is in an not existing directory) # and we need the transaction to be successful to be able to produce a summary report @catalog.host_config = false @configurer = Puppet::Configurer.new end it "should send a transaction report with valid data" do @configurer.stubs(:save_last_run_summary) Puppet::Transaction::Report.indirection.expects(:save).with do |report, x| report.time.class == Time and report.logs.length > 0 end Puppet[:report] = true @configurer.run :catalog => @catalog end it "should save a correct last run summary" do report = Puppet::Transaction::Report.new("apply") Puppet::Transaction::Report.indirection.stubs(:save) Puppet[:lastrunfile] = tmpfile("lastrunfile") Puppet[:report] = true # We only record integer seconds in the timestamp, and truncate # backwards, so don't use a more accurate timestamp in the test. # --daniel 2011-03-07 t1 = Time.now.tv_sec @configurer.run :catalog => @catalog, :report => report t2 = Time.now.tv_sec summary = nil File.open(Puppet[:lastrunfile], "r") do |fd| summary = YAML.load(fd.read) end summary.should be_a(Hash) %w{time changes events resources}.each do |key| summary.should be_key(key) end summary["time"].should be_key("notify") summary["time"]["last_run"].should be_between(t1, t2) end end end diff --git a/spec/integration/defaults_spec.rb b/spec/integration/defaults_spec.rb index c9b41d331..8aa59288e 100755 --- a/spec/integration/defaults_spec.rb +++ b/spec/integration/defaults_spec.rb @@ -1,259 +1,258 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/defaults' require 'puppet/rails' describe "Puppet defaults" do include Puppet::Util::Execution after { Puppet.settings.clear } describe "when setting the :factpath" do it "should add the :factpath to Facter's search paths" do Facter.expects(:search).with("/my/fact/path") Puppet.settings[:factpath] = "/my/fact/path" end end describe "when setting the :certname" do it "should fail if the certname is not downcased" do lambda { Puppet.settings[:certname] = "Host.Domain.Com" }.should raise_error(ArgumentError) end end describe "when configuring the :crl" do it "should warn if :cacrl is set to false" do Puppet.expects(:warning) Puppet.settings[:cacrl] = 'false' end end describe "when setting the :catalog_format" do it "should log a deprecation notice" do Puppet.expects(:warning) Puppet.settings[:catalog_format] = 'marshal' end it "should copy the value to :preferred_serialization_format" do Puppet.settings[:catalog_format] = 'marshal' Puppet.settings[:preferred_serialization_format].should == 'marshal' end end it "should have a clientyamldir setting" do Puppet.settings[:clientyamldir].should_not be_nil end it "should have different values for the yamldir and clientyamldir" do Puppet.settings[:yamldir].should_not == Puppet.settings[:clientyamldir] end it "should have a client_datadir setting" do Puppet.settings[:client_datadir].should_not be_nil end it "should have different values for the server_datadir and client_datadir" do Puppet.settings[:server_datadir].should_not == Puppet.settings[:client_datadir] end # See #1232 it "should not specify a user or group for the clientyamldir" do Puppet.settings.setting(:clientyamldir).owner.should be_nil Puppet.settings.setting(:clientyamldir).group.should be_nil end it "should use the service user and group for the yamldir" do Puppet.settings.stubs(:service_user_available?).returns true Puppet.settings.setting(:yamldir).owner.should == Puppet.settings[:user] Puppet.settings.setting(:yamldir).group.should == Puppet.settings[:group] end # See #1232 it "should not specify a user or group for the rundir" do Puppet.settings.setting(:rundir).owner.should be_nil Puppet.settings.setting(:rundir).group.should be_nil end it "should specify that the host private key should be owned by the service user" do Puppet.settings.stubs(:service_user_available?).returns true Puppet.settings.setting(:hostprivkey).owner.should == Puppet.settings[:user] end it "should specify that the host certificate should be owned by the service user" do Puppet.settings.stubs(:service_user_available?).returns true Puppet.settings.setting(:hostcert).owner.should == Puppet.settings[:user] end it "should use a bind address of ''" do Puppet.settings.clear Puppet.settings[:bindaddress].should == "" end [:factdest].each do |setting| it "should force the :factdest to be a directory" do Puppet.settings[setting].should =~ /\/$/ end end [:modulepath, :factpath].each do |setting| it "should configure '#{setting}' not to be a file setting, so multi-directory settings are acceptable" do Puppet.settings.setting(setting).should be_instance_of(Puppet::Util::Settings::Setting) end end it "should add /usr/sbin and /sbin to the path if they're not there" do withenv("PATH" => "/usr/bin:/usr/local/bin") do Puppet.settings[:path] = "none" # this causes it to ignore the setting ENV["PATH"].split(File::PATH_SEPARATOR).should be_include("/usr/sbin") ENV["PATH"].split(File::PATH_SEPARATOR).should be_include("/sbin") end end it "should default to pson for the preferred serialization format" do Puppet.settings.value(:preferred_serialization_format).should == "pson" end describe "when enabling storeconfigs" do before do Puppet::Resource::Catalog.indirection.stubs(:cache_class=) Puppet::Node::Facts.indirection.stubs(:cache_class=) Puppet::Node.indirection.stubs(:cache_class=) Puppet.features.stubs(:rails?).returns true end it "should set the Catalog cache class to :active_record" do Puppet::Resource::Catalog.indirection.expects(:cache_class=).with(:active_record) Puppet.settings[:storeconfigs] = true end it "should not set the Catalog cache class to :active_record if asynchronous storeconfigs is enabled" do Puppet::Resource::Catalog.indirection.expects(:cache_class=).with(:active_record).never Puppet.settings.expects(:value).with(:async_storeconfigs).returns true Puppet.settings[:storeconfigs] = true end it "should set the Facts cache class to :active_record" do Puppet::Node::Facts.indirection.expects(:cache_class=).with(:active_record) Puppet.settings[:storeconfigs] = true end it "should set the Node cache class to :active_record" do Puppet::Node.indirection.expects(:cache_class=).with(:active_record) Puppet.settings[:storeconfigs] = true end it "should fail if rails is not available" do Puppet.features.stubs(:rails?).returns false lambda { Puppet.settings[:storeconfigs] = true }.should raise_error end end describe "when enabling asynchronous storeconfigs" do before do Puppet::Resource::Catalog.indirection.stubs(:cache_class=) Puppet::Node::Facts.indirection.stubs(:cache_class=) Puppet::Node.indirection.stubs(:cache_class=) Puppet.features.stubs(:rails?).returns true end it "should set storeconfigs to true" do Puppet.settings[:async_storeconfigs] = true Puppet.settings[:storeconfigs].should be_true end it "should set the Catalog cache class to :queue" do Puppet::Resource::Catalog.indirection.expects(:cache_class=).with(:queue) Puppet.settings[:async_storeconfigs] = true end it "should set the Facts cache class to :active_record" do Puppet::Node::Facts.indirection.expects(:cache_class=).with(:active_record) Puppet.settings[:storeconfigs] = true end it "should set the Node cache class to :active_record" do Puppet::Node.indirection.expects(:cache_class=).with(:active_record) Puppet.settings[:storeconfigs] = true end end describe "when enabling thin storeconfigs" do before do Puppet::Resource::Catalog.indirection.stubs(:cache_class=) Puppet::Node::Facts.indirection.stubs(:cache_class=) Puppet::Node.indirection.stubs(:cache_class=) Puppet.features.stubs(:rails?).returns true end it "should set storeconfigs to true" do Puppet.settings[:thin_storeconfigs] = true Puppet.settings[:storeconfigs].should be_true end end it "should have a setting for determining the configuration version and should default to an empty string" do Puppet.settings[:config_version].should == "" end describe "when enabling reports" do it "should use the default server value when report server is unspecified" do Puppet.settings[:server] = "server" Puppet.settings[:report_server].should == "server" end it "should use the default masterport value when report port is unspecified" do Puppet.settings[:masterport] = "1234" Puppet.settings[:report_port].should == "1234" end it "should set report_server when reportserver is set" do Puppet.settings[:reportserver] = "reportserver" Puppet.settings[:report_server].should == "reportserver" end it "should use report_port when set" do Puppet.settings[:masterport] = "1234" Puppet.settings[:report_port] = "5678" Puppet.settings[:report_port].should == "5678" end it "should prefer report_server over reportserver" do Puppet.settings[:reportserver] = "reportserver" Puppet.settings[:report_server] = "report_server" Puppet.settings[:report_server].should == "report_server" end end it "should have a :caname setting that defaults to the cert name" do Puppet.settings[:certname] = "foo" Puppet.settings[:ca_name].should == "Puppet CA: foo" end it "should have a 'prerun_command' that defaults to the empty string" do Puppet.settings[:prerun_command].should == "" end it "should have a 'postrun_command' that defaults to the empty string" do Puppet.settings[:postrun_command].should == "" end it "should have a 'certificate_revocation' setting that defaults to true" do Puppet.settings[:certificate_revocation].should be_true end it "should have an http_compression setting that defaults to false" do Puppet.settings[:http_compression].should be_false end describe "reportdir" do subject { Puppet.settings[:reportdir] } it { should == "#{Puppet[:vardir]}/reports" } end describe "reporturl" do subject { Puppet.settings[:reporturl] } it { should == "http://localhost:3000/reports" } end end diff --git a/spec/integration/file_serving/content_spec.rb b/spec/integration/file_serving/content_spec.rb index d9d79ec4f..a95ddc520 100755 --- a/spec/integration/file_serving/content_spec.rb +++ b/spec/integration/file_serving/content_spec.rb @@ -1,20 +1,20 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Created by Luke Kanies on 2007-10-18. # Copyright (c) 2007. All rights reserved. require 'spec_helper' require 'puppet/file_serving/content' require 'shared_behaviours/file_serving' describe Puppet::FileServing::Content, " when finding files" do it_should_behave_like "Puppet::FileServing::Files" before do @test_class = Puppet::FileServing::Content @indirection = Puppet::FileServing::Content.indirection end after { Puppet::Util::Cacher.expire } end diff --git a/spec/integration/file_serving/fileset_spec.rb b/spec/integration/file_serving/fileset_spec.rb index 858186794..f4b869847 100755 --- a/spec/integration/file_serving/fileset_spec.rb +++ b/spec/integration/file_serving/fileset_spec.rb @@ -1,14 +1,13 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/file_serving/fileset' describe Puppet::FileServing::Fileset do it "should be able to recurse on a single file" do @path = Tempfile.new("fileset_integration") fileset = Puppet::FileServing::Fileset.new(@path.path) lambda { fileset.files }.should_not raise_error end end diff --git a/spec/integration/file_serving/metadata_spec.rb b/spec/integration/file_serving/metadata_spec.rb index f5ae616e1..ba7d3311f 100755 --- a/spec/integration/file_serving/metadata_spec.rb +++ b/spec/integration/file_serving/metadata_spec.rb @@ -1,21 +1,21 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Created by Luke Kanies on 2007-10-18. # Copyright (c) 2007. All rights reserved. require 'spec_helper' require 'puppet/file_serving/metadata' require 'shared_behaviours/file_serving' require 'puppet/indirector/file_metadata/file_server' describe Puppet::FileServing::Metadata, " when finding files" do it_should_behave_like "Puppet::FileServing::Files" before do @test_class = Puppet::FileServing::Metadata @indirection = Puppet::FileServing::Metadata.indirection end after { Puppet::Util::Cacher.expire } end diff --git a/spec/integration/file_serving/terminus_helper_spec.rb b/spec/integration/file_serving/terminus_helper_spec.rb index 650ae4d7b..7500b1fc0 100755 --- a/spec/integration/file_serving/terminus_helper_spec.rb +++ b/spec/integration/file_serving/terminus_helper_spec.rb @@ -1,22 +1,21 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/file_serving/terminus_helper' class TerminusHelperIntegrationTester include Puppet::FileServing::TerminusHelper def model Puppet::FileServing::Metadata end end describe Puppet::FileServing::TerminusHelper do it "should be able to recurse on a single file" do @path = Tempfile.new("fileset_integration") request = Puppet::Indirector::Request.new(:metadata, :find, @path.path, :recurse => true) tester = TerminusHelperIntegrationTester.new lambda { tester.path2instances(request, @path.path) }.should_not raise_error end end diff --git a/spec/integration/indirector/catalog/compiler_spec.rb b/spec/integration/indirector/catalog/compiler_spec.rb index 054b0377a..f51a3f24e 100755 --- a/spec/integration/indirector/catalog/compiler_spec.rb +++ b/spec/integration/indirector/catalog/compiler_spec.rb @@ -1,65 +1,64 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/resource/catalog' Puppet::Resource::Catalog.indirection.terminus(:compiler) describe Puppet::Resource::Catalog::Compiler do before do Facter.stubs(:value).returns "something" @catalog = Puppet::Resource::Catalog.new @catalog.add_resource(@one = Puppet::Resource.new(:file, "/one")) @catalog.add_resource(@two = Puppet::Resource.new(:file, "/two")) end after { Puppet.settings.clear } it "should remove virtual resources when filtering" do @one.virtual = true Puppet::Resource::Catalog.indirection.terminus.filter(@catalog).resource_refs.should == [ @two.ref ] end it "should not remove exported resources when filtering" do @one.exported = true Puppet::Resource::Catalog.indirection.terminus.filter(@catalog).resource_refs.sort.should == [ @one.ref, @two.ref ] end it "should remove virtual exported resources when filtering" do @one.exported = true @one.virtual = true Puppet::Resource::Catalog.indirection.terminus.filter(@catalog).resource_refs.should == [ @two.ref ] end it "should filter out virtual resources when finding a catalog" do @one.virtual = true request = stub 'request', :name => "mynode" Puppet::Resource::Catalog.indirection.terminus.stubs(:extract_facts_from_request) Puppet::Resource::Catalog.indirection.terminus.stubs(:node_from_request) Puppet::Resource::Catalog.indirection.terminus.stubs(:compile).returns(@catalog) Puppet::Resource::Catalog.indirection.find(request).resource_refs.should == [ @two.ref ] end it "should not filter out exported resources when finding a catalog" do @one.exported = true request = stub 'request', :name => "mynode" Puppet::Resource::Catalog.indirection.terminus.stubs(:extract_facts_from_request) Puppet::Resource::Catalog.indirection.terminus.stubs(:node_from_request) Puppet::Resource::Catalog.indirection.terminus.stubs(:compile).returns(@catalog) Puppet::Resource::Catalog.indirection.find(request).resource_refs.sort.should == [ @one.ref, @two.ref ] end it "should filter out virtual exported resources when finding a catalog" do @one.exported = true @one.virtual = true request = stub 'request', :name => "mynode" Puppet::Resource::Catalog.indirection.terminus.stubs(:extract_facts_from_request) Puppet::Resource::Catalog.indirection.terminus.stubs(:node_from_request) Puppet::Resource::Catalog.indirection.terminus.stubs(:compile).returns(@catalog) Puppet::Resource::Catalog.indirection.find(request).resource_refs.should == [ @two.ref ] end end diff --git a/spec/integration/indirector/catalog/queue_spec.rb b/spec/integration/indirector/catalog/queue_spec.rb index 5c781c1ae..569f096bf 100755 --- a/spec/integration/indirector/catalog/queue_spec.rb +++ b/spec/integration/indirector/catalog/queue_spec.rb @@ -1,58 +1,57 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/resource/catalog' describe "Puppet::Resource::Catalog::Queue", :if => Puppet.features.pson? do before do Puppet::Resource::Catalog.indirection.terminus(:queue) @catalog = Puppet::Resource::Catalog.new @one = Puppet::Resource.new(:file, "/one") @two = Puppet::Resource.new(:file, "/two") @catalog.add_resource(@one, @two) @catalog.add_edge(@one, @two) Puppet[:trace] = true end after { Puppet.settings.clear } it "should render catalogs to pson and send them via the queue client when catalogs are saved" do terminus = Puppet::Resource::Catalog.indirection.terminus(:queue) client = mock 'client' terminus.stubs(:client).returns client client.expects(:send_message).with(:catalog, @catalog.to_pson) request = Puppet::Indirector::Request.new(:catalog, :save, "foo", :instance => @catalog) terminus.save(request) end it "should intern catalog messages when they are passed via a subscription" do client = mock 'client' Puppet::Resource::Catalog::Queue.stubs(:client).returns client pson = @catalog.to_pson client.expects(:subscribe).with(:catalog).yields(pson) Puppet.expects(:err).never result = [] Puppet::Resource::Catalog::Queue.subscribe do |catalog| result << catalog end catalog = result.shift catalog.should be_instance_of(Puppet::Resource::Catalog) catalog.resource(:file, "/one").should be_instance_of(Puppet::Resource) catalog.resource(:file, "/two").should be_instance_of(Puppet::Resource) catalog.should be_edge(catalog.resource(:file, "/one"), catalog.resource(:file, "/two")) end end diff --git a/spec/integration/indirector/direct_file_server_spec.rb b/spec/integration/indirector/direct_file_server_spec.rb index 6ab3e4d83..e53b48d69 100755 --- a/spec/integration/indirector/direct_file_server_spec.rb +++ b/spec/integration/indirector/direct_file_server_spec.rb @@ -1,73 +1,73 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Created by Luke Kanies on 2007-10-19. # Copyright (c) 2007. All rights reserved. require 'spec_helper' require 'puppet/indirector/file_content/file' describe Puppet::Indirector::DirectFileServer, " when interacting with the filesystem and the model" do before do # We just test a subclass, since it's close enough. @terminus = Puppet::Indirector::FileContent::File.new @filepath = "/path/to/my/file" end it "should return an instance of the model" do FileTest.expects(:exists?).with(@filepath).returns(true) @terminus.find(@terminus.indirection.request(:find, "file://host#{@filepath}")).should be_instance_of(Puppet::FileServing::Content) end it "should return an instance capable of returning its content" do FileTest.expects(:exists?).with(@filepath).returns(true) File.stubs(:lstat).with(@filepath).returns(stub("stat", :ftype => "file")) File.expects(:read).with(@filepath).returns("my content") instance = @terminus.find(@terminus.indirection.request(:find, "file://host#{@filepath}")) instance.content.should == "my content" end end describe Puppet::Indirector::DirectFileServer, " when interacting with FileServing::Fileset and the model" do before do @terminus = Puppet::Indirector::FileContent::File.new @path = Tempfile.new("direct_file_server_testing") path = @path.path @path.close! @path = path Dir.mkdir(@path) File.open(File.join(@path, "one"), "w") { |f| f.print "one content" } File.open(File.join(@path, "two"), "w") { |f| f.print "two content" } @request = @terminus.indirection.request(:search, "file:///#{@path}", :recurse => true) end after do system("rm -rf #{@path}") end it "should return an instance for every file in the fileset" do result = @terminus.search(@request) result.should be_instance_of(Array) result.length.should == 3 result.each { |r| r.should be_instance_of(Puppet::FileServing::Content) } end it "should return instances capable of returning their content" do @terminus.search(@request).each do |instance| case instance.full_path when /one/; instance.content.should == "one content" when /two/; instance.content.should == "two content" when @path else raise "No valid key for #{instance.path.inspect}" end end end end diff --git a/spec/integration/indirector/file_content/file_server_spec.rb b/spec/integration/indirector/file_content/file_server_spec.rb index e1eb28f91..88d2345d8 100755 --- a/spec/integration/indirector/file_content/file_server_spec.rb +++ b/spec/integration/indirector/file_content/file_server_spec.rb @@ -1,94 +1,94 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Created by Luke Kanies on 2007-10-18. # Copyright (c) 2007. All rights reserved. require 'spec_helper' require 'puppet/indirector/file_content/file_server' require 'shared_behaviours/file_server_terminus' require 'puppet_spec/files' describe Puppet::Indirector::FileContent::FileServer, " when finding files" do it_should_behave_like "Puppet::Indirector::FileServerTerminus" include PuppetSpec::Files before do @terminus = Puppet::Indirector::FileContent::FileServer.new @test_class = Puppet::FileServing::Content end it "should find plugin file content in the environment specified in the request" do path = tmpfile("file_content_with_env") Dir.mkdir(path) modpath = File.join(path, "mod") FileUtils.mkdir_p(File.join(modpath, "lib")) file = File.join(modpath, "lib", "file.rb") File.open(file, "w") { |f| f.puts "1" } Puppet.settings[:modulepath] = "/no/such/file" env = Puppet::Node::Environment.new("foo") env.stubs(:modulepath).returns [path] result = Puppet::FileServing::Content.indirection.search("plugins", :environment => "foo", :recurse => true) result.should_not be_nil result.length.should == 2 result[1].should be_instance_of(Puppet::FileServing::Content) result[1].content.should == "1\n" end it "should find file content in modules" do path = tmpfile("file_content") Dir.mkdir(path) modpath = File.join(path, "mymod") FileUtils.mkdir_p(File.join(modpath, "files")) file = File.join(modpath, "files", "myfile") File.open(file, "w") { |f| f.puts "1" } Puppet.settings[:modulepath] = path result = Puppet::FileServing::Content.indirection.find("modules/mymod/myfile") result.should_not be_nil result.should be_instance_of(Puppet::FileServing::Content) result.content.should == "1\n" end it "should find file content in files when node name expansions are used" do Puppet::Util::Cacher.expire FileTest.stubs(:exists?).returns true FileTest.stubs(:exists?).with(Puppet[:fileserverconfig]).returns(true) @path = tmpfile("file_server_testing") Dir.mkdir(@path) subdir = File.join(@path, "mynode") Dir.mkdir(subdir) File.open(File.join(subdir, "myfile"), "w") { |f| f.puts "1" } # Use a real mount, so the integration is a bit deeper. @mount1 = Puppet::FileServing::Configuration::Mount::File.new("one") @mount1.stubs(:allowed?).returns true @mount1.path = File.join(@path, "%h") @parser = stub 'parser', :changed? => false @parser.stubs(:parse).returns("one" => @mount1) Puppet::FileServing::Configuration::Parser.stubs(:new).returns(@parser) path = File.join(@path, "myfile") result = Puppet::FileServing::Content.indirection.find("one/myfile", :environment => "foo", :node => "mynode") result.should_not be_nil result.should be_instance_of(Puppet::FileServing::Content) result.content.should == "1\n" end end diff --git a/spec/integration/indirector/file_metadata/file_server_spec.rb b/spec/integration/indirector/file_metadata/file_server_spec.rb index 7a973fcca..9e84134a6 100755 --- a/spec/integration/indirector/file_metadata/file_server_spec.rb +++ b/spec/integration/indirector/file_metadata/file_server_spec.rb @@ -1,18 +1,18 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Created by Luke Kanies on 2007-10-18. # Copyright (c) 2007. All rights reserved. require 'spec_helper' require 'puppet/indirector/file_metadata/file_server' require 'shared_behaviours/file_server_terminus' describe Puppet::Indirector::FileMetadata::FileServer, " when finding files" do it_should_behave_like "Puppet::Indirector::FileServerTerminus" before do @terminus = Puppet::Indirector::FileMetadata::FileServer.new @test_class = Puppet::FileServing::Metadata end end diff --git a/spec/integration/indirector/node/ldap_spec.rb b/spec/integration/indirector/node/ldap_spec.rb index 9891702bd..7e53141dc 100755 --- a/spec/integration/indirector/node/ldap_spec.rb +++ b/spec/integration/indirector/node/ldap_spec.rb @@ -1,15 +1,14 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/indirector/node/ldap' describe Puppet::Node::Ldap do it "should use a restrictive filter when searching for nodes in a class" do ldap = Puppet::Node.indirection.terminus(:ldap) Puppet::Node.indirection.stubs(:terminus).returns ldap ldap.expects(:ldapsearch).with("(&(objectclass=puppetClient)(puppetclass=foo))") Puppet::Node.indirection.search "eh", :class => "foo" end end diff --git a/spec/integration/network/client_spec.rb b/spec/integration/network/client_spec.rb index 574da6a78..72174c75c 100755 --- a/spec/integration/network/client_spec.rb +++ b/spec/integration/network/client_spec.rb @@ -1,19 +1,18 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/network/client' describe Puppet::Network::Client do %w{ca file report runner status}.each do |name| it "should have a #{name} client" do Puppet::Network::Client.client(name).should be_instance_of(Class) end [:name, :handler, :drivername].each do |data| it "should have a #{data} value for the #{name} client" do Puppet::Network::Client.client(name).send(data).should_not be_nil end end end end diff --git a/spec/integration/network/formats_spec.rb b/spec/integration/network/formats_spec.rb index 44f153d33..af505f267 100755 --- a/spec/integration/network/formats_spec.rb +++ b/spec/integration/network/formats_spec.rb @@ -1,107 +1,106 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/network/formats' class PsonIntTest attr_accessor :string def ==(other) other.class == self.class and string == other.string end def self.from_pson(data) new(data[0]) end def initialize(string) @string = string end def to_pson(*args) { 'type' => self.class.name, 'data' => [@string] }.to_pson(*args) end def self.canonical_order(s) s.gsub(/\{"data":\[(.*?)\],"type":"PsonIntTest"\}/,'{"type":"PsonIntTest","data":[\1]}') end end describe Puppet::Network::FormatHandler.format(:s) do before do @format = Puppet::Network::FormatHandler.format(:s) end it "should support certificates" do @format.should be_supported(Puppet::SSL::Certificate) end it "should not support catalogs" do @format.should_not be_supported(Puppet::Resource::Catalog) end end describe Puppet::Network::FormatHandler.format(:pson) do describe "when pson is absent", :if => (! Puppet.features.pson?) do before do @pson = Puppet::Network::FormatHandler.format(:pson) end it "should not be suitable" do @pson.should_not be_suitable end end describe "when pson is available", :if => Puppet.features.pson? do before do @pson = Puppet::Network::FormatHandler.format(:pson) end it "should be able to render an instance to pson" do instance = PsonIntTest.new("foo") PsonIntTest.canonical_order(@pson.render(instance)).should == PsonIntTest.canonical_order('{"type":"PsonIntTest","data":["foo"]}' ) end it "should be able to render arrays to pson" do @pson.render([1,2]).should == '[1,2]' end it "should be able to render arrays containing hashes to pson" do @pson.render([{"one"=>1},{"two"=>2}]).should == '[{"one":1},{"two":2}]' end it "should be able to render multiple instances to pson" do Puppet.features.add(:pson, :libs => ["pson"]) one = PsonIntTest.new("one") two = PsonIntTest.new("two") PsonIntTest.canonical_order(@pson.render([one,two])).should == PsonIntTest.canonical_order('[{"type":"PsonIntTest","data":["one"]},{"type":"PsonIntTest","data":["two"]}]') end it "should be able to intern pson into an instance" do @pson.intern(PsonIntTest, '{"type":"PsonIntTest","data":["foo"]}').should == PsonIntTest.new("foo") end it "should be able to intern pson with no class information into an instance" do @pson.intern(PsonIntTest, '["foo"]').should == PsonIntTest.new("foo") end it "should be able to intern multiple instances from pson" do @pson.intern_multiple(PsonIntTest, '[{"type": "PsonIntTest", "data": ["one"]},{"type": "PsonIntTest", "data": ["two"]}]').should == [ PsonIntTest.new("one"), PsonIntTest.new("two") ] end it "should be able to intern multiple instances from pson with no class information" do @pson.intern_multiple(PsonIntTest, '[["one"],["two"]]').should == [ PsonIntTest.new("one"), PsonIntTest.new("two") ] end end end diff --git a/spec/integration/network/handler_spec.rb b/spec/integration/network/handler_spec.rb index 5012d3ab9..dc0837c13 100755 --- a/spec/integration/network/handler_spec.rb +++ b/spec/integration/network/handler_spec.rb @@ -1,25 +1,24 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/network/client' describe Puppet::Network::Handler do %w{ca filebucket fileserver master report runner status}.each do |name| it "should have a #{name} client" do Puppet::Network::Handler.handler(name).should be_instance_of(Class) end it "should have a name" do Puppet::Network::Handler.handler(name).name.to_s.downcase.should == name.to_s.downcase end it "should have an interface" do Puppet::Network::Handler.handler(name).interface.should_not be_nil end it "should have a prefix for the interface" do Puppet::Network::Handler.handler(name).interface.prefix.should_not be_nil end end end diff --git a/spec/integration/network/server/mongrel_spec.rb b/spec/integration/network/server/mongrel_spec.rb index 2a18cb569..fd5903b9e 100755 --- a/spec/integration/network/server/mongrel_spec.rb +++ b/spec/integration/network/server/mongrel_spec.rb @@ -1,65 +1,64 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/network/server' require 'socket' describe Puppet::Network::Server do describe "when using mongrel", :if => Puppet.features.mongrel? do before :each do Puppet[:servertype] = 'mongrel' Puppet[:server] = '127.0.0.1' @params = { :port => 34346, :handlers => [ :node ] } @server = Puppet::Network::Server.new(@params) end after { Puppet.settings.clear } describe "before listening" do it "should not be reachable at the specified address and port" do lambda { TCPSocket.new('127.0.0.1', 34346) }.should raise_error(Errno::ECONNREFUSED) end end describe "when listening" do it "should be reachable on the specified address and port" do @server.listen lambda { TCPSocket.new('127.0.0.1', 34346) }.should_not raise_error end it "should default to '127.0.0.1' as its bind address" do @server = Puppet::Network::Server.new(@params.merge(:port => 34343)) @server.stubs(:unlisten) # we're breaking listening internally, so we have to keep it from unlistening @server.send(:http_server).expects(:listen).with { |args| args[:address] == "127.0.0.1" } @server.listen end it "should use any specified bind address" do Puppet[:bindaddress] = "0.0.0.0" @server = Puppet::Network::Server.new(@params.merge(:port => 34343)) @server.stubs(:unlisten) # we're breaking listening internally, so we have to keep it from unlistening @server.send(:http_server).expects(:listen).with { |args| args[:address] == "0.0.0.0" } @server.listen end it "should not allow multiple servers to listen on the same address and port" do @server.listen @server2 = Puppet::Network::Server.new(@params) lambda { @server2.listen }.should raise_error end end describe "after unlistening" do it "should not be reachable on the port and address assigned" do @server.listen @server.unlisten lambda { TCPSocket.new('127.0.0.1', 34346) }.should raise_error(Errno::ECONNREFUSED) end end after :each do @server.unlisten if @server.listening? end end end diff --git a/spec/integration/network/server/webrick_spec.rb b/spec/integration/network/server/webrick_spec.rb index b39dd2378..81c35af4f 100755 --- a/spec/integration/network/server/webrick_spec.rb +++ b/spec/integration/network/server/webrick_spec.rb @@ -1,87 +1,86 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/network/server' require 'puppet/ssl/certificate_authority' require 'socket' describe Puppet::Network::Server do describe "when using webrick" do before :each do Puppet[:servertype] = 'webrick' Puppet[:server] = '127.0.0.1' @params = { :port => 34343, :handlers => [ :node ], :xmlrpc_handlers => [ :status ] } # Get a safe temporary file @tmpfile = Tempfile.new("webrick_integration_testing") @dir = @tmpfile.path + "_dir" Puppet.settings[:confdir] = @dir Puppet.settings[:vardir] = @dir Puppet.settings[:group] = Process.gid Puppet::SSL::Host.ca_location = :local ca = Puppet::SSL::CertificateAuthority.new ca.generate(Puppet[:certname]) unless Puppet::SSL::Certificate.indirection.find(Puppet[:certname]) end after do @tmpfile.delete Puppet.settings.clear system("rm -rf #{@dir}") Puppet::SSL::Host.ca_location = :none Puppet::Util::Cacher.expire end describe "before listening" do it "should not be reachable at the specified address and port" do lambda { TCPSocket.new('127.0.0.1', 34343) }.should raise_error end end describe "when listening" do it "should be reachable on the specified address and port" do @server = Puppet::Network::Server.new(@params.merge(:port => 34343)) @server.listen lambda { TCPSocket.new('127.0.0.1', 34343) }.should_not raise_error end it "should default to '0.0.0.0' as its bind address" do Puppet.settings.clear Puppet[:servertype] = 'webrick' Puppet[:bindaddress].should == '0.0.0.0' end it "should use any specified bind address" do Puppet[:bindaddress] = "127.0.0.1" @server = Puppet::Network::Server.new(@params.merge(:port => 34343)) @server.stubs(:unlisten) # we're breaking listening internally, so we have to keep it from unlistening @server.send(:http_server).expects(:listen).with { |args| args[:address] == "127.0.0.1" } @server.listen end it "should not allow multiple servers to listen on the same address and port" do @server = Puppet::Network::Server.new(@params.merge(:port => 34343)) @server.listen @server2 = Puppet::Network::Server.new(@params.merge(:port => 34343)) lambda { @server2.listen }.should raise_error end after :each do @server.unlisten if @server && @server.listening? end end describe "after unlistening" do it "should not be reachable on the port and address assigned" do @server = Puppet::Network::Server.new(@params.merge(:port => 34343)) @server.listen @server.unlisten lambda { TCPSocket.new('127.0.0.1', 34343) }.should raise_error(Errno::ECONNREFUSED) end end end end diff --git a/spec/integration/node/environment_spec.rb b/spec/integration/node/environment_spec.rb index 1610e2efc..25a14afd4 100755 --- a/spec/integration/node/environment_spec.rb +++ b/spec/integration/node/environment_spec.rb @@ -1,58 +1,57 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet_spec/files' describe Puppet::Node::Environment do include PuppetSpec::Files it "should be able to return each module from its environment with the environment, name, and path set correctly" do base = tmpfile("env_modules") Dir.mkdir(base) dirs = [] mods = {} %w{1 2}.each do |num| dir = File.join(base, "dir#{num}") dirs << dir Dir.mkdir(dir) mod = "mod#{num}" moddir = File.join(dir, mod) mods[mod] = moddir Dir.mkdir(moddir) end environment = Puppet::Node::Environment.new("foo") environment.stubs(:modulepath).returns dirs environment.modules.each do |mod| mod.environment.should == environment mod.path.should == mods[mod.name] end end it "should not yield the same module from different module paths" do base = tmpfile("env_modules") Dir.mkdir(base) dirs = [] mods = {} %w{1 2}.each do |num| dir = File.join(base, "dir#{num}") dirs << dir Dir.mkdir(dir) mod = "mod" moddir = File.join(dir, mod) mods[mod] = moddir Dir.mkdir(moddir) end environment = Puppet::Node::Environment.new("foo") environment.stubs(:modulepath).returns dirs mods = environment.modules mods.length.should == 1 mods[0].path.should == File.join(base, "dir1", "mod") end end diff --git a/spec/integration/node/facts_spec.rb b/spec/integration/node/facts_spec.rb index a1f35a233..f54d7f9aa 100755 --- a/spec/integration/node/facts_spec.rb +++ b/spec/integration/node/facts_spec.rb @@ -1,47 +1,47 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Created by Luke Kanies on 2008-4-8. # Copyright (c) 2008. All rights reserved. require 'spec_helper' describe Puppet::Node::Facts do describe "when using the indirector" do after { Puppet::Util::Cacher.expire } it "should expire any cached node instances when it is saved" do Puppet::Node::Facts.indirection.stubs(:terminus_class).returns :yaml Puppet::Node::Facts.indirection.terminus(:yaml).should equal(Puppet::Node::Facts.indirection.terminus(:yaml)) terminus = Puppet::Node::Facts.indirection.terminus(:yaml) terminus.stubs :save Puppet::Node.indirection.expects(:expire).with("me") facts = Puppet::Node::Facts.new("me") Puppet::Node::Facts.indirection.save(facts) end it "should be able to delegate to the :yaml terminus" do Puppet::Node::Facts.indirection.stubs(:terminus_class).returns :yaml # Load now, before we stub the exists? method. terminus = Puppet::Node::Facts.indirection.terminus(:yaml) terminus.expects(:path).with("me").returns "/my/yaml/file" FileTest.expects(:exist?).with("/my/yaml/file").returns false Puppet::Node::Facts.indirection.find("me").should be_nil end it "should be able to delegate to the :facter terminus" do Puppet::Node::Facts.indirection.stubs(:terminus_class).returns :facter Facter.expects(:to_hash).returns "facter_hash" facts = Puppet::Node::Facts.new("me") Puppet::Node::Facts.expects(:new).with("me", "facter_hash").returns facts Puppet::Node::Facts.indirection.find("me").should equal(facts) end end end diff --git a/spec/integration/node_spec.rb b/spec/integration/node_spec.rb index afcb1cda5..e15ddfc1e 100755 --- a/spec/integration/node_spec.rb +++ b/spec/integration/node_spec.rb @@ -1,93 +1,93 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Created by Luke Kanies on 2007-9-23. # Copyright (c) 2007. All rights reserved. require 'spec_helper' require 'puppet/node' describe Puppet::Node do describe "when delegating indirection calls" do before do @name = "me" @node = Puppet::Node.new(@name) end it "should be able to use the exec terminus" do Puppet::Node.indirection.stubs(:terminus_class).returns :exec # Load now so we can stub terminus = Puppet::Node.indirection.terminus(:exec) terminus.expects(:query).with(@name).returns "myresults" terminus.expects(:translate).with(@name, "myresults").returns "translated_results" terminus.expects(:create_node).with(@name, "translated_results").returns @node Puppet::Node.indirection.find(@name).should equal(@node) end it "should be able to use the yaml terminus" do Puppet::Node.indirection.stubs(:terminus_class).returns :yaml # Load now, before we stub the exists? method. terminus = Puppet::Node.indirection.terminus(:yaml) terminus.expects(:path).with(@name).returns "/my/yaml/file" FileTest.expects(:exist?).with("/my/yaml/file").returns false Puppet::Node.indirection.find(@name).should be_nil end it "should have an ldap terminus" do Puppet::Node.indirection.terminus(:ldap).should_not be_nil end it "should be able to use the plain terminus" do Puppet::Node.indirection.stubs(:terminus_class).returns :plain # Load now, before we stub the exists? method. Puppet::Node.indirection.terminus(:plain) Puppet::Node.expects(:new).with(@name).returns @node Puppet::Node.indirection.find(@name).should equal(@node) end describe "and using the memory terminus" do before do @name = "me" @old_terminus = Puppet::Node.indirection.terminus_class @terminus = Puppet::Node.indirection.terminus(:memory) Puppet::Node.indirection.stubs(:terminus).returns @terminus @node = Puppet::Node.new(@name) end it "should find no nodes by default" do Puppet::Node.indirection.find(@name).should be_nil end it "should be able to find nodes that were previously saved" do Puppet::Node.indirection.save(@node) Puppet::Node.indirection.find(@name).should equal(@node) end it "should replace existing saved nodes when a new node with the same name is saved" do Puppet::Node.indirection.save(@node) two = Puppet::Node.new(@name) Puppet::Node.indirection.save(two) Puppet::Node.indirection.find(@name).should equal(two) end it "should be able to remove previously saved nodes" do Puppet::Node.indirection.save(@node) Puppet::Node.indirection.destroy(@node.name) Puppet::Node.indirection.find(@name).should be_nil end it "should fail when asked to destroy a node that does not exist" do proc { Puppet::Node.indirection.destroy(@node) }.should raise_error(ArgumentError) end end end end diff --git a/spec/integration/parser/collector_spec.rb b/spec/integration/parser/collector_spec.rb index 148d105bf..c14fa4184 100755 --- a/spec/integration/parser/collector_spec.rb +++ b/spec/integration/parser/collector_spec.rb @@ -1,38 +1,37 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/parser/collector' describe Puppet::Parser::Collector do before do @scope = Puppet::Parser::Scope.new(:compiler => Puppet::Parser::Compiler.new(Puppet::Node.new("mynode"))) @resource = Puppet::Parser::Resource.new("file", "/tmp/testing", :scope => @scope, :source => "fakesource") {:owner => "root", :group => "bin", :mode => "644"}.each do |param, value| @resource[param] = value end end def query(text) code = "File <| #{text} |>" parser = Puppet::Parser::Parser.new(@scope.compiler) return parser.parse(code).code[0].query end {true => [%{title == "/tmp/testing"}, %{(title == "/tmp/testing")}, %{group == bin}, %{title == "/tmp/testing" and group == bin}, %{title == bin or group == bin}, %{title == "/tmp/testing" or title == bin}, %{title == "/tmp/testing"}, %{(title == "/tmp/testing" or title == bin) and group == bin}], false => [%{title == bin}, %{title == bin or (title == bin and group == bin)}, %{title != "/tmp/testing"}, %{title != "/tmp/testing" and group != bin}] }.each do |result, ary| ary.each do |string| it "should return '#{result}' when collecting resources with '#{string}'" do str, code = query(string).evaluate @scope code.should be_instance_of(Proc) code.call(@resource).should == result end end end end diff --git a/spec/integration/parser/compiler_spec.rb b/spec/integration/parser/compiler_spec.rb index 2eb91ec7d..9f6aae907 100755 --- a/spec/integration/parser/compiler_spec.rb +++ b/spec/integration/parser/compiler_spec.rb @@ -1,134 +1,133 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe Puppet::Parser::Compiler do before :each do @node = Puppet::Node.new "testnode" @scope_resource = stub 'scope_resource', :builtin? => true, :finish => nil, :ref => 'Class[main]' @scope = stub 'scope', :resource => @scope_resource, :source => mock("source") end after do Puppet.settings.clear end it "should be able to determine the configuration version from a local version control repository" do # This should always work, because we should always be # in the puppet repo when we run this. version = %x{git rev-parse HEAD}.chomp Puppet.settings[:config_version] = 'git rev-parse HEAD' @parser = Puppet::Parser::Parser.new "development" @compiler = Puppet::Parser::Compiler.new(@node) @compiler.catalog.version.should == version end it "should not create duplicate resources when a class is referenced both directly and indirectly by the node classifier (4792)" do Puppet[:code] = <<-PP class foo { notify { foo_notify: } include bar } class bar { notify { bar_notify: } } PP @node.stubs(:classes).returns(['foo', 'bar']) catalog = Puppet::Parser::Compiler.compile(@node) catalog.resource("Notify[foo_notify]").should_not be_nil catalog.resource("Notify[bar_notify]").should_not be_nil end describe "when resolving class references" do it "should favor local scope, even if there's an included class in topscope" do Puppet[:code] = <<-PP class experiment { class baz { } notify {"x" : require => Class[Baz] } } class baz { } include baz include experiment include experiment::baz PP catalog = Puppet::Parser::Compiler.compile(Puppet::Node.new("mynode")) notify_resource = catalog.resource( "Notify[x]" ) notify_resource[:require].title.should == "Experiment::Baz" end it "should favor local scope, even if there's an unincluded class in topscope" do Puppet[:code] = <<-PP class experiment { class baz { } notify {"x" : require => Class[Baz] } } class baz { } include experiment include experiment::baz PP catalog = Puppet::Parser::Compiler.compile(Puppet::Node.new("mynode")) notify_resource = catalog.resource( "Notify[x]" ) notify_resource[:require].title.should == "Experiment::Baz" end end it "should recompute the version after input files are re-parsed" do Puppet[:code] = 'class foo { }' Time.stubs(:now).returns(1) node = Puppet::Node.new('mynode') Puppet::Parser::Compiler.compile(node).version.should == 1 Time.stubs(:now).returns(2) Puppet::Parser::Compiler.compile(node).version.should == 1 # no change because files didn't change Puppet::Resource::TypeCollection.any_instance.stubs(:stale?).returns(true).then.returns(false) # pretend change Puppet::Parser::Compiler.compile(node).version.should == 2 end ['class', 'define', 'node'].each do |thing| it "should not allow #{thing} inside evaluated conditional constructs" do Puppet[:code] = <<-PP if true { #{thing} foo { } notify { decoy: } } PP begin Puppet::Parser::Compiler.compile(Puppet::Node.new("mynode")) raise "compilation should have raised Puppet::Error" rescue Puppet::Error => e e.message.should =~ /at line 2/ end end end it "should not allow classes inside unevaluated conditional constructs" do Puppet[:code] = <<-PP if false { class foo { } } PP lambda { Puppet::Parser::Compiler.compile(Puppet::Node.new("mynode")) }.should raise_error(Puppet::Error) end end diff --git a/spec/integration/parser/functions/require_spec.rb b/spec/integration/parser/functions/require_spec.rb index c9eb0ae32..aa15f92be 100755 --- a/spec/integration/parser/functions/require_spec.rb +++ b/spec/integration/parser/functions/require_spec.rb @@ -1,44 +1,43 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe "The require function" do before :each do @node = Puppet::Node.new("mynode") @compiler = Puppet::Parser::Compiler.new(@node) @compiler.send(:evaluate_main) @compiler.catalog.client_version = "0.25" @scope = @compiler.topscope # preload our functions Puppet::Parser::Functions.function(:include) Puppet::Parser::Functions.function(:require) end it "should add a dependency between the 'required' class and our class" do @compiler.known_resource_types.add Puppet::Resource::Type.new(:hostclass, "requiredclass") @scope.function_require("requiredclass") @scope.resource["require"].should_not be_nil ref = @scope.resource["require"].shift ref.type.should == "Class" ref.title.should == "Requiredclass" end it "should queue relationships between the 'required' class and our classes" do @compiler.known_resource_types.add Puppet::Resource::Type.new(:hostclass, "requiredclass1") @compiler.known_resource_types.add Puppet::Resource::Type.new(:hostclass, "requiredclass2") @scope.function_require("requiredclass1") @scope.function_require("requiredclass2") @scope.resource["require"].should_not be_nil (ref1,ref2) = @scope.resource["require"] ref1.type.should == "Class" ref1.title.should == "Requiredclass1" ref2.type.should == "Class" ref2.title.should == "Requiredclass2" end end diff --git a/spec/integration/parser/functions_spec.rb b/spec/integration/parser/functions_spec.rb index 397576182..6791987d7 100755 --- a/spec/integration/parser/functions_spec.rb +++ b/spec/integration/parser/functions_spec.rb @@ -1,21 +1,20 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe Puppet::Parser::Functions do before :each do Puppet::Parser::Functions.rmfunction("template") if Puppet::Parser::Functions.function("template") end it "should support multiple threads autoloading the same function" do threads = [] lambda { 10.times { |a| threads << Thread.new { Puppet::Parser::Functions.function("template") } } }.should_not raise_error threads.each { |t| t.join } end end diff --git a/spec/integration/parser/parser_spec.rb b/spec/integration/parser/parser_spec.rb index 1526be049..65c9ee302 100755 --- a/spec/integration/parser/parser_spec.rb +++ b/spec/integration/parser/parser_spec.rb @@ -1,122 +1,121 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe Puppet::Parser::Parser do module ParseMatcher class ParseAs def initialize(klass) @parser = Puppet::Parser::Parser.new "development" @class = klass end def result_instance @result.code[0] end def matches?(string) @string = string @result = @parser.parse(string) result_instance.instance_of?(@class) end def description "parse as a #{@class}" end def failure_message " expected #{@string} to parse as #{@class} but was #{result_instance.class}" end def negative_failure_message " expected #{@string} not to parse as #{@class}" end end def parse_as(klass) ParseAs.new(klass) end class ParseWith def initialize(block) @parser = Puppet::Parser::Parser.new "development" @block = block end def result_instance @result.code[0] end def matches?(string) @string = string @result = @parser.parse(string) @block.call(result_instance) end def description "parse with the block evaluating to true" end def failure_message " expected #{@string} to parse with a true result in the block" end def negative_failure_message " expected #{@string} not to parse with a true result in the block" end end def parse_with(&block) ParseWith.new(block) end end include ParseMatcher before :each do @resource_type_collection = Puppet::Resource::TypeCollection.new("env") @parser = Puppet::Parser::Parser.new "development" end describe "when parsing comments before statement" do it "should associate the documentation to the statement AST node" do ast = @parser.parse(""" # comment class test {} """) ast.code[0].should be_a(Puppet::Parser::AST::Hostclass) ast.code[0].name.should == 'test' ast.code[0].instantiate('')[0].doc.should == "comment\n" end end describe "when parsing" do it "should be able to parse normal left to right relationships" do "Notify[foo] -> Notify[bar]".should parse_as(Puppet::Parser::AST::Relationship) end it "should be able to parse right to left relationships" do "Notify[foo] <- Notify[bar]".should parse_as(Puppet::Parser::AST::Relationship) end it "should be able to parse normal left to right subscriptions" do "Notify[foo] ~> Notify[bar]".should parse_as(Puppet::Parser::AST::Relationship) end it "should be able to parse right to left subscriptions" do "Notify[foo] <~ Notify[bar]".should parse_as(Puppet::Parser::AST::Relationship) end it "should correctly set the arrow type of a relationship" do "Notify[foo] <~ Notify[bar]".should parse_with { |rel| rel.arrow == "<~" } end it "should be able to parse deep hash access" do %q{ $hash = { 'a' => { 'b' => { 'c' => 'it works' } } } $out = $hash['a']['b']['c'] }.should parse_with { |v| v.value.is_a?(Puppet::Parser::AST::ASTHash) } end end end diff --git a/spec/integration/parser/ruby_manifest_spec.rb b/spec/integration/parser/ruby_manifest_spec.rb index 6955e89e5..7f3bb71e9 100755 --- a/spec/integration/parser/ruby_manifest_spec.rb +++ b/spec/integration/parser/ruby_manifest_spec.rb @@ -1,128 +1,127 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'tempfile' require 'puppet_spec/files' describe "Pure ruby manifests" do include PuppetSpec::Files before do @node = Puppet::Node.new "testnode" @scope_resource = stub 'scope_resource', :builtin? => true, :finish => nil, :ref => 'Class[main]' @scope = stub 'scope', :resource => @scope_resource, :source => mock("source") @test_dir = tmpdir('ruby_manifest_test') end after do Puppet.settings.clear end def write_file(name, contents) path = File.join(@test_dir, name) File.open(path, "w") { |f| f.write(contents) } path end def compile(contents) Puppet[:code] = contents Dir.chdir(@test_dir) do Puppet::Parser::Compiler.compile(Puppet::Node.new("mynode")) end end it "should allow classes" do write_file('foo.rb', ["hostclass 'one' do notify('one_notify') end", "hostclass 'two' do notify('two_notify') end"].join("\n")) catalog = compile("import 'foo'\ninclude one") catalog.resource("Notify[one_notify]").should_not be_nil catalog.resource("Notify[two_notify]").should be_nil end it "should allow defines" do write_file('foo.rb', 'define "bar", :arg do notify("bar_#{@name}_#{@arg}") end') catalog = compile("import 'foo'\nbar { instance: arg => 'xyz' }") catalog.resource("Notify[bar_instance_xyz]").should_not be_nil catalog.resource("Bar[instance]").should_not be_nil end it "should allow node declarations" do write_file('foo.rb', "node 'mynode' do notify('mynode') end") catalog = compile("import 'foo'") node_declaration = catalog.resource("Notify[mynode]") node_declaration.should_not be_nil node_declaration.title.should == 'mynode' end it "should allow access to the environment" do write_file('foo.rb', ["hostclass 'bar' do", " if environment.is_a? Puppet::Node::Environment", " notify('success')", " end", "end"].join("\n")) compile("import 'foo'\ninclude bar").resource("Notify[success]").should_not be_nil end it "should allow creation of resources of built-in types" do write_file('foo.rb', "hostclass 'bar' do file 'test_file', :owner => 'root', :mode => '644' end") catalog = compile("import 'foo'\ninclude bar") file = catalog.resource("File[test_file]") file.should be_a(Puppet::Resource) file.type.should == 'File' file.title.should == 'test_file' file.exported.should_not be file.virtual.should_not be file[:owner].should == 'root' file[:mode].should == '644' file[:stage].should be_nil # TODO: is this correct behavior? end it "should allow calling user-defined functions" do write_file('foo.rb', "hostclass 'bar' do user_func 'name', :arg => 'xyz' end") catalog = compile(['define user_func($arg) { notify {"n_$arg": } }', 'import "foo"', 'include bar'].join("\n")) catalog.resource("Notify[n_xyz]").should_not be_nil catalog.resource("User_func[name]").should_not be_nil end it "should be properly cached for multiple compiles" do # Note: we can't test this by calling compile() twice, because # that sets Puppet[:code], which clears out all cached # environments. Puppet[:filetimeout] = 1000 write_file('foo.rb', "hostclass 'bar' do notify('success') end") Puppet[:code] = "import 'foo'\ninclude bar" # Compile the catalog and check it catalog = Dir.chdir(@test_dir) do Puppet::Parser::Compiler.compile(Puppet::Node.new("mynode")) end catalog.resource("Notify[success]").should_not be_nil # Secretly change the file to make it invalid. This change # shouldn't be noticed because the we've set a high # Puppet[:filetimeout]. write_file('foo.rb', "raise 'should not be executed'") # Compile the catalog a second time and make sure it's still ok. catalog = Dir.chdir(@test_dir) do Puppet::Parser::Compiler.compile(Puppet::Node.new("mynode")) end catalog.resource("Notify[success]").should_not be_nil end it "should be properly reloaded when stale" do Puppet[:filetimeout] = -1 # force stale check to happen all the time write_file('foo.rb', "hostclass 'bar' do notify('version1') end") catalog = compile("import 'foo'\ninclude bar") catalog.resource("Notify[version1]").should_not be_nil sleep 1 # so that timestamp will change forcing file reload write_file('foo.rb', "hostclass 'bar' do notify('version2') end") catalog = compile("import 'foo'\ninclude bar") catalog.resource("Notify[version1]").should be_nil catalog.resource("Notify[version2]").should_not be_nil end end diff --git a/spec/integration/provider/mailalias/aliases_spec.rb b/spec/integration/provider/mailalias/aliases_spec.rb index ac8095ac7..232704e61 100755 --- a/spec/integration/provider/mailalias/aliases_spec.rb +++ b/spec/integration/provider/mailalias/aliases_spec.rb @@ -1,10 +1,10 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec require 'spec_helper' require 'shared_behaviours/all_parsedfile_providers' provider_class = Puppet::Type.type(:mailalias).provider(:aliases) describe provider_class do # #1560, in which we corrupt the format of complex mail aliases. it_should_behave_like "all parsedfile providers", provider_class end diff --git a/spec/integration/provider/mount_spec.rb b/spec/integration/provider/mount_spec.rb old mode 100644 new mode 100755 diff --git a/spec/integration/provider/package_spec.rb b/spec/integration/provider/package_spec.rb index 00c52fc89..2d75826e8 100755 --- a/spec/integration/provider/package_spec.rb +++ b/spec/integration/provider/package_spec.rb @@ -1,24 +1,23 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe "Package Provider" do Puppet::Type.type(:package).providers.each do |name| provider = Puppet::Type.type(:package).provider(name) describe name, :if => provider.suitable? do it "should fail when asked to install an invalid package" do pending("This test hangs forever with recent versions of RubyGems") if provider.name == :gem pkg = Puppet::Type.newpackage :name => "nosuch#{provider.name}", :provider => provider.name lambda { pkg.provider.install }.should raise_error end it "should be able to get a list of existing packages" do provider.instances.each do |package| package.should be_instance_of(provider) package.properties[:provider].should == provider.name end end end end end diff --git a/spec/integration/provider/service/init_spec.rb b/spec/integration/provider/service/init_spec.rb index 17b74ed0a..ef7d98b4c 100755 --- a/spec/integration/provider/service/init_spec.rb +++ b/spec/integration/provider/service/init_spec.rb @@ -1,25 +1,24 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' provider = Puppet::Type.type(:service).provider(:init) describe provider do describe "when running on FreeBSD", :if => (Facter.value(:operatingsystem) == "FreeBSD") do it "should set its default path to include /etc/init.d and /usr/local/etc/init.d" do provider.defpath.should == ["/etc/rc.d", "/usr/local/etc/rc.d"] end end describe "when running on HP-UX", :if => (Facter.value(:operatingsystem) == "HP-UX")do it "should set its default path to include /sbin/init.d" do provider.defpath.should == "/sbin/init.d" end end describe "when not running on FreeBSD or HP-UX", :if => (! %w{HP-UX FreeBSD}.include?(Facter.value(:operatingsystem))) do it "should set its default path to include /etc/init.d" do provider.defpath.should == "/etc/init.d" end end end diff --git a/spec/integration/reference/providers_spec.rb b/spec/integration/reference/providers_spec.rb index 23b22aae1..6d87ee02e 100755 --- a/spec/integration/reference/providers_spec.rb +++ b/spec/integration/reference/providers_spec.rb @@ -1,17 +1,16 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/util/reference' reference = Puppet::Util::Reference.reference(:providers) describe reference do it "should exist" do reference.should_not be_nil end it "should be able to be rendered as markdown" do lambda { reference.to_markdown }.should_not raise_error end end diff --git a/spec/integration/reports_spec.rb b/spec/integration/reports_spec.rb index b9a57bb17..d5a08d28a 100755 --- a/spec/integration/reports_spec.rb +++ b/spec/integration/reports_spec.rb @@ -1,18 +1,18 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Created by Luke Kanies on 2007-10-12. # Copyright (c) 2007. All rights reserved. require 'spec_helper' require 'puppet/reports' describe Puppet::Reports, " when using report types" do before do Puppet.settings.stubs(:use) end it "should load report types as modules" do Puppet::Reports.report(:store).should be_instance_of(Module) end end diff --git a/spec/integration/resource/catalog_spec.rb b/spec/integration/resource/catalog_spec.rb index 5f646d4ad..41a475d98 100755 --- a/spec/integration/resource/catalog_spec.rb +++ b/spec/integration/resource/catalog_spec.rb @@ -1,60 +1,60 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Created by Luke Kanies on 2007-4-8. # Copyright (c) 2008. All rights reserved. require 'spec_helper' describe Puppet::Resource::Catalog do describe "when pson is available", :if => Puppet.features.pson? do it "should support pson" do Puppet::Resource::Catalog.supported_formats.should be_include(:pson) end end describe "when using the indirector" do after { Puppet::Util::Cacher.expire } before do # This is so the tests work w/out networking. Facter.stubs(:to_hash).returns({"hostname" => "foo.domain.com"}) Facter.stubs(:value).returns("eh") end it "should be able to delegate to the :yaml terminus" do Puppet::Resource::Catalog.indirection.stubs(:terminus_class).returns :yaml # Load now, before we stub the exists? method. terminus = Puppet::Resource::Catalog.indirection.terminus(:yaml) terminus.expects(:path).with("me").returns "/my/yaml/file" FileTest.expects(:exist?).with("/my/yaml/file").returns false Puppet::Resource::Catalog.indirection.find("me").should be_nil end it "should be able to delegate to the :compiler terminus" do Puppet::Resource::Catalog.indirection.stubs(:terminus_class).returns :compiler # Load now, before we stub the exists? method. compiler = Puppet::Resource::Catalog.indirection.terminus(:compiler) node = mock 'node' node.stub_everything Puppet::Node.indirection.expects(:find).returns(node) compiler.expects(:compile).with(node).returns nil Puppet::Resource::Catalog.indirection.find("me").should be_nil end it "should pass provided node information directly to the terminus" do terminus = mock 'terminus' Puppet::Resource::Catalog.indirection.stubs(:terminus).returns terminus node = mock 'node' terminus.expects(:find).with { |request| request.options[:use_node] == node } Puppet::Resource::Catalog.indirection.find("me", :use_node => node) end end end diff --git a/spec/integration/resource/type_collection_spec.rb b/spec/integration/resource/type_collection_spec.rb index 7d9f25a39..6ea2e7fe7 100755 --- a/spec/integration/resource/type_collection_spec.rb +++ b/spec/integration/resource/type_collection_spec.rb @@ -1,96 +1,95 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet_spec/files' require 'puppet/resource/type_collection' describe Puppet::Resource::TypeCollection do describe "when autoloading from modules" do include PuppetSpec::Files before do @dir = tmpfile("autoload_testing") Puppet[:modulepath] = @dir FileUtils.mkdir_p @dir @code = Puppet::Resource::TypeCollection.new("env") Puppet::Node::Environment.new("env").stubs(:known_resource_types).returns @code end # Setup a module. def mk_module(name, files = {}) mdir = File.join(@dir, name) mandir = File.join(mdir, "manifests") FileUtils.mkdir_p mandir defs = files.delete(:define) Dir.chdir(mandir) do files.each do |file, classes| File.open("#{file}.pp", "w") do |f| classes.each { |klass| if defs f.puts "define #{klass} {}" else f.puts "class #{klass} {}" end } end end end end it "should return nil when a class can't be found or loaded" do @code.find_hostclass('', 'nosuchclass').should be_nil end it "should load the module's init file first" do name = "simple" mk_module(name, :init => [name]) @code.find_hostclass("", name).name.should == name end it "should load the module's init file even when searching from a different namespace" do name = "simple" mk_module(name, :init => [name]) @code.find_hostclass("other::ns", name).name.should == name end it "should be able to load definitions from the module base file" do name = "simpdef" mk_module(name, :define => true, :init => [name]) @code.find_definition("", name).name.should == name end it "should be able to load qualified classes from the module base file" do modname = "both" name = "sub" mk_module(modname, :init => %w{both both::sub}) @code.find_hostclass("both", name).name.should == "both::sub" end it "should be able load classes from a separate file" do modname = "separate" name = "sub" mk_module(modname, :init => %w{separate}, :sub => %w{separate::sub}) @code.find_hostclass("separate", name).name.should == "separate::sub" end it "should not fail when loading from a separate file if there is no module file" do modname = "alone" name = "sub" mk_module(modname, :sub => %w{alone::sub}) lambda { @code.find_hostclass("alone", name) }.should_not raise_error end it "should be able to load definitions from their own file" do name = "mymod" mk_module(name, :define => true, :mydefine => ["mymod::mydefine"]) @code.find_definition("", "mymod::mydefine").name.should == "mymod::mydefine" end end end diff --git a/spec/integration/ssl/certificate_authority_spec.rb b/spec/integration/ssl/certificate_authority_spec.rb index a29fc0275..c5e145459 100755 --- a/spec/integration/ssl/certificate_authority_spec.rb +++ b/spec/integration/ssl/certificate_authority_spec.rb @@ -1,134 +1,134 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Created by Luke Kanies on 2008-4-17. # Copyright (c) 2008. All rights reserved. require 'spec_helper' require 'puppet/ssl/certificate_authority' require 'tempfile' describe Puppet::SSL::CertificateAuthority do before do # Get a safe temporary file file = Tempfile.new("ca_integration_testing") @dir = file.path file.delete Puppet.settings[:confdir] = @dir Puppet.settings[:vardir] = @dir Puppet.settings[:group] = Process.gid Puppet::SSL::Host.ca_location = :local @ca = Puppet::SSL::CertificateAuthority.new end after { Puppet::SSL::Host.ca_location = :none system("rm -rf #{@dir}") Puppet.settings.clear Puppet::Util::Cacher.expire Puppet::SSL::CertificateAuthority.instance_variable_set("@instance", nil) } it "should create a CA host" do @ca.host.should be_ca end it "should be able to generate a certificate" do @ca.generate_ca_certificate @ca.host.certificate.should be_instance_of(Puppet::SSL::Certificate) end it "should be able to generate a new host certificate" do @ca.generate("newhost") Puppet::SSL::Certificate.indirection.find("newhost").should be_instance_of(Puppet::SSL::Certificate) end it "should be able to revoke a host certificate" do @ca.generate("newhost") @ca.revoke("newhost") lambda { @ca.verify("newhost") }.should raise_error end it "should have a CRL" do @ca.generate_ca_certificate @ca.crl.should_not be_nil end it "should be able to read in a previously created CRL" do @ca.generate_ca_certificate # Create it to start with. @ca.crl Puppet::SSL::CertificateAuthority.new.crl.should_not be_nil end describe "when signing certificates" do before do @host = Puppet::SSL::Host.new("luke.madstop.com") # We have to provide the key, since when we're in :ca_only mode, we can only interact # with the CA key. key = Puppet::SSL::Key.new(@host.name) key.generate @host.key = key @host.generate_certificate_request path = File.join(Puppet[:requestdir], "luke.madstop.com.pem") end it "should be able to sign certificates" do @ca.sign("luke.madstop.com") end it "should save the signed certificate" do @ca.sign("luke.madstop.com") Puppet::SSL::Certificate.indirection.find("luke.madstop.com").should be_instance_of(Puppet::SSL::Certificate) end it "should be able to sign multiple certificates" do @other = Puppet::SSL::Host.new("other.madstop.com") okey = Puppet::SSL::Key.new(@other.name) okey.generate @other.key = okey @other.generate_certificate_request @ca.sign("luke.madstop.com") @ca.sign("other.madstop.com") Puppet::SSL::Certificate.indirection.find("other.madstop.com").should be_instance_of(Puppet::SSL::Certificate) Puppet::SSL::Certificate.indirection.find("luke.madstop.com").should be_instance_of(Puppet::SSL::Certificate) end it "should save the signed certificate to the :signeddir" do @ca.sign("luke.madstop.com") client_cert = File.join(Puppet[:signeddir], "luke.madstop.com.pem") File.read(client_cert).should == Puppet::SSL::Certificate.indirection.find("luke.madstop.com").content.to_s end it "should save valid certificates" do @ca.sign("luke.madstop.com") unless ssl = Puppet::Util::which('openssl') pending "No ssl available" else ca_cert = Puppet[:cacert] client_cert = File.join(Puppet[:signeddir], "luke.madstop.com.pem") output = %x{openssl verify -CAfile #{ca_cert} #{client_cert}} $CHILD_STATUS.should == 0 end end end end diff --git a/spec/integration/ssl/certificate_request_spec.rb b/spec/integration/ssl/certificate_request_spec.rb index eeb1a1ad8..688466c37 100755 --- a/spec/integration/ssl/certificate_request_spec.rb +++ b/spec/integration/ssl/certificate_request_spec.rb @@ -1,62 +1,62 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Created by Luke Kanies on 2008-4-17. # Copyright (c) 2008. All rights reserved. require 'spec_helper' require 'puppet/ssl/certificate_request' require 'tempfile' describe Puppet::SSL::CertificateRequest do before do # Get a safe temporary file file = Tempfile.new("csr_integration_testing") @dir = file.path file.delete Dir.mkdir(@dir) Puppet.settings.clear Puppet.settings[:confdir] = @dir Puppet.settings[:vardir] = @dir Puppet.settings[:group] = Process.gid Puppet::SSL::Host.ca_location = :none @csr = Puppet::SSL::CertificateRequest.new("luke.madstop.com") @key = OpenSSL::PKey::RSA.new(512) end after do system("rm -rf #{@dir}") Puppet.settings.clear # This is necessary so the terminus instances don't lie around. Puppet::Util::Cacher.expire end it "should be able to generate CSRs" do @csr.generate(@key) end it "should be able to save CSRs" do Puppet::SSL::CertificateRequest.indirection.save(@csr) end it "should be able to find saved certificate requests via the Indirector" do @csr.generate(@key) Puppet::SSL::CertificateRequest.indirection.save(@csr) Puppet::SSL::CertificateRequest.indirection.find("luke.madstop.com").should be_instance_of(Puppet::SSL::CertificateRequest) end it "should save the completely CSR when saving" do @csr.generate(@key) Puppet::SSL::CertificateRequest.indirection.save(@csr) Puppet::SSL::CertificateRequest.indirection.find("luke.madstop.com").content.to_s.should == @csr.content.to_s end end diff --git a/spec/integration/ssl/certificate_revocation_list_spec.rb b/spec/integration/ssl/certificate_revocation_list_spec.rb index 24693cb27..051a81569 100755 --- a/spec/integration/ssl/certificate_revocation_list_spec.rb +++ b/spec/integration/ssl/certificate_revocation_list_spec.rb @@ -1,43 +1,43 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Created by Luke Kanies on 2008-5-5. # Copyright (c) 2008. All rights reserved. require 'spec_helper' require 'puppet/ssl/certificate_revocation_list' require 'tempfile' describe Puppet::SSL::CertificateRevocationList do before do # Get a safe temporary file file = Tempfile.new("ca_integration_testing") @dir = file.path file.delete Puppet.settings[:confdir] = @dir Puppet.settings[:vardir] = @dir Puppet.settings[:group] = Process.gid Puppet::SSL::Host.ca_location = :local end after { Puppet::SSL::Host.ca_location = :none system("rm -rf #{@dir}") Puppet.settings.clear # This is necessary so the terminus instances don't lie around. Puppet::Util::Cacher.expire } it "should be able to read in written out CRLs with no revoked certificates" do ca = Puppet::SSL::CertificateAuthority.new raise "CRL not created" unless FileTest.exist?(Puppet[:hostcrl]) crl = Puppet::SSL::CertificateRevocationList.new("crl_int_testing") crl.read(Puppet[:hostcrl]) end end diff --git a/spec/integration/ssl/host_spec.rb b/spec/integration/ssl/host_spec.rb index 2ea1d1bc6..e9c37c151 100755 --- a/spec/integration/ssl/host_spec.rb +++ b/spec/integration/ssl/host_spec.rb @@ -1,91 +1,91 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Created by Luke Kanies on 2008-4-17. # Copyright (c) 2008. All rights reserved. require 'spec_helper' require 'puppet/ssl/host' require 'tempfile' describe Puppet::SSL::Host do before do # Get a safe temporary file file = Tempfile.new("host_integration_testing") @dir = file.path file.delete Puppet.settings[:confdir] = @dir Puppet.settings[:vardir] = @dir Puppet.settings[:group] = Process.gid Puppet::SSL::Host.ca_location = :local @host = Puppet::SSL::Host.new("luke.madstop.com") @ca = Puppet::SSL::CertificateAuthority.new end after { Puppet::SSL::Host.ca_location = :none system("rm -rf #{@dir}") Puppet.settings.clear Puppet::Util::Cacher.expire } it "should be considered a CA host if its name is equal to 'ca'" do Puppet::SSL::Host.new(Puppet::SSL::CA_NAME).should be_ca end describe "when managing its key" do it "should be able to generate and save a key" do @host.generate_key end it "should save the key such that the Indirector can find it" do @host.generate_key Puppet::SSL::Key.indirection.find(@host.name).content.to_s.should == @host.key.to_s end it "should save the private key into the :privatekeydir" do @host.generate_key File.read(File.join(Puppet.settings[:privatekeydir], "luke.madstop.com.pem")).should == @host.key.to_s end end describe "when managing its certificate request" do it "should be able to generate and save a certificate request" do @host.generate_certificate_request end it "should save the certificate request such that the Indirector can find it" do @host.generate_certificate_request Puppet::SSL::CertificateRequest.indirection.find(@host.name).content.to_s.should == @host.certificate_request.to_s end it "should save the private certificate request into the :privatekeydir" do @host.generate_certificate_request File.read(File.join(Puppet.settings[:requestdir], "luke.madstop.com.pem")).should == @host.certificate_request.to_s end end describe "when the CA host" do it "should never store its key in the :privatekeydir" do Puppet.settings.use(:main, :ssl, :ca) @ca = Puppet::SSL::Host.new(Puppet::SSL::Host.ca_name) @ca.generate_key FileTest.should_not be_exist(File.join(Puppet[:privatekeydir], "ca.pem")) end end it "should pass the verification of its own SSL store" do @host.generate @ca = Puppet::SSL::CertificateAuthority.new @ca.sign(@host.name) @host.ssl_store.verify(@host.certificate.content).should be_true end end diff --git a/spec/integration/transaction/report_spec.rb b/spec/integration/transaction/report_spec.rb index b4efbd754..183d93f76 100755 --- a/spec/integration/transaction/report_spec.rb +++ b/spec/integration/transaction/report_spec.rb @@ -1,29 +1,29 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Created by Luke Kanies on 2008-4-8. # Copyright (c) 2008. All rights reserved. require 'spec_helper' describe Puppet::Transaction::Report do describe "when using the indirector" do after do Puppet::Util::Cacher.expire Puppet.settings.stubs(:use) end it "should be able to delegate to the :processor terminus" do Puppet::Transaction::Report.indirection.stubs(:terminus_class).returns :processor terminus = Puppet::Transaction::Report.indirection.terminus(:processor) Facter.stubs(:value).returns "host.domain.com" report = Puppet::Transaction::Report.new("apply") terminus.expects(:process).with(report) Puppet::Transaction::Report.indirection.save(report) end end end diff --git a/spec/integration/transaction_spec.rb b/spec/integration/transaction_spec.rb index cb5d22c0d..41a1ebac3 100755 --- a/spec/integration/transaction_spec.rb +++ b/spec/integration/transaction_spec.rb @@ -1,285 +1,284 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet_spec/files' require 'puppet/transaction' require 'puppet_spec/files' describe Puppet::Transaction do include PuppetSpec::Files before do Puppet::Util::Storage.stubs(:store) end def mk_catalog(*resources) catalog = Puppet::Resource::Catalog.new(Puppet::Node.new("mynode")) resources.each { |res| catalog.add_resource res } catalog end it "should not apply generated resources if the parent resource fails" do catalog = Puppet::Resource::Catalog.new resource = Puppet::Type.type(:file).new :path => "/foo/bar", :backup => false catalog.add_resource resource child_resource = Puppet::Type.type(:file).new :path => "/foo/bar/baz", :backup => false resource.expects(:eval_generate).returns([child_resource]) transaction = Puppet::Transaction.new(catalog) resource.expects(:retrieve).raises "this is a failure" resource.stubs(:err) child_resource.expects(:retrieve).never transaction.evaluate end it "should not apply virtual resources" do catalog = Puppet::Resource::Catalog.new resource = Puppet::Type.type(:file).new :path => "/foo/bar", :backup => false resource.virtual = true catalog.add_resource resource transaction = Puppet::Transaction.new(catalog) resource.expects(:evaluate).never transaction.evaluate end it "should apply exported resources" do catalog = Puppet::Resource::Catalog.new path = tmpfile("exported_files") resource = Puppet::Type.type(:file).new :path => path, :backup => false, :ensure => :file resource.exported = true catalog.add_resource resource catalog.apply FileTest.should be_exist(path) end it "should not apply virtual exported resources" do catalog = Puppet::Resource::Catalog.new resource = Puppet::Type.type(:file).new :path => "/foo/bar", :backup => false resource.exported = true resource.virtual = true catalog.add_resource resource transaction = Puppet::Transaction.new(catalog) resource.expects(:evaluate).never transaction.evaluate end # Verify that one component requiring another causes the contained # resources in the requiring component to get refreshed. it "should propagate events from a contained resource through its container to its dependent container's contained resources" do transaction = nil file = Puppet::Type.type(:file).new :path => tmpfile("event_propagation"), :ensure => :present execfile = File.join(tmpdir("exec_event"), "exectestingness2") exec = Puppet::Type.type(:exec).new :command => "touch #{execfile}", :path => ENV['PATH'] catalog = mk_catalog(file) fcomp = Puppet::Type.type(:component).new(:name => "Foo[file]") catalog.add_resource fcomp catalog.add_edge(fcomp, file) ecomp = Puppet::Type.type(:component).new(:name => "Foo[exec]") catalog.add_resource ecomp catalog.add_resource exec catalog.add_edge(ecomp, exec) ecomp[:subscribe] = Puppet::Resource.new(:foo, "file") exec[:refreshonly] = true exec.expects(:refresh) catalog.apply end # Make sure that multiple subscriptions get triggered. it "should propagate events to all dependent resources" do path = tmpfile("path") file1 = tmpfile("file1") file2 = tmpfile("file2") file = Puppet::Type.type(:file).new( :path => path, :ensure => "file" ) exec1 = Puppet::Type.type(:exec).new( :path => ENV["PATH"], :command => "touch #{file1}", :refreshonly => true, :subscribe => Puppet::Resource.new(:file, path) ) exec2 = Puppet::Type.type(:exec).new( :path => ENV["PATH"], :command => "touch #{file2}", :refreshonly => true, :subscribe => Puppet::Resource.new(:file, path) ) catalog = mk_catalog(file, exec1, exec2) catalog.apply FileTest.should be_exist(file1) FileTest.should be_exist(file2) end it "should not let one failed refresh result in other refreshes failing" do path = tmpfile("path") newfile = tmpfile("file") file = Puppet::Type.type(:file).new( :path => path, :ensure => "file" ) exec1 = Puppet::Type.type(:exec).new( :path => ENV["PATH"], :command => "touch /this/cannot/possibly/exist", :logoutput => true, :refreshonly => true, :subscribe => file, :title => "one" ) exec2 = Puppet::Type.type(:exec).new( :path => ENV["PATH"], :command => "touch #{newfile}", :logoutput => true, :refreshonly => true, :subscribe => [file, exec1], :title => "two" ) exec1.stubs(:err) catalog = mk_catalog(file, exec1, exec2) catalog.apply FileTest.should be_exists(newfile) end it "should still trigger skipped resources" do catalog = mk_catalog catalog.add_resource(*Puppet::Type.type(:schedule).mkdefaultschedules) Puppet[:ignoreschedules] = false file = Puppet::Type.type(:file).new( :name => tmpfile("file"), :ensure => "file", :backup => false ) fname = tmpfile("exec") exec = Puppet::Type.type(:exec).new( :name => "touch #{fname}", :path => "/usr/bin:/bin", :schedule => "monthly", :subscribe => Puppet::Resource.new("file", file.name) ) catalog.add_resource(file, exec) # Run it once catalog.apply FileTest.should be_exists(fname) # Now remove it, so it can get created again File.unlink(fname) file[:content] = "some content" catalog.apply FileTest.should be_exists(fname) # Now remove it, so it can get created again File.unlink(fname) # And tag our exec exec.tag("testrun") # And our file, so it runs file.tag("norun") Puppet[:tags] = "norun" file[:content] = "totally different content" catalog.apply FileTest.should be_exists(fname) end it "should not attempt to evaluate resources with failed dependencies" do exec = Puppet::Type.type(:exec).new( :command => "/bin/mkdir /this/path/cannot/possibly/exit", :title => "mkdir" ) file1 = Puppet::Type.type(:file).new( :title => "file1", :path => tmpfile("file1"), :require => exec, :ensure => :file ) file2 = Puppet::Type.type(:file).new( :title => "file2", :path => tmpfile("file2"), :require => file1, :ensure => :file ) catalog = mk_catalog(exec, file1, file2) catalog.apply FileTest.should_not be_exists(file1[:path]) FileTest.should_not be_exists(file2[:path]) end it "should not trigger subscribing resources on failure" do file1 = tmpfile("file1") file2 = tmpfile("file2") create_file1 = Puppet::Type.type(:exec).new( :command => "/usr/bin/touch #{file1}" ) exec = Puppet::Type.type(:exec).new( :command => "/bin/mkdir /this/path/cannot/possibly/exit", :title => "mkdir", :notify => create_file1 ) create_file2 = Puppet::Type.type(:exec).new( :command => "/usr/bin/touch #{file2}", :subscribe => exec ) catalog = mk_catalog(exec, create_file1, create_file2) catalog.apply FileTest.should_not be_exists(file1) FileTest.should_not be_exists(file2) end # #801 -- resources only checked in noop should be rescheduled immediately. it "should immediately reschedule noop resources" do Puppet::Type.type(:schedule).mkdefaultschedules resource = Puppet::Type.type(:notify).new(:name => "mymessage", :noop => true) catalog = Puppet::Resource::Catalog.new catalog.add_resource resource trans = catalog.apply trans.resource_harness.should be_scheduled(trans.resource_status(resource), resource) end end diff --git a/spec/integration/type/file_spec.rb b/spec/integration/type/file_spec.rb index 44d90a50b..4bed8c6c1 100755 --- a/spec/integration/type/file_spec.rb +++ b/spec/integration/type/file_spec.rb @@ -1,512 +1,511 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet_spec/files' describe Puppet::Type.type(:file) do include PuppetSpec::Files before do # stub this to not try to create state.yaml Puppet::Util::Storage.stubs(:store) end it "should not attempt to manage files that do not exist if no means of creating the file is specified" do file = Puppet::Type.type(:file).new :path => "/my/file", :mode => "755" catalog = Puppet::Resource::Catalog.new catalog.add_resource file file.parameter(:mode).expects(:retrieve).never transaction = Puppet::Transaction.new(catalog) transaction.resource_harness.evaluate(file).should_not be_failed end describe "when writing files" do it "should backup files to a filebucket when one is configured" do bucket = Puppet::Type.type(:filebucket).new :path => tmpfile("filebucket"), :name => "mybucket" file = Puppet::Type.type(:file).new :path => tmpfile("bucket_backs"), :backup => "mybucket", :content => "foo" catalog = Puppet::Resource::Catalog.new catalog.add_resource file catalog.add_resource bucket File.open(file[:path], "w") { |f| f.puts "bar" } md5 = Digest::MD5.hexdigest(File.read(file[:path])) catalog.apply bucket.bucket.getfile(md5).should == "bar\n" end it "should backup files in the local directory when a backup string is provided" do file = Puppet::Type.type(:file).new :path => tmpfile("bucket_backs"), :backup => ".bak", :content => "foo" catalog = Puppet::Resource::Catalog.new catalog.add_resource file File.open(file[:path], "w") { |f| f.puts "bar" } catalog.apply backup = file[:path] + ".bak" FileTest.should be_exist(backup) File.read(backup).should == "bar\n" end it "should fail if no backup can be performed" do dir = tmpfile("backups") Dir.mkdir(dir) path = File.join(dir, "testfile") file = Puppet::Type.type(:file).new :path => path, :backup => ".bak", :content => "foo" catalog = Puppet::Resource::Catalog.new catalog.add_resource file File.open(file[:path], "w") { |f| f.puts "bar" } # Create a directory where the backup should be so that writing to it fails Dir.mkdir(File.join(dir, "testfile.bak")) Puppet::Util::Log.stubs(:newmessage) catalog.apply File.read(file[:path]).should == "bar\n" end it "should not backup symlinks" do link = tmpfile("link") dest1 = tmpfile("dest1") dest2 = tmpfile("dest2") bucket = Puppet::Type.type(:filebucket).new :path => tmpfile("filebucket"), :name => "mybucket" file = Puppet::Type.type(:file).new :path => link, :target => dest2, :ensure => :link, :backup => "mybucket" catalog = Puppet::Resource::Catalog.new catalog.add_resource file catalog.add_resource bucket File.open(dest1, "w") { |f| f.puts "whatever" } File.symlink(dest1, link) md5 = Digest::MD5.hexdigest(File.read(file[:path])) catalog.apply File.readlink(link).should == dest2 Find.find(bucket[:path]) { |f| File.file?(f) }.should be_nil end it "should backup directories to the local filesystem by copying the whole directory" do file = Puppet::Type.type(:file).new :path => tmpfile("bucket_backs"), :backup => ".bak", :content => "foo", :force => true catalog = Puppet::Resource::Catalog.new catalog.add_resource file Dir.mkdir(file[:path]) otherfile = File.join(file[:path], "foo") File.open(otherfile, "w") { |f| f.print "yay" } catalog.apply backup = file[:path] + ".bak" FileTest.should be_directory(backup) File.read(File.join(backup, "foo")).should == "yay" end it "should backup directories to filebuckets by backing up each file separately" do bucket = Puppet::Type.type(:filebucket).new :path => tmpfile("filebucket"), :name => "mybucket" file = Puppet::Type.type(:file).new :path => tmpfile("bucket_backs"), :backup => "mybucket", :content => "foo", :force => true catalog = Puppet::Resource::Catalog.new catalog.add_resource file catalog.add_resource bucket Dir.mkdir(file[:path]) foofile = File.join(file[:path], "foo") barfile = File.join(file[:path], "bar") File.open(foofile, "w") { |f| f.print "fooyay" } File.open(barfile, "w") { |f| f.print "baryay" } foomd5 = Digest::MD5.hexdigest(File.read(foofile)) barmd5 = Digest::MD5.hexdigest(File.read(barfile)) catalog.apply bucket.bucket.getfile(foomd5).should == "fooyay" bucket.bucket.getfile(barmd5).should == "baryay" end it "should propagate failures encountered when renaming the temporary file" do file = Puppet::Type.type(:file).new :path => tmpfile("fail_rename"), :content => "foo" file.stubs(:remove_existing) # because it tries to make a backup catalog = Puppet::Resource::Catalog.new catalog.add_resource file File.open(file[:path], "w") { |f| f.print "bar" } File.expects(:rename).raises ArgumentError lambda { file.write(:content) }.should raise_error(Puppet::Error) File.read(file[:path]).should == "bar" end end describe "when recursing" do def build_path(dir) Dir.mkdir(dir) File.chmod(0750, dir) @dirs = [dir] @files = [] %w{one two}.each do |subdir| fdir = File.join(dir, subdir) Dir.mkdir(fdir) File.chmod(0750, fdir) @dirs << fdir %w{three}.each do |file| ffile = File.join(fdir, file) @files << ffile File.open(ffile, "w") { |f| f.puts "test #{file}" } File.chmod(0640, ffile) end end end it "should be able to recurse over a nonexistent file" do @path = tmpfile("file_integration_tests") @file = Puppet::Type::File.new( :name => @path, :mode => 0644, :recurse => true, :backup => false ) @catalog = Puppet::Resource::Catalog.new @catalog.add_resource @file lambda { @file.eval_generate }.should_not raise_error end it "should be able to recursively set properties on existing files" do @path = tmpfile("file_integration_tests") build_path(@path) @file = Puppet::Type::File.new( :name => @path, :mode => 0644, :recurse => true, :backup => false ) @catalog = Puppet::Resource::Catalog.new @catalog.add_resource @file @catalog.apply @dirs.each do |path| (File.stat(path).mode & 007777).should == 0755 end @files.each do |path| (File.stat(path).mode & 007777).should == 0644 end end it "should be able to recursively make links to other files" do source = tmpfile("file_link_integration_source") build_path(source) dest = tmpfile("file_link_integration_dest") @file = Puppet::Type::File.new(:name => dest, :target => source, :recurse => true, :ensure => :link, :backup => false) @catalog = Puppet::Resource::Catalog.new @catalog.add_resource @file @catalog.apply @dirs.each do |path| link_path = path.sub(source, dest) File.lstat(link_path).should be_directory end @files.each do |path| link_path = path.sub(source, dest) File.lstat(link_path).ftype.should == "link" end end it "should be able to recursively copy files" do source = tmpfile("file_source_integration_source") build_path(source) dest = tmpfile("file_source_integration_dest") @file = Puppet::Type::File.new(:name => dest, :source => source, :recurse => true, :backup => false) @catalog = Puppet::Resource::Catalog.new @catalog.add_resource @file @catalog.apply @dirs.each do |path| newpath = path.sub(source, dest) File.lstat(newpath).should be_directory end @files.each do |path| newpath = path.sub(source, dest) File.lstat(newpath).ftype.should == "file" end end it "should not recursively manage files managed by a more specific explicit file" do dir = tmpfile("recursion_vs_explicit_1") subdir = File.join(dir, "subdir") file = File.join(subdir, "file") FileUtils.mkdir_p(subdir) File.open(file, "w") { |f| f.puts "" } base = Puppet::Type::File.new(:name => dir, :recurse => true, :backup => false, :mode => "755") sub = Puppet::Type::File.new(:name => subdir, :recurse => true, :backup => false, :mode => "644") @catalog = Puppet::Resource::Catalog.new @catalog.add_resource base @catalog.add_resource sub @catalog.apply (File.stat(file).mode & 007777).should == 0644 end it "should recursively manage files even if there is an explicit file whose name is a prefix of the managed file" do dir = tmpfile("recursion_vs_explicit_2") managed = File.join(dir, "file") generated = File.join(dir, "file_with_a_name_starting_with_the_word_file") FileUtils.mkdir_p(dir) File.open(managed, "w") { |f| f.puts "" } File.open(generated, "w") { |f| f.puts "" } @catalog = Puppet::Resource::Catalog.new @catalog.add_resource Puppet::Type::File.new(:name => dir, :recurse => true, :backup => false, :mode => "755") @catalog.add_resource Puppet::Type::File.new(:name => managed, :recurse => true, :backup => false, :mode => "644") @catalog.apply (File.stat(generated).mode & 007777).should == 0755 end end describe "when generating resources" do before do @source = tmpfile("generating_in_catalog_source") @dest = tmpfile("generating_in_catalog_dest") Dir.mkdir(@source) s1 = File.join(@source, "one") s2 = File.join(@source, "two") File.open(s1, "w") { |f| f.puts "uno" } File.open(s2, "w") { |f| f.puts "dos" } @file = Puppet::Type::File.new(:name => @dest, :source => @source, :recurse => true, :backup => false) @catalog = Puppet::Resource::Catalog.new @catalog.add_resource @file end it "should add each generated resource to the catalog" do @catalog.apply do |trans| @catalog.resource(:file, File.join(@dest, "one")).should be_instance_of(@file.class) @catalog.resource(:file, File.join(@dest, "two")).should be_instance_of(@file.class) end end it "should have an edge to each resource in the relationship graph" do @catalog.apply do |trans| one = @catalog.resource(:file, File.join(@dest, "one")) @catalog.relationship_graph.edge?(@file, one).should be two = @catalog.resource(:file, File.join(@dest, "two")) @catalog.relationship_graph.edge?(@file, two).should be end end end describe "when copying files" do # Ticket #285. it "should be able to copy files with pound signs in their names" do source = tmpfile("filewith#signs") dest = tmpfile("destwith#signs") File.open(source, "w") { |f| f.print "foo" } file = Puppet::Type::File.new(:name => dest, :source => source) catalog = Puppet::Resource::Catalog.new catalog.add_resource file catalog.apply File.read(dest).should == "foo" end it "should be able to copy files with spaces in their names" do source = tmpfile("filewith spaces") dest = tmpfile("destwith spaces") File.open(source, "w") { |f| f.print "foo" } File.chmod(0755, source) file = Puppet::Type::File.new(:path => dest, :source => source) catalog = Puppet::Resource::Catalog.new catalog.add_resource file catalog.apply File.read(dest).should == "foo" (File.stat(dest).mode & 007777).should == 0755 end it "should be able to copy individual files even if recurse has been specified" do source = tmpfile("source") dest = tmpfile("dest") File.open(source, "w") { |f| f.print "foo" } file = Puppet::Type::File.new(:name => dest, :source => source, :recurse => true) catalog = Puppet::Resource::Catalog.new catalog.add_resource file catalog.apply File.read(dest).should == "foo" end end it "should be able to create files when 'content' is specified but 'ensure' is not" do dest = tmpfile("files_with_content") file = Puppet::Type.type(:file).new( :name => dest, :content => "this is some content, yo" ) catalog = Puppet::Resource::Catalog.new catalog.add_resource file catalog.apply File.read(dest).should == "this is some content, yo" end it "should create files with content if both 'content' and 'ensure' are set" do dest = tmpfile("files_with_content") file = Puppet::Type.type(:file).new( :name => dest, :ensure => "file", :content => "this is some content, yo" ) catalog = Puppet::Resource::Catalog.new catalog.add_resource file catalog.apply File.read(dest).should == "this is some content, yo" end it "should delete files with sources but that are set for deletion" do dest = tmpfile("dest_source_with_ensure") source = tmpfile("source_source_with_ensure") File.open(source, "w") { |f| f.puts "yay" } File.open(dest, "w") { |f| f.puts "boo" } file = Puppet::Type.type(:file).new( :name => dest, :ensure => :absent, :source => source, :backup => false ) catalog = Puppet::Resource::Catalog.new catalog.add_resource file catalog.apply File.should_not be_exist(dest) end describe "when purging files" do before do @sourcedir = tmpfile("purge_source") @destdir = tmpfile("purge_dest") Dir.mkdir(@sourcedir) Dir.mkdir(@destdir) @sourcefile = File.join(@sourcedir, "sourcefile") @copiedfile = File.join(@destdir, "sourcefile") @localfile = File.join(@destdir, "localfile") @purgee = File.join(@destdir, "to_be_purged") File.open(@localfile, "w") { |f| f.puts "rahtest" } File.open(@sourcefile, "w") { |f| f.puts "funtest" } # this file should get removed File.open(@purgee, "w") { |f| f.puts "footest" } @lfobj = Puppet::Type.newfile( :title => "localfile", :path => @localfile, :content => "rahtest\n", :ensure => :file, :backup => false ) @destobj = Puppet::Type.newfile( :title => "destdir", :path => @destdir, :source => @sourcedir, :backup => false, :purge => true, :recurse => true ) @catalog = Puppet::Resource::Catalog.new @catalog.add_resource @lfobj, @destobj end it "should still copy remote files" do @catalog.apply FileTest.should be_exist(@copiedfile) end it "should not purge managed, local files" do @catalog.apply FileTest.should be_exist(@localfile) end it "should purge files that are neither remote nor otherwise managed" do @catalog.apply FileTest.should_not be_exist(@purgee) end end end diff --git a/spec/integration/type/package_spec.rb b/spec/integration/type/package_spec.rb index 191abd259..7d03cb9c0 100755 --- a/spec/integration/type/package_spec.rb +++ b/spec/integration/type/package_spec.rb @@ -1,25 +1,24 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe Puppet::Type.type(:package), "when choosing a default package provider" do before do # the default provider is cached. Puppet::Type.type(:package).defaultprovider = nil end def provider_name(os) {"Ubuntu" => :apt, "Debian" => :apt, "Darwin" => :pkgdmg, "RedHat" => :up2date, "Fedora" => :yum, "FreeBSD" => :ports, "OpenBSD" => :openbsd, "Solaris" => :sun}[os] end it "should have a default provider" do Puppet::Type.type(:package).defaultprovider.should_not be_nil end it "should choose the correct provider each platform" do unless default_provider = provider_name(Facter.value(:operatingsystem)) pending("No default provider specified in this test for #{Facter.value(:operatingsystem)}") end Puppet::Type.type(:package).defaultprovider.name.should == default_provider end end diff --git a/spec/integration/type/tidy_spec.rb b/spec/integration/type/tidy_spec.rb index f1b74c039..675aaf4cd 100755 --- a/spec/integration/type/tidy_spec.rb +++ b/spec/integration/type/tidy_spec.rb @@ -1,32 +1,31 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet_spec/files' require 'puppet/file_bucket/dipper' describe Puppet::Type.type(:tidy) do include PuppetSpec::Files before do Puppet::Util::Storage.stubs(:store) end # Testing #355. it "should be able to remove dead links" do dir = tmpfile("tidy_link_testing") link = File.join(dir, "link") target = tmpfile("no_such_file_tidy_link_testing") Dir.mkdir(dir) File.symlink(target, link) tidy = Puppet::Type.type(:tidy).new :path => dir, :recurse => true catalog = Puppet::Resource::Catalog.new catalog.add_resource(tidy) catalog.apply FileTest.should_not be_symlink(link) end end diff --git a/spec/integration/type_spec.rb b/spec/integration/type_spec.rb index 0a141924b..4be01d558 100755 --- a/spec/integration/type_spec.rb +++ b/spec/integration/type_spec.rb @@ -1,22 +1,21 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/type' describe Puppet::Type do it "should not lose its provider list when it is reloaded" do type = Puppet::Type.newtype(:integration_test) do newparam(:name) {} end provider = type.provide(:myprovider) {} # reload it type = Puppet::Type.newtype(:integration_test) do newparam(:name) {} end type.provider(:myprovider).should equal(provider) end end diff --git a/spec/integration/util/autoload_spec.rb b/spec/integration/util/autoload_spec.rb index 8ae8339fe..92fc6554c 100755 --- a/spec/integration/util/autoload_spec.rb +++ b/spec/integration/util/autoload_spec.rb @@ -1,114 +1,113 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/util/autoload' require 'fileutils' class AutoloadIntegrator @things = [] def self.newthing(name) @things << name end def self.thing?(name) @things.include? name end def self.clear @things.clear end end require 'puppet_spec/files' describe Puppet::Util::Autoload do include PuppetSpec::Files def with_file(name, *path) path = File.join(*path) # Now create a file to load File.open(path, "w") { |f| f.puts "\nAutoloadIntegrator.newthing(:#{name.to_s})\n" } yield File.delete(path) end def with_loader(name, path) dir = tmpfile(name + path) $LOAD_PATH << dir Dir.mkdir(dir) rbdir = File.join(dir, path.to_s) Dir.mkdir(rbdir) loader = Puppet::Util::Autoload.new(name, path) yield rbdir, loader Dir.rmdir(rbdir) Dir.rmdir(dir) $LOAD_PATH.pop AutoloadIntegrator.clear end it "should make instances available by the loading class" do loader = Puppet::Util::Autoload.new("foo", "bar") Puppet::Util::Autoload["foo"].should == loader end it "should not fail when asked to load a missing file" do Puppet::Util::Autoload.new("foo", "bar").load(:eh).should be_false end it "should load and return true when it successfully loads a file" do with_loader("foo", "bar") { |dir,loader| with_file(:mything, dir, "mything.rb") { loader.load(:mything).should be_true loader.should be_loaded(:mything) AutoloadIntegrator.should be_thing(:mything) } } end it "should consider a file loaded when asked for the name without an extension" do with_loader("foo", "bar") { |dir,loader| with_file(:noext, dir, "noext.rb") { loader.load(:noext) loader.should be_loaded(:noext) } } end it "should consider a file loaded when asked for the name with an extension" do with_loader("foo", "bar") { |dir,loader| with_file(:noext, dir, "withext.rb") { loader.load(:withext) loader.should be_loaded("withext.rb") } } end it "should register the fact that the instance is loaded with the Autoload base class" do with_loader("foo", "bar") { |dir,loader| with_file(:baseload, dir, "baseload.rb") { loader.load(:baseload) Puppet::Util::Autoload.should be_loaded("bar/withext.rb") } } end it "should be able to load files directly from modules" do modulepath = tmpfile("autoload_module_testing") libdir = File.join(modulepath, "mymod", "lib", "foo") FileUtils.mkdir_p(libdir) file = File.join(libdir, "plugin.rb") Puppet[:modulepath] = modulepath with_loader("foo", "foo") do |dir, loader| with_file(:plugin, file.split("/")) do loader.load(:plugin) loader.should be_loaded("plugin.rb") end end end end diff --git a/spec/integration/util/feature_spec.rb b/spec/integration/util/feature_spec.rb index 6a5433efe..c3c13764d 100755 --- a/spec/integration/util/feature_spec.rb +++ b/spec/integration/util/feature_spec.rb @@ -1,54 +1,53 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/util/feature' require 'puppet_spec/files' describe Puppet::Util::Feature do include PuppetSpec::Files it "should be able to load features from disk" do libdir = tmpfile("feature_lib") Dir.mkdir(libdir) $LOAD_PATH << libdir $features = Puppet::Util::Feature.new("feature_lib") Dir.mkdir(File.join(libdir, "feature_lib")) File.open(File.join(libdir, "feature_lib", "able_to_load.rb"), "w") do |f| f.puts "$features.add(:able_to_load) { true }" end $features.should be_able_to_load end # TODO: Make this a spec test or remove it. def test_dynamic_loading $features = @features cleanup { $features = nil } # Now create a feature and make sure it loads. FileUtils.mkdir_p(@path) nope = File.join(@path, "nope.rb") File.open(nope, "w") { |f| f.puts "$features.add(:nope, :libs => %w{nosuchlib})" } assert_nothing_raised("Failed to autoload features") do assert(! @features.nope?, "'nope' returned true") end # First make sure "yep?" returns false assert_nothing_raised("Missing feature threw an exception") do assert(! @features.notyep?, "'notyep' returned true before definition") end yep = File.join(@path, "yep.rb") File.open(yep, "w") { |f| f.puts "$features.add(:yep, :libs => %w{puppet})" } assert(@features.yep?, "false 'yep' is apparently cached or feature could not be loaded") end end diff --git a/spec/integration/util/file_locking_spec.rb b/spec/integration/util/file_locking_spec.rb index 6582a336c..9e829df0e 100755 --- a/spec/integration/util/file_locking_spec.rb +++ b/spec/integration/util/file_locking_spec.rb @@ -1,57 +1,56 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/util/file_locking' describe Puppet::Util::FileLocking do before :each do @file = Tempfile.new("puppetspec") filepath = @file.path @file.close!() @file = filepath @data = {:a => :b, :c => "A string", :d => "another string", :e => %w{an array of strings}} File.open(@file, "w") { |f| f.puts YAML.dump(@data) } end it "should be able to keep file corruption from happening when there are multiple writers threads" do threads = [] sync = Sync.new 9.times { |a| threads << Thread.new { 9.times { |b| sync.synchronize(Sync::SH) { Puppet::Util::FileLocking.readlock(@file) { |f| YAML.load(f.read).should == @data } } sleep 0.01 sync.synchronize(Sync::EX) { Puppet::Util::FileLocking.writelock(@file) { |f| f.puts YAML.dump(@data) } } } } } threads.each { |th| th.join } end it "should be able to keep file corruption from happening when there are multiple writers processes" do unless Process.fork 50.times { |b| Puppet::Util::FileLocking.writelock(@file) { |f| f.puts YAML.dump(@data) } sleep 0.01 } Kernel.exit! end 50.times { |c| Puppet::Util::FileLocking.readlock(@file) { |f| YAML.load(f.read).should == @data } } end end diff --git a/spec/integration/util/rdoc/parser_spec.rb b/spec/integration/util/rdoc/parser_spec.rb index b76846fae..ce316309b 100755 --- a/spec/integration/util/rdoc/parser_spec.rb +++ b/spec/integration/util/rdoc/parser_spec.rb @@ -1,59 +1,58 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/resource/type_collection' require 'puppet/util/rdoc/parser' require 'puppet/util/rdoc' require 'puppet/util/rdoc/code_objects' require 'rdoc/options' require 'rdoc/rdoc' describe RDoc::Parser do require 'puppet_spec/files' include PuppetSpec::Files before :each do tmpdir = tmpfile('rdoc_parser_tmp') Dir.mkdir(tmpdir) @parsedfile = File.join(tmpdir, 'init.pp') File.open(@parsedfile, 'w') do |f| f.puts '# comment' f.puts 'class ::test {}' end @top_level = stub_everything 'toplevel', :file_relative_name => @parsedfile @module = stub_everything 'module' @puppet_top_level = RDoc::PuppetTopLevel.new(@top_level) RDoc::PuppetTopLevel.stubs(:new).returns(@puppet_top_level) @puppet_top_level.expects(:add_module).returns(@module) @parser = RDoc::Parser.new(@top_level, @parsedfile, nil, Options.instance, RDoc::Stats.new) end after(:each) do File.unlink(@parsedfile) end def get_test_class(toplevel) # toplevel -> main -> test toplevel.classes[0].classes[0] end it "should parse to RDoc data structure" do @parser.expects(:document_class).with { |n,k,c| n == "::test" and k.is_a?(Puppet::Resource::Type) } @parser.scan end it "should get a PuppetClass for the main class" do @parser.scan.classes[0].should be_a(RDoc::PuppetClass) end it "should produce a PuppetClass whose name is test" do get_test_class(@parser.scan).name.should == "test" end it "should produce a PuppetClass whose comment is 'comment'" do get_test_class(@parser.scan).comment.should == "comment\n" end end diff --git a/spec/integration/util/settings_spec.rb b/spec/integration/util/settings_spec.rb index f5bdb790f..b05c63107 100755 --- a/spec/integration/util/settings_spec.rb +++ b/spec/integration/util/settings_spec.rb @@ -1,30 +1,29 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet_spec/files' describe Puppet::Util::Settings do include PuppetSpec::Files def minimal_default_settings { :noop => {:default => false, :desc => "noop"} } end it "should be able to make needed directories" do settings = Puppet::Util::Settings.new settings.setdefaults :main, minimal_default_settings.update( :maindir => [tmpfile("main"), "a"] ) settings.use(:main) File.should be_directory(settings[:maindir]) end it "should make its directories with the corret modes" do settings = Puppet::Util::Settings.new settings.setdefaults :main, minimal_default_settings.update( :maindir => {:default => tmpfile("main"), :desc => "a", :mode => 0750} ) settings.use(:main) (File.stat(settings[:maindir]).mode & 007777).should == 0750 end end diff --git a/spec/lib/puppet/face/basetest.rb b/spec/lib/puppet/face/basetest.rb new file mode 100755 index 000000000..00616f74f --- /dev/null +++ b/spec/lib/puppet/face/basetest.rb @@ -0,0 +1 @@ +Puppet::Face.define(:basetest, '0.0.1') diff --git a/spec/lib/puppet/faces/huzzah.rb b/spec/lib/puppet/face/huzzah.rb old mode 100644 new mode 100755 similarity index 59% rename from spec/lib/puppet/faces/huzzah.rb rename to spec/lib/puppet/face/huzzah.rb index e86730250..3428c6816 --- a/spec/lib/puppet/faces/huzzah.rb +++ b/spec/lib/puppet/face/huzzah.rb @@ -1,5 +1,5 @@ -require 'puppet/faces' -Puppet::Faces.define(:huzzah, '2.0.1') do +require 'puppet/face' +Puppet::Face.define(:huzzah, '2.0.1') do summary "life is a thing for celebration" action :bar do "is where beer comes from" end end diff --git a/spec/lib/puppet/faces/basetest.rb b/spec/lib/puppet/faces/basetest.rb deleted file mode 100644 index d20c52b97..000000000 --- a/spec/lib/puppet/faces/basetest.rb +++ /dev/null @@ -1 +0,0 @@ -Puppet::Faces.define(:basetest, '0.0.1') diff --git a/spec/lib/puppet_spec/files.rb b/spec/lib/puppet_spec/files.rb old mode 100644 new mode 100755 diff --git a/spec/lib/puppet_spec/fixtures.rb b/spec/lib/puppet_spec/fixtures.rb old mode 100644 new mode 100755 diff --git a/spec/lib/puppet_spec/verbose.rb b/spec/lib/puppet_spec/verbose.rb old mode 100644 new mode 100755 diff --git a/spec/monkey_patches/alias_should_to_must.rb b/spec/monkey_patches/alias_should_to_must.rb old mode 100644 new mode 100755 diff --git a/spec/monkey_patches/publicize_methods.rb b/spec/monkey_patches/publicize_methods.rb old mode 100644 new mode 100755 diff --git a/spec/shared_behaviours/all_parsedfile_providers.rb b/spec/shared_behaviours/all_parsedfile_providers.rb old mode 100644 new mode 100755 diff --git a/spec/shared_behaviours/file_server_terminus.rb b/spec/shared_behaviours/file_server_terminus.rb old mode 100644 new mode 100755 index 94a044d2e..f59169382 --- a/spec/shared_behaviours/file_server_terminus.rb +++ b/spec/shared_behaviours/file_server_terminus.rb @@ -1,45 +1,45 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Created by Luke Kanies on 2007-10-18. # Copyright (c) 2007. All rights reserved. shared_examples_for "Puppet::Indirector::FileServerTerminus" do # This only works if the shared behaviour is included before # the 'before' block in the including context. before do Puppet::Util::Cacher.expire FileTest.stubs(:exists?).returns true FileTest.stubs(:exists?).with(Puppet[:fileserverconfig]).returns(true) @path = Tempfile.new("file_server_testing") path = @path.path @path.close! @path = path Dir.mkdir(@path) File.open(File.join(@path, "myfile"), "w") { |f| f.print "my content" } # Use a real mount, so the integration is a bit deeper. @mount1 = Puppet::FileServing::Configuration::Mount::File.new("one") @mount1.path = @path @parser = stub 'parser', :changed? => false @parser.stubs(:parse).returns("one" => @mount1) Puppet::FileServing::Configuration::Parser.stubs(:new).returns(@parser) # Stub out the modules terminus @modules = mock 'modules terminus' @request = Puppet::Indirector::Request.new(:indirection, :method, "puppet://myhost/one/myfile") end it "should use the file server configuration to find files" do @modules.stubs(:find).returns(nil) @terminus.indirection.stubs(:terminus).with(:modules).returns(@modules) path = File.join(@path, "myfile") @terminus.find(@request).should be_instance_of(@test_class) end end diff --git a/spec/shared_behaviours/file_serving.rb b/spec/shared_behaviours/file_serving.rb old mode 100644 new mode 100755 index 84173448a..3afab5b59 --- a/spec/shared_behaviours/file_serving.rb +++ b/spec/shared_behaviours/file_serving.rb @@ -1,71 +1,71 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Created by Luke Kanies on 2007-10-18. # Copyright (c) 2007. All rights reserved. shared_examples_for "Puppet::FileServing::Files" do it "should use the rest terminus when the 'puppet' URI scheme is used and a host name is present" do uri = "puppet://myhost/fakemod/my/file" # It appears that the mocking somehow interferes with the caching subsystem. # This mock somehow causes another terminus to get generated. term = @indirection.terminus(:rest) @indirection.stubs(:terminus).with(:rest).returns term term.expects(:find) @indirection.find(uri) end it "should use the rest terminus when the 'puppet' URI scheme is used, no host name is present, and the process name is not 'puppet' or 'apply'" do uri = "puppet:///fakemod/my/file" Puppet.settings.stubs(:value).returns "foo" Puppet.settings.stubs(:value).with(:name).returns("puppetd") Puppet.settings.stubs(:value).with(:modulepath).returns("") @indirection.terminus(:rest).expects(:find) @indirection.find(uri) end it "should use the file_server terminus when the 'puppet' URI scheme is used, no host name is present, and the process name is 'puppet'" do uri = "puppet:///fakemod/my/file" Puppet::Node::Environment.stubs(:new).returns(stub("env", :name => "testing", :module => nil, :modulepath => [])) Puppet.settings.stubs(:value).returns "" Puppet.settings.stubs(:value).with(:name).returns("puppet") Puppet.settings.stubs(:value).with(:fileserverconfig).returns("/whatever") @indirection.terminus(:file_server).expects(:find) @indirection.terminus(:file_server).stubs(:authorized?).returns(true) @indirection.find(uri) end it "should use the file_server terminus when the 'puppet' URI scheme is used, no host name is present, and the process name is 'apply'" do uri = "puppet:///fakemod/my/file" Puppet::Node::Environment.stubs(:new).returns(stub("env", :name => "testing", :module => nil, :modulepath => [])) Puppet.settings.stubs(:value).returns "" Puppet.settings.stubs(:value).with(:name).returns("apply") Puppet.settings.stubs(:value).with(:fileserverconfig).returns("/whatever") @indirection.terminus(:file_server).expects(:find) @indirection.terminus(:file_server).stubs(:authorized?).returns(true) @indirection.find(uri) end it "should use the file terminus when the 'file' URI scheme is used" do uri = "file:///fakemod/my/file" @indirection.terminus(:file).expects(:find) @indirection.find(uri) end it "should use the file terminus when a fully qualified path is provided" do uri = "/fakemod/my/file" @indirection.terminus(:file).expects(:find) @indirection.find(uri) end it "should use the configuration to test whether the request is allowed" do uri = "fakemod/my/file" mount = mock 'mount' config = stub 'configuration', :split_path => [mount, "eh"] @indirection.terminus(:file_server).stubs(:configuration).returns config @indirection.terminus(:file_server).expects(:find) mount.expects(:allowed?).returns(true) @indirection.find(uri, :node => "foo", :ip => "bar") end end diff --git a/spec/shared_behaviours/memory_terminus.rb b/spec/shared_behaviours/memory_terminus.rb old mode 100644 new mode 100755 diff --git a/spec/shared_behaviours/path_parameters.rb b/spec/shared_behaviours/path_parameters.rb old mode 100644 new mode 100755 diff --git a/spec/shared_behaviours/things_that_declare_options.rb b/spec/shared_behaviours/things_that_declare_options.rb old mode 100644 new mode 100755 diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb old mode 100644 new mode 100755 diff --git a/spec/unit/agent/locker_spec.rb b/spec/unit/agent/locker_spec.rb index c1eb9bbbb..341859e3b 100755 --- a/spec/unit/agent/locker_spec.rb +++ b/spec/unit/agent/locker_spec.rb @@ -1,100 +1,99 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/agent' require 'puppet/agent/locker' class LockerTester include Puppet::Agent::Locker end describe Puppet::Agent::Locker do before do @locker = LockerTester.new @locker.stubs(:lockfile_path).returns "/my/lock" end it "should use a Pidlock instance as its lockfile" do @locker.lockfile.should be_instance_of(Puppet::Util::Pidlock) end it "should use 'lockfile_path' to determine its lockfile path" do @locker.expects(:lockfile_path).returns "/my/lock" lock = Puppet::Util::Pidlock.new("/my/lock") Puppet::Util::Pidlock.expects(:new).with("/my/lock").returns lock @locker.lockfile end it "should reuse the same lock file each time" do @locker.lockfile.should equal(@locker.lockfile) end it "should use the lock file to anonymously lock the process when disabled" do @locker.lockfile.expects(:lock).with(:anonymous => true) @locker.disable end it "should use the lock file to anonymously unlock the process when enabled" do @locker.lockfile.expects(:unlock).with(:anonymous => true) @locker.enable end it "should have a method that yields when a lock is attained" do @locker.lockfile.expects(:lock).returns true yielded = false @locker.lock do yielded = true end yielded.should be_true end it "should return true when the lock method successfully locked" do @locker.lockfile.expects(:lock).returns true @locker.lock {}.should be_true end it "should return true when the lock method does not receive the lock" do @locker.lockfile.expects(:lock).returns false @locker.lock {}.should be_false end it "should not yield when the lock method does not receive the lock" do @locker.lockfile.expects(:lock).returns false yielded = false @locker.lock { yielded = true } yielded.should be_false end it "should not unlock when a lock was not received" do @locker.lockfile.expects(:lock).returns false @locker.lockfile.expects(:unlock).never @locker.lock {} end it "should unlock after yielding upon obtaining a lock" do @locker.lockfile.stubs(:lock).returns true @locker.lockfile.expects(:unlock) @locker.lock {} end it "should unlock after yielding upon obtaining a lock, even if the block throws an exception" do @locker.lockfile.stubs(:lock).returns true @locker.lockfile.expects(:unlock) lambda { @locker.lock { raise "foo" } }.should raise_error(RuntimeError) end it "should be considered running if the lockfile is locked" do @locker.lockfile.expects(:locked?).returns true @locker.should be_running end end diff --git a/spec/unit/agent_spec.rb b/spec/unit/agent_spec.rb index 78fb5fde6..bfa44f61c 100755 --- a/spec/unit/agent_spec.rb +++ b/spec/unit/agent_spec.rb @@ -1,281 +1,281 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Created by Luke Kanies on 2007-11-12. # Copyright (c) 2007. All rights reserved. require 'spec_helper' require 'puppet/agent' class AgentTestClient def run # no-op end def stop # no-op end end def without_warnings flag = $VERBOSE $VERBOSE = nil yield $VERBOSE = flag end describe Puppet::Agent do before do @agent = Puppet::Agent.new(AgentTestClient) # So we don't actually try to hit the filesystem. @agent.stubs(:lock).yields # make Puppet::Application safe for stubbing; restore in an :after block; silence warnings for this. without_warnings { Puppet::Application = Class.new(Puppet::Application) } Puppet::Application.stubs(:clear?).returns(true) Puppet::Application.class_eval do class << self def controlled_run(&block) block.call end end end end after do # restore Puppet::Application from stub-safe subclass, and silence warnings without_warnings { Puppet::Application = Puppet::Application.superclass } end it "should set its client class at initialization" do Puppet::Agent.new("foo").client_class.should == "foo" end it "should include the Locker module" do Puppet::Agent.ancestors.should be_include(Puppet::Agent::Locker) end it "should create an instance of its client class and run it when asked to run" do client = mock 'client' AgentTestClient.expects(:new).returns client client.expects(:run) @agent.stubs(:running?).returns false @agent.run end it "should determine its lock file path by asking the client class" do AgentTestClient.expects(:lockfile_path).returns "/my/lock" @agent.lockfile_path.should == "/my/lock" end it "should be considered running if the lock file is locked" do lockfile = mock 'lockfile' @agent.expects(:lockfile).returns lockfile lockfile.expects(:locked?).returns true @agent.should be_running end describe "when being run" do before do @agent.stubs(:running?).returns false end it "should splay" do @agent.expects(:splay) @agent.stubs(:running?).returns false @agent.run end it "should do nothing if already running" do @agent.expects(:running?).returns true AgentTestClient.expects(:new).never @agent.run end it "should use Puppet::Application.controlled_run to manage process state behavior" do calls = sequence('calls') Puppet::Application.expects(:controlled_run).yields.in_sequence(calls) AgentTestClient.expects(:new).once.in_sequence(calls) @agent.run end it "should not fail if a client class instance cannot be created" do AgentTestClient.expects(:new).raises "eh" Puppet.expects(:err) @agent.run end it "should not fail if there is an exception while running its client" do client = AgentTestClient.new AgentTestClient.expects(:new).returns client client.expects(:run).raises "eh" Puppet.expects(:err) @agent.run end it "should use a mutex to restrict multi-threading" do client = AgentTestClient.new AgentTestClient.expects(:new).returns client mutex = mock 'mutex' @agent.expects(:sync).returns mutex mutex.expects(:synchronize) client.expects(:run).never # if it doesn't run, then we know our yield is what triggers it @agent.run end it "should use a filesystem lock to restrict multiple processes running the agent" do client = AgentTestClient.new AgentTestClient.expects(:new).returns client @agent.expects(:lock) client.expects(:run).never # if it doesn't run, then we know our yield is what triggers it @agent.run end it "should make its client instance available while running" do client = AgentTestClient.new AgentTestClient.expects(:new).returns client client.expects(:run).with { @agent.client.should equal(client); true } @agent.run end it "should run the client instance with any arguments passed to it" do client = AgentTestClient.new AgentTestClient.expects(:new).returns client client.expects(:run).with("testargs") @agent.run("testargs") end end describe "when splaying" do before do Puppet.settings.stubs(:value).with(:splay).returns true Puppet.settings.stubs(:value).with(:splaylimit).returns "10" end it "should do nothing if splay is disabled" do Puppet.settings.expects(:value).returns false @agent.expects(:sleep).never @agent.splay end it "should do nothing if it has already splayed" do @agent.expects(:splayed?).returns true @agent.expects(:sleep).never @agent.splay end it "should log that it is splaying" do @agent.stubs :sleep Puppet.expects :info @agent.splay end it "should sleep for a random portion of the splaylimit plus 1" do Puppet.settings.expects(:value).with(:splaylimit).returns "50" @agent.expects(:rand).with(51).returns 10 @agent.expects(:sleep).with(10) @agent.splay end it "should mark that it has splayed" do @agent.stubs(:sleep) @agent.splay @agent.should be_splayed end end describe "when checking execution state" do describe 'with regular run status' do before :each do Puppet::Application.stubs(:restart_requested?).returns(false) Puppet::Application.stubs(:stop_requested?).returns(false) Puppet::Application.stubs(:interrupted?).returns(false) Puppet::Application.stubs(:clear?).returns(true) end it 'should be false for :stopping?' do @agent.stopping?.should be_false end it 'should be false for :needing_restart?' do @agent.needing_restart?.should be_false end end describe 'with a stop requested' do before :each do Puppet::Application.stubs(:clear?).returns(false) Puppet::Application.stubs(:restart_requested?).returns(false) Puppet::Application.stubs(:stop_requested?).returns(true) Puppet::Application.stubs(:interrupted?).returns(true) end it 'should be true for :stopping?' do @agent.stopping?.should be_true end it 'should be false for :needing_restart?' do @agent.needing_restart?.should be_false end end describe 'with a restart requested' do before :each do Puppet::Application.stubs(:clear?).returns(false) Puppet::Application.stubs(:restart_requested?).returns(true) Puppet::Application.stubs(:stop_requested?).returns(false) Puppet::Application.stubs(:interrupted?).returns(true) end it 'should be false for :stopping?' do @agent.stopping?.should be_false end it 'should be true for :needing_restart?' do @agent.needing_restart?.should be_true end end end describe "when starting" do before do @agent.stubs(:observe_signal) end it "should create a timer with the runinterval, a tolerance of 1, and :start? set to true" do Puppet.settings.expects(:value).with(:runinterval).returns 5 timer = stub 'timer', :sound_alarm => nil EventLoop::Timer.expects(:new).with(:interval => 5, :start? => true, :tolerance => 1).returns timer @agent.stubs(:run) @agent.start end it "should run once immediately" do timer = mock 'timer' EventLoop::Timer.expects(:new).returns timer timer.expects(:sound_alarm) @agent.start end it "should run within the block passed to the timer" do timer = stub 'timer', :sound_alarm => nil EventLoop::Timer.expects(:new).returns(timer).yields @agent.expects(:run) @agent.start end end end diff --git a/spec/unit/application/agent_spec.rb b/spec/unit/application/agent_spec.rb index ad2748b7f..03cf14429 100755 --- a/spec/unit/application/agent_spec.rb +++ b/spec/unit/application/agent_spec.rb @@ -1,593 +1,592 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/agent' require 'puppet/application/agent' require 'puppet/network/server' require 'puppet/daemon' require 'puppet/network/handler' describe Puppet::Application::Agent do before :each do @puppetd = Puppet::Application[:agent] @puppetd.stubs(:puts) @daemon = stub_everything 'daemon' Puppet::Daemon.stubs(:new).returns(@daemon) Puppet[:daemonize] = false @agent = stub_everything 'agent' Puppet::Agent.stubs(:new).returns(@agent) @puppetd.preinit Puppet::Util::Log.stubs(:newdestination) Puppet::Util::Log.stubs(:level=) Puppet::Node.indirection.stubs(:terminus_class=) Puppet::Node.indirection.stubs(:cache_class=) Puppet::Node::Facts.indirection.stubs(:terminus_class=) end it "should operate in agent run_mode" do @puppetd.class.run_mode.name.should == :agent end it "should ask Puppet::Application to parse Puppet configuration file" do @puppetd.should_parse_config?.should be_true end it "should declare a main command" do @puppetd.should respond_to(:main) end it "should declare a onetime command" do @puppetd.should respond_to(:onetime) end it "should declare a fingerprint command" do @puppetd.should respond_to(:fingerprint) end it "should declare a preinit block" do @puppetd.should respond_to(:preinit) end describe "in preinit" do it "should catch INT" do Signal.expects(:trap).with { |arg,block| arg == :INT } @puppetd.preinit end it "should init client to true" do @puppetd.preinit @puppetd.options[:client].should be_true end it "should init fqdn to nil" do @puppetd.preinit @puppetd.options[:fqdn].should be_nil end it "should init serve to []" do @puppetd.preinit @puppetd.options[:serve].should == [] end it "should use MD5 as default digest algorithm" do @puppetd.preinit @puppetd.options[:digest].should == :MD5 end it "should not fingerprint by default" do @puppetd.preinit @puppetd.options[:fingerprint].should be_false end end describe "when handling options" do before do @puppetd.command_line.stubs(:args).returns([]) end [:centrallogging, :disable, :enable, :debug, :fqdn, :test, :verbose, :digest].each do |option| it "should declare handle_#{option} method" do @puppetd.should respond_to("handle_#{option}".to_sym) end it "should store argument value when calling handle_#{option}" do @puppetd.options.expects(:[]=).with(option, 'arg') @puppetd.send("handle_#{option}".to_sym, 'arg') end end it "should set an existing handler on server" do Puppet::Network::Handler.stubs(:handler).with("handler").returns(true) @puppetd.handle_serve("handler") @puppetd.options[:serve].should == [ :handler ] end it "should set client to false with --no-client" do @puppetd.handle_no_client(nil) @puppetd.options[:client].should be_false end it "should set waitforcert to 0 with --onetime and if --waitforcert wasn't given" do Puppet[:onetime] = true Puppet::SSL::Host.any_instance.expects(:wait_for_cert).with(0) @puppetd.setup_host end it "should use supplied waitforcert when --onetime is specified" do Puppet[:onetime] = true @puppetd.handle_waitforcert(60) Puppet::SSL::Host.any_instance.expects(:wait_for_cert).with(60) @puppetd.setup_host end it "should use a default value for waitforcert when --onetime and --waitforcert are not specified" do Puppet::SSL::Host.any_instance.expects(:wait_for_cert).with(120) @puppetd.setup_host end it "should set the log destination with --logdest" do @puppetd.options.stubs(:[]=).with { |opt,val| opt == :setdest } Puppet::Log.expects(:newdestination).with("console") @puppetd.handle_logdest("console") end it "should put the setdest options to true" do @puppetd.options.expects(:[]=).with(:setdest,true) @puppetd.handle_logdest("console") end it "should parse the log destination from the command line" do @puppetd.command_line.stubs(:args).returns(%w{--logdest /my/file}) Puppet::Util::Log.expects(:newdestination).with("/my/file") @puppetd.parse_options end it "should store the waitforcert options with --waitforcert" do @puppetd.options.expects(:[]=).with(:waitforcert,42) @puppetd.handle_waitforcert("42") end it "should set args[:Port] with --port" do @puppetd.handle_port("42") @puppetd.args[:Port].should == "42" end end describe "during setup" do before :each do @puppetd.options.stubs(:[]) Puppet.stubs(:info) FileTest.stubs(:exists?).returns(true) Puppet[:libdir] = "/dev/null/lib" Puppet::SSL::Host.stubs(:ca_location=) Puppet::Transaction::Report.indirection.stubs(:terminus_class=) Puppet::Transaction::Report.indirection.stubs(:cache_class=) Puppet::Resource::Catalog.indirection.stubs(:terminus_class=) Puppet::Resource::Catalog.indirection.stubs(:cache_class=) Puppet::Node::Facts.indirection.stubs(:terminus_class=) @host = stub_everything 'host' Puppet::SSL::Host.stubs(:new).returns(@host) Puppet.stubs(:settraps) end describe "with --test" do before :each do #Puppet.settings.stubs(:handlearg) @puppetd.options.stubs(:[]=) end it "should call setup_test" do @puppetd.options.stubs(:[]).with(:test).returns(true) @puppetd.expects(:setup_test) @puppetd.setup end it "should set options[:verbose] to true" do @puppetd.options.expects(:[]=).with(:verbose,true) @puppetd.setup_test end it "should set options[:onetime] to true" do Puppet[:onetime] = false @puppetd.setup_test Puppet[:onetime].should == true end it "should set options[:detailed_exitcodes] to true" do @puppetd.options.expects(:[]=).with(:detailed_exitcodes,true) @puppetd.setup_test end end it "should call setup_logs" do @puppetd.expects(:setup_logs) @puppetd.setup end describe "when setting up logs" do before :each do Puppet::Util::Log.stubs(:newdestination) end it "should set log level to debug if --debug was passed" do @puppetd.options.stubs(:[]).with(:debug).returns(true) Puppet::Util::Log.expects(:level=).with(:debug) @puppetd.setup_logs end it "should set log level to info if --verbose was passed" do @puppetd.options.stubs(:[]).with(:verbose).returns(true) Puppet::Util::Log.expects(:level=).with(:info) @puppetd.setup_logs end [:verbose, :debug].each do |level| it "should set console as the log destination with level #{level}" do @puppetd.options.stubs(:[]).with(level).returns(true) Puppet::Util::Log.expects(:newdestination).with(:console) @puppetd.setup_logs end end it "should set syslog as the log destination if no --logdest" do @puppetd.options.stubs(:[]).with(:setdest).returns(false) Puppet::Util::Log.expects(:newdestination).with(:syslog) @puppetd.setup_logs end end it "should print puppet config if asked to in Puppet config" do @puppetd.stubs(:exit) Puppet[:configprint] = "pluginsync" Puppet.settings.expects(:print_configs) @puppetd.setup end it "should exit after printing puppet config if asked to in Puppet config" do Puppet[:modulepath] = '/my/path' Puppet[:configprint] = "modulepath" Puppet::Util::Settings.any_instance.expects(:puts).with('/my/path') lambda { @puppetd.setup }.should raise_error(SystemExit) end it "should set a central log destination with --centrallogs" do @puppetd.options.stubs(:[]).with(:centrallogs).returns(true) Puppet[:server] = "puppet.reductivelabs.com" Puppet::Util::Log.stubs(:newdestination).with(:syslog) Puppet::Util::Log.expects(:newdestination).with("puppet.reductivelabs.com") @puppetd.setup end it "should use :main, :puppetd, and :ssl" do Puppet.settings.expects(:use).with(:main, :agent, :ssl) @puppetd.setup end it "should install a remote ca location" do Puppet::SSL::Host.expects(:ca_location=).with(:remote) @puppetd.setup end it "should install a none ca location in fingerprint mode" do @puppetd.options.stubs(:[]).with(:fingerprint).returns(true) Puppet::SSL::Host.expects(:ca_location=).with(:none) @puppetd.setup end it "should tell the report handler to use REST" do Puppet::Transaction::Report.indirection.expects(:terminus_class=).with(:rest) @puppetd.setup end it "should tell the report handler to cache locally as yaml" do Puppet::Transaction::Report.indirection.expects(:cache_class=).with(:yaml) @puppetd.setup end it "should change the catalog_terminus setting to 'rest'" do Puppet[:catalog_terminus] = :foo @puppetd.setup Puppet[:catalog_terminus].should == :rest end it "should tell the catalog handler to use cache" do Puppet::Resource::Catalog.indirection.expects(:cache_class=).with(:yaml) @puppetd.setup end it "should change the facts_terminus setting to 'facter'" do Puppet[:facts_terminus] = :foo @puppetd.setup Puppet[:facts_terminus].should == :facter end it "should create an agent" do Puppet::Agent.stubs(:new).with(Puppet::Configurer) @puppetd.setup end [:enable, :disable].each do |action| it "should delegate to enable_disable_client if we #{action} the agent" do @puppetd.options.stubs(:[]).with(action).returns(true) @puppetd.expects(:enable_disable_client).with(@agent) @puppetd.setup end end describe "when enabling or disabling agent" do [:enable, :disable].each do |action| it "should call client.#{action}" do @puppetd.stubs(:exit) @puppetd.options.stubs(:[]).with(action).returns(true) @agent.expects(action) @puppetd.enable_disable_client(@agent) end end it "should finally exit" do lambda { @puppetd.enable_disable_client(@agent) }.should raise_error(SystemExit) end end it "should inform the daemon about our agent if :client is set to 'true'" do @puppetd.options.expects(:[]).with(:client).returns true @daemon.expects(:agent=).with(@agent) @puppetd.setup end it "should not inform the daemon about our agent if :client is set to 'false'" do @puppetd.options[:client] = false @daemon.expects(:agent=).never @puppetd.setup end it "should daemonize if needed" do Puppet[:daemonize] = true @daemon.expects(:daemonize) @puppetd.setup end it "should wait for a certificate" do @puppetd.options.stubs(:[]).with(:waitforcert).returns(123) @host.expects(:wait_for_cert).with(123) @puppetd.setup end it "should not wait for a certificate in fingerprint mode" do @puppetd.options.stubs(:[]).with(:fingerprint).returns(true) @puppetd.options.stubs(:[]).with(:waitforcert).returns(123) @host.expects(:wait_for_cert).never @puppetd.setup end it "should setup listen if told to and not onetime" do Puppet[:listen] = true @puppetd.options.stubs(:[]).with(:onetime).returns(false) @puppetd.expects(:setup_listen) @puppetd.setup end describe "when setting up listen" do before :each do Puppet[:authconfig] = 'auth' FileTest.stubs(:exists?).with('auth').returns(true) File.stubs(:exist?).returns(true) @puppetd.options.stubs(:[]).with(:serve).returns([]) @puppetd.stubs(:exit) @server = stub_everything 'server' Puppet::Network::Server.stubs(:new).returns(@server) end it "should exit if no authorization file" do Puppet.stubs(:err) FileTest.stubs(:exists?).with(Puppet[:authconfig]).returns(false) @puppetd.expects(:exit) @puppetd.setup_listen end it "should create a server to listen on at least the Runner handler" do Puppet::Network::Server.expects(:new).with { |args| args[:xmlrpc_handlers] == [:Runner] } @puppetd.setup_listen end it "should create a server to listen for specific handlers" do @puppetd.options.stubs(:[]).with(:serve).returns([:handler]) Puppet::Network::Server.expects(:new).with { |args| args[:xmlrpc_handlers] == [:handler] } @puppetd.setup_listen end it "should use puppet default port" do Puppet[:puppetport] = 32768 Puppet::Network::Server.expects(:new).with { |args| args[:port] == 32768 } @puppetd.setup_listen end end end describe "when running" do before :each do @puppetd.agent = @agent @puppetd.daemon = @daemon @puppetd.options.stubs(:[]).with(:fingerprint).returns(false) end it "should dispatch to fingerprint if --fingerprint is used" do @puppetd.options.stubs(:[]).with(:fingerprint).returns(true) @puppetd.stubs(:fingerprint) @puppetd.run_command end it "should dispatch to onetime if --onetime is used" do @puppetd.options.stubs(:[]).with(:onetime).returns(true) @puppetd.stubs(:onetime) @puppetd.run_command end it "should dispatch to main if --onetime and --fingerprint are not used" do @puppetd.options.stubs(:[]).with(:onetime).returns(false) @puppetd.stubs(:main) @puppetd.run_command end describe "with --onetime" do before :each do @agent.stubs(:run).returns(:report) @puppetd.options.stubs(:[]).with(:client).returns(:client) @puppetd.options.stubs(:[]).with(:detailed_exitcodes).returns(false) @puppetd.stubs(:exit).with(0) Puppet.stubs(:newservice) end it "should exit if no defined --client" do $stderr.stubs(:puts) @puppetd.options.stubs(:[]).with(:client).returns(nil) @puppetd.expects(:exit).with(43) @puppetd.onetime end it "should setup traps" do @daemon.expects(:set_signal_traps) @puppetd.onetime end it "should let the agent run" do @agent.expects(:run).returns(:report) @puppetd.onetime end it "should finish by exiting with 0 error code" do @puppetd.expects(:exit).with(0) @puppetd.onetime end describe "and --detailed-exitcodes" do before :each do @puppetd.options.stubs(:[]).with(:detailed_exitcodes).returns(true) end it "should exit with report's computed exit status" do Puppet[:noop] = false report = stub 'report', :exit_status => 666 @agent.stubs(:run).returns(report) @puppetd.expects(:exit).with(666) @puppetd.onetime end it "should exit with the report's computer exit status, even if --noop is set." do Puppet[:noop] = true report = stub 'report', :exit_status => 666 @agent.stubs(:run).returns(report) @puppetd.expects(:exit).with(666) @puppetd.onetime end end end describe "with --fingerprint" do before :each do @cert = stub_everything 'cert' @puppetd.options.stubs(:[]).with(:fingerprint).returns(true) @puppetd.options.stubs(:[]).with(:digest).returns(:MD5) @host = stub_everything 'host' @puppetd.stubs(:host).returns(@host) end it "should fingerprint the certificate if it exists" do @host.expects(:certificate).returns(@cert) @cert.expects(:fingerprint).with(:MD5).returns "fingerprint" @puppetd.fingerprint end it "should fingerprint the certificate request if no certificate have been signed" do @host.expects(:certificate).returns(nil) @host.expects(:certificate_request).returns(@cert) @cert.expects(:fingerprint).with(:MD5).returns "fingerprint" @puppetd.fingerprint end it "should display the fingerprint" do @host.stubs(:certificate).returns(@cert) @cert.stubs(:fingerprint).with(:MD5).returns("DIGEST") Puppet.expects(:notice).with("DIGEST") @puppetd.fingerprint end end describe "without --onetime and --fingerprint" do before :each do Puppet.stubs(:notice) @puppetd.options.stubs(:[]).with(:client) end it "should start our daemon" do @daemon.expects(:start) @puppetd.main end end end end diff --git a/spec/unit/application/apply_spec.rb b/spec/unit/application/apply_spec.rb index b4141fc17..66c658e7f 100755 --- a/spec/unit/application/apply_spec.rb +++ b/spec/unit/application/apply_spec.rb @@ -1,434 +1,433 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/application/apply' require 'puppet/file_bucket/dipper' require 'puppet/configurer' describe Puppet::Application::Apply do before :each do @apply = Puppet::Application[:apply] Puppet::Util::Log.stubs(:newdestination) Puppet::Util::Log.stubs(:level=) end [:debug,:loadclasses,:verbose,:use_nodes,:detailed_exitcodes].each do |option| it "should declare handle_#{option} method" do @apply.should respond_to("handle_#{option}".to_sym) end it "should store argument value when calling handle_#{option}" do @apply.options.expects(:[]=).with(option, 'arg') @apply.send("handle_#{option}".to_sym, 'arg') end end it "should set the code to the provided code when :execute is used" do @apply.options.expects(:[]=).with(:code, 'arg') @apply.send("handle_execute".to_sym, 'arg') end it "should ask Puppet::Application to parse Puppet configuration file" do @apply.should_parse_config?.should be_true end describe "when applying options" do it "should set the log destination with --logdest" do Puppet::Log.expects(:newdestination).with("console") @apply.handle_logdest("console") end it "should put the logset options to true" do @apply.options.expects(:[]=).with(:logset,true) @apply.handle_logdest("console") end end describe "during setup" do before :each do Puppet::Log.stubs(:newdestination) Puppet::Log.stubs(:level=) Puppet.stubs(:parse_config) Puppet::FileBucket::Dipper.stubs(:new) STDIN.stubs(:read) Puppet::Transaction::Report.indirection.stubs(:cache_class=) @apply.options.stubs(:[]).with(any_parameters) end it "should set show_diff on --noop" do Puppet.stubs(:[]=) Puppet.stubs(:[]).with(:config) Puppet.stubs(:[]).with(:noop).returns(true) Puppet.expects(:[]=).with(:show_diff, true) @apply.setup end it "should set console as the log destination if logdest option wasn't provided" do Puppet::Log.expects(:newdestination).with(:console) @apply.setup end it "should set INT trap" do Signal.expects(:trap).with(:INT) @apply.setup end it "should set log level to debug if --debug was passed" do @apply.options.stubs(:[]).with(:debug).returns(true) Puppet::Log.expects(:level=).with(:debug) @apply.setup end it "should set log level to info if --verbose was passed" do @apply.options.stubs(:[]).with(:verbose).returns(true) Puppet::Log.expects(:level=).with(:info) @apply.setup end it "should print puppet config if asked to in Puppet config" do @apply.stubs(:exit) Puppet.settings.stubs(:print_configs?).returns(true) Puppet.settings.expects(:print_configs) @apply.setup end it "should exit after printing puppet config if asked to in Puppet config" do Puppet.settings.stubs(:print_configs?).returns(true) lambda { @apply.setup }.should raise_error(SystemExit) end it "should tell the report handler to cache locally as yaml" do Puppet::Transaction::Report.indirection.expects(:cache_class=).with(:yaml) @apply.setup end end describe "when executing" do it "should dispatch to parseonly if parseonly is set" do @apply.stubs(:options).returns({}) Puppet.stubs(:[]).with(:parseonly).returns(true) @apply.expects(:parseonly) @apply.run_command end it "should dispatch to 'apply' if it was called with 'apply'" do @apply.options[:catalog] = "foo" @apply.expects(:apply) @apply.run_command end it "should dispatch to main if parseonly is not set" do @apply.stubs(:options).returns({}) Puppet.stubs(:[]).with(:parseonly).returns(false) @apply.expects(:main) @apply.run_command end describe "the parseonly command" do before :each do @environment = Puppet::Node::Environment.new("env") Puppet.stubs(:[]).with(:environment).returns(@environment) Puppet.stubs(:[]).with(:manifest).returns("site.pp") Puppet.stubs(:err) @apply.stubs(:exit) @apply.options.stubs(:[]).with(:code).returns "some code" end it "should use the environment to parse the file" do @environment.stubs(:perform_initial_import) @apply.parseonly end it "should exit with exit code 0 if no error" do @apply.expects(:exit).with(0) @apply.parseonly end it "should exit with exit code 1 if error" do @environment.stubs(:perform_initial_import).raises(Puppet::ParseError) @apply.expects(:exit).with(1) @apply.parseonly end it "should exit with exit code 1 if error, even if --noop is set" do Puppet[:noop] = true @environment.stubs(:perform_initial_import).raises(Puppet::ParseError) @apply.expects(:exit).with(1) @apply.parseonly end end describe "the main command" do before :each do Puppet.stubs(:[]) Puppet.settings.stubs(:use) Puppet.stubs(:[]).with(:prerun_command).returns "" Puppet.stubs(:[]).with(:postrun_command).returns "" Puppet.stubs(:[]).with(:trace).returns(true) @apply.options.stubs(:[]) @facts = stub_everything 'facts' Puppet::Node::Facts.indirection.stubs(:find).returns(@facts) @node = stub_everything 'node' Puppet::Node.indirection.stubs(:find).returns(@node) @catalog = stub_everything 'catalog' @catalog.stubs(:to_ral).returns(@catalog) Puppet::Resource::Catalog.indirection.stubs(:find).returns(@catalog) STDIN.stubs(:read) @transaction = stub_everything 'transaction' @catalog.stubs(:apply).returns(@transaction) @apply.stubs(:exit) Puppet::Util::Storage.stubs(:load) Puppet::Configurer.any_instance.stubs(:save_last_run_summary) # to prevent it from trying to write files end it "should set the code to run from --code" do @apply.options.stubs(:[]).with(:code).returns("code to run") Puppet.expects(:[]=).with(:code,"code to run") @apply.main end it "should set the code to run from STDIN if no arguments" do @apply.command_line.stubs(:args).returns([]) STDIN.stubs(:read).returns("code to run") Puppet.expects(:[]=).with(:code,"code to run") @apply.main end it "should set the manifest if a file is passed on command line and the file exists" do File.stubs(:exist?).with('site.pp').returns true @apply.command_line.stubs(:args).returns(['site.pp']) Puppet.expects(:[]=).with(:manifest,"site.pp") @apply.main end it "should raise an error if a file is passed on command line and the file does not exist" do File.stubs(:exist?).with('noexist.pp').returns false @apply.command_line.stubs(:args).returns(['noexist.pp']) lambda { @apply.main }.should raise_error(RuntimeError, 'Could not find file noexist.pp') end it "should set the manifest to the first file and warn other files will be skipped" do File.stubs(:exist?).with('starwarsIV').returns true File.expects(:exist?).with('starwarsI').never @apply.command_line.stubs(:args).returns(['starwarsIV', 'starwarsI', 'starwarsII']) Puppet.expects(:[]=).with(:manifest,"starwarsIV") Puppet.expects(:warning).with('Only one file can be applied per run. Skipping starwarsI, starwarsII') @apply.main end it "should collect the node facts" do Puppet::Node::Facts.indirection.expects(:find).returns(@facts) @apply.main end it "should raise an error if we can't find the node" do Puppet::Node::Facts.indirection.expects(:find).returns(nil) lambda { @apply.main }.should raise_error end it "should look for the node" do Puppet::Node.indirection.expects(:find).returns(@node) @apply.main end it "should raise an error if we can't find the node" do Puppet::Node.indirection.expects(:find).returns(nil) lambda { @apply.main }.should raise_error end it "should merge in our node the loaded facts" do @facts.stubs(:values).returns("values") @node.expects(:merge).with("values") @apply.main end it "should load custom classes if loadclasses" do @apply.options.stubs(:[]).with(:loadclasses).returns(true) Puppet.stubs(:[]).with(:classfile).returns("/etc/puppet/classes.txt") FileTest.stubs(:exists?).with("/etc/puppet/classes.txt").returns(true) FileTest.stubs(:readable?).with("/etc/puppet/classes.txt").returns(true) File.stubs(:read).with("/etc/puppet/classes.txt").returns("class") @node.expects(:classes=) @apply.main end it "should compile the catalog" do Puppet::Resource::Catalog.indirection.expects(:find).returns(@catalog) @apply.main end it "should transform the catalog to ral" do @catalog.expects(:to_ral).returns(@catalog) @apply.main end it "should finalize the catalog" do @catalog.expects(:finalize) @apply.main end it "should call the prerun and postrun commands on a Configurer instance" do Puppet::Configurer.any_instance.expects(:execute_prerun_command) Puppet::Configurer.any_instance.expects(:execute_postrun_command) @apply.main end it "should apply the catalog" do @catalog.expects(:apply).returns(stub_everything('transaction')) @apply.main end it "should save the last run summary" do Puppet.stubs(:[]).with(:noop).returns(false) report = Puppet::Transaction::Report.new("apply") Puppet::Transaction::Report.stubs(:new).returns(report) Puppet::Configurer.any_instance.expects(:save_last_run_summary).with(report) @apply.main end describe "with detailed_exitcodes" do it "should exit with report's computed exit status" do Puppet.stubs(:[]).with(:noop).returns(false) @apply.options.stubs(:[]).with(:detailed_exitcodes).returns(true) Puppet::Transaction::Report.any_instance.stubs(:exit_status).returns(666) @apply.expects(:exit).with(666) @apply.main end it "should exit with report's computed exit status, even if --noop is set" do Puppet.stubs(:[]).with(:noop).returns(true) @apply.options.stubs(:[]).with(:detailed_exitcodes).returns(true) Puppet::Transaction::Report.any_instance.stubs(:exit_status).returns(666) @apply.expects(:exit).with(666) @apply.main end it "should always exit with 0 if option is disabled" do Puppet.stubs(:[]).with(:noop).returns(false) @apply.options.stubs(:[]).with(:detailed_exitcodes).returns(false) report = stub 'report', :exit_status => 666 @transaction.stubs(:report).returns(report) @apply.expects(:exit).with(0) @apply.main end it "should always exit with 0 if --noop" do Puppet.stubs(:[]).with(:noop).returns(true) @apply.options.stubs(:[]).with(:detailed_exitcodes).returns(true) report = stub 'report', :exit_status => 666 @transaction.stubs(:report).returns(report) @apply.expects(:exit).with(0) @apply.main end end end describe "the 'apply' command" do it "should read the catalog in from disk if a file name is provided" do @apply.options[:catalog] = "/my/catalog.pson" File.expects(:read).with("/my/catalog.pson").returns "something" Puppet::Resource::Catalog.stubs(:convert_from).with(:pson,'something').returns Puppet::Resource::Catalog.new @apply.apply end it "should read the catalog in from stdin if '-' is provided" do @apply.options[:catalog] = "-" $stdin.expects(:read).returns "something" Puppet::Resource::Catalog.stubs(:convert_from).with(:pson,'something').returns Puppet::Resource::Catalog.new @apply.apply end it "should deserialize the catalog from the default format" do @apply.options[:catalog] = "/my/catalog.pson" File.stubs(:read).with("/my/catalog.pson").returns "something" Puppet::Resource::Catalog.stubs(:default_format).returns :rot13_piglatin Puppet::Resource::Catalog.stubs(:convert_from).with(:rot13_piglatin,'something').returns Puppet::Resource::Catalog.new @apply.apply end it "should fail helpfully if deserializing fails" do @apply.options[:catalog] = "/my/catalog.pson" File.stubs(:read).with("/my/catalog.pson").returns "something syntacically invalid" lambda { @apply.apply }.should raise_error(Puppet::Error) end it "should convert plain data structures into a catalog if deserialization does not do so" do @apply.options[:catalog] = "/my/catalog.pson" File.stubs(:read).with("/my/catalog.pson").returns "something" Puppet::Resource::Catalog.stubs(:convert_from).with(:pson,"something").returns({:foo => "bar"}) Puppet::Resource::Catalog.expects(:pson_create).with({:foo => "bar"}).returns(Puppet::Resource::Catalog.new) @apply.apply end it "should convert the catalog to a RAL catalog and use a Configurer instance to apply it" do @apply.options[:catalog] = "/my/catalog.pson" File.stubs(:read).with("/my/catalog.pson").returns "something" catalog = Puppet::Resource::Catalog.new Puppet::Resource::Catalog.stubs(:convert_from).with(:pson,'something').returns catalog catalog.expects(:to_ral).returns "mycatalog" configurer = stub 'configurer' Puppet::Configurer.expects(:new).returns configurer configurer.expects(:run).with(:catalog => "mycatalog") @apply.apply end end end end diff --git a/spec/unit/application/config_spec.rb b/spec/unit/application/config_spec.rb index 0c1279630..dc2fb5717 100755 --- a/spec/unit/application/config_spec.rb +++ b/spec/unit/application/config_spec.rb @@ -1,10 +1,9 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/application/config' describe Puppet::Application::Config do - it "should be a subclass of Puppet::Application::FacesBase" do - Puppet::Application::Config.superclass.should equal(Puppet::Application::FacesBase) + it "should be a subclass of Puppet::Application::FaceBase" do + Puppet::Application::Config.superclass.should equal(Puppet::Application::FaceBase) end end diff --git a/spec/unit/application/configurer_spec.rb b/spec/unit/application/configurer_spec.rb index 2db07565c..791a367ea 100755 --- a/spec/unit/application/configurer_spec.rb +++ b/spec/unit/application/configurer_spec.rb @@ -1,33 +1,32 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/application/configurer' require 'puppet/indirector/catalog/rest' require 'puppet/indirector/report/rest' require 'tempfile' describe "Puppet::Application::Configurer" do it "should retrieve and apply a catalog and submit a report" do pending "REVISIT: 2.7 changes broke this, and we want the merge published" dirname = Dir.mktmpdir("puppetdir") Puppet[:vardir] = dirname Puppet[:confdir] = dirname Puppet[:certname] = "foo" @catalog = Puppet::Resource::Catalog.new @file = Puppet::Resource.new(:file, File.join(dirname, "tmp_dir_resource"), :parameters => {:ensure => :present}) @catalog.add_resource(@file) @report = Puppet::Transaction::Report.new("apply") Puppet::Transaction::Report.stubs(:new).returns(@report) Puppet::Resource::Catalog::Rest.any_instance.stubs(:find).returns(@catalog) @report.expects(:save) Puppet::Util::Log.stubs(:newdestination) Puppet::Application::Configurer.new.run @report.status.should == "changed" end end diff --git a/spec/unit/application/describe_spec.rb b/spec/unit/application/describe_spec.rb index f1eb77869..e79ac21b7 100755 --- a/spec/unit/application/describe_spec.rb +++ b/spec/unit/application/describe_spec.rb @@ -1,84 +1,83 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/application/describe' describe Puppet::Application::Describe do before :each do @describe = Puppet::Application[:describe] end it "should ask Puppet::Application to not parse Puppet configuration file" do @describe.should_parse_config?.should be_false end it "should declare a main command" do @describe.should respond_to(:main) end it "should declare a preinit block" do @describe.should respond_to(:preinit) end [:providers,:list,:meta].each do |option| it "should declare handle_#{option} method" do @describe.should respond_to("handle_#{option}".to_sym) end it "should store argument value when calling handle_#{option}" do @describe.options.expects(:[]=).with("#{option}".to_sym, 'arg') @describe.send("handle_#{option}".to_sym, 'arg') end end describe "in preinit" do it "should set options[:parameteers] to true" do @describe.preinit @describe.options[:parameters].should be_true end end describe "when handling parameters" do it "should set options[:parameters] to false" do @describe.handle_short(nil) @describe.options[:parameters].should be_false end end describe "during setup" do it "should collect arguments in options[:types]" do @describe.command_line.stubs(:args).returns(['1','2']) @describe.setup @describe.options[:types].should == ['1','2'] end end describe "when running" do before :each do @typedoc = stub 'type_doc' TypeDoc.stubs(:new).returns(@typedoc) end it "should call list_types if options list is set" do @describe.options[:list] = true @typedoc.expects(:list_types) @describe.run_command end it "should call format_type for each given types" do @describe.options[:list] = false @describe.options[:types] = ['type'] @typedoc.expects(:format_type).with('type', @describe.options) @describe.run_command end end end diff --git a/spec/unit/application/doc_spec.rb b/spec/unit/application/doc_spec.rb index b5d1a39d4..66a833b9d 100755 --- a/spec/unit/application/doc_spec.rb +++ b/spec/unit/application/doc_spec.rb @@ -1,349 +1,348 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/application/doc' require 'puppet/util/reference' require 'puppet/util/rdoc' describe Puppet::Application::Doc do before :each do @doc = Puppet::Application[:doc] @doc.stubs(:puts) @doc.preinit Puppet::Util::Log.stubs(:newdestination) Puppet::Util::Log.stubs(:level=) end it "should ask Puppet::Application to not parse Puppet configuration file" do @doc.should_parse_config?.should be_false end it "should declare a other command" do @doc.should respond_to(:other) end it "should declare a rdoc command" do @doc.should respond_to(:rdoc) end it "should declare a fallback for unknown options" do @doc.should respond_to(:handle_unknown) end it "should declare a preinit block" do @doc.should respond_to(:preinit) end describe "in preinit" do it "should set references to []" do @doc.preinit @doc.options[:references].should == [] end it "should init mode to text" do @doc.preinit @doc.options[:mode].should == :text end it "should init format to to_markdown" do @doc.preinit @doc.options[:format].should == :to_markdown end end describe "when handling options" do [:all, :outputdir, :verbose, :debug, :charset].each do |option| it "should declare handle_#{option} method" do @doc.should respond_to("handle_#{option}".to_sym) end it "should store argument value when calling handle_#{option}" do @doc.options.expects(:[]=).with(option, 'arg') @doc.send("handle_#{option}".to_sym, 'arg') end end it "should store the format if valid" do Puppet::Util::Reference.stubs(:method_defined?).with('to_format').returns(true) @doc.options.expects(:[]=).with(:format, 'to_format') @doc.handle_format('format') end it "should raise an error if the format is not valid" do Puppet::Util::Reference.stubs(:method_defined?).with('to_format').returns(false) lambda { @doc.handle_format('format') } end it "should store the mode if valid" do Puppet::Util::Reference.stubs(:modes).returns(stub('mode', :include? => true)) @doc.options.expects(:[]=).with(:mode, :mode) @doc.handle_mode('mode') end it "should store the mode if :rdoc" do Puppet::Util::Reference.modes.stubs(:include?).with('rdoc').returns(false) @doc.options.expects(:[]=).with(:mode, :rdoc) @doc.handle_mode('rdoc') end it "should raise an error if the mode is not valid" do Puppet::Util::Reference.modes.stubs(:include?).with('unknown').returns(false) lambda { @doc.handle_mode('unknown') } end it "should list all references on list and exit" do reference = stubs 'reference' ref = stubs 'ref' Puppet::Util::Reference.stubs(:references).returns([reference]) Puppet::Util::Reference.expects(:reference).with(reference).returns(ref) ref.expects(:doc) @doc.expects(:exit) @doc.handle_list(nil) end it "should add reference to references list with --reference" do @doc.options[:references] = [:ref1] @doc.handle_reference('ref2') @doc.options[:references].should == [:ref1,:ref2] end end describe "during setup" do before :each do Puppet::Log.stubs(:newdestination) @doc.command_line.stubs(:args).returns([]) end it "should default to rdoc mode if there are command line arguments" do @doc.command_line.stubs(:args).returns(["1"]) @doc.stubs(:setup_rdoc) @doc.options.expects(:[]=).with(:mode,:rdoc) @doc.setup end it "should call setup_rdoc in rdoc mode" do @doc.options.stubs(:[]).with(:mode).returns(:rdoc) @doc.expects(:setup_rdoc) @doc.setup end it "should call setup_reference if not rdoc" do @doc.options.stubs(:[]).with(:mode).returns(:test) @doc.expects(:setup_reference) @doc.setup end describe "in non-rdoc mode" do it "should get all non-dynamic reference if --all" do @doc.options.stubs(:[]).with(:all).returns(true) @doc.options.stubs(:[]).with(:references).returns([]) static = stub 'static', :dynamic? => false dynamic = stub 'dynamic', :dynamic? => true Puppet::Util::Reference.stubs(:reference).with(:static).returns(static) Puppet::Util::Reference.stubs(:reference).with(:dynamic).returns(dynamic) Puppet::Util::Reference.stubs(:references).returns([:static,:dynamic]) @doc.options.stubs(:[]=).with(:references, [:static]) @doc.setup_reference end it "should default to :type if no references" do @doc.options.stubs(:[]).with(:all).returns(false) array = stub 'array', :empty? => true @doc.options.stubs(:[]).with(:references).returns(array) array.expects(:<<).with(:type) @doc.setup_reference end end describe "in rdoc mode" do before :each do @doc.options.stubs(:[]).returns(false) Puppet.stubs(:parse_config) Puppet::Util::Log.stubs(:level=) Puppet::Util::Log.stubs(:newdestination) end describe "when there are unknown args" do it "should expand --modulepath if any" do @doc.unknown_args = [ { :opt => "--modulepath", :arg => "path" } ] Puppet.settings.stubs(:handlearg) File.expects(:expand_path).with("path") @doc.setup_rdoc end it "should expand --manifestdir if any" do @doc.unknown_args = [ { :opt => "--manifestdir", :arg => "path" } ] Puppet.settings.stubs(:handlearg) File.expects(:expand_path).with("path") @doc.setup_rdoc end it "should give them to Puppet.settings" do @doc.unknown_args = [ { :opt => :option, :arg => :argument } ] Puppet.settings.expects(:handlearg).with(:option,:argument) @doc.setup_rdoc end end it "should operate in master run_mode" do @doc.class.run_mode.name.should == :master @doc.setup_rdoc end it "should parse puppet configuration" do Puppet.expects(:parse_config) @doc.setup_rdoc end it "should set log level to debug if --debug" do @doc.options.stubs(:[]).with(:debug).returns(true) Puppet::Util::Log.expects(:level=).with(:debug) @doc.setup_rdoc end it "should set log level to info if --verbose" do @doc.options.stubs(:[]).with(:verbose).returns(true) Puppet::Util::Log.expects(:level=).with(:info) @doc.setup_rdoc end it "should set log destination to console if --verbose" do @doc.options.stubs(:[]).with(:verbose).returns(true) Puppet::Util::Log.expects(:newdestination).with(:console) @doc.setup_rdoc end it "should set log destination to console if --debug" do @doc.options.stubs(:[]).with(:debug).returns(true) Puppet::Util::Log.expects(:newdestination).with(:console) @doc.setup_rdoc end end end describe "when running" do describe "in rdoc mode" do before :each do @doc.manifest = false Puppet.stubs(:info) Puppet.stubs(:[]).with(:trace).returns(false) @env = stub 'env' Puppet::Node::Environment.stubs(:new).returns(@env) @env.stubs(:modulepath).returns(['modules']) @env.stubs(:[]).with(:manifest).returns('manifests/site.pp') Puppet.stubs(:[]).with(:modulepath).returns('modules') Puppet.stubs(:[]).with(:manifestdir).returns('manifests') @doc.options.stubs(:[]).with(:all).returns(false) @doc.options.stubs(:[]).with(:outputdir).returns('doc') @doc.options.stubs(:[]).with(:charset).returns(nil) Puppet.settings.stubs(:[]=).with(:document_all, false) Puppet.settings.stubs(:setdefaults) Puppet::Util::RDoc.stubs(:rdoc) @doc.stubs(:exit) File.stubs(:expand_path).with('modules').returns('modules') File.stubs(:expand_path).with('manifests').returns('manifests') @doc.command_line.stubs(:args).returns([]) end it "should set document_all on --all" do @doc.options.expects(:[]).with(:all).returns(true) Puppet.settings.expects(:[]=).with(:document_all, true) @doc.rdoc end it "should call Puppet::Util::RDoc.rdoc in full mode" do Puppet::Util::RDoc.expects(:rdoc).with('doc', ['modules','manifests'], nil) @doc.rdoc end it "should call Puppet::Util::RDoc.rdoc with a charset if --charset has been provided" do @doc.options.expects(:[]).with(:charset).returns("utf-8") Puppet::Util::RDoc.expects(:rdoc).with('doc', ['modules','manifests'], "utf-8") @doc.rdoc end it "should call Puppet::Util::RDoc.rdoc in full mode with outputdir set to doc if no --outputdir" do @doc.options.expects(:[]).with(:outputdir).returns(false) Puppet::Util::RDoc.expects(:rdoc).with('doc', ['modules','manifests'], nil) @doc.rdoc end it "should call Puppet::Util::RDoc.manifestdoc in manifest mode" do @doc.manifest = true Puppet::Util::RDoc.expects(:manifestdoc) @doc.rdoc end it "should get modulepath and manifestdir values from the environment" do @env.expects(:modulepath).returns(['envmodules1','envmodules2']) @env.expects(:[]).with(:manifest).returns('envmanifests/site.pp') Puppet::Util::RDoc.expects(:rdoc).with('doc', ['envmodules1','envmodules2','envmanifests'], nil) @doc.rdoc end end describe "in the other modes" do it "should get reference in given format" do reference = stub 'reference' @doc.options.stubs(:[]).with(:mode).returns(:none) @doc.options.stubs(:[]).with(:references).returns([:ref]) require 'puppet/util/reference' Puppet::Util::Reference.expects(:reference).with(:ref).returns(reference) @doc.options.stubs(:[]).with(:format).returns(:format) @doc.stubs(:exit) reference.expects(:send).with { |format,contents| format == :format }.returns('doc') @doc.other end end end end diff --git a/spec/unit/application/faces_base_spec.rb b/spec/unit/application/face_base_spec.rb similarity index 91% rename from spec/unit/application/faces_base_spec.rb rename to spec/unit/application/face_base_spec.rb index 18bd30295..939712ef8 100755 --- a/spec/unit/application/faces_base_spec.rb +++ b/spec/unit/application/face_base_spec.rb @@ -1,188 +1,187 @@ #!/usr/bin/env rspec - require 'spec_helper' -require 'puppet/application/faces_base' +require 'puppet/application/face_base' require 'tmpdir' -class Puppet::Application::FacesBase::Basetest < Puppet::Application::FacesBase +class Puppet::Application::FaceBase::Basetest < Puppet::Application::FaceBase end -describe Puppet::Application::FacesBase do +describe Puppet::Application::FaceBase do before :all do - Puppet::Faces.define(:basetest, '0.0.1') do + Puppet::Face.define(:basetest, '0.0.1') do option("--[no-]boolean") option("--mandatory MANDATORY") option("--optional [OPTIONAL]") action :foo do option("--action") when_invoked { |*args| args.length } end end end let :app do - app = Puppet::Application::FacesBase::Basetest.new + app = Puppet::Application::FaceBase::Basetest.new app.command_line.stubs(:subcommand_name).returns('subcommand') Puppet::Util::Log.stubs(:newdestination) app end describe "#find_global_settings_argument" do it "should not match --ca to --ca-location" do option = mock('ca option', :optparse_args => ["--ca"]) Puppet.settings.expects(:each).yields(:ca, option) app.find_global_settings_argument("--ca-location").should be_nil end end describe "#parse_options" do before :each do app.command_line.stubs(:args).returns %w{} end describe "parsing the command line" do context "with just an action" do before :all do # We have to stub Signal.trap to avoid a crazy mess where we take # over signal handling and make it impossible to cancel the test # suite run. # # It would be nice to fix this elsewhere, but it is actually hard to # capture this in rspec 2.5 and all. :( --daniel 2011-04-08 Signal.stubs(:trap) app.command_line.stubs(:args).returns %w{foo} app.preinit app.parse_options end - it "should set the faces based on the type" do + it "should set the face based on the type" do app.face.name.should == :basetest end - it "should set the format based on the faces default" do + it "should set the format based on the face default" do app.format.should == :pson end it "should find the action" do app.action.should be app.action.name.should == :foo end end it "should fail if no action is given" do expect { app.preinit; app.parse_options }. to raise_error OptionParser::MissingArgument, /No action given/ end it "should report a sensible error when options with = fail" do app.command_line.stubs(:args).returns %w{--action=bar foo} expect { app.preinit; app.parse_options }. to raise_error OptionParser::InvalidOption, /invalid option: --action/ end it "should fail if an action option is before the action" do app.command_line.stubs(:args).returns %w{--action foo} expect { app.preinit; app.parse_options }. to raise_error OptionParser::InvalidOption, /invalid option: --action/ end it "should fail if an unknown option is before the action" do app.command_line.stubs(:args).returns %w{--bar foo} expect { app.preinit; app.parse_options }. to raise_error OptionParser::InvalidOption, /invalid option: --bar/ end it "should fail if an unknown option is after the action" do app.command_line.stubs(:args).returns %w{foo --bar} expect { app.preinit; app.parse_options }. to raise_error OptionParser::InvalidOption, /invalid option: --bar/ end it "should accept --bar as an argument to a mandatory option after action" do app.command_line.stubs(:args).returns %w{foo --mandatory --bar} app.preinit app.parse_options app.action.name.should == :foo app.options.should == { :mandatory => "--bar" } end it "should accept --bar as an argument to a mandatory option before action" do app.command_line.stubs(:args).returns %w{--mandatory --bar foo} app.preinit app.parse_options app.action.name.should == :foo app.options.should == { :mandatory => "--bar" } end it "should not skip when --foo=bar is given" do app.command_line.stubs(:args).returns %w{--mandatory=bar --bar foo} expect { app.preinit; app.parse_options }. to raise_error OptionParser::InvalidOption, /invalid option: --bar/ end { "boolean options before" => %w{--trace foo}, "boolean options after" => %w{foo --trace} }.each do |name, args| it "should accept global boolean settings #{name} the action" do app.command_line.stubs(:args).returns args app.preinit app.parse_options Puppet[:trace].should be_true end end { "before" => %w{--syslogfacility user1 foo}, " after" => %w{foo --syslogfacility user1} }.each do |name, args| it "should accept global settings with arguments #{name} the action" do app.command_line.stubs(:args).returns args app.preinit app.parse_options Puppet[:syslogfacility].should == "user1" end end end end describe "#setup" do it "should remove the action name from the arguments" do app.command_line.stubs(:args).returns %w{--mandatory --bar foo} app.preinit app.parse_options app.setup app.arguments.should == [{ :mandatory => "--bar" }] end it "should pass positional arguments" do app.command_line.stubs(:args).returns %w{--mandatory --bar foo bar baz quux} app.preinit app.parse_options app.setup app.arguments.should == ['bar', 'baz', 'quux', { :mandatory => "--bar" }] end end describe "#main" do before :each do app.expects(:exit).with(0) - app.face = Puppet::Faces[:basetest, '0.0.1'] + app.face = Puppet::Face[:basetest, '0.0.1'] app.action = app.face.get_action(:foo) app.format = :pson app.arguments = ["myname", "myarg"] end - it "should send the specified verb and name to the faces" do + it "should send the specified verb and name to the face" do app.face.expects(:foo).with(*app.arguments) app.main end it "should use its render method to render any result" do app.expects(:render).with(app.arguments.length + 1) app.stubs(:puts) # meh. Don't print nil, thanks. --daniel 2011-04-12 app.main end end end diff --git a/spec/unit/application/faces_spec.rb b/spec/unit/application/faces_spec.rb index c4d15a297..cc159b6a5 100755 --- a/spec/unit/application/faces_spec.rb +++ b/spec/unit/application/faces_spec.rb @@ -1,16 +1,14 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/application/faces' describe Puppet::Application::Faces do it "should be an application" do Puppet::Application::Faces.superclass.should equal(Puppet::Application) end it "should always call 'list'" do - faces = Puppet::Application::Faces.new - faces.expects(:list) - faces.main + subject.expects(:list) + subject.main end end diff --git a/spec/unit/application/filebucket_spec.rb b/spec/unit/application/filebucket_spec.rb index 1ee12d89c..8ba86be9e 100755 --- a/spec/unit/application/filebucket_spec.rb +++ b/spec/unit/application/filebucket_spec.rb @@ -1,224 +1,223 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/application/filebucket' require 'puppet/file_bucket/dipper' describe Puppet::Application::Filebucket do before :each do @filebucket = Puppet::Application[:filebucket] end it "should ask Puppet::Application to not parse Puppet configuration file" do @filebucket.should_parse_config?.should be_false end it "should declare a get command" do @filebucket.should respond_to(:get) end it "should declare a backup command" do @filebucket.should respond_to(:backup) end it "should declare a restore command" do @filebucket.should respond_to(:restore) end [:bucket, :debug, :local, :remote, :verbose].each do |option| it "should declare handle_#{option} method" do @filebucket.should respond_to("handle_#{option}".to_sym) end it "should store argument value when calling handle_#{option}" do @filebucket.options.expects(:[]=).with("#{option}".to_sym, 'arg') @filebucket.send("handle_#{option}".to_sym, 'arg') end end describe "during setup" do before :each do Puppet::Log.stubs(:newdestination) Puppet.stubs(:settraps) Puppet::Log.stubs(:level=) Puppet.stubs(:parse_config) Puppet::FileBucket::Dipper.stubs(:new) @filebucket.options.stubs(:[]).with(any_parameters) end it "should set console as the log destination" do Puppet::Log.expects(:newdestination).with(:console) @filebucket.setup end it "should trap INT" do Signal.expects(:trap).with(:INT) @filebucket.setup end it "should set log level to debug if --debug was passed" do @filebucket.options.stubs(:[]).with(:debug).returns(true) Puppet::Log.expects(:level=).with(:debug) @filebucket.setup end it "should set log level to info if --verbose was passed" do @filebucket.options.stubs(:[]).with(:verbose).returns(true) Puppet::Log.expects(:level=).with(:info) @filebucket.setup end it "should Parse puppet config" do Puppet.expects(:parse_config) @filebucket.setup end it "should print puppet config if asked to in Puppet config" do @filebucket.stubs(:exit) Puppet.settings.stubs(:print_configs?).returns(true) Puppet.settings.expects(:print_configs) @filebucket.setup end it "should exit after printing puppet config if asked to in Puppet config" do Puppet.settings.stubs(:print_configs?).returns(true) lambda { @filebucket.setup }.should raise_error(SystemExit) end describe "with local bucket" do before :each do @filebucket.options.stubs(:[]).with(:local).returns(true) end it "should create a client with the default bucket if none passed" do Puppet.stubs(:[]).with(:bucketdir).returns("path") Puppet::FileBucket::Dipper.expects(:new).with { |h| h[:Path] == "path" } @filebucket.setup end it "should create a local Dipper with the given bucket" do @filebucket.options.stubs(:[]).with(:bucket).returns("path") Puppet::FileBucket::Dipper.expects(:new).with { |h| h[:Path] == "path" } @filebucket.setup end end describe "with remote bucket" do it "should create a remote Client to the configured server" do Puppet.stubs(:[]).with(:server).returns("puppet.reductivelabs.com") Puppet::FileBucket::Dipper.expects(:new).with { |h| h[:Server] == "puppet.reductivelabs.com" } @filebucket.setup end end end describe "when running" do before :each do Puppet::Log.stubs(:newdestination) Puppet.stubs(:settraps) Puppet::Log.stubs(:level=) Puppet.stubs(:parse_config) Puppet::FileBucket::Dipper.stubs(:new) @filebucket.options.stubs(:[]).with(any_parameters) @client = stub 'client' Puppet::FileBucket::Dipper.stubs(:new).returns(@client) @filebucket.setup end it "should use the first non-option parameter as the dispatch" do @filebucket.command_line.stubs(:args).returns(['get']) @filebucket.expects(:get) @filebucket.run_command end describe "the command get" do before :each do @filebucket.stubs(:print) @filebucket.stubs(:args).returns([]) end it "should call the client getfile method" do @client.expects(:getfile) @filebucket.get end it "should call the client getfile method with the given md5" do md5="DEADBEEF" @filebucket.stubs(:args).returns([md5]) @client.expects(:getfile).with(md5) @filebucket.get end it "should print the file content" do @client.stubs(:getfile).returns("content") @filebucket.expects(:print).returns("content") @filebucket.get end end describe "the command backup" do it "should call the client backup method for each given parameter" do @filebucket.stubs(:puts) FileTest.stubs(:exists?).returns(true) FileTest.stubs(:readable?).returns(true) @filebucket.stubs(:args).returns(["file1", "file2"]) @client.expects(:backup).with("file1") @client.expects(:backup).with("file2") @filebucket.backup end end describe "the command restore" do it "should call the client getfile method with the given md5" do md5="DEADBEEF" file="testfile" @filebucket.stubs(:args).returns([file, md5]) @client.expects(:restore).with(file,md5) @filebucket.restore end end end end diff --git a/spec/unit/application/indirection_base_spec.rb b/spec/unit/application/indirection_base_spec.rb index 98eb3a118..63ab11eed 100755 --- a/spec/unit/application/indirection_base_spec.rb +++ b/spec/unit/application/indirection_base_spec.rb @@ -1,39 +1,38 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/application/indirection_base' -require 'puppet/faces/indirector' +require 'puppet/face/indirector' ######################################################################## # Stub for testing; the names are critical, sadly. --daniel 2011-03-30 class Puppet::Application::TestIndirection < Puppet::Application::IndirectionBase end -face = Puppet::Faces::Indirector.define(:testindirection, '0.0.1') do +face = Puppet::Face::Indirector.define(:testindirection, '0.0.1') do end # REVISIT: This horror is required because we don't allow anything to be # :current except for if it lives on, and is loaded from, disk. --daniel 2011-03-29 face.instance_variable_set('@version', :current) -Puppet::Faces.register(face) +Puppet::Face.register(face) ######################################################################## describe Puppet::Application::IndirectionBase do subject { Puppet::Application::TestIndirection.new } it "should accept a terminus command line option" do # It would be nice not to have to stub this, but whatever... writing an # entire indirection stack would cause us more grief. --daniel 2011-03-31 terminus = mock("test indirection terminus") Puppet::Indirector::Indirection.expects(:instance). with(:testindirection).twice.returns() subject.command_line. instance_variable_set('@args', %w{--terminus foo save}) # Not a very nice thing. :( $stderr.stubs(:puts) expect { subject.run }.should raise_error SystemExit end end diff --git a/spec/unit/application/inspect_spec.rb b/spec/unit/application/inspect_spec.rb index f1518299a..fda61c6e4 100755 --- a/spec/unit/application/inspect_spec.rb +++ b/spec/unit/application/inspect_spec.rb @@ -1,278 +1,277 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/application/inspect' require 'puppet/resource/catalog' require 'puppet/indirector/catalog/yaml' require 'puppet/indirector/report/rest' require 'puppet/indirector/file_bucket_file/rest' describe Puppet::Application::Inspect do include PuppetSpec::Files before :each do @inspect = Puppet::Application[:inspect] end describe "during setup" do it "should print its configuration if asked" do Puppet[:configprint] = "all" Puppet.settings.expects(:print_configs).returns(true) lambda { @inspect.setup }.should raise_error(SystemExit) end it "should fail if reporting is turned off" do Puppet[:report] = false lambda { @inspect.setup }.should raise_error(/report=true/) end end describe "when executing" do before :each do Puppet[:report] = true @inspect.options[:logset] = true Puppet::Transaction::Report::Rest.any_instance.stubs(:save) @inspect.setup end it "should retrieve the local catalog" do Puppet::Resource::Catalog::Yaml.any_instance.expects(:find).with {|request| request.key == Puppet[:certname] }.returns(Puppet::Resource::Catalog.new) @inspect.run_command end it "should save the report to REST" do Puppet::Resource::Catalog::Yaml.any_instance.stubs(:find).returns(Puppet::Resource::Catalog.new) Puppet::Transaction::Report::Rest.any_instance.expects(:save).with {|request| request.instance.host == Puppet[:certname] } @inspect.run_command end it "should audit the specified properties" do catalog = Puppet::Resource::Catalog.new file = Tempfile.new("foo") file.puts("file contents") file.close resource = Puppet::Resource.new(:file, file.path, :parameters => {:audit => "all"}) catalog.add_resource(resource) Puppet::Resource::Catalog::Yaml.any_instance.stubs(:find).returns(catalog) events = nil Puppet::Transaction::Report::Rest.any_instance.expects(:save).with do |request| events = request.instance.resource_statuses.values.first.events end @inspect.run_command properties = events.inject({}) do |property_values, event| property_values.merge(event.property => event.previous_value) end properties["ensure"].should == :file properties["content"].should == "{md5}#{Digest::MD5.hexdigest("file contents\n")}" properties.has_key?("target").should == false end it "should set audited to true for all events" do catalog = Puppet::Resource::Catalog.new file = Tempfile.new("foo") resource = Puppet::Resource.new(:file, file.path, :parameters => {:audit => "all"}) catalog.add_resource(resource) Puppet::Resource::Catalog::Yaml.any_instance.stubs(:find).returns(catalog) events = nil Puppet::Transaction::Report::Rest.any_instance.expects(:save).with do |request| events = request.instance.resource_statuses.values.first.events end @inspect.run_command events.each do |event| event.audited.should == true end end it "should not report irrelevent attributes if the resource is absent" do catalog = Puppet::Resource::Catalog.new file = Tempfile.new("foo") resource = Puppet::Resource.new(:file, file.path, :parameters => {:audit => "all"}) file.delete catalog.add_resource(resource) Puppet::Resource::Catalog::Yaml.any_instance.stubs(:find).returns(catalog) events = nil Puppet::Transaction::Report::Rest.any_instance.expects(:save).with do |request| events = request.instance.resource_statuses.values.first.events end @inspect.run_command properties = events.inject({}) do |property_values, event| property_values.merge(event.property => event.previous_value) end properties.should == {"ensure" => :absent} end describe "when archiving to a bucket" do before :each do Puppet[:archive_files] = true Puppet[:archive_file_server] = "filebucketserver" @catalog = Puppet::Resource::Catalog.new Puppet::Resource::Catalog::Yaml.any_instance.stubs(:find).returns(@catalog) end describe "when auditing files" do before :each do @file = tmpfile("foo") @resource = Puppet::Resource.new(:file, @file, :parameters => {:audit => "content"}) @catalog.add_resource(@resource) end it "should send an existing file to the file bucket" do File.open(@file, 'w') { |f| f.write('stuff') } Puppet::FileBucketFile::Rest.any_instance.expects(:head).with do |request| request.server == Puppet[:archive_file_server] end.returns(false) Puppet::FileBucketFile::Rest.any_instance.expects(:save).with do |request| request.server == Puppet[:archive_file_server] and request.instance.contents == 'stuff' end @inspect.run_command end it "should not send unreadable files" do File.open(@file, 'w') { |f| f.write('stuff') } File.chmod(0, @file) Puppet::FileBucketFile::Rest.any_instance.expects(:head).never Puppet::FileBucketFile::Rest.any_instance.expects(:save).never @inspect.run_command end it "should not try to send non-existent files" do Puppet::FileBucketFile::Rest.any_instance.expects(:head).never Puppet::FileBucketFile::Rest.any_instance.expects(:save).never @inspect.run_command end it "should not try to send files whose content we are not auditing" do @resource[:audit] = "group" Puppet::FileBucketFile::Rest.any_instance.expects(:head).never Puppet::FileBucketFile::Rest.any_instance.expects(:save).never @inspect.run_command end it "should continue if bucketing a file fails" do File.open(@file, 'w') { |f| f.write('stuff') } Puppet::FileBucketFile::Rest.any_instance.stubs(:head).returns false Puppet::FileBucketFile::Rest.any_instance.stubs(:save).raises "failure" Puppet::Transaction::Report::Rest.any_instance.expects(:save).with do |request| @report = request.instance end @inspect.run_command @report.logs.first.should_not == nil @report.logs.first.message.should =~ /Could not back up/ end end describe "when auditing non-files" do before :each do Puppet::Type.newtype(:stub_type) do newparam(:name) do desc "The name var" isnamevar end newproperty(:content) do desc "content" def retrieve :whatever end end end @resource = Puppet::Resource.new(:stub_type, 'foo', :parameters => {:audit => "all"}) @catalog.add_resource(@resource) end after :each do Puppet::Type.rmtype(:stub_type) end it "should not try to send non-files" do Puppet::FileBucketFile::Rest.any_instance.expects(:head).never Puppet::FileBucketFile::Rest.any_instance.expects(:save).never @inspect.run_command end end end describe "when there are failures" do before :each do Puppet::Type.newtype(:stub_type) do newparam(:name) do desc "The name var" isnamevar end newproperty(:content) do desc "content" def retrieve raise "failed" end end end @catalog = Puppet::Resource::Catalog.new Puppet::Resource::Catalog::Yaml.any_instance.stubs(:find).returns(@catalog) Puppet::Transaction::Report::Rest.any_instance.expects(:save).with do |request| @report = request.instance end end after :each do Puppet::Type.rmtype(:stub_type) end it "should mark the report failed and create failed events for each property" do @resource = Puppet::Resource.new(:stub_type, 'foo', :parameters => {:audit => "all"}) @catalog.add_resource(@resource) @inspect.run_command @report.status.should == "failed" @report.logs.select{|log| log.message =~ /Could not inspect/}.size.should == 1 @report.resource_statuses.size.should == 1 @report.resource_statuses['Stub_type[foo]'].events.size.should == 1 event = @report.resource_statuses['Stub_type[foo]'].events.first event.property.should == "content" event.status.should == "failure" event.audited.should == true event.instance_variables.should_not include("@previous_value") end it "should continue to the next resource" do @resource = Puppet::Resource.new(:stub_type, 'foo', :parameters => {:audit => "all"}) @other_resource = Puppet::Resource.new(:stub_type, 'bar', :parameters => {:audit => "all"}) @catalog.add_resource(@resource) @catalog.add_resource(@other_resource) @inspect.run_command @report.resource_statuses.size.should == 2 @report.resource_statuses.keys.should =~ ['Stub_type[foo]', 'Stub_type[bar]'] end end end after :all do Puppet::Resource::Catalog.indirection.reset_terminus_class Puppet::Transaction::Report.indirection.terminus_class = :processor end end diff --git a/spec/unit/application/kick_spec.rb b/spec/unit/application/kick_spec.rb index 8481ec227..29e4caea4 100755 --- a/spec/unit/application/kick_spec.rb +++ b/spec/unit/application/kick_spec.rb @@ -1,311 +1,310 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/application/kick' describe Puppet::Application::Kick, :if => Puppet.features.posix? do before :each do require 'puppet/util/ldap/connection' Puppet::Util::Ldap::Connection.stubs(:new).returns(stub_everything) @kick = Puppet::Application[:kick] Puppet::Util::Log.stubs(:newdestination) Puppet::Util::Log.stubs(:level=) end describe ".new" do it "should take a command-line object as an argument" do command_line = stub_everything "command_line" lambda{ Puppet::Application::Kick.new( command_line ) }.should_not raise_error end end it "should ask Puppet::Application to not parse Puppet configuration file" do @kick.should_parse_config?.should be_false end it "should declare a main command" do @kick.should respond_to(:main) end it "should declare a test command" do @kick.should respond_to(:test) end it "should declare a preinit block" do @kick.should respond_to(:preinit) end describe "during preinit" do before :each do @kick.stubs(:trap) end it "should catch INT and TERM" do @kick.stubs(:trap).with { |arg,block| arg == :INT or arg == :TERM } @kick.preinit end it "should set parallel option to 1" do @kick.preinit @kick.options[:parallel].should == 1 end it "should set verbose by default" do @kick.preinit @kick.options[:verbose].should be_true end it "should set fqdn by default" do @kick.preinit @kick.options[:fqdn].should be_true end it "should set ignoreschedules to 'false'" do @kick.preinit @kick.options[:ignoreschedules].should be_false end it "should set foreground to 'false'" do @kick.preinit @kick.options[:foreground].should be_false end end describe "when applying options" do before do @kick.preinit end [:all, :foreground, :debug, :ping, :test].each do |option| it "should declare handle_#{option} method" do @kick.should respond_to("handle_#{option}".to_sym) end it "should store argument value when calling handle_#{option}" do @kick.options.expects(:[]=).with(option, 'arg') @kick.send("handle_#{option}".to_sym, 'arg') end end it "should add to the host list with the host option" do @kick.handle_host('host') @kick.hosts.should == ['host'] end it "should add to the tag list with the tag option" do @kick.handle_tag('tag') @kick.tags.should == ['tag'] end it "should add to the class list with the class option" do @kick.handle_class('class') @kick.classes.should == ['class'] end end describe "during setup" do before :each do @kick.classes = [] @kick.tags = [] @kick.hosts = [] Puppet::Log.stubs(:level=) @kick.stubs(:trap) @kick.stubs(:puts) Puppet.stubs(:parse_config) @kick.options.stubs(:[]).with(any_parameters) end it "should set log level to debug if --debug was passed" do @kick.options.stubs(:[]).with(:debug).returns(true) Puppet::Log.expects(:level=).with(:debug) @kick.setup end it "should set log level to info if --verbose was passed" do @kick.options.stubs(:[]).with(:verbose).returns(true) Puppet::Log.expects(:level=).with(:info) @kick.setup end it "should Parse puppet config" do Puppet.expects(:parse_config) @kick.setup end describe "when using the ldap node terminus" do before :each do Puppet.stubs(:[]).with(:node_terminus).returns("ldap") end it "should pass the fqdn option to search" do @kick.options.stubs(:[]).with(:fqdn).returns(:something) @kick.options.stubs(:[]).with(:all).returns(true) @kick.stubs(:puts) Puppet::Node.indirection.expects(:search).with("whatever",:fqdn => :something).returns([]) @kick.setup end it "should search for all nodes if --all" do @kick.options.stubs(:[]).with(:all).returns(true) @kick.stubs(:puts) Puppet::Node.indirection.expects(:search).with("whatever",:fqdn => nil).returns([]) @kick.setup end it "should search for nodes including given classes" do @kick.options.stubs(:[]).with(:all).returns(false) @kick.stubs(:puts) @kick.classes = ['class'] Puppet::Node.indirection.expects(:search).with("whatever", :class => "class", :fqdn => nil).returns([]) @kick.setup end end describe "when using regular nodes" do it "should fail if some classes have been specified" do $stderr.stubs(:puts) @kick.classes = ['class'] @kick.expects(:exit).with(24) @kick.setup end end end describe "when running" do before :each do @kick.stubs(:puts) end it "should dispatch to test if --test is used" do @kick.options.stubs(:[]).with(:test).returns(true) @kick.expects(:test) @kick.run_command end it "should dispatch to main if --test is not used" do @kick.options.stubs(:[]).with(:test).returns(false) @kick.expects(:main) @kick.run_command end describe "the test command" do it "should exit with exit code 0 " do @kick.expects(:exit).with(0) @kick.test end end describe "the main command" do before :each do @kick.options.stubs(:[]).with(:parallel).returns(1) @kick.options.stubs(:[]).with(:ping).returns(false) @kick.options.stubs(:[]).with(:ignoreschedules).returns(false) @kick.options.stubs(:[]).with(:foreground).returns(false) @kick.options.stubs(:[]).with(:debug).returns(false) @kick.stubs(:print) @kick.stubs(:exit) @kick.preinit @kick.stubs(:parse_options) @kick.setup $stderr.stubs(:puts) end it "should create as much childs as --parallel" do @kick.options.stubs(:[]).with(:parallel).returns(3) @kick.hosts = ['host1', 'host2', 'host3'] @kick.stubs(:exit).raises(SystemExit) Process.stubs(:wait).returns(1).then.returns(2).then.returns(3).then.raises(Errno::ECHILD) @kick.expects(:fork).times(3).returns(1).then.returns(2).then.returns(3) lambda { @kick.main }.should raise_error end it "should delegate to run_for_host per host" do @kick.hosts = ['host1', 'host2'] @kick.stubs(:exit).raises(SystemExit) @kick.stubs(:fork).returns(1).yields Process.stubs(:wait).returns(1).then.raises(Errno::ECHILD) @kick.expects(:run_for_host).times(2) lambda { @kick.main }.should raise_error end describe "during call of run_for_host" do before do require 'puppet/run' options = { :background => true, :ignoreschedules => false, :tags => [] } @kick.preinit @agent_run = Puppet::Run.new( options.dup ) @agent_run.stubs(:status).returns("success") Puppet::Run.indirection.expects(:terminus_class=).with( :rest ) Puppet::Run.expects(:new).with( options ).returns(@agent_run) end it "should call run on a Puppet::Run for the given host" do Puppet::Run.indirection.expects(:save).with(@agent_run, 'https://host:8139/production/run/host').returns(@agent_run) @kick.run_for_host('host') end it "should exit the child with 0 on success" do @agent_run.stubs(:status).returns("success") @kick.expects(:exit).with(0) @kick.run_for_host('host') end it "should exit the child with 3 on running" do @agent_run.stubs(:status).returns("running") @kick.expects(:exit).with(3) @kick.run_for_host('host') end it "should exit the child with 12 on unknown answer" do @agent_run.stubs(:status).returns("whatever") @kick.expects(:exit).with(12) @kick.run_for_host('host') end end end end end diff --git a/spec/unit/application/master_spec.rb b/spec/unit/application/master_spec.rb index ca4c5d0bc..890f8eebc 100755 --- a/spec/unit/application/master_spec.rb +++ b/spec/unit/application/master_spec.rb @@ -1,451 +1,450 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/application/master' require 'puppet/daemon' require 'puppet/network/server' describe Puppet::Application::Master do before :each do @master = Puppet::Application[:master] @daemon = stub_everything 'daemon' Puppet::Daemon.stubs(:new).returns(@daemon) Puppet::Util::Log.stubs(:newdestination) Puppet::Util::Log.stubs(:level=) Puppet::Node.indirection.stubs(:terminus_class=) Puppet::Node.indirection.stubs(:cache_class=) Puppet::Node::Facts.indirection.stubs(:terminus_class=) Puppet::Node::Facts.indirection.stubs(:cache_class=) Puppet::Transaction::Report.indirection.stubs(:terminus_class=) Puppet::Resource::Catalog.indirection.stubs(:terminus_class=) Puppet::SSL::Host.stubs(:ca_location=) end it "should operate in master run_mode" do @master.class.run_mode.name.should equal(:master) end it "should ask Puppet::Application to parse Puppet configuration file" do @master.should_parse_config?.should be_true end it "should declare a main command" do @master.should respond_to(:main) end it "should declare a parseonly command" do @master.should respond_to(:parseonly) end it "should declare a compile command" do @master.should respond_to(:compile) end it "should declare a preinit block" do @master.should respond_to(:preinit) end describe "during preinit" do before :each do @master.stubs(:trap) end it "should catch INT" do @master.stubs(:trap).with { |arg,block| arg == :INT } @master.preinit end it "should create a Puppet Daemon" do Puppet::Daemon.expects(:new).returns(@daemon) @master.preinit end it "should give ARGV to the Daemon" do argv = stub 'argv' ARGV.stubs(:dup).returns(argv) @daemon.expects(:argv=).with(argv) @master.preinit end end [:debug,:verbose].each do |option| it "should declare handle_#{option} method" do @master.should respond_to("handle_#{option}".to_sym) end it "should store argument value when calling handle_#{option}" do @master.options.expects(:[]=).with(option, 'arg') @master.send("handle_#{option}".to_sym, 'arg') end end describe "when applying options" do before do @master.command_line.stubs(:args).returns([]) end it "should set the log destination with --logdest" do Puppet::Log.expects(:newdestination).with("console") @master.handle_logdest("console") end it "should put the setdest options to true" do @master.options.expects(:[]=).with(:setdest,true) @master.handle_logdest("console") end it "should parse the log destination from ARGV" do @master.command_line.stubs(:args).returns(%w{--logdest /my/file}) Puppet::Util::Log.expects(:newdestination).with("/my/file") @master.parse_options end end describe "during setup" do before :each do Puppet::Log.stubs(:newdestination) Puppet.stubs(:settraps) Puppet::Log.stubs(:level=) Puppet::SSL::CertificateAuthority.stubs(:instance) Puppet::SSL::CertificateAuthority.stubs(:ca?) Puppet.settings.stubs(:use) @master.options.stubs(:[]).with(any_parameters) end it "should set log level to debug if --debug was passed" do @master.options.stubs(:[]).with(:debug).returns(true) Puppet::Log.expects(:level=).with(:debug) @master.setup end it "should set log level to info if --verbose was passed" do @master.options.stubs(:[]).with(:verbose).returns(true) Puppet::Log.expects(:level=).with(:info) @master.setup end it "should set console as the log destination if no --logdest and --daemonize" do @master.stubs(:[]).with(:daemonize).returns(:false) Puppet::Log.expects(:newdestination).with(:syslog) @master.setup end it "should set syslog as the log destination if no --logdest and not --daemonize" do Puppet::Log.expects(:newdestination).with(:syslog) @master.setup end it "should set syslog as the log destination if --rack" do @master.options.stubs(:[]).with(:rack).returns(:true) Puppet::Log.expects(:newdestination).with(:syslog) @master.setup end it "should print puppet config if asked to in Puppet config" do @master.stubs(:exit) Puppet.settings.stubs(:print_configs?).returns(true) Puppet.settings.expects(:print_configs) @master.setup end it "should exit after printing puppet config if asked to in Puppet config" do Puppet.settings.stubs(:print_configs?).returns(true) lambda { @master.setup }.should raise_error(SystemExit) end it "should tell Puppet.settings to use :main,:ssl,:master and :metrics category" do Puppet.settings.expects(:use).with(:main,:master,:ssl,:metrics) @master.setup end it "should cache class in yaml" do Puppet::Node.indirection.expects(:cache_class=).with(:yaml) @master.setup end describe "with no ca" do it "should set the ca_location to none" do Puppet::SSL::Host.expects(:ca_location=).with(:none) @master.setup end end describe "with a ca configured" do before :each do Puppet::SSL::CertificateAuthority.stubs(:ca?).returns(true) end it "should set the ca_location to local" do Puppet::SSL::Host.expects(:ca_location=).with(:local) @master.setup end it "should tell Puppet.settings to use :ca category" do Puppet.settings.expects(:use).with(:ca) @master.setup end it "should instantiate the CertificateAuthority singleton" do Puppet::SSL::CertificateAuthority.expects(:instance) @master.setup end end end describe "when running" do before do @master.preinit end it "should dispatch to parseonly if parseonly is set" do Puppet.stubs(:[]).with(:parseonly).returns(true) @master.options[:node] = nil @master.expects(:parseonly) @master.run_command end it "should dispatch to compile if called with --compile" do @master.options[:node] = "foo" @master.expects(:compile) @master.run_command end it "should dispatch to main if parseonly is not set" do Puppet.stubs(:[]).with(:parseonly).returns(false) @master.options[:node] = nil @master.expects(:main) @master.run_command end describe "the parseonly command" do before :each do @environment = Puppet::Node::Environment.new("env") Puppet.stubs(:[]).with(:environment).returns(@environment) Puppet.stubs(:[]).with(:manifest).returns("site.pp") Puppet.stubs(:err) @master.stubs(:exit) end it "should use a Puppet Resource Type Collection to parse the file" do @environment.expects(:perform_initial_import) @master.parseonly end it "should exit with exit code 0 if no error" do @master.expects(:exit).with(0) @master.parseonly end it "should exit with exit code 1 if error" do @environment.stubs(:perform_initial_import).raises(Puppet::ParseError) @master.expects(:exit).with(1) @master.parseonly end end describe "the compile command" do before do Puppet.stubs(:[]).with(:environment) Puppet.stubs(:[]).with(:manifest).returns("site.pp") Puppet.stubs(:err) @master.stubs(:jj) @master.stubs(:exit) Puppet.features.stubs(:pson?).returns true end it "should fail if pson isn't available" do Puppet.features.expects(:pson?).returns false lambda { @master.compile }.should raise_error end it "should compile a catalog for the specified node" do @master.options[:node] = "foo" Puppet::Resource::Catalog.indirection.expects(:find).with("foo").returns Puppet::Resource::Catalog.new $stdout.stubs(:puts) @master.compile end it "should convert the catalog to a pure-resource catalog and use 'jj' to pretty-print the catalog" do catalog = Puppet::Resource::Catalog.new Puppet::Resource::Catalog.indirection.expects(:find).returns catalog catalog.expects(:to_resource).returns("rescat") @master.options[:node] = "foo" @master.expects(:jj).with("rescat") @master.compile end it "should exit with error code 30 if no catalog can be found" do @master.options[:node] = "foo" Puppet::Resource::Catalog.indirection.expects(:find).returns nil @master.expects(:exit).with(30) $stderr.expects(:puts) @master.compile end it "should exit with error code 30 if there's a failure" do @master.options[:node] = "foo" Puppet::Resource::Catalog.indirection.expects(:find).raises ArgumentError @master.expects(:exit).with(30) $stderr.expects(:puts) @master.compile end end describe "the main command" do before :each do @master.preinit @server = stub_everything 'server' Puppet::Network::Server.stubs(:new).returns(@server) @app = stub_everything 'app' Puppet::SSL::Host.stubs(:localhost) Puppet::SSL::CertificateAuthority.stubs(:ca?) Process.stubs(:uid).returns(1000) Puppet.stubs(:service) Puppet.stubs(:[]) Puppet.stubs(:notice) Puppet.stubs(:start) end it "should create a Server" do Puppet::Network::Server.expects(:new) @master.main end it "should give the server to the daemon" do @daemon.expects(:server=).with(@server) @master.main end it "should create the server with the right XMLRPC handlers" do Puppet::Network::Server.expects(:new).with { |args| args[:xmlrpc_handlers] == [:Status, :FileServer, :Master, :Report, :Filebucket]} @master.main end it "should create the server with a :ca xmlrpc handler if needed" do Puppet.stubs(:[]).with(:ca).returns(true) Puppet::Network::Server.expects(:new).with { |args| args[:xmlrpc_handlers].include?(:CA) } @master.main end it "should generate a SSL cert for localhost" do Puppet::SSL::Host.expects(:localhost) @master.main end it "should make sure to *only* hit the CA for data" do Puppet::SSL::CertificateAuthority.stubs(:ca?).returns(true) Puppet::SSL::Host.expects(:ca_location=).with(:only) @master.main end it "should drop privileges if running as root" do Puppet.features.stubs(:root?).returns true Puppet::Util.expects(:chuser) @master.main end it "should daemonize if needed" do Puppet.stubs(:[]).with(:daemonize).returns(true) @daemon.expects(:daemonize) @master.main end it "should start the service" do @daemon.expects(:start) @master.main end describe "with --rack", :if => Puppet.features.rack? do before do require 'puppet/network/http/rack' Puppet::Network::HTTP::Rack.stubs(:new).returns(@app) end it "it should create the app with REST and XMLRPC support" do @master.options.stubs(:[]).with(:rack).returns(:true) Puppet::Network::HTTP::Rack.expects(:new).with { |args| args[:xmlrpc_handlers] == [:Status, :FileServer, :Master, :Report, :Filebucket] and args[:protocols] == [:rest, :xmlrpc] } @master.main end it "it should not start a daemon" do @master.options.stubs(:[]).with(:rack).returns(:true) @daemon.expects(:start).never @master.main end it "it should return the app" do @master.options.stubs(:[]).with(:rack).returns(:true) app = @master.main app.should equal(@app) end end end end end diff --git a/spec/unit/application/queue_spec.rb b/spec/unit/application/queue_spec.rb index 8a2e25b25..87713ca97 100755 --- a/spec/unit/application/queue_spec.rb +++ b/spec/unit/application/queue_spec.rb @@ -1,183 +1,182 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/application/queue' require 'puppet/indirector/catalog/queue' describe Puppet::Application::Queue do before :each do @queue = Puppet::Application[:queue] @queue.stubs(:puts) @daemon = stub_everything 'daemon', :daemonize => nil Puppet::Util::Log.stubs(:newdestination) Puppet::Util::Log.stubs(:level=) Puppet::Resource::Catalog.indirection.stubs(:terminus_class=) end it "should ask Puppet::Application to parse Puppet configuration file" do @queue.should_parse_config?.should be_true end it "should declare a main command" do @queue.should respond_to(:main) end it "should declare a preinit block" do @queue.should respond_to(:preinit) end describe "in preinit" do it "should catch INT" do Signal.expects(:trap).with { |arg,block| arg == :INT } @queue.preinit end it "should init :verbose to false" do @queue.preinit @queue.options[:verbose].should be_false end it "should init :debug to false" do @queue.preinit @queue.options[:debug].should be_false end it "should create a Daemon instance and copy ARGV to it" do ARGV.expects(:dup).returns "eh" daemon = mock("daemon") daemon.expects(:argv=).with("eh") Puppet::Daemon.expects(:new).returns daemon @queue.preinit end end describe "when handling options" do [:debug, :verbose].each do |option| it "should declare handle_#{option} method" do @queue.should respond_to("handle_#{option}".to_sym) end it "should store argument value when calling handle_#{option}" do @queue.options.expects(:[]=).with(option, 'arg') @queue.send("handle_#{option}".to_sym, 'arg') end end end describe "during setup" do before :each do @queue.options.stubs(:[]) @queue.daemon.stubs(:daemonize) Puppet.stubs(:info) Puppet.features.stubs(:stomp?).returns true Puppet::Resource::Catalog.indirection.stubs(:terminus_class=) Puppet.stubs(:settraps) Puppet.settings.stubs(:print_config?) Puppet.settings.stubs(:print_config) end it "should fail if the stomp feature is missing" do Puppet.features.expects(:stomp?).returns false lambda { @queue.setup }.should raise_error(ArgumentError) end it "should print puppet config if asked to in Puppet config" do @queue.stubs(:exit) Puppet.settings.stubs(:print_configs?).returns(true) Puppet.settings.expects(:print_configs) @queue.setup end it "should exit after printing puppet config if asked to in Puppet config" do Puppet.settings.stubs(:print_configs?).returns(true) lambda { @queue.setup }.should raise_error(SystemExit) end it "should call setup_logs" do @queue.expects(:setup_logs) @queue.setup end describe "when setting up logs" do before :each do Puppet::Util::Log.stubs(:newdestination) end it "should set log level to debug if --debug was passed" do @queue.options.stubs(:[]).with(:debug).returns(true) Puppet::Util::Log.expects(:level=).with(:debug) @queue.setup_logs end it "should set log level to info if --verbose was passed" do @queue.options.stubs(:[]).with(:verbose).returns(true) Puppet::Util::Log.expects(:level=).with(:info) @queue.setup_logs end [:verbose, :debug].each do |level| it "should set console as the log destination with level #{level}" do @queue.options.stubs(:[]).with(level).returns(true) Puppet::Util::Log.expects(:newdestination).with(:console) @queue.setup_logs end end end it "should configure the Catalog class to use ActiveRecord" do Puppet::Resource::Catalog.indirection.expects(:terminus_class=).with(:active_record) @queue.setup end it "should daemonize if needed" do Puppet.expects(:[]).with(:daemonize).returns(true) @queue.daemon.expects(:daemonize) @queue.setup end end describe "when running" do before :each do @queue.stubs(:sleep_forever) Puppet::Resource::Catalog::Queue.stubs(:subscribe) Thread.list.each { |t| t.stubs(:join) } end it "should subscribe to the queue" do Puppet::Resource::Catalog::Queue.expects(:subscribe) @queue.main end it "should log and save each catalog passed by the queue" do catalog = Puppet::Resource::Catalog.new('eh') Puppet::Resource::Catalog.indirection.expects(:save).with(catalog) Puppet::Resource::Catalog::Queue.expects(:subscribe).yields(catalog) Puppet.expects(:notice).times(2) @queue.main end it "should join all of the running threads" do Thread.list.each { |t| t.expects(:join) } @queue.main end end end diff --git a/spec/unit/application/resource_spec.rb b/spec/unit/application/resource_spec.rb index a97fdc953..673bd65d7 100755 --- a/spec/unit/application/resource_spec.rb +++ b/spec/unit/application/resource_spec.rb @@ -1,233 +1,232 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/application/resource' describe Puppet::Application::Resource do before :each do @resource = Puppet::Application[:resource] Puppet::Util::Log.stubs(:newdestination) Puppet::Util::Log.stubs(:level=) Puppet::Resource.indirection.stubs(:terminus_class=) end it "should ask Puppet::Application to not parse Puppet configuration file" do @resource.should_parse_config?.should be_false end it "should declare a main command" do @resource.should respond_to(:main) end it "should declare a host option" do @resource.should respond_to(:handle_host) end it "should declare a types option" do @resource.should respond_to(:handle_types) end it "should declare a param option" do @resource.should respond_to(:handle_param) end it "should declare a preinit block" do @resource.should respond_to(:preinit) end describe "in preinit" do it "should set hosts to nil" do @resource.preinit @resource.host.should be_nil end it "should init extra_params to empty array" do @resource.preinit @resource.extra_params.should == [] end it "should load Facter facts" do Facter.expects(:loadfacts).once @resource.preinit end end describe "when handling options" do [:debug, :verbose, :edit].each do |option| it "should declare handle_#{option} method" do @resource.should respond_to("handle_#{option}".to_sym) end it "should store argument value when calling handle_#{option}" do @resource.options.expects(:[]=).with(option, 'arg') @resource.send("handle_#{option}".to_sym, 'arg') end end it "should set options[:host] to given host" do @resource.handle_host(:whatever) @resource.host.should == :whatever end it "should load an display all types with types option" do type1 = stub_everything 'type1', :name => :type1 type2 = stub_everything 'type2', :name => :type2 Puppet::Type.stubs(:loadall) Puppet::Type.stubs(:eachtype).multiple_yields(type1,type2) @resource.stubs(:exit) @resource.expects(:puts).with(['type1','type2']) @resource.handle_types(nil) end it "should add param to extra_params list" do @resource.extra_params = [ :param1 ] @resource.handle_param("whatever") @resource.extra_params.should == [ :param1, :whatever ] end end describe "during setup" do before :each do Puppet::Log.stubs(:newdestination) Puppet::Log.stubs(:level=) Puppet.stubs(:parse_config) end it "should set console as the log destination" do Puppet::Log.expects(:newdestination).with(:console) @resource.setup end it "should set log level to debug if --debug was passed" do @resource.options.stubs(:[]).with(:debug).returns(true) Puppet::Log.expects(:level=).with(:debug) @resource.setup end it "should set log level to info if --verbose was passed" do @resource.options.stubs(:[]).with(:debug).returns(false) @resource.options.stubs(:[]).with(:verbose).returns(true) Puppet::Log.expects(:level=).with(:info) @resource.setup end it "should Parse puppet config" do Puppet.expects(:parse_config) @resource.setup end end describe "when running" do before :each do @type = stub_everything 'type', :properties => [] @resource.command_line.stubs(:args).returns(['type']) Puppet::Type.stubs(:type).returns(@type) end it "should raise an error if no type is given" do @resource.command_line.stubs(:args).returns([]) lambda { @resource.main }.should raise_error end it "should raise an error when editing a remote host" do @resource.options.stubs(:[]).with(:edit).returns(true) @resource.host = 'host' lambda { @resource.main }.should raise_error end it "should raise an error if the type is not found" do Puppet::Type.stubs(:type).returns(nil) lambda { @resource.main }.should raise_error end describe "with a host" do before :each do @resource.stubs(:puts) @resource.host = 'host' Puppet::Resource.indirection.stubs(:find ).never Puppet::Resource.indirection.stubs(:search).never Puppet::Resource.indirection.stubs(:save ).never end it "should search for resources" do @resource.command_line.stubs(:args).returns(['type']) Puppet::Resource.indirection.expects(:search).with('https://host:8139/production/resources/type/', {}).returns([]) @resource.main end it "should describe the given resource" do @resource.command_line.stubs(:args).returns(['type', 'name']) x = stub_everything 'resource' Puppet::Resource.indirection.expects(:find).with('https://host:8139/production/resources/type/name').returns(x) @resource.main end it "should add given parameters to the object" do @resource.command_line.stubs(:args).returns(['type','name','param=temp']) res = stub "resource" Puppet::Resource.indirection.expects(:save).with(res, 'https://host:8139/production/resources/type/name').returns(res) res.expects(:collect) res.expects(:to_manifest) Puppet::Resource.expects(:new).with('type', 'name', :parameters => {'param' => 'temp'}).returns(res) @resource.main end end describe "without a host" do before :each do @resource.stubs(:puts) @resource.host = nil Puppet::Resource.indirection.stubs(:find ).never Puppet::Resource.indirection.stubs(:search).never Puppet::Resource.indirection.stubs(:save ).never end it "should search for resources" do Puppet::Resource.indirection.expects(:search).with('type/', {}).returns([]) @resource.main end it "should describe the given resource" do @resource.command_line.stubs(:args).returns(['type','name']) x = stub_everything 'resource' Puppet::Resource.indirection.expects(:find).with('type/name').returns(x) @resource.main end it "should add given parameters to the object" do @resource.command_line.stubs(:args).returns(['type','name','param=temp']) res = stub "resource" Puppet::Resource.indirection.expects(:save).with(res, 'type/name').returns(res) res.expects(:collect) res.expects(:to_manifest) Puppet::Resource.expects(:new).with('type', 'name', :parameters => {'param' => 'temp'}).returns(res) @resource.main end end end end diff --git a/spec/unit/application_spec.rb b/spec/unit/application_spec.rb index a1a46c814..f46959092 100755 --- a/spec/unit/application_spec.rb +++ b/spec/unit/application_spec.rb @@ -1,610 +1,609 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/application' require 'puppet' require 'getoptlong' describe Puppet::Application do before do @app = Class.new(Puppet::Application).new @appclass = @app.class @app.stubs(:name).returns("test_app") # avoid actually trying to parse any settings Puppet.settings.stubs(:parse) end describe "finding" do before do @klass = Puppet::Application @klass.stubs(:puts) end it "should find classes in the namespace" do @klass.find("Agent").should == @klass::Agent end it "should not find classes outside the namespace" do lambda { @klass.find("String") }.should raise_error(SystemExit) end it "should exit if it can't find a class" do lambda { @klass.find("ThisShallNeverEverEverExistAsdf") }.should raise_error(SystemExit) end end describe ".run_mode" do it "should default to user" do @appclass.run_mode.name.should == :user end it "should set and get a value" do @appclass.run_mode :agent @appclass.run_mode.name.should == :agent end end it "should sadly and frighteningly allow run_mode to change at runtime" do class TestApp < Puppet::Application run_mode :master def run_command # This is equivalent to calling these methods externally to the # instance, but since this is what "real world" code is likely to do # (and we need the class anyway) we may as well test that. --daniel 2011-02-03 set_run_mode self.class.run_mode "agent" end end Puppet[:run_mode].should == "user" expect { app = TestApp.new Puppet[:run_mode].should == "master" app.run app.class.run_mode.name.should == :agent $puppet_application_mode.name.should == :agent }.should_not raise_error Puppet[:run_mode].should == "agent" end it "it should not allow run mode to be set multiple times" do pending "great floods of tears, you can do this right now" # --daniel 2011-02-03 app = Puppet::Application.new expect { app.set_run_mode app.class.run_mode "master" $puppet_application_mode.name.should == :master app.set_run_mode app.class.run_mode "agent" $puppet_application_mode.name.should == :agent }.should raise_error end it "should explode when an invalid run mode is set at runtime, for great victory" # ...but you can, and while it will explode, that only happens too late for # us to easily test. --daniel 2011-02-03 it "should have a run entry-point" do @app.should respond_to(:run) end it "should have a read accessor to options" do @app.should respond_to(:options) end it "should include a default setup method" do @app.should respond_to(:setup) end it "should include a default preinit method" do @app.should respond_to(:preinit) end it "should include a default run_command method" do @app.should respond_to(:run_command) end it "should invoke main as the default" do @app.expects( :main ) @app.run_command end describe 'when invoking clear!' do before :each do Puppet::Application.run_status = :stop_requested Puppet::Application.clear! end it 'should have nil run_status' do Puppet::Application.run_status.should be_nil end it 'should return false for restart_requested?' do Puppet::Application.restart_requested?.should be_false end it 'should return false for stop_requested?' do Puppet::Application.stop_requested?.should be_false end it 'should return false for interrupted?' do Puppet::Application.interrupted?.should be_false end it 'should return true for clear?' do Puppet::Application.clear?.should be_true end end describe 'after invoking stop!' do before :each do Puppet::Application.run_status = nil Puppet::Application.stop! end after :each do Puppet::Application.run_status = nil end it 'should have run_status of :stop_requested' do Puppet::Application.run_status.should == :stop_requested end it 'should return true for stop_requested?' do Puppet::Application.stop_requested?.should be_true end it 'should return false for restart_requested?' do Puppet::Application.restart_requested?.should be_false end it 'should return true for interrupted?' do Puppet::Application.interrupted?.should be_true end it 'should return false for clear?' do Puppet::Application.clear?.should be_false end end describe 'when invoking restart!' do before :each do Puppet::Application.run_status = nil Puppet::Application.restart! end after :each do Puppet::Application.run_status = nil end it 'should have run_status of :restart_requested' do Puppet::Application.run_status.should == :restart_requested end it 'should return true for restart_requested?' do Puppet::Application.restart_requested?.should be_true end it 'should return false for stop_requested?' do Puppet::Application.stop_requested?.should be_false end it 'should return true for interrupted?' do Puppet::Application.interrupted?.should be_true end it 'should return false for clear?' do Puppet::Application.clear?.should be_false end end describe 'when performing a controlled_run' do it 'should not execute block if not :clear?' do Puppet::Application.run_status = :stop_requested target = mock 'target' target.expects(:some_method).never Puppet::Application.controlled_run do target.some_method end end it 'should execute block if :clear?' do Puppet::Application.run_status = nil target = mock 'target' target.expects(:some_method).once Puppet::Application.controlled_run do target.some_method end end describe 'on POSIX systems', :if => Puppet.features.posix? do it 'should signal process with HUP after block if restart requested during block execution' do Puppet::Application.run_status = nil target = mock 'target' target.expects(:some_method).once old_handler = trap('HUP') { target.some_method } begin Puppet::Application.controlled_run do Puppet::Application.run_status = :restart_requested end ensure trap('HUP', old_handler) end end end after :each do Puppet::Application.run_status = nil end end describe "when parsing command-line options" do before :each do @app.command_line.stubs(:args).returns([]) Puppet.settings.stubs(:optparse_addargs).returns([]) end it "should pass the banner to the option parser" do option_parser = stub "option parser" option_parser.stubs(:on) option_parser.stubs(:parse!) @app.class.instance_eval do banner "banner" end OptionParser.expects(:new).with("banner").returns(option_parser) @app.parse_options end it "should get options from Puppet.settings.optparse_addargs" do Puppet.settings.expects(:optparse_addargs).returns([]) @app.parse_options end it "should add Puppet.settings options to OptionParser" do Puppet.settings.stubs(:optparse_addargs).returns( [["--option","-o", "Funny Option"]]) Puppet.settings.expects(:handlearg).with("--option", 'true') @app.command_line.stubs(:args).returns(["--option"]) @app.parse_options end it "should ask OptionParser to parse the command-line argument" do @app.command_line.stubs(:args).returns(%w{ fake args }) OptionParser.any_instance.expects(:parse!).with(%w{ fake args }) @app.parse_options end describe "when using --help" do it "should call exit" do @app.expects(:exit) @app.stubs(:puts) @app.handle_help(nil) end end describe "when using --version" do it "should declare a version option" do @app.should respond_to(:handle_version) end it "should exit after printing the version" do @app.stubs(:puts) lambda { @app.handle_version(nil) }.should raise_error(SystemExit) end end describe "when dealing with an argument not declared directly by the application" do it "should pass it to handle_unknown if this method exists" do Puppet.settings.stubs(:optparse_addargs).returns([["--not-handled", :REQUIRED]]) @app.expects(:handle_unknown).with("--not-handled", "value").returns(true) @app.command_line.stubs(:args).returns(["--not-handled", "value"]) @app.parse_options end it "should pass it to Puppet.settings if handle_unknown says so" do Puppet.settings.stubs(:optparse_addargs).returns([["--topuppet", :REQUIRED]]) @app.stubs(:handle_unknown).with("--topuppet", "value").returns(false) Puppet.settings.expects(:handlearg).with("--topuppet", "value") @app.command_line.stubs(:args).returns(["--topuppet", "value"]) @app.parse_options end it "should pass it to Puppet.settings if there is no handle_unknown method" do Puppet.settings.stubs(:optparse_addargs).returns([["--topuppet", :REQUIRED]]) @app.stubs(:respond_to?).returns(false) Puppet.settings.expects(:handlearg).with("--topuppet", "value") @app.command_line.stubs(:args).returns(["--topuppet", "value"]) @app.parse_options end it "should transform boolean false value to string for Puppet.settings" do Puppet.settings.expects(:handlearg).with("--option", "false") @app.handlearg("--option", false) end it "should transform boolean true value to string for Puppet.settings" do Puppet.settings.expects(:handlearg).with("--option", "true") @app.handlearg("--option", true) end it "should transform boolean option to normal form for Puppet.settings" do Puppet.settings.expects(:handlearg).with("--option", "true") @app.handlearg("--[no-]option", true) end it "should transform boolean option to no- form for Puppet.settings" do Puppet.settings.expects(:handlearg).with("--no-option", "false") @app.handlearg("--[no-]option", false) end end end describe "when calling default setup" do before :each do @app.stubs(:should_parse_config?).returns(false) @app.options.stubs(:[]) end [ :debug, :verbose ].each do |level| it "should honor option #{level}" do @app.options.stubs(:[]).with(level).returns(true) Puppet::Util::Log.stubs(:newdestination) Puppet::Util::Log.expects(:level=).with(level == :verbose ? :info : :debug) @app.setup end end it "should honor setdest option" do @app.options.stubs(:[]).with(:setdest).returns(false) Puppet::Util::Log.expects(:newdestination).with(:syslog) @app.setup end end describe "when configuring routes" do include PuppetSpec::Files before :each do Puppet::Node.indirection.reset_terminus_class end after :each do Puppet::Node.indirection.reset_terminus_class end it "should use the routes specified for only the active application" do Puppet[:route_file] = tmpfile('routes') File.open(Puppet[:route_file], 'w') do |f| f.print <<-ROUTES test_app: node: terminus: exec other_app: node: terminus: plain catalog: terminus: invalid ROUTES end @app.configure_indirector_routes Puppet::Node.indirection.terminus_class.should == 'exec' end it "should not fail if the route file doesn't exist" do Puppet[:route_file] = "/dev/null/non-existent" expect { @app.configure_indirector_routes }.should_not raise_error end it "should raise an error if the routes file is invalid" do Puppet[:route_file] = tmpfile('routes') File.open(Puppet[:route_file], 'w') do |f| f.print <<-ROUTES invalid : : yaml ROUTES end expect { @app.configure_indirector_routes }.should raise_error end end describe "when running" do before :each do @app.stubs(:preinit) @app.stubs(:setup) @app.stubs(:parse_options) end it "should call preinit" do @app.stubs(:run_command) @app.expects(:preinit) @app.run end it "should call parse_options" do @app.stubs(:run_command) @app.expects(:parse_options) @app.run end it "should call run_command" do @app.expects(:run_command) @app.run end it "should parse Puppet configuration if should_parse_config is called" do @app.stubs(:run_command) @app.class.should_parse_config Puppet.settings.expects(:parse) @app.run end it "should not parse_option if should_not_parse_config is called" do @app.stubs(:run_command) @app.class.should_not_parse_config Puppet.settings.expects(:parse).never @app.run end it "should parse Puppet configuration if needed" do @app.stubs(:run_command) @app.stubs(:should_parse_config?).returns(true) Puppet.settings.expects(:parse) @app.run end it "should call run_command" do @app.expects(:run_command) @app.run end it "should call main as the default command" do @app.expects(:main) @app.run end it "should warn and exit if no command can be called" do $stderr.expects(:puts) @app.expects(:exit).with(1) @app.run end it "should raise an error if dispatch returns no command" do @app.stubs(:get_command).returns(nil) $stderr.expects(:puts) @app.expects(:exit).with(1) @app.run end it "should raise an error if dispatch returns an invalid command" do @app.stubs(:get_command).returns(:this_function_doesnt_exist) $stderr.expects(:puts) @app.expects(:exit).with(1) @app.run end end describe "when metaprogramming" do describe "when calling option" do it "should create a new method named after the option" do @app.class.option("--test1","-t") do end @app.should respond_to(:handle_test1) end it "should transpose in option name any '-' into '_'" do @app.class.option("--test-dashes-again","-t") do end @app.should respond_to(:handle_test_dashes_again) end it "should create a new method called handle_test2 with option(\"--[no-]test2\")" do @app.class.option("--[no-]test2","-t") do end @app.should respond_to(:handle_test2) end describe "when a block is passed" do it "should create a new method with it" do @app.class.option("--[no-]test2","-t") do raise "I can't believe it, it works!" end lambda { @app.handle_test2 }.should raise_error end it "should declare the option to OptionParser" do OptionParser.any_instance.stubs(:on) OptionParser.any_instance.expects(:on).with { |*arg| arg[0] == "--[no-]test3" } @app.class.option("--[no-]test3","-t") do end @app.parse_options end it "should pass a block that calls our defined method" do OptionParser.any_instance.stubs(:on) OptionParser.any_instance.stubs(:on).with('--test4','-t').yields(nil) @app.expects(:send).with(:handle_test4, nil) @app.class.option("--test4","-t") do end @app.parse_options end end describe "when no block is given" do it "should declare the option to OptionParser" do OptionParser.any_instance.stubs(:on) OptionParser.any_instance.expects(:on).with("--test4","-t") @app.class.option("--test4","-t") @app.parse_options end it "should give to OptionParser a block that adds the the value to the options array" do OptionParser.any_instance.stubs(:on) OptionParser.any_instance.stubs(:on).with("--test4","-t").yields(nil) @app.options.expects(:[]=).with(:test4,nil) @app.class.option("--test4","-t") @app.parse_options end end end end end diff --git a/spec/unit/configurer/downloader_spec.rb b/spec/unit/configurer/downloader_spec.rb index 8c455cb5b..17b285d53 100755 --- a/spec/unit/configurer/downloader_spec.rb +++ b/spec/unit/configurer/downloader_spec.rb @@ -1,200 +1,199 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/configurer/downloader' describe Puppet::Configurer::Downloader do require 'puppet_spec/files' include PuppetSpec::Files it "should require a name" do lambda { Puppet::Configurer::Downloader.new }.should raise_error(ArgumentError) end it "should require a path and a source at initialization" do lambda { Puppet::Configurer::Downloader.new("name") }.should raise_error(ArgumentError) end it "should set the name, path and source appropriately" do dler = Puppet::Configurer::Downloader.new("facts", "path", "source") dler.name.should == "facts" dler.path.should == "path" dler.source.should == "source" end it "should be able to provide a timeout value" do Puppet::Configurer::Downloader.should respond_to(:timeout) end it "should use the configtimeout, converted to an integer, as its timeout" do Puppet.settings.expects(:value).with(:configtimeout).returns "50" Puppet::Configurer::Downloader.timeout.should == 50 end describe "when creating the file that does the downloading" do before do @dler = Puppet::Configurer::Downloader.new("foo", "path", "source") end it "should create a file instance with the right path and source" do Puppet::Type.type(:file).expects(:new).with { |opts| opts[:path] == "path" and opts[:source] == "source" } @dler.file end it "should tag the file with the downloader name" do Puppet::Type.type(:file).expects(:new).with { |opts| opts[:tag] == "foo" } @dler.file end it "should always recurse" do Puppet::Type.type(:file).expects(:new).with { |opts| opts[:recurse] == true } @dler.file end it "should always purge" do Puppet::Type.type(:file).expects(:new).with { |opts| opts[:purge] == true } @dler.file end it "should never be in noop" do Puppet::Type.type(:file).expects(:new).with { |opts| opts[:noop] == false } @dler.file end it "should always set the owner to the current UID" do Process.expects(:uid).returns 51 Puppet::Type.type(:file).expects(:new).with { |opts| opts[:owner] == 51 } @dler.file end it "should always set the group to the current GID" do Process.expects(:gid).returns 61 Puppet::Type.type(:file).expects(:new).with { |opts| opts[:group] == 61 } @dler.file end it "should always force the download" do Puppet::Type.type(:file).expects(:new).with { |opts| opts[:force] == true } @dler.file end it "should never back up when downloading" do Puppet::Type.type(:file).expects(:new).with { |opts| opts[:backup] == false } @dler.file end it "should support providing an 'ignore' parameter" do Puppet::Type.type(:file).expects(:new).with { |opts| opts[:ignore] == [".svn"] } @dler = Puppet::Configurer::Downloader.new("foo", "path", "source", ".svn") @dler.file end it "should split the 'ignore' parameter on whitespace" do Puppet::Type.type(:file).expects(:new).with { |opts| opts[:ignore] == %w{.svn CVS} } @dler = Puppet::Configurer::Downloader.new("foo", "path", "source", ".svn CVS") @dler.file end end describe "when creating the catalog to do the downloading" do before do @dler = Puppet::Configurer::Downloader.new("foo", "/download/path", "source") end it "should create a catalog and add the file to it" do catalog = @dler.catalog catalog.resources.size.should == 1 catalog.resources.first.class.should == Puppet::Type::File catalog.resources.first.name.should == "/download/path" end it "should specify that it is not managing a host catalog" do @dler.catalog.host_config.should == false end end describe "when downloading" do before do @dl_name = tmpfile("downloadpath") source_name = tmpfile("source") File.open(source_name, 'w') {|f| f.write('hola mundo') } @dler = Puppet::Configurer::Downloader.new("foo", @dl_name, source_name) end it "should not skip downloaded resources when filtering on tags" do Puppet[:tags] = 'maytag' @dler.evaluate File.exists?(@dl_name).should be_true end it "should log that it is downloading" do Puppet.expects(:info) Timeout.stubs(:timeout) @dler.evaluate end it "should set a timeout for the download" do Puppet::Configurer::Downloader.expects(:timeout).returns 50 Timeout.expects(:timeout).with(50) @dler.evaluate end it "should apply the catalog within the timeout block" do catalog = mock 'catalog' @dler.expects(:catalog).returns(catalog) Timeout.expects(:timeout).yields catalog.expects(:apply) @dler.evaluate end it "should return all changed file paths" do trans = mock 'transaction' catalog = mock 'catalog' @dler.expects(:catalog).returns(catalog) catalog.expects(:apply).yields(trans) Timeout.expects(:timeout).yields resource = mock 'resource' resource.expects(:[]).with(:path).returns "/changed/file" trans.expects(:changed?).returns([resource]) @dler.evaluate.should == %w{/changed/file} end it "should yield the resources if a block is given" do trans = mock 'transaction' catalog = mock 'catalog' @dler.expects(:catalog).returns(catalog) catalog.expects(:apply).yields(trans) Timeout.expects(:timeout).yields resource = mock 'resource' resource.expects(:[]).with(:path).returns "/changed/file" trans.expects(:changed?).returns([resource]) yielded = nil @dler.evaluate { |r| yielded = r } yielded.should == resource end it "should catch and log exceptions" do Puppet.expects(:err) Timeout.stubs(:timeout).raises(Puppet::Error, "testing") lambda { @dler.evaluate }.should_not raise_error end end end diff --git a/spec/unit/configurer/fact_handler_spec.rb b/spec/unit/configurer/fact_handler_spec.rb index c7d061ad1..70d9b17c0 100755 --- a/spec/unit/configurer/fact_handler_spec.rb +++ b/spec/unit/configurer/fact_handler_spec.rb @@ -1,164 +1,163 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/configurer' require 'puppet/configurer/fact_handler' class FactHandlerTester include Puppet::Configurer::FactHandler end describe Puppet::Configurer::FactHandler do before do @facthandler = FactHandlerTester.new end it "should have a method for downloading fact plugins" do @facthandler.should respond_to(:download_fact_plugins) end it "should have a boolean method for determining whether fact plugins should be downloaded" do @facthandler.should respond_to(:download_fact_plugins?) end it "should download fact plugins when :factsync is true" do Puppet.settings.expects(:value).with(:factsync).returns true @facthandler.should be_download_fact_plugins end it "should not download fact plugins when :factsync is false" do Puppet.settings.expects(:value).with(:factsync).returns false @facthandler.should_not be_download_fact_plugins end it "should not download fact plugins when downloading is disabled" do Puppet::Configurer::Downloader.expects(:new).never @facthandler.expects(:download_fact_plugins?).returns false @facthandler.download_fact_plugins end it "should use an Agent Downloader, with the name, source, destination, and ignore set correctly, to download fact plugins when downloading is enabled" do downloader = mock 'downloader' Puppet.settings.expects(:value).with(:factsource).returns "fsource" Puppet.settings.expects(:value).with(:factdest).returns "fdest" Puppet.settings.expects(:value).with(:factsignore).returns "fignore" Puppet::Configurer::Downloader.expects(:new).with("fact", "fdest", "fsource", "fignore").returns downloader downloader.expects(:evaluate) @facthandler.expects(:download_fact_plugins?).returns true @facthandler.download_fact_plugins end it "should warn about factsync deprecation when factsync is enabled" do Puppet::Configurer::Downloader.stubs(:new).returns mock("downloader", :evaluate => nil) @facthandler.expects(:download_fact_plugins?).returns true Puppet.expects(:warning) @facthandler.download_fact_plugins end it "should have a method for retrieving facts" do @facthandler.should respond_to(:find_facts) end it "should use the Facts class with the :certname to find the facts" do Puppet.settings.expects(:value).with(:certname).returns "foo" Puppet::Node::Facts.indirection.expects(:find).with("foo").returns "myfacts" @facthandler.stubs(:reload_facter) @facthandler.find_facts.should == "myfacts" end it "should reload Facter and find local facts when asked to find facts" do @facthandler.expects(:reload_facter) Puppet.settings.expects(:value).with(:certname).returns "myhost" Puppet::Node::Facts.indirection.expects(:find).with("myhost") @facthandler.find_facts end it "should fail if finding facts fails" do @facthandler.stubs(:reload_facter) Puppet.settings.stubs(:value).with(:trace).returns false Puppet.settings.stubs(:value).with(:certname).returns "myhost" Puppet::Node::Facts.indirection.expects(:find).raises RuntimeError lambda { @facthandler.find_facts }.should raise_error(Puppet::Error) end it "should have a method to prepare the facts for uploading" do @facthandler.should respond_to(:facts_for_uploading) end # I couldn't get marshal to work for this, only yaml, so we hard-code yaml. it "should serialize and CGI escape the fact values for uploading" do facts = stub 'facts' facts.expects(:support_format?).with(:b64_zlib_yaml).returns true facts.expects(:render).returns "my text" text = CGI.escape("my text") @facthandler.expects(:find_facts).returns facts @facthandler.facts_for_uploading.should == {:facts_format => :b64_zlib_yaml, :facts => text} end it "should properly accept facts containing a '+'" do facts = stub 'facts' facts.expects(:support_format?).with(:b64_zlib_yaml).returns true facts.expects(:render).returns "my+text" text = "my%2Btext" @facthandler.expects(:find_facts).returns facts @facthandler.facts_for_uploading.should == {:facts_format => :b64_zlib_yaml, :facts => text} end it "use compressed yaml as the serialization if zlib is supported" do facts = stub 'facts' facts.expects(:support_format?).with(:b64_zlib_yaml).returns true facts.expects(:render).with(:b64_zlib_yaml).returns "my text" text = CGI.escape("my text") @facthandler.expects(:find_facts).returns facts @facthandler.facts_for_uploading end it "should use yaml as the serialization if zlib is not supported" do facts = stub 'facts' facts.expects(:support_format?).with(:b64_zlib_yaml).returns false facts.expects(:render).with(:yaml).returns "my text" text = CGI.escape("my text") @facthandler.expects(:find_facts).returns facts @facthandler.facts_for_uploading end describe "when reloading Facter" do before do Facter.stubs(:clear) Facter.stubs(:load) Facter.stubs(:loadfacts) end it "should clear Facter" do Facter.expects(:clear) @facthandler.reload_facter end it "should load all Facter facts" do Facter.expects(:loadfacts) @facthandler.reload_facter end it "should use the Facter terminus load all Puppet Fact plugins" do Puppet::Node::Facts::Facter.expects(:load_fact_plugins) @facthandler.reload_facter end end end diff --git a/spec/unit/configurer/plugin_handler_spec.rb b/spec/unit/configurer/plugin_handler_spec.rb index bd2ed3855..7d99960df 100755 --- a/spec/unit/configurer/plugin_handler_spec.rb +++ b/spec/unit/configurer/plugin_handler_spec.rb @@ -1,116 +1,115 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/configurer' require 'puppet/configurer/plugin_handler' class PluginHandlerTester include Puppet::Configurer::PluginHandler end describe Puppet::Configurer::PluginHandler do before do @pluginhandler = PluginHandlerTester.new # PluginHandler#load_plugin has an extra-strong rescue clause # this mock is to make sure that we don't silently ignore errors Puppet.expects(:err).never end it "should have a method for downloading plugins" do @pluginhandler.should respond_to(:download_plugins) end it "should have a boolean method for determining whether plugins should be downloaded" do @pluginhandler.should respond_to(:download_plugins?) end it "should download plugins when :pluginsync is true" do Puppet.settings.expects(:value).with(:pluginsync).returns true @pluginhandler.should be_download_plugins end it "should not download plugins when :pluginsync is false" do Puppet.settings.expects(:value).with(:pluginsync).returns false @pluginhandler.should_not be_download_plugins end it "should not download plugins when downloading is disabled" do Puppet::Configurer::Downloader.expects(:new).never @pluginhandler.expects(:download_plugins?).returns false @pluginhandler.download_plugins end it "should use an Agent Downloader, with the name, source, destination, and ignore set correctly, to download plugins when downloading is enabled" do downloader = mock 'downloader' Puppet.settings.expects(:value).with(:pluginsource).returns "psource" Puppet.settings.expects(:value).with(:plugindest).returns "pdest" Puppet.settings.expects(:value).with(:pluginsignore).returns "pignore" Puppet::Configurer::Downloader.expects(:new).with("plugin", "pdest", "psource", "pignore").returns downloader downloader.expects(:evaluate).returns [] @pluginhandler.expects(:download_plugins?).returns true @pluginhandler.download_plugins end it "should be able to load plugins" do @pluginhandler.should respond_to(:load_plugin) end it "should load each downloaded file" do FileTest.stubs(:exist?).returns true downloader = mock 'downloader' Puppet::Configurer::Downloader.expects(:new).returns downloader downloader.expects(:evaluate).returns %w{one two} @pluginhandler.expects(:download_plugins?).returns true @pluginhandler.expects(:load_plugin).with("one") @pluginhandler.expects(:load_plugin).with("two") @pluginhandler.download_plugins end it "should load plugins when asked to do so" do FileTest.stubs(:exist?).returns true @pluginhandler.expects(:load).with("foo") @pluginhandler.load_plugin("foo") end it "should not try to load files that don't exist" do FileTest.expects(:exist?).with("foo").returns false @pluginhandler.expects(:load).never @pluginhandler.load_plugin("foo") end it "should not try to load directories" do FileTest.stubs(:exist?).returns true FileTest.expects(:directory?).with("foo").returns true @pluginhandler.expects(:load).never @pluginhandler.load_plugin("foo") end it "should warn but not fail if loading a file raises an exception" do FileTest.stubs(:exist?).returns true @pluginhandler.expects(:load).with("foo").raises "eh" Puppet.expects(:err) @pluginhandler.load_plugin("foo") end it "should warn but not fail if loading a file raises a LoadError" do FileTest.stubs(:exist?).returns true @pluginhandler.expects(:load).with("foo").raises LoadError.new("eh") Puppet.expects(:err) @pluginhandler.load_plugin("foo") end end diff --git a/spec/unit/configurer_spec.rb b/spec/unit/configurer_spec.rb index c2482e6be..7b76c3221 100755 --- a/spec/unit/configurer_spec.rb +++ b/spec/unit/configurer_spec.rb @@ -1,526 +1,526 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Created by Luke Kanies on 2007-11-12. # Copyright (c) 2007. All rights reserved. require 'spec_helper' require 'puppet/configurer' describe Puppet::Configurer do before do Puppet.settings.stubs(:use).returns(true) @agent = Puppet::Configurer.new end it "should include the Plugin Handler module" do Puppet::Configurer.ancestors.should be_include(Puppet::Configurer::PluginHandler) end it "should include the Fact Handler module" do Puppet::Configurer.ancestors.should be_include(Puppet::Configurer::FactHandler) end it "should use the puppetdlockfile as its lockfile path" do Puppet.settings.expects(:value).with(:puppetdlockfile).returns("/my/lock") Puppet::Configurer.lockfile_path.should == "/my/lock" end describe "when executing a pre-run hook" do it "should do nothing if the hook is set to an empty string" do Puppet.settings[:prerun_command] = "" Puppet::Util.expects(:exec).never @agent.execute_prerun_command end it "should execute any pre-run command provided via the 'prerun_command' setting" do Puppet.settings[:prerun_command] = "/my/command" Puppet::Util.expects(:execute).with { |args| args[0] == "/my/command" } @agent.execute_prerun_command end it "should fail if the command fails" do Puppet.settings[:prerun_command] = "/my/command" Puppet::Util.expects(:execute).raises Puppet::ExecutionFailure lambda { @agent.execute_prerun_command }.should raise_error(Puppet::Configurer::CommandHookError) end end describe "when executing a post-run hook" do it "should do nothing if the hook is set to an empty string" do Puppet.settings[:postrun_command] = "" Puppet::Util.expects(:exec).never @agent.execute_postrun_command end it "should execute any post-run command provided via the 'postrun_command' setting" do Puppet.settings[:postrun_command] = "/my/command" Puppet::Util.expects(:execute).with { |args| args[0] == "/my/command" } @agent.execute_postrun_command end it "should fail if the command fails" do Puppet.settings[:postrun_command] = "/my/command" Puppet::Util.expects(:execute).raises Puppet::ExecutionFailure lambda { @agent.execute_postrun_command }.should raise_error(Puppet::Configurer::CommandHookError) end end end describe Puppet::Configurer, "when executing a catalog run" do before do Puppet.settings.stubs(:use).returns(true) @agent = Puppet::Configurer.new @agent.stubs(:prepare) @agent.stubs(:facts_for_uploading).returns({}) @catalog = Puppet::Resource::Catalog.new @catalog.stubs(:apply) @agent.stubs(:retrieve_catalog).returns @catalog @agent.stubs(:save_last_run_summary) Puppet::Transaction::Report.indirection.stubs(:save) end it "should prepare for the run" do @agent.expects(:prepare) @agent.run end it "should initialize a transaction report if one is not provided" do report = Puppet::Transaction::Report.new("apply") Puppet::Transaction::Report.expects(:new).at_least_once.returns report @agent.run end it "should pass the new report to the catalog" do report = Puppet::Transaction::Report.new("apply") Puppet::Transaction::Report.stubs(:new).returns report @catalog.expects(:apply).with{|options| options[:report] == report} @agent.run end it "should use the provided report if it was passed one" do report = Puppet::Transaction::Report.new("apply") Puppet::Transaction::Report.expects(:new).never @catalog.expects(:apply).with{|options| options[:report] == report} @agent.run(:report => report) end it "should set the report as a log destination" do report = Puppet::Transaction::Report.new("apply") Puppet::Transaction::Report.expects(:new).returns report @agent.stubs(:send_report) Puppet::Util::Log.expects(:newdestination).with(report) @agent.run end it "should retrieve the catalog" do @agent.expects(:retrieve_catalog) @agent.run end it "should log a failure and do nothing if no catalog can be retrieved" do @agent.expects(:retrieve_catalog).returns nil Puppet.expects(:err).with "Could not retrieve catalog; skipping run" @agent.run end it "should apply the catalog with all options to :run" do @agent.expects(:retrieve_catalog).returns @catalog @catalog.expects(:apply).with { |args| args[:one] == true } @agent.run :one => true end it "should accept a catalog and use it instead of retrieving a different one" do @agent.expects(:retrieve_catalog).never @catalog.expects(:apply) @agent.run :one => true, :catalog => @catalog end it "should benchmark how long it takes to apply the catalog" do @agent.expects(:benchmark).with(:notice, "Finished catalog run") @agent.expects(:retrieve_catalog).returns @catalog @catalog.expects(:apply).never # because we're not yielding @agent.run end it "should execute post-run hooks after the run" do @agent.expects(:execute_postrun_command) @agent.run end it "should send the report" do report = Puppet::Transaction::Report.new("apply") Puppet::Transaction::Report.expects(:new).returns(report) @agent.expects(:send_report).with { |r, trans| r == report } @agent.run end it "should send the transaction report with a reference to the transaction if a run was actually made" do report = Puppet::Transaction::Report.new("apply") Puppet::Transaction::Report.expects(:new).returns(report) trans = stub 'transaction' @catalog.expects(:apply).returns trans @agent.expects(:send_report).with { |r, t| t == trans } @agent.run :catalog => @catalog end it "should send the transaction report even if the catalog could not be retrieved" do @agent.expects(:retrieve_catalog).returns nil report = Puppet::Transaction::Report.new("apply") Puppet::Transaction::Report.expects(:new).returns(report) @agent.expects(:send_report) @agent.run end it "should send the transaction report even if there is a failure" do @agent.expects(:retrieve_catalog).raises "whatever" report = Puppet::Transaction::Report.new("apply") Puppet::Transaction::Report.expects(:new).returns(report) @agent.expects(:send_report) lambda { @agent.run }.should raise_error end it "should remove the report as a log destination when the run is finished" do report = Puppet::Transaction::Report.new("apply") Puppet::Transaction::Report.expects(:new).returns(report) report.expects(:<<).at_least_once @agent.run Puppet::Util::Log.destinations.should_not include(report) end it "should return the report as the result of the run" do report = Puppet::Transaction::Report.new("apply") Puppet::Transaction::Report.expects(:new).returns(report) @agent.run.should equal(report) end end describe Puppet::Configurer, "when sending a report" do include PuppetSpec::Files before do Puppet.settings.stubs(:use).returns(true) @configurer = Puppet::Configurer.new Puppet[:lastrunfile] = tmpfile('last_run_file') @report = Puppet::Transaction::Report.new("apply") @trans = stub 'transaction' end it "should finalize the report" do @report.expects(:finalize_report) @configurer.send_report(@report, @trans) end it "should print a report summary if configured to do so" do Puppet.settings[:summarize] = true @report.expects(:summary).returns "stuff" @configurer.expects(:puts).with("stuff") @configurer.send_report(@report, nil) end it "should not print a report summary if not configured to do so" do Puppet.settings[:summarize] = false @configurer.expects(:puts).never @configurer.send_report(@report, nil) end it "should save the report if reporting is enabled" do Puppet.settings[:report] = true Puppet::Transaction::Report.indirection.expects(:save).with(@report) @configurer.send_report(@report, nil) end it "should not save the report if reporting is disabled" do Puppet.settings[:report] = false Puppet::Transaction::Report.indirection.expects(:save).never @configurer.send_report(@report, nil) end it "should save the last run summary if reporting is enabled" do Puppet.settings[:report] = true @configurer.expects(:save_last_run_summary).with(@report) @configurer.send_report(@report, nil) end it "should save the last run summary if reporting is disabled" do Puppet.settings[:report] = false @configurer.expects(:save_last_run_summary).with(@report) @configurer.send_report(@report, nil) end it "should log but not fail if saving the report fails" do Puppet.settings[:report] = true Puppet::Transaction::Report.indirection.expects(:save).with(@report).raises "whatever" Puppet.expects(:err) lambda { @configurer.send_report(@report, nil) }.should_not raise_error end end describe Puppet::Configurer, "when saving the summary report file" do before do Puppet.settings.stubs(:use).returns(true) @configurer = Puppet::Configurer.new @report = stub 'report' @trans = stub 'transaction' @lastrunfd = stub 'lastrunfd' Puppet::Util::FileLocking.stubs(:writelock).yields(@lastrunfd) end it "should write the raw summary to the lastrunfile setting value" do Puppet::Util::FileLocking.expects(:writelock).with(Puppet[:lastrunfile], 0660) @configurer.save_last_run_summary(@report) end it "should write the raw summary as yaml" do @report.expects(:raw_summary).returns("summary") @lastrunfd.expects(:print).with(YAML.dump("summary")) @configurer.save_last_run_summary(@report) end it "should log but not fail if saving the last run summary fails" do Puppet::Util::FileLocking.expects(:writelock).raises "exception" Puppet.expects(:err) lambda { @configurer.save_last_run_summary(@report) }.should_not raise_error end end describe Puppet::Configurer, "when retrieving a catalog" do before do Puppet.settings.stubs(:use).returns(true) @agent = Puppet::Configurer.new @agent.stubs(:facts_for_uploading).returns({}) @catalog = Puppet::Resource::Catalog.new # this is the default when using a Configurer instance Puppet::Resource::Catalog.indirection.stubs(:terminus_class).returns :rest @agent.stubs(:convert_catalog).returns @catalog end describe "and configured to only retrieve a catalog from the cache" do before do Puppet.settings[:use_cached_catalog] = true end it "should first look in the cache for a catalog" do Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| options[:ignore_terminus] == true }.returns @catalog Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| options[:ignore_cache] == true }.never @agent.retrieve_catalog.should == @catalog end it "should compile a new catalog if none is found in the cache" do Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| options[:ignore_terminus] == true }.returns nil Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| options[:ignore_cache] == true }.returns @catalog @agent.retrieve_catalog.should == @catalog end end describe "when not using a REST terminus for catalogs" do it "should not pass any facts when retrieving the catalog" do @agent.expects(:facts_for_uploading).never Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| options[:facts].nil? }.returns @catalog @agent.retrieve_catalog end end describe "when using a REST terminus for catalogs" do it "should pass the prepared facts and the facts format as arguments when retrieving the catalog" do @agent.expects(:facts_for_uploading).returns(:facts => "myfacts", :facts_format => :foo) Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| options[:facts] == "myfacts" and options[:facts_format] == :foo }.returns @catalog @agent.retrieve_catalog end end it "should use the Catalog class to get its catalog" do Puppet::Resource::Catalog.indirection.expects(:find).returns @catalog @agent.retrieve_catalog end it "should use its certname to retrieve the catalog" do Facter.stubs(:value).returns "eh" Puppet.settings[:certname] = "myhost.domain.com" Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| name == "myhost.domain.com" }.returns @catalog @agent.retrieve_catalog end it "should default to returning a catalog retrieved directly from the server, skipping the cache" do Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| options[:ignore_cache] == true }.returns @catalog @agent.retrieve_catalog.should == @catalog end it "should log and return the cached catalog when no catalog can be retrieved from the server" do Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| options[:ignore_cache] == true }.returns nil Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| options[:ignore_terminus] == true }.returns @catalog Puppet.expects(:notice) @agent.retrieve_catalog.should == @catalog end it "should not look in the cache for a catalog if one is returned from the server" do Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| options[:ignore_cache] == true }.returns @catalog Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| options[:ignore_terminus] == true }.never @agent.retrieve_catalog.should == @catalog end it "should return the cached catalog when retrieving the remote catalog throws an exception" do Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| options[:ignore_cache] == true }.raises "eh" Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| options[:ignore_terminus] == true }.returns @catalog @agent.retrieve_catalog.should == @catalog end it "should log and return nil if no catalog can be retrieved from the server and :usecacheonfailure is disabled" do Puppet.stubs(:[]) Puppet.expects(:[]).with(:usecacheonfailure).returns false Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| options[:ignore_cache] == true }.returns nil Puppet.expects(:warning) @agent.retrieve_catalog.should be_nil end it "should return nil if no cached catalog is available and no catalog can be retrieved from the server" do Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| options[:ignore_cache] == true }.returns nil Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| options[:ignore_terminus] == true }.returns nil @agent.retrieve_catalog.should be_nil end it "should convert the catalog before returning" do Puppet::Resource::Catalog.indirection.stubs(:find).returns @catalog @agent.expects(:convert_catalog).with { |cat, dur| cat == @catalog }.returns "converted catalog" @agent.retrieve_catalog.should == "converted catalog" end it "should return nil if there is an error while retrieving the catalog" do Puppet::Resource::Catalog.indirection.expects(:find).at_least_once.raises "eh" @agent.retrieve_catalog.should be_nil end end describe Puppet::Configurer, "when converting the catalog" do before do Puppet.settings.stubs(:use).returns(true) @agent = Puppet::Configurer.new @catalog = Puppet::Resource::Catalog.new @oldcatalog = stub 'old_catalog', :to_ral => @catalog end it "should convert the catalog to a RAL-formed catalog" do @oldcatalog.expects(:to_ral).returns @catalog @agent.convert_catalog(@oldcatalog, 10).should equal(@catalog) end it "should finalize the catalog" do @catalog.expects(:finalize) @agent.convert_catalog(@oldcatalog, 10) end it "should record the passed retrieval time with the RAL catalog" do @catalog.expects(:retrieval_duration=).with 10 @agent.convert_catalog(@oldcatalog, 10) end it "should write the RAL catalog's class file" do @catalog.expects(:write_class_file) @agent.convert_catalog(@oldcatalog, 10) end end describe Puppet::Configurer, "when preparing for a run" do before do Puppet.settings.stubs(:use).returns(true) @agent = Puppet::Configurer.new @agent.stubs(:dostorage) @agent.stubs(:download_fact_plugins) @agent.stubs(:download_plugins) @agent.stubs(:execute_prerun_command) @facts = {"one" => "two", "three" => "four"} end it "should initialize the metadata store" do @agent.class.stubs(:facts).returns(@facts) @agent.expects(:dostorage) @agent.prepare({}) end it "should download fact plugins" do @agent.expects(:download_fact_plugins) @agent.prepare({}) end it "should download plugins" do @agent.expects(:download_plugins) @agent.prepare({}) end it "should perform the pre-run commands" do @agent.expects(:execute_prerun_command) @agent.prepare({}) end end diff --git a/spec/unit/daemon_spec.rb b/spec/unit/daemon_spec.rb index 7b01f831b..ed8dec2a3 100755 --- a/spec/unit/daemon_spec.rb +++ b/spec/unit/daemon_spec.rb @@ -1,296 +1,295 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/daemon' def without_warnings flag = $VERBOSE $VERBOSE = nil yield $VERBOSE = flag end describe Puppet::Daemon do before do @daemon = Puppet::Daemon.new end it "should be able to manage an agent" do @daemon.should respond_to(:agent) end it "should be able to manage a network server" do @daemon.should respond_to(:server) end it "should reopen the Log logs when told to reopen logs" do Puppet::Util::Log.expects(:reopen) @daemon.reopen_logs end describe "when setting signal traps" do {:INT => :stop, :TERM => :stop, :HUP => :restart, :USR1 => :reload, :USR2 => :reopen_logs}.each do |signal, method| it "should log and call #{method} when it receives #{signal}" do Signal.expects(:trap).with(signal).yields Puppet.expects(:notice) @daemon.expects(method) @daemon.set_signal_traps end end end describe "when starting" do before do @daemon.stubs(:create_pidfile) @daemon.stubs(:set_signal_traps) EventLoop.current.stubs(:run) end it "should fail if it has neither agent nor server" do lambda { @daemon.start }.should raise_error(Puppet::DevError) end it "should create its pidfile" do @daemon.stubs(:agent).returns stub('agent', :start => nil) @daemon.expects(:create_pidfile) @daemon.start end it "should start the agent if the agent is configured" do agent = mock 'agent' agent.expects(:start) @daemon.stubs(:agent).returns agent @daemon.start end it "should start its server if one is configured" do server = mock 'server' server.expects(:start) @daemon.stubs(:server).returns server @daemon.start end it "should let the current EventLoop run" do @daemon.stubs(:agent).returns stub('agent', :start => nil) EventLoop.current.expects(:run) @daemon.start end end describe "when stopping" do before do @daemon.stubs(:remove_pidfile) @daemon.stubs(:exit) Puppet::Util::Log.stubs(:close_all) # to make the global safe to mock, set it to a subclass of itself, # then restore it in an after pass without_warnings { Puppet::Application = Class.new(Puppet::Application) } end after do # restore from the superclass so we lose the stub garbage without_warnings { Puppet::Application = Puppet::Application.superclass } end it "should stop its server if one is configured" do server = mock 'server' server.expects(:stop) @daemon.stubs(:server).returns server @daemon.stop end it 'should request a stop from Puppet::Application' do Puppet::Application.expects(:stop!) @daemon.stop end it "should remove its pidfile" do @daemon.expects(:remove_pidfile) @daemon.stop end it "should close all logs" do Puppet::Util::Log.expects(:close_all) @daemon.stop end it "should exit unless called with ':exit => false'" do @daemon.expects(:exit) @daemon.stop end it "should not exit if called with ':exit => false'" do @daemon.expects(:exit).never @daemon.stop :exit => false end end describe "when creating its pidfile" do it "should use an exclusive mutex" do Puppet.settings.expects(:value).with(:name).returns "me" Puppet::Util.expects(:synchronize_on).with("me",Sync::EX) @daemon.create_pidfile end it "should lock the pidfile using the Pidlock class" do pidfile = mock 'pidfile' Puppet.settings.stubs(:value).with(:name).returns "eh" Puppet.settings.expects(:value).with(:pidfile).returns "/my/file" Puppet::Util::Pidlock.expects(:new).with("/my/file").returns pidfile pidfile.expects(:lock).returns true @daemon.create_pidfile end it "should fail if it cannot lock" do pidfile = mock 'pidfile' Puppet.settings.stubs(:value).with(:name).returns "eh" Puppet.settings.stubs(:value).with(:pidfile).returns "/my/file" Puppet::Util::Pidlock.expects(:new).with("/my/file").returns pidfile pidfile.expects(:lock).returns false lambda { @daemon.create_pidfile }.should raise_error end end describe "when removing its pidfile" do it "should use an exclusive mutex" do Puppet.settings.expects(:value).with(:name).returns "me" Puppet::Util.expects(:synchronize_on).with("me",Sync::EX) @daemon.remove_pidfile end it "should do nothing if the pidfile is not present" do pidfile = mock 'pidfile', :locked? => false Puppet::Util::Pidlock.expects(:new).with("/my/file").returns pidfile Puppet.settings.stubs(:value).with(:name).returns "eh" Puppet.settings.stubs(:value).with(:pidfile).returns "/my/file" pidfile.expects(:unlock).never @daemon.remove_pidfile end it "should unlock the pidfile using the Pidlock class" do pidfile = mock 'pidfile', :locked? => true Puppet::Util::Pidlock.expects(:new).with("/my/file").returns pidfile pidfile.expects(:unlock).returns true Puppet.settings.stubs(:value).with(:name).returns "eh" Puppet.settings.stubs(:value).with(:pidfile).returns "/my/file" @daemon.remove_pidfile end it "should warn if it cannot remove the pidfile" do pidfile = mock 'pidfile', :locked? => true Puppet::Util::Pidlock.expects(:new).with("/my/file").returns pidfile pidfile.expects(:unlock).returns false Puppet.settings.stubs(:value).with(:name).returns "eh" Puppet.settings.stubs(:value).with(:pidfile).returns "/my/file" Puppet.expects :err @daemon.remove_pidfile end end describe "when reloading" do it "should do nothing if no agent is configured" do @daemon.reload end it "should do nothing if the agent is running" do agent = mock 'agent' agent.expects(:running?).returns true @daemon.stubs(:agent).returns agent @daemon.reload end it "should run the agent if one is available and it is not running" do agent = mock 'agent' agent.expects(:running?).returns false agent.expects :run @daemon.stubs(:agent).returns agent @daemon.reload end end describe "when restarting" do before do without_warnings { Puppet::Application = Class.new(Puppet::Application) } end after do without_warnings { Puppet::Application = Puppet::Application.superclass } end it 'should set Puppet::Application.restart!' do Puppet::Application.expects(:restart!) @daemon.stubs(:reexec) @daemon.restart end it "should reexec itself if no agent is available" do @daemon.expects(:reexec) @daemon.restart end it "should reexec itself if the agent is not running" do agent = mock 'agent' agent.expects(:running?).returns false @daemon.stubs(:agent).returns agent @daemon.expects(:reexec) @daemon.restart end end describe "when reexecing it self" do before do @daemon.stubs(:exec) @daemon.stubs(:stop) end it "should fail if no argv values are available" do @daemon.expects(:argv).returns nil lambda { @daemon.reexec }.should raise_error(Puppet::DevError) end it "should shut down without exiting" do @daemon.argv = %w{foo} @daemon.expects(:stop).with(:exit => false) @daemon.reexec end it "should call 'exec' with the original executable and arguments" do @daemon.argv = %w{foo} @daemon.expects(:exec).with($0 + " foo") @daemon.reexec end end end diff --git a/spec/unit/dsl/resource_api_spec.rb b/spec/unit/dsl/resource_api_spec.rb index 30273affe..559a43333 100755 --- a/spec/unit/dsl/resource_api_spec.rb +++ b/spec/unit/dsl/resource_api_spec.rb @@ -1,181 +1,180 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/dsl/resource_api' describe Puppet::DSL::ResourceAPI do before do @compiler = Puppet::Parser::Compiler.new(Puppet::Node.new("foo")) @scope = Puppet::Parser::Scope.new(:compiler => @compiler, :source => "foo") @resource = Puppet::Parser::Resource.new(:mytype, "myresource", :scope => @scope) @api = Puppet::DSL::ResourceAPI.new(@resource, @scope, proc { }) end it "should include the resource type collection helper" do Puppet::DSL::ResourceAPI.ancestors.should be_include(Puppet::Resource::TypeCollectionHelper) end it "should use the scope's environment as its environment" do @scope.expects(:environment).returns "myenv" @api.environment.should == "myenv" end it "should be able to set all of its parameters as instance variables" do @resource["foo"] = "myval" @api.set_instance_variables @api.instance_variable_get("@foo").should == "myval" end describe "when calling a function" do it "should return false if the function does not exist" do Puppet::Parser::Functions.expects(:function).with("myfunc").returns nil @api.call_function("myfunc", "foo").should be_false end it "should use the scope the call the provided function with the provided arguments and return the results" do scope = stub 'scope' @api.stubs(:scope).returns scope Puppet::Parser::Functions.expects(:function).with("myfunc").returns "myfunc_method" scope.expects(:myfunc_method).with("one", "two") @api.call_function("myfunc", ["one", "two"]) end it "should call 'include' when asked to call 'acquire'" do scope = stub 'scope' @api.stubs(:scope).returns scope @api.stubs(:valid_type?).returns false scope.expects(:function_include).with("one", "two") @api.acquire("one", "two") end end describe "when determining if a provided name is a valid type" do it "should be valid if it's :class" do @api.should be_valid_type(:class) end it "should be valid if it's :node" do @api.should be_valid_type(:node) end it "should be valid if it's a builtin type" do Puppet::Type.expects(:type).with(:mytype).returns "whatever" @api.should be_valid_type(:mytype) end it "should be valid if it's a defined resource type in the environment's known resource types" do collection = stub 'collection' @api.stubs(:known_resource_types).returns collection collection.expects(:definition).with(:mytype).returns "whatever" @api.should be_valid_type(:mytype) end it "should not be valid unless it's a node, class, builtin type, or defined resource" do collection = stub 'collection' @api.stubs(:known_resource_types).returns collection collection.expects(:definition).returns nil Puppet::Type.expects(:type).returns nil @api.should_not be_valid_type(:mytype) end end describe "when creating a resource" do before do @api.scope.stubs(:source).returns stub("source") @api.scope.compiler.stubs(:add_resource) @created_resource = Puppet::Parser::Resource.new("yay", "eh", :scope => @api.scope) end it "should create and return a resource of the type specified" do Puppet::Parser::Resource.expects(:new).with { |type, title, args| type == "mytype" }.returns @created_resource @api.create_resource("mytype", "myname", {:foo => "bar"}).should == [@created_resource] end it "should use the name from the first element of the provided argument array" do Puppet::Parser::Resource.expects(:new).with { |type, title, args| title == "myname" }.returns @created_resource @api.create_resource("mytype", "myname", {:foo => "bar"}) end it "should create multiple resources if the first element of the argument array is an array" do second_resource = Puppet::Parser::Resource.new('yay', "eh", :scope => @api.scope) Puppet::Parser::Resource.expects(:new).with { |type, title, args| title == "first" }.returns @created_resource Puppet::Parser::Resource.expects(:new).with { |type, title, args| title == "second" }.returns @created_resource @api.create_resource("mytype", ["first", "second"], {:foo => "bar"}) end it "should provide its scope as the scope" do Puppet::Parser::Resource.expects(:new).with { |type, title, args| args[:scope] == @api.scope }.returns @created_resource @api.create_resource("mytype", "myname", {:foo => "bar"}) end it "should set each provided argument as a parameter on the created resource" do result = @api.create_resource("mytype", "myname", {"foo" => "bar", "biz" => "baz"}).shift result["foo"].should == "bar" result["biz"].should == "baz" end it "should add the resource to the scope's copmiler" do Puppet::Parser::Resource.expects(:new).returns @created_resource @api.scope.compiler.expects(:add_resource).with(@api.scope, @created_resource) @api.create_resource("mytype", "myname", {:foo => "bar"}) end it "should fail if the resource parameters are not a hash" do lambda { @api.create_resource("mytype", "myname", %w{foo bar}) }.should raise_error(ArgumentError) end end describe "when an unknown method is called" do it "should create a resource if the method name is a valid type" do @api.expects(:valid_type?).with(:mytype).returns true @api.expects(:create_resource).with(:mytype, "myname", {:foo => "bar"}).returns true @api.mytype("myname", :foo => "bar") end it "should call any function whose name matches the undefined method if the name is not a valid type" do @api.expects(:valid_type?).with(:myfunc).returns false @api.expects(:create_resource).never Puppet::Parser::Functions.expects(:function).with(:myfunc).returns true @api.expects(:call_function).with(:myfunc, %w{foo bar}) @api.myfunc("foo", "bar") end it "should raise a method missing error if the method is neither a type nor a function" do @api.expects(:valid_type?).with(:myfunc).returns false @api.expects(:create_resource).never Puppet::Parser::Functions.expects(:function).with(:myfunc).returns false @api.expects(:call_function).never lambda { @api.myfunc("foo", "bar") }.should raise_error(NoMethodError) end end it "should mark the specified resource as exported when creating a single exported resource" do resources = @api.export @api.file("/my/file", :ensure => :present) resources[0].should be_exported end it "should mark all created resources as exported when creating exported resources using a block" do @compiler.expects(:add_resource).with { |s, res| res.exported == true } @api.export { file "/my/file", :ensure => :present } end it "should mark the specified resource as virtual when creating a single virtual resource" do resources = @api.virtual @api.file("/my/file", :ensure => :present) resources[0].should be_virtual end it "should mark all created resources as virtual when creating virtual resources using a block" do @compiler.expects(:add_resource).with { |s, res| res.virtual == true } @api.virtual { file "/my/file", :ensure => :present } end end diff --git a/spec/unit/dsl/resource_type_api_spec.rb b/spec/unit/dsl/resource_type_api_spec.rb index c8f6cca52..ea81f7da4 100755 --- a/spec/unit/dsl/resource_type_api_spec.rb +++ b/spec/unit/dsl/resource_type_api_spec.rb @@ -1,54 +1,53 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/dsl/resource_type_api' describe Puppet::DSL::ResourceTypeAPI do # Verify that the block creates a single AST node through the API, # instantiate that AST node into a types, and return that type. def test_api_call(&block) main_object = Puppet::DSL::ResourceTypeAPI.new main_object.instance_eval(&block) created_ast_objects = main_object.instance_eval { @__created_ast_objects__ } created_ast_objects.length.should == 1 new_types = created_ast_objects[0].instantiate('') new_types.length.should == 1 new_types[0] ensure Thread.current[:ruby_file_parse_result] = nil end [:definition, :node, :hostclass].each do |type| method = type == :definition ? "define" : type it "should be able to create a #{type}" do newtype = test_api_call { send(method, "myname").should == nil } newtype.should be_a(Puppet::Resource::Type) newtype.type.should == type end it "should use the provided name when creating a #{type}" do newtype = test_api_call { send(method, "myname") } newtype.name.should == "myname" end unless type == :definition it "should pass in any provided options when creating a #{type}" do newtype = test_api_call { send(method, "myname", :line => 200) } newtype.line.should == 200 end end it "should set any provided block as the type's ruby code" do newtype = test_api_call { send(method, "myname") { 'method_result' } } newtype.ruby_code.call.should == 'method_result' end end describe "when creating a definition" do it "should use the provided options to define valid arguments for the resource type" do newtype = test_api_call { define("myname", :arg1, :arg2) } newtype.arguments.should == { 'arg1' => nil, 'arg2' => nil } end end end diff --git a/spec/unit/face/catalog_spec.rb b/spec/unit/face/catalog_spec.rb new file mode 100755 index 000000000..28c2aa9be --- /dev/null +++ b/spec/unit/face/catalog_spec.rb @@ -0,0 +1,4 @@ +require 'puppet/face' +describe Puppet::Face[:catalog, '0.0.1'] do + it "should actually have some testing..." +end diff --git a/spec/unit/face/certificate_request_spec.rb b/spec/unit/face/certificate_request_spec.rb new file mode 100755 index 000000000..a83a92df8 --- /dev/null +++ b/spec/unit/face/certificate_request_spec.rb @@ -0,0 +1,3 @@ +describe Puppet::Face[:certificate_request, '0.0.1'] do + it "should actually have some tests..." +end diff --git a/spec/unit/face/certificate_revocation_list_spec.rb b/spec/unit/face/certificate_revocation_list_spec.rb new file mode 100755 index 000000000..22c0fa2bf --- /dev/null +++ b/spec/unit/face/certificate_revocation_list_spec.rb @@ -0,0 +1,3 @@ +describe Puppet::Face[:certificate_revocation_list, '0.0.1'] do + it "should actually have some tests..." +end diff --git a/spec/unit/faces/certificate_spec.rb b/spec/unit/face/certificate_spec.rb similarity index 74% rename from spec/unit/faces/certificate_spec.rb rename to spec/unit/face/certificate_spec.rb index ba264f967..dbcc888ad 100755 --- a/spec/unit/faces/certificate_spec.rb +++ b/spec/unit/face/certificate_spec.rb @@ -1,14 +1,14 @@ require 'puppet/ssl/host' -describe Puppet::Faces[:certificate, '0.0.1'] do +describe Puppet::Face[:certificate, '0.0.1'] do it "should have a ca-location option" do subject.should be_option :ca_location end it "should set the ca location when invoked" do - pending "#6983: This is broken in the actual faces..." + pending "#6983: This is broken in the actual face..." Puppet::SSL::Host.expects(:ca_location=).with(:foo) Puppet::SSL::Host.indirection.expects(:save) subject.sign :ca_location => :foo end end diff --git a/spec/unit/faces/config_spec.rb b/spec/unit/face/config_spec.rb similarity index 91% rename from spec/unit/faces/config_spec.rb rename to spec/unit/face/config_spec.rb index b71995e9f..6004d700f 100755 --- a/spec/unit/faces/config_spec.rb +++ b/spec/unit/face/config_spec.rb @@ -1,24 +1,23 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' -describe Puppet::Faces[:config, '0.0.1'] do +describe Puppet::Face[:config, '0.0.1'] do it "should use Settings#print_config_options when asked to print" do Puppet.settings.stubs(:puts) Puppet.settings.expects(:print_config_options) subject.print end it "should set 'configprint' to all desired values and call print_config_options when a specific value is provided" do Puppet.settings.stubs(:puts) Puppet.settings.expects(:print_config_options) subject.print("libdir", "ssldir") Puppet.settings[:configprint].should == "libdir,ssldir" end it "should always return nil" do Puppet.settings.stubs(:puts) Puppet.settings.expects(:print_config_options) subject.print("libdir").should be_nil end end diff --git a/spec/unit/faces/configurer_spec.rb b/spec/unit/face/configurer_spec.rb similarity index 91% rename from spec/unit/faces/configurer_spec.rb rename to spec/unit/face/configurer_spec.rb index 6982c00ae..56b45031f 100755 --- a/spec/unit/faces/configurer_spec.rb +++ b/spec/unit/face/configurer_spec.rb @@ -1,26 +1,25 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/indirector/catalog/rest' require 'tempfile' -describe Puppet::Faces[:configurer, '0.0.1'] do +describe Puppet::Face[:configurer, '0.0.1'] do describe "#synchronize" do it "should retrieve and apply a catalog and return a report" do pending "REVISIT: 2.7 changes broke this, and we want the merge published" dirname = Dir.mktmpdir("puppetdir") Puppet[:vardir] = dirname Puppet[:confdir] = dirname @catalog = Puppet::Resource::Catalog.new @file = Puppet::Resource.new(:file, File.join(dirname, "tmp_dir_resource"), :parameters => {:ensure => :present}) @catalog.add_resource(@file) Puppet::Resource::Catalog::Rest.any_instance.stubs(:find).returns(@catalog) report = subject.synchronize("foo") report.kind.should == "apply" report.status.should == "changed" end end end diff --git a/spec/unit/faces/facts_spec.rb b/spec/unit/face/facts_spec.rb similarity index 85% rename from spec/unit/faces/facts_spec.rb rename to spec/unit/face/facts_spec.rb index 46496a839..e6411f836 100755 --- a/spec/unit/faces/facts_spec.rb +++ b/spec/unit/face/facts_spec.rb @@ -1,21 +1,20 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' -describe Puppet::Faces[:facts, '0.0.1'] do +describe Puppet::Face[:facts, '0.0.1'] do it "should define an 'upload' fact" do subject.should be_action(:upload) end it "should set its default format to :yaml" do subject.default_format.should == :yaml end describe "when uploading" do it "should set the terminus_class to :facter" it "should set the cach_eclass to :rest" it "should find the current certname" end end diff --git a/spec/unit/faces/file_spec.rb b/spec/unit/face/file_spec.rb similarity index 52% rename from spec/unit/faces/file_spec.rb rename to spec/unit/face/file_spec.rb index fcb52c67e..97e8bcc08 100755 --- a/spec/unit/faces/file_spec.rb +++ b/spec/unit/face/file_spec.rb @@ -1,3 +1,3 @@ -describe Puppet::Faces[:file, '0.0.1'] do +describe Puppet::Face[:file, '0.0.1'] do it "should actually have some tests..." end diff --git a/spec/unit/faces/help_spec.rb b/spec/unit/face/help_spec.rb old mode 100644 new mode 100755 similarity index 81% rename from spec/unit/faces/help_spec.rb rename to spec/unit/face/help_spec.rb index cd74a5bf1..e67f29e07 --- a/spec/unit/faces/help_spec.rb +++ b/spec/unit/face/help_spec.rb @@ -1,112 +1,112 @@ require 'spec_helper' -require 'puppet/faces/help' +require 'puppet/face/help' -describe Puppet::Faces[:help, '0.0.1'] do +describe Puppet::Face[:help, '0.0.1'] do it "should have a help action" do subject.should be_action :help end it "should have a default action of help" do pending "REVISIT: we don't support default actions yet" end it "should accept a call with no arguments" do expect { subject.help() }.should_not raise_error end it "should accept a face name" do expect { subject.help(:help) }.should_not raise_error end it "should accept a face and action name" do expect { subject.help(:help, :help) }.should_not raise_error end it "should fail if more than a face and action are given" do expect { subject.help(:help, :help, :for_the_love_of_god) }. should raise_error ArgumentError end it "should treat :current and 'current' identically" do subject.help(:help, :version => :current).should == subject.help(:help, :version => 'current') end it "should complain when the request version of a face is missing" do expect { subject.help(:huzzah, :bar, :version => '17.0.0') }. should raise_error Puppet::Error end it "should find a face by version" do - face = Puppet::Faces[:huzzah, :current] + face = Puppet::Face[:huzzah, :current] subject.help(:huzzah, :version => face.version). should == subject.help(:huzzah, :version => :current) end context "when listing subcommands" do - subject { Puppet::Faces[:help, :current].help } + subject { Puppet::Face[:help, :current].help } # Check a precondition for the next block; if this fails you have - # something odd in your set of faces, and we skip testing things that + # something odd in your set of face, and we skip testing things that # matter. --daniel 2011-04-10 it "should have at least one face with a summary" do - Puppet::Faces.faces.should be_any do |name| - Puppet::Faces[name, :current].summary + Puppet::Face.faces.should be_any do |name| + Puppet::Face[name, :current].summary end end - Puppet::Faces.faces.each do |name| - face = Puppet::Faces[name, :current] + Puppet::Face.faces.each do |name| + face = Puppet::Face[name, :current] summary = face.summary it { should =~ %r{ #{name} } } it { should =~ %r{ #{name} +#{summary}} } if summary end - Puppet::Faces[:help, :current].legacy_applications.each do |appname| + Puppet::Face[:help, :current].legacy_applications.each do |appname| it { should =~ %r{ #{appname} } } - summary = Puppet::Faces[:help, :current].horribly_extract_summary_from(appname) + summary = Puppet::Face[:help, :current].horribly_extract_summary_from(appname) summary and it { should =~ %r{ #{summary}\b} } end end context "#legacy_applications" do - subject { Puppet::Faces[:help, :current].legacy_applications } + subject { Puppet::Face[:help, :current].legacy_applications } # If we don't, these tests are ... less than useful, because they assume # it. When this breaks you should consider ditching the entire feature # and tests, but if not work out how to fake one. --daniel 2011-04-11 it { should have_at_least(1).item } # Meh. This is nasty, but we can't control the other list; the specific # bug that caused these to be listed is annoyingly subtle and has a nasty # fix, so better to have a "fail if you do something daft" trigger in # place here, I think. --daniel 2011-04-11 - %w{faces_base indirection_base}.each do |name| + %w{face_base indirection_base}.each do |name| it { should_not include name } end end context "help for legacy applications" do - subject { Puppet::Faces[:help, :current] } + subject { Puppet::Face[:help, :current] } let :appname do subject.legacy_applications.first end # This test is purposely generic, so that as we eliminate legacy commands # we don't get into a loop where we either test a face-based replacement # and fail to notice breakage, or where we have to constantly rewrite this # test and all. --daniel 2011-04-11 it "should return the legacy help when given the subcommand" do help = subject.help(appname) help.should =~ /puppet-#{appname}/ %w{SYNOPSIS USAGE DESCRIPTION OPTIONS COPYRIGHT}.each do |heading| help.should =~ /^#{heading}$/ end end it "should fail when asked for an action on a legacy command" do expect { subject.help(appname, :whatever) }. to raise_error ArgumentError, /Legacy subcommands don't take actions/ end end end diff --git a/spec/unit/faces/indirector_spec.rb b/spec/unit/face/indirector_spec.rb similarity index 71% rename from spec/unit/faces/indirector_spec.rb rename to spec/unit/face/indirector_spec.rb index c1aed9617..bb06fcfe2 100755 --- a/spec/unit/faces/indirector_spec.rb +++ b/spec/unit/face/indirector_spec.rb @@ -1,60 +1,59 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' -require 'puppet/faces/indirector' +require 'puppet/face/indirector' -describe Puppet::Faces::Indirector do +describe Puppet::Face::Indirector do subject do - instance = Puppet::Faces::Indirector.new(:test, '0.0.1') + instance = Puppet::Face::Indirector.new(:test, '0.0.1') indirection = stub('indirection', :name => :stub_indirection, :reset_terminus_class => nil) instance.stubs(:indirection).returns indirection instance end it "should be able to return a list of indirections" do - Puppet::Faces::Indirector.indirections.should be_include("catalog") + Puppet::Face::Indirector.indirections.should be_include("catalog") end it "should be able to return a list of terminuses for a given indirection" do - Puppet::Faces::Indirector.terminus_classes(:catalog).should be_include("compiler") + Puppet::Face::Indirector.terminus_classes(:catalog).should be_include("compiler") end describe "as an instance" do it "should be able to determine its indirection" do # Loading actions here an get, um, complicated - Puppet::Faces.stubs(:load_actions) - Puppet::Faces::Indirector.new(:catalog, '0.0.1').indirection.should equal(Puppet::Resource::Catalog.indirection) + Puppet::Face.stubs(:load_actions) + Puppet::Face::Indirector.new(:catalog, '0.0.1').indirection.should equal(Puppet::Resource::Catalog.indirection) end end [:find, :search, :save, :destroy].each do |method| it "should define a '#{method}' action" do - Puppet::Faces::Indirector.should be_action(method) + Puppet::Face::Indirector.should be_action(method) end it "should call the indirection method with options when the '#{method}' action is invoked" do subject.indirection.expects(method).with(:test, "myargs", {}) subject.send(method, :test, "myargs") end it "should forward passed options" do subject.indirection.expects(method).with(:test, "action", {'one'=>'1'}) subject.send(method, :test, 'action', {'one'=>'1'}) end end it "should be able to override its indirection name" do subject.set_indirection_name :foo subject.indirection_name.should == :foo end it "should be able to set its terminus class" do subject.indirection.expects(:terminus_class=).with(:myterm) subject.set_terminus(:myterm) end it "should define a class-level 'info' action" do - Puppet::Faces::Indirector.should be_action(:info) + Puppet::Face::Indirector.should be_action(:info) end end diff --git a/spec/unit/faces/key_spec.rb b/spec/unit/face/key_spec.rb similarity index 52% rename from spec/unit/faces/key_spec.rb rename to spec/unit/face/key_spec.rb index 9b7a58706..10d664790 100755 --- a/spec/unit/faces/key_spec.rb +++ b/spec/unit/face/key_spec.rb @@ -1,3 +1,3 @@ -describe Puppet::Faces[:key, '0.0.1'] do +describe Puppet::Face[:key, '0.0.1'] do it "should actually have some tests..." end diff --git a/spec/unit/faces/node_spec.rb b/spec/unit/face/node_spec.rb similarity index 66% rename from spec/unit/faces/node_spec.rb rename to spec/unit/face/node_spec.rb index c6ed71f59..90d258db9 100755 --- a/spec/unit/faces/node_spec.rb +++ b/spec/unit/face/node_spec.rb @@ -1,9 +1,8 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' -describe Puppet::Faces[:node, '0.0.1'] do +describe Puppet::Face[:node, '0.0.1'] do it "should set its default format to :yaml" do subject.default_format.should == :yaml end end diff --git a/spec/unit/faces/report_spec.rb b/spec/unit/face/report_spec.rb similarity index 51% rename from spec/unit/faces/report_spec.rb rename to spec/unit/face/report_spec.rb index 30897d5e7..b1b28167e 100755 --- a/spec/unit/faces/report_spec.rb +++ b/spec/unit/face/report_spec.rb @@ -1,3 +1,3 @@ -describe Puppet::Faces[:report, '0.0.1'] do +describe Puppet::Face[:report, '0.0.1'] do it "should actually have some tests..." end diff --git a/spec/unit/faces/resource_spec.rb b/spec/unit/face/resource_spec.rb similarity index 50% rename from spec/unit/faces/resource_spec.rb rename to spec/unit/face/resource_spec.rb index e3f2e1c62..084e2a6a9 100755 --- a/spec/unit/faces/resource_spec.rb +++ b/spec/unit/face/resource_spec.rb @@ -1,3 +1,3 @@ -describe Puppet::Faces[:resource, '0.0.1'] do +describe Puppet::Face[:resource, '0.0.1'] do it "should actually have some tests..." end diff --git a/spec/unit/face/resource_type_spec.rb b/spec/unit/face/resource_type_spec.rb new file mode 100755 index 000000000..2adaedca1 --- /dev/null +++ b/spec/unit/face/resource_type_spec.rb @@ -0,0 +1,3 @@ +describe Puppet::Face[:resource_type, '0.0.1'] do + it "should actually have some tests..." +end diff --git a/spec/unit/faces_spec.rb b/spec/unit/face_spec.rb old mode 100644 new mode 100755 similarity index 100% rename from spec/unit/faces_spec.rb rename to spec/unit/face_spec.rb diff --git a/spec/unit/faces/catalog_spec.rb b/spec/unit/faces/catalog_spec.rb deleted file mode 100755 index e0a771d10..000000000 --- a/spec/unit/faces/catalog_spec.rb +++ /dev/null @@ -1,4 +0,0 @@ -require 'puppet/faces' -describe Puppet::Faces[:catalog, '0.0.1'] do - it "should actually have some testing..." -end diff --git a/spec/unit/faces/certificate_request_spec.rb b/spec/unit/faces/certificate_request_spec.rb deleted file mode 100755 index 1a71a8379..000000000 --- a/spec/unit/faces/certificate_request_spec.rb +++ /dev/null @@ -1,3 +0,0 @@ -describe Puppet::Faces[:certificate_request, '0.0.1'] do - it "should actually have some tests..." -end diff --git a/spec/unit/faces/certificate_revocation_list_spec.rb b/spec/unit/faces/certificate_revocation_list_spec.rb deleted file mode 100755 index 4f41edef6..000000000 --- a/spec/unit/faces/certificate_revocation_list_spec.rb +++ /dev/null @@ -1,3 +0,0 @@ -describe Puppet::Faces[:certificate_revocation_list, '0.0.1'] do - it "should actually have some tests..." -end diff --git a/spec/unit/faces/resource_type_spec.rb b/spec/unit/faces/resource_type_spec.rb deleted file mode 100755 index fcbf07520..000000000 --- a/spec/unit/faces/resource_type_spec.rb +++ /dev/null @@ -1,3 +0,0 @@ -describe Puppet::Faces[:resource_type, '0.0.1'] do - it "should actually have some tests..." -end diff --git a/spec/unit/file_bucket/dipper_spec.rb b/spec/unit/file_bucket/dipper_spec.rb index e218e8616..910b2808d 100755 --- a/spec/unit/file_bucket/dipper_spec.rb +++ b/spec/unit/file_bucket/dipper_spec.rb @@ -1,114 +1,113 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'pathname' require 'puppet/file_bucket/dipper' require 'puppet/indirector/file_bucket_file/rest' describe Puppet::FileBucket::Dipper do include PuppetSpec::Files def make_tmp_file(contents) file = tmpfile("file_bucket_file") File.open(file, 'w') { |f| f.write(contents) } file end it "should fail in an informative way when there are failures checking for the file on the server" do @dipper = Puppet::FileBucket::Dipper.new(:Path => "/my/bucket") file = make_tmp_file('contents') Puppet::FileBucket::File.indirection.expects(:head).raises ArgumentError lambda { @dipper.backup(file) }.should raise_error(Puppet::Error) end it "should fail in an informative way when there are failures backing up to the server" do @dipper = Puppet::FileBucket::Dipper.new(:Path => "/my/bucket") file = make_tmp_file('contents') Puppet::FileBucket::File.indirection.expects(:head).returns false Puppet::FileBucket::File.indirection.expects(:save).raises ArgumentError lambda { @dipper.backup(file) }.should raise_error(Puppet::Error) end it "should backup files to a local bucket" do Puppet[:bucketdir] = "/non/existent/directory" file_bucket = tmpdir("bucket") @dipper = Puppet::FileBucket::Dipper.new(:Path => file_bucket) file = make_tmp_file('my contents') checksum = "2975f560750e71c478b8e3b39a956adb" Digest::MD5.hexdigest('my contents').should == checksum @dipper.backup(file).should == checksum File.exists?("#{file_bucket}/2/9/7/5/f/5/6/0/2975f560750e71c478b8e3b39a956adb/contents").should == true end it "should not backup a file that is already in the bucket" do @dipper = Puppet::FileBucket::Dipper.new(:Path => "/my/bucket") file = make_tmp_file('my contents') checksum = Digest::MD5.hexdigest('my contents') Puppet::FileBucket::File.indirection.expects(:head).returns true Puppet::FileBucket::File.indirection.expects(:save).never @dipper.backup(file).should == checksum end it "should retrieve files from a local bucket" do @dipper = Puppet::FileBucket::Dipper.new(:Path => "/my/bucket") checksum = Digest::MD5.hexdigest('my contents') request = nil Puppet::FileBucketFile::File.any_instance.expects(:find).with{ |r| request = r }.once.returns(Puppet::FileBucket::File.new('my contents')) @dipper.getfile(checksum).should == 'my contents' request.key.should == "md5/#{checksum}" end it "should backup files to a remote server" do @dipper = Puppet::FileBucket::Dipper.new(:Server => "puppetmaster", :Port => "31337") file = make_tmp_file('my contents') checksum = Digest::MD5.hexdigest('my contents') real_path = Pathname.new(file).realpath request1 = nil request2 = nil Puppet::FileBucketFile::Rest.any_instance.expects(:head).with { |r| request1 = r }.once.returns(nil) Puppet::FileBucketFile::Rest.any_instance.expects(:save).with { |r| request2 = r }.once @dipper.backup(file).should == checksum [request1, request2].each do |r| r.server.should == 'puppetmaster' r.port.should == 31337 r.key.should == "md5/#{checksum}#{real_path}" end end it "should retrieve files from a remote server" do @dipper = Puppet::FileBucket::Dipper.new(:Server => "puppetmaster", :Port => "31337") checksum = Digest::MD5.hexdigest('my contents') request = nil Puppet::FileBucketFile::Rest.any_instance.expects(:find).with { |r| request = r }.returns(Puppet::FileBucket::File.new('my contents')) @dipper.getfile(checksum).should == "my contents" request.server.should == 'puppetmaster' request.port.should == 31337 request.key.should == "md5/#{checksum}" end end diff --git a/spec/unit/file_bucket/file_spec.rb b/spec/unit/file_bucket/file_spec.rb index d7dfb8d70..c4444ae77 100755 --- a/spec/unit/file_bucket/file_spec.rb +++ b/spec/unit/file_bucket/file_spec.rb @@ -1,107 +1,106 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/file_bucket/file' require 'digest/md5' require 'digest/sha1' describe Puppet::FileBucket::File do include PuppetSpec::Files before do # this is the default from spec_helper, but it keeps getting reset at odd times @bucketdir = tmpdir('bucket') Puppet[:bucketdir] = @bucketdir @digest = "4a8ec4fa5f01b4ab1a0ab8cbccb709f0" @checksum = "{md5}4a8ec4fa5f01b4ab1a0ab8cbccb709f0" @dir = File.join(@bucketdir, '4/a/8/e/c/4/f/a/4a8ec4fa5f01b4ab1a0ab8cbccb709f0') @contents = "file contents" end it "should have a to_s method to return the contents" do Puppet::FileBucket::File.new(@contents).to_s.should == @contents end it "should raise an error if changing content" do x = Puppet::FileBucket::File.new("first") proc { x.contents = "new" }.should raise_error end it "should require contents to be a string" do proc { Puppet::FileBucket::File.new(5) }.should raise_error(ArgumentError) end it "should set the contents appropriately" do Puppet::FileBucket::File.new(@contents).contents.should == @contents end it "should default to 'md5' as the checksum algorithm if the algorithm is not in the name" do Puppet::FileBucket::File.new(@contents).checksum_type.should == "md5" end it "should calculate the checksum" do Puppet::FileBucket::File.new(@contents).checksum.should == @checksum end describe "when using back-ends" do it "should redirect using Puppet::Indirector" do Puppet::Indirector::Indirection.instance(:file_bucket_file).model.should equal(Puppet::FileBucket::File) end it "should have a :save instance method" do Puppet::FileBucket::File.indirection.should respond_to(:save) end end it "should return a url-ish name" do Puppet::FileBucket::File.new(@contents).name.should == "md5/4a8ec4fa5f01b4ab1a0ab8cbccb709f0" end it "should reject a url-ish name with an invalid checksum" do bucket = Puppet::FileBucket::File.new(@contents) lambda { bucket.name = "sha1/4a8ec4fa5f01b4ab1a0ab8cbccb709f0/new/path" }.should raise_error end it "should convert the contents to PSON" do Puppet::FileBucket::File.new(@contents).to_pson.should == '{"contents":"file contents"}' end it "should load from PSON" do Puppet::FileBucket::File.from_pson({"contents"=>"file contents"}).contents.should == "file contents" end def make_bucketed_file FileUtils.mkdir_p(@dir) File.open("#{@dir}/contents", 'w') { |f| f.write @contents } end describe "using the indirector's find method" do it "should return nil if a file doesn't exist" do bucketfile = Puppet::FileBucket::File.indirection.find("md5/#{@digest}") bucketfile.should == nil end it "should find a filebucket if the file exists" do make_bucketed_file bucketfile = Puppet::FileBucket::File.indirection.find("md5/#{@digest}") bucketfile.should_not == nil end describe "using RESTish digest notation" do it "should return nil if a file doesn't exist" do bucketfile = Puppet::FileBucket::File.indirection.find("md5/#{@digest}") bucketfile.should == nil end it "should find a filebucket if the file exists" do make_bucketed_file bucketfile = Puppet::FileBucket::File.indirection.find("md5/#{@digest}") bucketfile.should_not == nil end end end end diff --git a/spec/unit/file_collection/lookup_spec.rb b/spec/unit/file_collection/lookup_spec.rb index 2ab6b56c0..2b0f8bfab 100755 --- a/spec/unit/file_collection/lookup_spec.rb +++ b/spec/unit/file_collection/lookup_spec.rb @@ -1,46 +1,45 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/file_collection/lookup' class LookupTester include Puppet::FileCollection::Lookup end describe Puppet::FileCollection::Lookup do before do @tester = LookupTester.new @file_collection = mock 'file_collection' Puppet::FileCollection.stubs(:collection).returns @file_collection end it "should use the file collection to determine the index of the file name" do @file_collection.expects(:index).with("/my/file").returns 50 @tester.file = "/my/file" @tester.file_index.should == 50 end it "should return nil as the file name if no index is set" do @tester.file.should be_nil end it "should use the file collection to convert the index to a file name" do @file_collection.expects(:path).with(25).returns "/path/to/file" @tester.file_index = 25 @tester.file.should == "/path/to/file" end it "should support a line attribute" do @tester.line = 50 @tester.line.should == 50 end it "should default to the global file collection" do Puppet::FileCollection.expects(:collection).returns "collection" @tester.file_collection.should == "collection" end end diff --git a/spec/unit/file_collection_spec.rb b/spec/unit/file_collection_spec.rb index 69b1ede93..518763629 100755 --- a/spec/unit/file_collection_spec.rb +++ b/spec/unit/file_collection_spec.rb @@ -1,53 +1,52 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/file_collection' describe Puppet::FileCollection do before do @collection = Puppet::FileCollection.new end it "should be able to convert a file name into an index" do @collection.index("/my/file").should be_instance_of(Fixnum) end it "should be able to convert an index into a file name" do index = @collection.index("/path/to/file") @collection.path(index).should == "/path/to/file" end it "should always give the same file name for a given index" do index = @collection.index("/path/to/file") @collection.path(index).should == @collection.path(index) end it "should always give the same index for a given file name" do @collection.index("/my/file").should == @collection.index("/my/file") end it "should always correctly relate a file name and its index even when multiple files are in the collection" do indexes = %w{a b c d e f}.inject({}) do |hash, letter| hash[letter] = @collection.index("/path/to/file/#{letter}") hash end indexes.each do |letter, index| @collection.index("/path/to/file/#{letter}").should == indexes[letter] @collection.path(index).should == @collection.path(index) end end it "should return nil as the file name when an unknown index is provided" do @collection.path(50).should be_nil end it "should provide a global collection" do Puppet::FileCollection.collection.should be_instance_of(Puppet::FileCollection) end it "should reuse the global collection" do Puppet::FileCollection.collection.should equal(Puppet::FileCollection.collection) end end diff --git a/spec/unit/file_serving/base_spec.rb b/spec/unit/file_serving/base_spec.rb index 0323490c1..17d59460e 100755 --- a/spec/unit/file_serving/base_spec.rb +++ b/spec/unit/file_serving/base_spec.rb @@ -1,132 +1,131 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/file_serving/base' describe Puppet::FileServing::Base do it "should accept a path" do Puppet::FileServing::Base.new("/module/dir/file").path.should == "/module/dir/file" end it "should require that paths be fully qualified" do lambda { Puppet::FileServing::Base.new("module/dir/file") }.should raise_error(ArgumentError) end it "should allow specification of whether links should be managed" do Puppet::FileServing::Base.new("/module/dir/file", :links => :manage).links.should == :manage end it "should have a :source attribute" do file = Puppet::FileServing::Base.new("/module/dir/file") file.should respond_to(:source) file.should respond_to(:source=) end it "should consider :ignore links equivalent to :manage links" do Puppet::FileServing::Base.new("/module/dir/file", :links => :ignore).links.should == :manage end it "should fail if :links is set to anything other than :manage, :follow, or :ignore" do proc { Puppet::FileServing::Base.new("/module/dir/file", :links => :else) }.should raise_error(ArgumentError) end it "should allow links values to be set as strings" do Puppet::FileServing::Base.new("/module/dir/file", :links => "follow").links.should == :follow end it "should default to :manage for :links" do Puppet::FileServing::Base.new("/module/dir/file").links.should == :manage end it "should allow specification of a path" do FileTest.stubs(:exists?).returns(true) Puppet::FileServing::Base.new("/module/dir/file", :path => "/my/file").path.should == "/my/file" end it "should allow specification of a relative path" do FileTest.stubs(:exists?).returns(true) Puppet::FileServing::Base.new("/module/dir/file", :relative_path => "my/file").relative_path.should == "my/file" end it "should have a means of determining if the file exists" do Puppet::FileServing::Base.new("/blah").should respond_to(:exist?) end it "should correctly indicate if the file is present" do File.expects(:lstat).with("/my/file").returns(mock("stat")) Puppet::FileServing::Base.new("/my/file").exist?.should be_true end it "should correctly indicate if the file is absent" do File.expects(:lstat).with("/my/file").raises RuntimeError Puppet::FileServing::Base.new("/my/file").exist?.should be_false end describe "when setting the relative path" do it "should require that the relative path be unqualified" do @file = Puppet::FileServing::Base.new("/module/dir/file") FileTest.stubs(:exists?).returns(true) proc { @file.relative_path = "/qualified/file" }.should raise_error(ArgumentError) end end describe "when determining the full file path" do before do @file = Puppet::FileServing::Base.new("/this/file") end it "should return the path if there is no relative path" do @file.full_path.should == "/this/file" end it "should return the path if the relative_path is set to ''" do @file.relative_path = "" @file.full_path.should == "/this/file" end it "should return the path if the relative_path is set to '.'" do @file.relative_path = "." @file.full_path.should == "/this/file" end it "should return the path joined with the relative path if there is a relative path and it is not set to '/' or ''" do @file.relative_path = "not/qualified" @file.full_path.should == "/this/file/not/qualified" end it "should strip extra slashes" do file = Puppet::FileServing::Base.new("//this//file") file.full_path.should == "/this/file" end end describe "when stat'ing files" do before do @file = Puppet::FileServing::Base.new("/this/file") end it "should stat the file's full path" do @file.stubs(:full_path).returns("/this/file") File.expects(:lstat).with("/this/file").returns stub("stat", :ftype => "file") @file.stat end it "should fail if the file does not exist" do @file.stubs(:full_path).returns("/this/file") File.expects(:lstat).with("/this/file").raises(Errno::ENOENT) proc { @file.stat }.should raise_error(Errno::ENOENT) end it "should use :lstat if :links is set to :manage" do File.expects(:lstat).with("/this/file").returns stub("stat", :ftype => "file") @file.stat end it "should use :stat if :links is set to :follow" do File.expects(:stat).with("/this/file").returns stub("stat", :ftype => "file") @file.links = :follow @file.stat end end end diff --git a/spec/unit/file_serving/configuration/parser_spec.rb b/spec/unit/file_serving/configuration/parser_spec.rb index 1321eafc4..3d6b3e234 100755 --- a/spec/unit/file_serving/configuration/parser_spec.rb +++ b/spec/unit/file_serving/configuration/parser_spec.rb @@ -1,181 +1,180 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/file_serving/configuration/parser' describe Puppet::FileServing::Configuration::Parser do it "should subclass the LoadedFile class" do Puppet::FileServing::Configuration::Parser.superclass.should equal(Puppet::Util::LoadedFile) end end module FSConfigurationParserTesting def mock_file_content(content) # We want an array, but we actually want our carriage returns on all of it. lines = content.split("\n").collect { |l| l + "\n" } @filehandle.stubs(:each).multiple_yields(*lines) end end describe Puppet::FileServing::Configuration::Parser do before :each do @path = "/my/config.conf" FileTest.stubs(:exists?).with(@path).returns(true) FileTest.stubs(:readable?).with(@path).returns(true) @filehandle = mock 'filehandle' File.expects(:open).with(@path).yields(@filehandle) @parser = Puppet::FileServing::Configuration::Parser.new(@path) end describe Puppet::FileServing::Configuration::Parser, " when parsing" do include FSConfigurationParserTesting it "should allow comments" do @filehandle.expects(:each).yields("# this is a comment\n") proc { @parser.parse }.should_not raise_error end it "should allow blank lines" do @filehandle.expects(:each).yields("\n") proc { @parser.parse }.should_not raise_error end it "should create a new mount for each section in the configuration" do mount1 = mock 'one', :validate => true mount2 = mock 'two', :validate => true Puppet::FileServing::Mount::File.expects(:new).with("one").returns(mount1) Puppet::FileServing::Mount::File.expects(:new).with("two").returns(mount2) mock_file_content "[one]\n[two]\n" @parser.parse end # This test is almost the exact same as the previous one. it "should return a hash of the created mounts" do mount1 = mock 'one', :validate => true mount2 = mock 'two', :validate => true Puppet::FileServing::Mount::File.expects(:new).with("one").returns(mount1) Puppet::FileServing::Mount::File.expects(:new).with("two").returns(mount2) mock_file_content "[one]\n[two]\n" result = @parser.parse result["one"].should equal(mount1) result["two"].should equal(mount2) end it "should only allow mount names that are alphanumeric plus dashes" do mock_file_content "[a*b]\n" proc { @parser.parse }.should raise_error(ArgumentError) end it "should fail if the value for path/allow/deny starts with an equals sign" do mock_file_content "[one]\npath = /testing" proc { @parser.parse }.should raise_error(ArgumentError) end it "should validate each created mount" do mount1 = mock 'one' Puppet::FileServing::Mount::File.expects(:new).with("one").returns(mount1) mock_file_content "[one]\n" mount1.expects(:validate) @parser.parse end it "should fail if any mount does not pass validation" do mount1 = mock 'one' Puppet::FileServing::Mount::File.expects(:new).with("one").returns(mount1) mock_file_content "[one]\n" mount1.expects(:validate).raises RuntimeError lambda { @parser.parse }.should raise_error(RuntimeError) end end describe Puppet::FileServing::Configuration::Parser, " when parsing mount attributes" do include FSConfigurationParserTesting before do @mount = stub 'testmount', :name => "one", :validate => true Puppet::FileServing::Mount::File.expects(:new).with("one").returns(@mount) @parser.stubs(:add_modules_mount) end it "should set the mount path to the path attribute from that section" do mock_file_content "[one]\npath /some/path\n" @mount.expects(:path=).with("/some/path") @parser.parse end it "should tell the mount to allow any allow values from the section" do mock_file_content "[one]\nallow something\n" @mount.expects(:info) @mount.expects(:allow).with("something") @parser.parse end it "should tell the mount to deny any deny values from the section" do mock_file_content "[one]\ndeny something\n" @mount.expects(:info) @mount.expects(:deny).with("something") @parser.parse end it "should fail on any attributes other than path, allow, and deny" do mock_file_content "[one]\ndo something\n" proc { @parser.parse }.should raise_error(ArgumentError) end end describe Puppet::FileServing::Configuration::Parser, " when parsing the modules mount" do include FSConfigurationParserTesting before do @mount = stub 'modulesmount', :name => "modules", :validate => true end it "should create an instance of the Modules Mount class" do mock_file_content "[modules]\n" Puppet::FileServing::Mount::Modules.expects(:new).with("modules").returns @mount @parser.parse end it "should warn if a path is set" do mock_file_content "[modules]\npath /some/path\n" Puppet::FileServing::Mount::Modules.expects(:new).with("modules").returns(@mount) Puppet.expects(:warning) @parser.parse end end describe Puppet::FileServing::Configuration::Parser, " when parsing the plugins mount" do include FSConfigurationParserTesting before do @mount = stub 'pluginsmount', :name => "plugins", :validate => true end it "should create an instance of the Plugins Mount class" do mock_file_content "[plugins]\n" Puppet::FileServing::Mount::Plugins.expects(:new).with("plugins").returns @mount @parser.parse end it "should warn if a path is set" do mock_file_content "[plugins]\npath /some/path\n" Puppet.expects(:warning) @parser.parse end end end diff --git a/spec/unit/file_serving/configuration_spec.rb b/spec/unit/file_serving/configuration_spec.rb index 4aba165e2..6ee1a4f38 100755 --- a/spec/unit/file_serving/configuration_spec.rb +++ b/spec/unit/file_serving/configuration_spec.rb @@ -1,249 +1,248 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/file_serving/configuration' describe Puppet::FileServing::Configuration do it "should make :new a private method" do proc { Puppet::FileServing::Configuration.new }.should raise_error end it "should return the same configuration each time :create is called" do Puppet::FileServing::Configuration.create.should equal(Puppet::FileServing::Configuration.create) end it "should have a method for removing the current configuration instance" do old = Puppet::FileServing::Configuration.create Puppet::Util::Cacher.expire Puppet::FileServing::Configuration.create.should_not equal(old) end after do Puppet::Util::Cacher.expire end end describe Puppet::FileServing::Configuration do before :each do @path = "/path/to/configuration/file.conf" Puppet.settings.stubs(:value).with(:trace).returns(false) Puppet.settings.stubs(:value).with(:fileserverconfig).returns(@path) end after :each do Puppet::Util::Cacher.expire end describe "when initializing" do it "should work without a configuration file" do FileTest.stubs(:exists?).with(@path).returns(false) proc { Puppet::FileServing::Configuration.create }.should_not raise_error end it "should parse the configuration file if present" do FileTest.stubs(:exists?).with(@path).returns(true) @parser = mock 'parser' @parser.expects(:parse).returns({}) Puppet::FileServing::Configuration::Parser.stubs(:new).returns(@parser) Puppet::FileServing::Configuration.create end it "should determine the path to the configuration file from the Puppet settings" do Puppet::FileServing::Configuration.create end end describe "when parsing the configuration file" do before do FileTest.stubs(:exists?).with(@path).returns(true) @parser = mock 'parser' Puppet::FileServing::Configuration::Parser.stubs(:new).returns(@parser) end it "should set the mount list to the results of parsing" do @parser.expects(:parse).returns("one" => mock("mount")) config = Puppet::FileServing::Configuration.create config.mounted?("one").should be_true end it "should not raise exceptions" do @parser.expects(:parse).raises(ArgumentError) proc { Puppet::FileServing::Configuration.create }.should_not raise_error end it "should replace the existing mount list with the results of reparsing" do @parser.expects(:parse).returns("one" => mock("mount")) config = Puppet::FileServing::Configuration.create config.mounted?("one").should be_true # Now parse again @parser.expects(:parse).returns("two" => mock('other')) config.send(:readconfig, false) config.mounted?("one").should be_false config.mounted?("two").should be_true end it "should not replace the mount list until the file is entirely parsed successfully" do @parser.expects(:parse).returns("one" => mock("mount")) @parser.expects(:parse).raises(ArgumentError) config = Puppet::FileServing::Configuration.create # Now parse again, so the exception gets thrown config.send(:readconfig, false) config.mounted?("one").should be_true end it "should add modules and plugins mounts even if the file does not exist" do FileTest.expects(:exists?).returns false # the file doesn't exist config = Puppet::FileServing::Configuration.create config.mounted?("modules").should be_true config.mounted?("plugins").should be_true end it "should allow all access to modules and plugins if no fileserver.conf exists" do FileTest.expects(:exists?).returns false # the file doesn't exist modules = stub 'modules', :empty? => true Puppet::FileServing::Mount::Modules.stubs(:new).returns(modules) modules.expects(:allow).with('*') plugins = stub 'plugins', :empty? => true Puppet::FileServing::Mount::Plugins.stubs(:new).returns(plugins) plugins.expects(:allow).with('*') Puppet::FileServing::Configuration.create end it "should not allow access from all to modules and plugins if the fileserver.conf provided some rules" do FileTest.expects(:exists?).returns false # the file doesn't exist modules = stub 'modules', :empty? => false Puppet::FileServing::Mount::Modules.stubs(:new).returns(modules) modules.expects(:allow).with('*').never plugins = stub 'plugins', :empty? => false Puppet::FileServing::Mount::Plugins.stubs(:new).returns(plugins) plugins.expects(:allow).with('*').never Puppet::FileServing::Configuration.create end it "should add modules and plugins mounts even if they are not returned by the parser" do @parser.expects(:parse).returns("one" => mock("mount")) FileTest.expects(:exists?).returns true # the file doesn't exist config = Puppet::FileServing::Configuration.create config.mounted?("modules").should be_true config.mounted?("plugins").should be_true end end describe "when finding the specified mount" do it "should choose the named mount if one exists" do config = Puppet::FileServing::Configuration.create config.expects(:mounts).returns("one" => "foo") config.find_mount("one", mock('env')).should == "foo" end it "should use the provided environment to find a matching module if the named module cannot be found" do config = Puppet::FileServing::Configuration.create mod = mock 'module' env = mock 'environment' env.expects(:module).with("foo").returns mod mount = mock 'mount' config.stubs(:mounts).returns("modules" => mount) Puppet::Util::Warnings.expects(:notice_once) config.find_mount("foo", env).should equal(mount) end it "should return nil if there is no such named mount and no module with the same name exists" do config = Puppet::FileServing::Configuration.create env = mock 'environment' env.expects(:module).with("foo").returns nil mount = mock 'mount' config.stubs(:mounts).returns("modules" => mount) config.find_mount("foo", env).should be_nil end end describe "when finding the mount name and relative path in a request key" do before do @config = Puppet::FileServing::Configuration.create @config.stubs(:find_mount) @request = stub 'request', :key => "foo/bar/baz", :options => {}, :node => nil, :environment => mock("env") end it "should reread the configuration" do @config.expects(:readconfig) @config.split_path(@request) end it "should treat the first field of the URI path as the mount name" do @config.expects(:find_mount).with { |name, node| name == "foo" } @config.split_path(@request) end it "should fail if the mount name is not alpha-numeric" do @request.expects(:key).returns "foo&bar/asdf" lambda { @config.split_path(@request) }.should raise_error(ArgumentError) end it "should support dashes in the mount name" do @request.expects(:key).returns "foo-bar/asdf" lambda { @config.split_path(@request) }.should_not raise_error(ArgumentError) end it "should use the mount name and environment to find the mount" do @config.expects(:find_mount).with { |name, env| name == "foo" and env == @request.environment } @request.stubs(:node).returns("mynode") @config.split_path(@request) end it "should return nil if the mount cannot be found" do @config.expects(:find_mount).returns nil @config.split_path(@request).should be_nil end it "should return the mount and the relative path if the mount is found" do mount = stub 'mount', :name => "foo" @config.expects(:find_mount).returns mount @config.split_path(@request).should == [mount, "bar/baz"] end it "should remove any double slashes" do @request.stubs(:key).returns "foo/bar//baz" mount = stub 'mount', :name => "foo" @config.expects(:find_mount).returns mount @config.split_path(@request).should == [mount, "bar/baz"] end it "should return the relative path as nil if it is an empty string" do @request.expects(:key).returns "foo" mount = stub 'mount', :name => "foo" @config.expects(:find_mount).returns mount @config.split_path(@request).should == [mount, nil] end it "should add 'modules/' to the relative path if the modules mount is used but not specified, for backward compatibility" do @request.expects(:key).returns "foo/bar" mount = stub 'mount', :name => "modules" @config.expects(:find_mount).returns mount @config.split_path(@request).should == [mount, "foo/bar"] end end end diff --git a/spec/unit/file_serving/content_spec.rb b/spec/unit/file_serving/content_spec.rb index 806515a63..2637ba6ce 100755 --- a/spec/unit/file_serving/content_spec.rb +++ b/spec/unit/file_serving/content_spec.rb @@ -1,118 +1,117 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/file_serving/content' describe Puppet::FileServing::Content do it "should should be a subclass of Base" do Puppet::FileServing::Content.superclass.should equal(Puppet::FileServing::Base) end it "should indirect file_content" do Puppet::FileServing::Content.indirection.name.should == :file_content end it "should should include the IndirectionHooks module in its indirection" do Puppet::FileServing::Content.indirection.singleton_class.included_modules.should include(Puppet::FileServing::IndirectionHooks) end it "should only support the raw format" do Puppet::FileServing::Content.supported_formats.should == [:raw] end it "should have a method for collecting its attributes" do Puppet::FileServing::Content.new("/path").should respond_to(:collect) end it "should not retrieve and store its contents when its attributes are collected if the file is a normal file" do content = Puppet::FileServing::Content.new("/path") result = "foo" File.stubs(:lstat).returns(stub("stat", :ftype => "file")) File.expects(:read).with("/path").never content.collect content.instance_variable_get("@content").should be_nil end it "should not attempt to retrieve its contents if the file is a directory" do content = Puppet::FileServing::Content.new("/path") result = "foo" File.stubs(:lstat).returns(stub("stat", :ftype => "directory")) File.expects(:read).with("/path").never content.collect content.instance_variable_get("@content").should be_nil end it "should have a method for setting its content" do content = Puppet::FileServing::Content.new("/path") content.should respond_to(:content=) end it "should make content available when set externally" do content = Puppet::FileServing::Content.new("/path") content.content = "foo/bar" content.content.should == "foo/bar" end it "should be able to create a content instance from raw file contents" do Puppet::FileServing::Content.should respond_to(:from_raw) end it "should create an instance with a fake file name and correct content when converting from raw" do instance = mock 'instance' Puppet::FileServing::Content.expects(:new).with("/this/is/a/fake/path").returns instance instance.expects(:content=).with "foo/bar" Puppet::FileServing::Content.from_raw("foo/bar").should equal(instance) end it "should return an opened File when converted to raw" do content = Puppet::FileServing::Content.new("/path") File.expects(:new).with("/path","r").returns :file content.to_raw.should == :file end end describe Puppet::FileServing::Content, "when returning the contents" do before do @path = "/my/path" @content = Puppet::FileServing::Content.new(@path, :links => :follow) end it "should fail if the file is a symlink and links are set to :manage" do @content.links = :manage File.expects(:lstat).with(@path).returns stub("stat", :ftype => "symlink") proc { @content.content }.should raise_error(ArgumentError) end it "should fail if a path is not set" do proc { @content.content }.should raise_error(Errno::ENOENT) end it "should raise Errno::ENOENT if the file is absent" do @content.path = "/there/is/absolutely/no/chance/that/this/path/exists" proc { @content.content }.should raise_error(Errno::ENOENT) end it "should return the contents of the path if the file exists" do File.expects(:stat).with(@path).returns stub("stat", :ftype => "file") File.expects(:read).with(@path).returns(:mycontent) @content.content.should == :mycontent end it "should cache the returned contents" do File.expects(:stat).with(@path).returns stub("stat", :ftype => "file") File.expects(:read).with(@path).returns(:mycontent) @content.content # The second run would throw a failure if the content weren't being cached. @content.content end end diff --git a/spec/unit/file_serving/fileset_spec.rb b/spec/unit/file_serving/fileset_spec.rb index 6a83621d2..a369ad39c 100755 --- a/spec/unit/file_serving/fileset_spec.rb +++ b/spec/unit/file_serving/fileset_spec.rb @@ -1,356 +1,355 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/file_serving/fileset' describe Puppet::FileServing::Fileset, " when initializing" do it "should require a path" do proc { Puppet::FileServing::Fileset.new }.should raise_error(ArgumentError) end it "should fail if its path is not fully qualified" do proc { Puppet::FileServing::Fileset.new("some/file") }.should raise_error(ArgumentError) end it "should not fail if the path is fully qualified, with a trailing separator" do path = "/some/path/with/trailing/separator" path_with_separator = "#{path}#{File::SEPARATOR}" File.stubs(:lstat).with(path).returns stub('stat') fileset = Puppet::FileServing::Fileset.new(path_with_separator) fileset.path.should == path end it "should fail if its path does not exist" do File.expects(:lstat).with("/some/file").returns nil proc { Puppet::FileServing::Fileset.new("/some/file") }.should raise_error(ArgumentError) end it "should accept a 'recurse' option" do File.expects(:lstat).with("/some/file").returns stub("stat") set = Puppet::FileServing::Fileset.new("/some/file", :recurse => true) set.recurse.should be_true end it "should accept a 'recurselimit' option" do File.expects(:lstat).with("/some/file").returns stub("stat") set = Puppet::FileServing::Fileset.new("/some/file", :recurselimit => 3) set.recurselimit.should == 3 end it "should accept an 'ignore' option" do File.expects(:lstat).with("/some/file").returns stub("stat") set = Puppet::FileServing::Fileset.new("/some/file", :ignore => ".svn") set.ignore.should == [".svn"] end it "should accept a 'links' option" do File.expects(:lstat).with("/some/file").returns stub("stat") set = Puppet::FileServing::Fileset.new("/some/file", :links => :manage) set.links.should == :manage end it "should accept a 'checksum_type' option" do File.expects(:lstat).with("/some/file").returns stub("stat") set = Puppet::FileServing::Fileset.new("/some/file", :checksum_type => :test) set.checksum_type.should == :test end it "should fail if 'links' is set to anything other than :manage or :follow" do proc { Puppet::FileServing::Fileset.new("/some/file", :links => :whatever) }.should raise_error(ArgumentError) end it "should default to 'false' for recurse" do File.expects(:lstat).with("/some/file").returns stub("stat") Puppet::FileServing::Fileset.new("/some/file").recurse.should == false end it "should default to :infinite for recurselimit" do File.expects(:lstat).with("/some/file").returns stub("stat") Puppet::FileServing::Fileset.new("/some/file").recurselimit.should == :infinite end it "should default to an empty ignore list" do File.expects(:lstat).with("/some/file").returns stub("stat") Puppet::FileServing::Fileset.new("/some/file").ignore.should == [] end it "should default to :manage for links" do File.expects(:lstat).with("/some/file").returns stub("stat") Puppet::FileServing::Fileset.new("/some/file").links.should == :manage end it "should support using an Indirector Request for its options" do File.expects(:lstat).with("/some/file").returns stub("stat") request = Puppet::Indirector::Request.new(:file_serving, :find, "foo") lambda { Puppet::FileServing::Fileset.new("/some/file", request) }.should_not raise_error end describe "using an indirector request" do before do File.stubs(:lstat).returns stub("stat") @values = {:links => :manage, :ignore => %w{a b}, :recurse => true, :recurselimit => 1234} @request = Puppet::Indirector::Request.new(:file_serving, :find, "foo") end [:recurse, :recurselimit, :ignore, :links].each do |option| it "should pass :recurse, :recurselimit, :ignore, and :links settings on to the fileset if present" do @request.stubs(:options).returns(option => @values[option]) Puppet::FileServing::Fileset.new("/my/file", @request).send(option).should == @values[option] end it "should pass :recurse, :recurselimit, :ignore, and :links settings on to the fileset if present with the keys stored as strings" do @request.stubs(:options).returns(option.to_s => @values[option]) Puppet::FileServing::Fileset.new("/my/file", @request).send(option).should == @values[option] end end it "should convert the integer as a string to their integer counterpart when setting options" do @request.stubs(:options).returns(:recurselimit => "1234") Puppet::FileServing::Fileset.new("/my/file", @request).recurselimit.should == 1234 end it "should convert the string 'true' to the boolean true when setting options" do @request.stubs(:options).returns(:recurse => "true") Puppet::FileServing::Fileset.new("/my/file", @request).recurse.should == true end it "should convert the string 'false' to the boolean false when setting options" do @request.stubs(:options).returns(:recurse => "false") Puppet::FileServing::Fileset.new("/my/file", @request).recurse.should == false end end end describe Puppet::FileServing::Fileset, " when determining whether to recurse" do before do @path = "/my/path" File.expects(:lstat).with(@path).returns stub("stat") @fileset = Puppet::FileServing::Fileset.new(@path) end it "should always recurse if :recurse is set to 'true' and with infinite recursion" do @fileset.recurse = true @fileset.recurselimit = :infinite @fileset.recurse?(0).should be_true end it "should never recurse if :recurse is set to 'false'" do @fileset.recurse = false @fileset.recurse?(-1).should be_false end it "should recurse if :recurse is set to true, :recurselimit is set to an integer and the current depth is less than that integer" do @fileset.recurse = true @fileset.recurselimit = 1 @fileset.recurse?(0).should be_true end it "should recurse if :recurse is set to true, :recurselimit is set to an integer and the current depth is equal to that integer" do @fileset.recurse = true @fileset.recurselimit = 1 @fileset.recurse?(1).should be_true end it "should not recurse if :recurse is set to true, :recurselimit is set to an integer and the current depth is greater than that integer" do @fileset.recurse = true @fileset.recurselimit = 1 @fileset.recurse?(2).should be_false end end describe Puppet::FileServing::Fileset, " when recursing" do before do @path = "/my/path" File.expects(:lstat).with(@path).returns stub("stat", :directory? => true) @fileset = Puppet::FileServing::Fileset.new(@path) @dirstat = stub 'dirstat', :directory? => true @filestat = stub 'filestat', :directory? => false end def mock_dir_structure(path, stat_method = :lstat) File.stubs(stat_method).with(path).returns(@dirstat) Dir.stubs(:entries).with(path).returns(%w{one two .svn CVS}) # Keep track of the files we're stubbing. @files = %w{.} %w{one two .svn CVS}.each do |subdir| @files << subdir # relative path subpath = File.join(path, subdir) File.stubs(stat_method).with(subpath).returns(@dirstat) Dir.stubs(:entries).with(subpath).returns(%w{.svn CVS file1 file2}) %w{file1 file2 .svn CVS}.each do |file| @files << File.join(subdir, file) # relative path File.stubs(stat_method).with(File.join(subpath, file)).returns(@filestat) end end end it "should recurse through the whole file tree if :recurse is set to 'true'" do mock_dir_structure(@path) @fileset.stubs(:recurse?).returns(true) @fileset.files.sort.should == @files.sort end it "should not recurse if :recurse is set to 'false'" do mock_dir_structure(@path) @fileset.stubs(:recurse?).returns(false) @fileset.files.should == %w{.} end # It seems like I should stub :recurse? here, or that I shouldn't stub the # examples above, but... it "should recurse to the level set if :recurselimit is set to an integer" do mock_dir_structure(@path) @fileset.recurse = true @fileset.recurselimit = 1 @fileset.files.should == %w{. one two .svn CVS} end it "should ignore the '.' and '..' directories in subdirectories" do mock_dir_structure(@path) @fileset.recurse = true @fileset.files.sort.should == @files.sort end it "should function if the :ignore value provided is nil" do mock_dir_structure(@path) @fileset.recurse = true @fileset.ignore = nil lambda { @fileset.files }.should_not raise_error end it "should ignore files that match a single pattern in the ignore list" do mock_dir_structure(@path) @fileset.recurse = true @fileset.ignore = ".svn" @fileset.files.find { |file| file.include?(".svn") }.should be_nil end it "should ignore files that match any of multiple patterns in the ignore list" do mock_dir_structure(@path) @fileset.recurse = true @fileset.ignore = %w{.svn CVS} @fileset.files.find { |file| file.include?(".svn") or file.include?("CVS") }.should be_nil end it "should use File.stat if :links is set to :follow" do mock_dir_structure(@path, :stat) @fileset.recurse = true @fileset.links = :follow @fileset.files.sort.should == @files.sort end it "should use File.lstat if :links is set to :manage" do mock_dir_structure(@path, :lstat) @fileset.recurse = true @fileset.links = :manage @fileset.files.sort.should == @files.sort end it "should succeed when paths have regexp significant characters" do @path = "/my/path/rV1x2DafFr0R6tGG+1bbk++++TM" File.expects(:lstat).with(@path).returns stub("stat", :directory? => true) @fileset = Puppet::FileServing::Fileset.new(@path) mock_dir_structure(@path) @fileset.recurse = true @fileset.files.sort.should == @files.sort end end describe Puppet::FileServing::Fileset, " when following links that point to missing files" do before do @path = "/my/path" File.expects(:lstat).with(@path).returns stub("stat", :directory? => true) @fileset = Puppet::FileServing::Fileset.new(@path) @fileset.links = :follow @fileset.recurse = true @stat = stub 'stat', :directory? => true File.expects(:stat).with(@path).returns(@stat) File.expects(:stat).with(File.join(@path, "mylink")).raises(Errno::ENOENT) Dir.stubs(:entries).with(@path).returns(["mylink"]) end it "should not fail" do proc { @fileset.files }.should_not raise_error end it "should still manage the link" do @fileset.files.sort.should == %w{. mylink}.sort end end describe Puppet::FileServing::Fileset, " when ignoring" do before do @path = "/my/path" File.expects(:lstat).with(@path).returns stub("stat", :directory? => true) @fileset = Puppet::FileServing::Fileset.new(@path) end it "should use ruby's globbing to determine what files should be ignored" do @fileset.ignore = ".svn" File.expects(:fnmatch?).with(".svn", "my_file") @fileset.ignore?("my_file") end it "should ignore files whose paths match a single provided ignore value" do @fileset.ignore = ".svn" File.stubs(:fnmatch?).with(".svn", "my_file").returns true @fileset.ignore?("my_file").should be_true end it "should ignore files whose paths match any of multiple provided ignore values" do @fileset.ignore = [".svn", "CVS"] File.stubs(:fnmatch?).with(".svn", "my_file").returns false File.stubs(:fnmatch?).with("CVS", "my_file").returns true @fileset.ignore?("my_file").should be_true end end describe Puppet::FileServing::Fileset, "when merging other filesets" do before do @paths = %w{/first/path /second/path /third/path} File.stubs(:lstat).returns stub("stat", :directory? => false) @filesets = @paths.collect do |path| File.stubs(:lstat).with(path).returns stub("stat", :directory? => true) Puppet::FileServing::Fileset.new(path, :recurse => true) end Dir.stubs(:entries).returns [] end it "should return a hash of all files in each fileset with the value being the base path" do Dir.expects(:entries).with("/first/path").returns(%w{one uno}) Dir.expects(:entries).with("/second/path").returns(%w{two dos}) Dir.expects(:entries).with("/third/path").returns(%w{three tres}) Puppet::FileServing::Fileset.merge(*@filesets).should == { "." => "/first/path", "one" => "/first/path", "uno" => "/first/path", "two" => "/second/path", "dos" => "/second/path", "three" => "/third/path", "tres" => "/third/path", } end it "should include the base directory from the first fileset" do Dir.expects(:entries).with("/first/path").returns(%w{one}) Dir.expects(:entries).with("/second/path").returns(%w{two}) Puppet::FileServing::Fileset.merge(*@filesets)["."].should == "/first/path" end it "should use the base path of the first found file when relative file paths conflict" do Dir.expects(:entries).with("/first/path").returns(%w{one}) Dir.expects(:entries).with("/second/path").returns(%w{one}) Puppet::FileServing::Fileset.merge(*@filesets)["one"].should == "/first/path" end end diff --git a/spec/unit/file_serving/indirection_hooks_spec.rb b/spec/unit/file_serving/indirection_hooks_spec.rb index 0ee2de5ea..4890505ab 100755 --- a/spec/unit/file_serving/indirection_hooks_spec.rb +++ b/spec/unit/file_serving/indirection_hooks_spec.rb @@ -1,63 +1,63 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Created by Luke Kanies on 2007-10-18. # Copyright (c) 2007. All rights reserved. require 'spec_helper' require 'puppet/file_serving/indirection_hooks' describe Puppet::FileServing::IndirectionHooks do before do @object = Object.new @object.extend(Puppet::FileServing::IndirectionHooks) @request = stub 'request', :key => "mymod/myfile", :options => {:node => "whatever"}, :server => nil, :protocol => nil end describe "when being used to select termini" do it "should return :file if the request key is fully qualified" do @request.expects(:key).returns "#{File::SEPARATOR}foo" @object.select_terminus(@request).should == :file end it "should return :file if the URI protocol is set to 'file'" do @request.expects(:protocol).returns "file" @object.select_terminus(@request).should == :file end it "should fail when a protocol other than :puppet or :file is used" do @request.stubs(:protocol).returns "http" proc { @object.select_terminus(@request) }.should raise_error(ArgumentError) end describe "and the protocol is 'puppet'" do before do @request.stubs(:protocol).returns "puppet" end it "should choose :rest when a server is specified" do @request.stubs(:protocol).returns "puppet" @request.expects(:server).returns "foo" @object.select_terminus(@request).should == :rest end # This is so a given file location works when bootstrapping with no server. it "should choose :rest when the Settings name isn't 'puppet'" do @request.stubs(:protocol).returns "puppet" @request.stubs(:server).returns "foo" Puppet.settings.stubs(:value).with(:name).returns "foo" @object.select_terminus(@request).should == :rest end it "should choose :file_server when the settings name is 'puppet' and no server is specified" do modules = mock 'modules' @request.expects(:protocol).returns "puppet" @request.expects(:server).returns nil Puppet.settings.expects(:value).with(:name).returns "puppet" @object.select_terminus(@request).should == :file_server end end end end diff --git a/spec/unit/file_serving/metadata_spec.rb b/spec/unit/file_serving/metadata_spec.rb index 24761027c..39f2a9548 100755 --- a/spec/unit/file_serving/metadata_spec.rb +++ b/spec/unit/file_serving/metadata_spec.rb @@ -1,286 +1,285 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/file_serving/metadata' describe Puppet::FileServing::Metadata do it "should should be a subclass of Base" do Puppet::FileServing::Metadata.superclass.should equal(Puppet::FileServing::Base) end it "should indirect file_metadata" do Puppet::FileServing::Metadata.indirection.name.should == :file_metadata end it "should should include the IndirectionHooks module in its indirection" do Puppet::FileServing::Metadata.indirection.singleton_class.included_modules.should include(Puppet::FileServing::IndirectionHooks) end it "should have a method that triggers attribute collection" do Puppet::FileServing::Metadata.new("/foo/bar").should respond_to(:collect) end it "should support pson serialization" do Puppet::FileServing::Metadata.new("/foo/bar").should respond_to(:to_pson) end it "should support to_pson_data_hash" do Puppet::FileServing::Metadata.new("/foo/bar").should respond_to(:to_pson_data_hash) end it "should support pson deserialization" do Puppet::FileServing::Metadata.should respond_to(:from_pson) end describe "when serializing" do before do @metadata = Puppet::FileServing::Metadata.new("/foo/bar") end it "should perform pson serialization by calling to_pson on it's pson_data_hash" do pdh = mock "data hash" pdh_as_pson = mock "data as pson" @metadata.expects(:to_pson_data_hash).returns pdh pdh.expects(:to_pson).returns pdh_as_pson @metadata.to_pson.should == pdh_as_pson end it "should serialize as FileMetadata" do @metadata.to_pson_data_hash['document_type'].should == "FileMetadata" end it "the data should include the path, relative_path, links, owner, group, mode, checksum, type, and destination" do @metadata.to_pson_data_hash['data'].keys.sort.should == %w{ path relative_path links owner group mode checksum type destination }.sort end it "should pass the path in the hash verbatum" do @metadata.to_pson_data_hash['data']['path'] == @metadata.path end it "should pass the relative_path in the hash verbatum" do @metadata.to_pson_data_hash['data']['relative_path'] == @metadata.relative_path end it "should pass the links in the hash verbatum" do @metadata.to_pson_data_hash['data']['links'] == @metadata.links end it "should pass the path owner in the hash verbatum" do @metadata.to_pson_data_hash['data']['owner'] == @metadata.owner end it "should pass the group in the hash verbatum" do @metadata.to_pson_data_hash['data']['group'] == @metadata.group end it "should pass the mode in the hash verbatum" do @metadata.to_pson_data_hash['data']['mode'] == @metadata.mode end it "should pass the ftype in the hash verbatum as the 'type'" do @metadata.to_pson_data_hash['data']['type'] == @metadata.ftype end it "should pass the destination verbatum" do @metadata.to_pson_data_hash['data']['destination'] == @metadata.destination end it "should pass the checksum in the hash as a nested hash" do @metadata.to_pson_data_hash['data']['checksum'].should be_is_a(Hash) end it "should pass the checksum_type in the hash verbatum as the checksum's type" do @metadata.to_pson_data_hash['data']['checksum']['type'] == @metadata.checksum_type end it "should pass the checksum in the hash verbatum as the checksum's value" do @metadata.to_pson_data_hash['data']['checksum']['value'] == @metadata.checksum end end end describe Puppet::FileServing::Metadata, " when finding the file to use for setting attributes" do before do @path = "/my/path" @metadata = Puppet::FileServing::Metadata.new(@path) # Use a link because it's easier to test -- no checksumming @stat = stub "stat", :uid => 10, :gid => 20, :mode => 0755, :ftype => "link" # Not quite. We don't want to checksum links, but we must because they might be being followed. @checksum = Digest::MD5.hexdigest("some content\n") # Remove these when :managed links are no longer checksumed. @metadata.stubs(:md5_file).returns(@checksum) # end it "should accept a base path path to which the file should be relative" do File.expects(:lstat).with(@path).returns @stat File.expects(:readlink).with(@path).returns "/what/ever" @metadata.collect end it "should use the set base path if one is not provided" do File.expects(:lstat).with(@path).returns @stat File.expects(:readlink).with(@path).returns "/what/ever" @metadata.collect end it "should raise an exception if the file does not exist" do File.expects(:lstat).with(@path).raises(Errno::ENOENT) proc { @metadata.collect}.should raise_error(Errno::ENOENT) end end describe Puppet::FileServing::Metadata, " when collecting attributes" do before do @path = "/my/file" # Use a real file mode, so we can validate the masking is done. @stat = stub 'stat', :uid => 10, :gid => 20, :mode => 33261, :ftype => "file" File.stubs(:lstat).returns(@stat) @checksum = Digest::MD5.hexdigest("some content\n") @metadata = Puppet::FileServing::Metadata.new("/my/file") @metadata.stubs(:md5_file).returns(@checksum) @metadata.collect end it "should be able to produce xmlrpc-style attribute information" do @metadata.should respond_to(:attributes_with_tabs) end # LAK:FIXME This should actually change at some point it "should set the owner by id" do @metadata.owner.should be_instance_of(Fixnum) end # LAK:FIXME This should actually change at some point it "should set the group by id" do @metadata.group.should be_instance_of(Fixnum) end it "should set the owner to the file's current owner" do @metadata.owner.should == 10 end it "should set the group to the file's current group" do @metadata.group.should == 20 end it "should set the mode to the file's masked mode" do @metadata.mode.should == 0755 end it "should set the checksum to the file's current checksum" do @metadata.checksum.should == "{md5}#{@checksum}" end describe "when managing files" do it "should default to a checksum of type MD5" do @metadata.checksum.should == "{md5}#{@checksum}" end it "should give a mtime checksum when checksum_type is set" do time = Time.now @metadata.checksum_type = "mtime" @metadata.expects(:mtime_file).returns(@time) @metadata.collect @metadata.checksum.should == "{mtime}#{@time}" end it "should produce tab-separated mode, type, owner, group, and checksum for xmlrpc" do @metadata.attributes_with_tabs.should == "#{0755.to_s}\tfile\t10\t20\t{md5}#{@checksum}" end end describe "when managing directories" do before do @stat.stubs(:ftype).returns("directory") @time = Time.now @metadata.expects(:ctime_file).returns(@time) end it "should only use checksums of type 'ctime' for directories" do @metadata.collect @metadata.checksum.should == "{ctime}#{@time}" end it "should only use checksums of type 'ctime' for directories even if checksum_type set" do @metadata.checksum_type = "mtime" @metadata.expects(:mtime_file).never @metadata.collect @metadata.checksum.should == "{ctime}#{@time}" end it "should produce tab-separated mode, type, owner, group, and checksum for xmlrpc" do @metadata.collect @metadata.attributes_with_tabs.should == "#{0755.to_s}\tdirectory\t10\t20\t{ctime}#{@time.to_s}" end end describe "when managing links" do before do @stat.stubs(:ftype).returns("link") File.expects(:readlink).with("/my/file").returns("/path/to/link") @metadata.collect @checksum = Digest::MD5.hexdigest("some content\n") # Remove these when :managed links are no longer checksumed. @file.stubs(:md5_file).returns(@checksum) # end it "should read links instead of returning their checksums" do @metadata.destination.should == "/path/to/link" end pending "should produce tab-separated mode, type, owner, group, and destination for xmlrpc" do # "We'd like this to be true, but we need to always collect the checksum because in the server/client/server round trip we lose the distintion between manage and follow." @metadata.attributes_with_tabs.should == "#{0755}\tlink\t10\t20\t/path/to/link" end it "should produce tab-separated mode, type, owner, group, checksum, and destination for xmlrpc" do @metadata.attributes_with_tabs.should == "#{0755}\tlink\t10\t20\t{md5}eb9c2bf0eb63f3a7bc0ea37ef18aeba5\t/path/to/link" end end end describe Puppet::FileServing::Metadata, " when pointing to a link" do describe "when links are managed" do before do @file = Puppet::FileServing::Metadata.new("/base/path/my/file", :links => :manage) File.expects(:lstat).with("/base/path/my/file").returns stub("stat", :uid => 1, :gid => 2, :ftype => "link", :mode => 0755) File.expects(:readlink).with("/base/path/my/file").returns "/some/other/path" @checksum = Digest::MD5.hexdigest("some content\n") # Remove these when :managed links are no longer checksumed. @file.stubs(:md5_file).returns(@checksum) # end it "should store the destination of the link in :destination if links are :manage" do @file.collect @file.destination.should == "/some/other/path" end pending "should not collect the checksum if links are :manage" do # We'd like this to be true, but we need to always collect the checksum because in the server/client/server round trip we lose the distintion between manage and follow. @file.collect @file.checksum.should be_nil end it "should collect the checksum if links are :manage" do # see pending note above @file.collect @file.checksum.should == "{md5}#{@checksum}" end end describe "when links are followed" do before do @file = Puppet::FileServing::Metadata.new("/base/path/my/file", :links => :follow) File.expects(:stat).with("/base/path/my/file").returns stub("stat", :uid => 1, :gid => 2, :ftype => "file", :mode => 0755) File.expects(:readlink).with("/base/path/my/file").never @checksum = Digest::MD5.hexdigest("some content\n") @file.stubs(:md5_file).returns(@checksum) end it "should not store the destination of the link in :destination if links are :follow" do @file.collect @file.destination.should be_nil end it "should collect the checksum if links are :follow" do @file.collect @file.checksum.should == "{md5}#{@checksum}" end end end diff --git a/spec/unit/file_serving/mount/file_spec.rb b/spec/unit/file_serving/mount/file_spec.rb index 5af680188..70c804abd 100755 --- a/spec/unit/file_serving/mount/file_spec.rb +++ b/spec/unit/file_serving/mount/file_spec.rb @@ -1,196 +1,195 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/file_serving/mount/file' module FileServingMountTesting def stub_facter(hostname) Facter.stubs(:value).with("hostname").returns(hostname.sub(/\..+/, '')) Facter.stubs(:value).with("domain").returns(hostname.sub(/^[^.]+\./, '')) end end describe Puppet::FileServing::Mount::File do it "should provide a method for clearing its cached host information" do old = Puppet::FileServing::Mount::File.localmap Puppet::Util::Cacher.expire Puppet::FileServing::Mount::File.localmap.should_not equal(old) end it "should be invalid if it does not have a path" do lambda { Puppet::FileServing::Mount::File.new("foo").validate }.should raise_error(ArgumentError) end it "should be valid if it has a path" do FileTest.stubs(:directory?).returns true FileTest.stubs(:readable?).returns true mount = Puppet::FileServing::Mount::File.new("foo") mount.path = "/foo" lambda { mount.validate }.should_not raise_error(ArgumentError) end end describe Puppet::FileServing::Mount::File, " when setting the path" do before do @mount = Puppet::FileServing::Mount::File.new("test") @dir = "/this/path/does/not/exist" end it "should fail if the path is not a directory" do FileTest.expects(:directory?).returns(false) proc { @mount.path = @dir }.should raise_error(ArgumentError) end it "should fail if the path is not readable" do FileTest.expects(:directory?).returns(true) FileTest.expects(:readable?).returns(false) proc { @mount.path = @dir }.should raise_error(ArgumentError) end end describe Puppet::FileServing::Mount::File, " when substituting hostnames and ip addresses into file paths" do include FileServingMountTesting before do FileTest.stubs(:directory?).returns(true) FileTest.stubs(:readable?).returns(true) @mount = Puppet::FileServing::Mount::File.new("test") @host = "host.domain.com" end it "should replace incidences of %h in the path with the client's short name" do @mount.path = "/dir/%h/yay" @mount.path(@host).should == "/dir/host/yay" end it "should replace incidences of %H in the path with the client's fully qualified name" do @mount.path = "/dir/%H/yay" @mount.path(@host).should == "/dir/host.domain.com/yay" end it "should replace incidences of %d in the path with the client's domain name" do @mount.path = "/dir/%d/yay" @mount.path(@host).should == "/dir/domain.com/yay" end it "should perform all necessary replacements" do @mount.path = "/%h/%d/%H" @mount.path(@host).should == "/host/domain.com/host.domain.com" end it "should use local host information if no client data is provided" do stub_facter("myhost.mydomain.com") @mount.path = "/%h/%d/%H" @mount.path.should == "/myhost/mydomain.com/myhost.mydomain.com" end after do Puppet::Util::Cacher.expire end end describe Puppet::FileServing::Mount::File, "when determining the complete file path" do include FileServingMountTesting before do FileTest.stubs(:exist?).returns(true) FileTest.stubs(:directory?).returns(true) FileTest.stubs(:readable?).returns(true) @mount = Puppet::FileServing::Mount::File.new("test") @mount.path = "/mount" stub_facter("myhost.mydomain.com") @host = "host.domain.com" end it "should return nil if the file is absent" do FileTest.stubs(:exist?).returns(false) @mount.complete_path("/my/path", nil).should be_nil end it "should write a log message if the file is absent" do FileTest.stubs(:exist?).returns(false) Puppet.expects(:info).with("File does not exist or is not accessible: /mount/my/path") @mount.complete_path("/my/path", nil) end it "should return the file path if the file is present" do FileTest.stubs(:exist?).with("/my/path").returns(true) @mount.complete_path("/my/path", nil).should == "/mount/my/path" end it "should treat a nil file name as the path to the mount itself" do FileTest.stubs(:exist?).returns(true) @mount.complete_path(nil, nil).should == "/mount" end it "should use the client host name if provided in the options" do @mount.path = "/mount/%h" @mount.complete_path("/my/path", @host).should == "/mount/host/my/path" end it "should perform replacements on the base path" do @mount.path = "/blah/%h" @mount.complete_path("/my/stuff", @host).should == "/blah/host/my/stuff" end it "should not perform replacements on the per-file path" do @mount.path = "/blah" @mount.complete_path("/%h/stuff", @host).should == "/blah/%h/stuff" end it "should look for files relative to its base directory" do @mount.complete_path("/my/stuff", @host).should == "/mount/my/stuff" end end describe Puppet::FileServing::Mount::File, "when finding files" do include FileServingMountTesting before do FileTest.stubs(:exist?).returns(true) FileTest.stubs(:directory?).returns(true) FileTest.stubs(:readable?).returns(true) @mount = Puppet::FileServing::Mount::File.new("test") @mount.path = "/mount" stub_facter("myhost.mydomain.com") @host = "host.domain.com" @request = stub 'request', :node => "foo" end it "should return the results of the complete file path" do FileTest.stubs(:exist?).returns(false) @mount.expects(:complete_path).with("/my/path", "foo").returns "eh" @mount.find("/my/path", @request).should == "eh" end end describe Puppet::FileServing::Mount::File, "when searching for files" do include FileServingMountTesting before do FileTest.stubs(:exist?).returns(true) FileTest.stubs(:directory?).returns(true) FileTest.stubs(:readable?).returns(true) @mount = Puppet::FileServing::Mount::File.new("test") @mount.path = "/mount" stub_facter("myhost.mydomain.com") @host = "host.domain.com" @request = stub 'request', :node => "foo" end it "should return the results of the complete file path as an array" do FileTest.stubs(:exist?).returns(false) @mount.expects(:complete_path).with("/my/path", "foo").returns "eh" @mount.search("/my/path", @request).should == ["eh"] end it "should return nil if the complete path is nil" do FileTest.stubs(:exist?).returns(false) @mount.expects(:complete_path).with("/my/path", "foo").returns nil @mount.search("/my/path", @request).should be_nil end end diff --git a/spec/unit/file_serving/mount/modules_spec.rb b/spec/unit/file_serving/mount/modules_spec.rb index 27c56e6f8..2d582daa2 100755 --- a/spec/unit/file_serving/mount/modules_spec.rb +++ b/spec/unit/file_serving/mount/modules_spec.rb @@ -1,63 +1,62 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/file_serving/mount/modules' describe Puppet::FileServing::Mount::Modules do before do @mount = Puppet::FileServing::Mount::Modules.new("modules") @environment = stub 'environment', :module => nil @request = stub 'request', :environment => @environment end describe "when finding files" do it "should use the provided environment to find the module" do @environment.expects(:module) @mount.find("foo", @request) end it "should treat the first field of the relative path as the module name" do @environment.expects(:module).with("foo") @mount.find("foo/bar/baz", @request) end it "should return nil if the specified module does not exist" do @environment.expects(:module).with("foo").returns nil @mount.find("foo/bar/baz", @request) end it "should return the file path from the module" do mod = mock 'module' mod.expects(:file).with("bar/baz").returns "eh" @environment.expects(:module).with("foo").returns mod @mount.find("foo/bar/baz", @request).should == "eh" end end describe "when searching for files" do it "should use the node's environment to search the module" do @environment.expects(:module) @mount.search("foo", @request) end it "should treat the first field of the relative path as the module name" do @environment.expects(:module).with("foo") @mount.search("foo/bar/baz", @request) end it "should return nil if the specified module does not exist" do @environment.expects(:module).with("foo").returns nil @mount.search("foo/bar/baz", @request) end it "should return the file path as an array from the module" do mod = mock 'module' mod.expects(:file).with("bar/baz").returns "eh" @environment.expects(:module).with("foo").returns mod @mount.search("foo/bar/baz", @request).should == ["eh"] end end end diff --git a/spec/unit/file_serving/mount/plugins_spec.rb b/spec/unit/file_serving/mount/plugins_spec.rb index 0ba8d489e..b6bed72a0 100755 --- a/spec/unit/file_serving/mount/plugins_spec.rb +++ b/spec/unit/file_serving/mount/plugins_spec.rb @@ -1,61 +1,60 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/file_serving/mount/plugins' describe Puppet::FileServing::Mount::Plugins do before do @mount = Puppet::FileServing::Mount::Plugins.new("plugins") @environment = stub 'environment', :module => nil @request = stub 'request', :environment => @environment end describe "when finding files" do it "should use the provided environment to find the modules" do @environment.expects(:modules).returns [] @mount.find("foo", @request) end it "should return nil if no module can be found with a matching plugin" do mod = mock 'module' mod.stubs(:plugin).with("foo/bar").returns nil @environment.stubs(:modules).returns [mod] @mount.find("foo/bar", @request).should be_nil end it "should return the file path from the module" do mod = mock 'module' mod.stubs(:plugin).with("foo/bar").returns "eh" @environment.stubs(:modules).returns [mod] @mount.find("foo/bar", @request).should == "eh" end end describe "when searching for files" do it "should use the node's environment to find the modules" do @environment.expects(:modules).returns [] @mount.search("foo", @request) end it "should return nil if no modules can be found that have plugins" do mod = mock 'module' mod.stubs(:plugins?).returns false @environment.stubs(:modules).returns [] @mount.search("foo/bar", @request).should be_nil end it "should return the plugin paths for each module that has plugins" do one = stub 'module', :plugins? => true, :plugin_directory => "/one" two = stub 'module', :plugins? => true, :plugin_directory => "/two" @environment.stubs(:modules).returns [one, two] @mount.search("foo/bar", @request).should == %w{/one /two} end end end diff --git a/spec/unit/file_serving/mount_spec.rb b/spec/unit/file_serving/mount_spec.rb index 1586984de..5d8e64f82 100755 --- a/spec/unit/file_serving/mount_spec.rb +++ b/spec/unit/file_serving/mount_spec.rb @@ -1,32 +1,31 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/file_serving/mount' describe Puppet::FileServing::Mount do it "should use 'mount[$name]' as its string form" do Puppet::FileServing::Mount.new("foo").to_s.should == "mount[foo]" end end describe Puppet::FileServing::Mount, " when initializing" do it "should fail on non-alphanumeric name" do proc { Puppet::FileServing::Mount.new("non alpha") }.should raise_error(ArgumentError) end it "should allow dashes in its name" do Puppet::FileServing::Mount.new("non-alpha").name.should == "non-alpha" end end describe Puppet::FileServing::Mount, " when finding files" do it "should fail" do lambda { Puppet::FileServing::Mount.new("test").find("foo", :one => "two") }.should raise_error(NotImplementedError) end end describe Puppet::FileServing::Mount, " when searching for files" do it "should fail" do lambda { Puppet::FileServing::Mount.new("test").search("foo", :one => "two") }.should raise_error(NotImplementedError) end end diff --git a/spec/unit/file_serving/terminus_helper_spec.rb b/spec/unit/file_serving/terminus_helper_spec.rb index cd669109f..7efe3fb98 100755 --- a/spec/unit/file_serving/terminus_helper_spec.rb +++ b/spec/unit/file_serving/terminus_helper_spec.rb @@ -1,98 +1,98 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Created by Luke Kanies on 2007-10-22. # Copyright (c) 2007. All rights reserved. require 'spec_helper' require 'puppet/file_serving/terminus_helper' describe Puppet::FileServing::TerminusHelper do before do @helper = Object.new @helper.extend(Puppet::FileServing::TerminusHelper) @model = mock 'model' @helper.stubs(:model).returns(@model) @request = stub 'request', :key => "url", :options => {} @fileset = stub 'fileset', :files => [], :path => "/my/file" Puppet::FileServing::Fileset.stubs(:new).with("/my/file", {}).returns(@fileset) end it "should use a fileset to find paths" do @fileset = stub 'fileset', :files => [], :path => "/my/files" Puppet::FileServing::Fileset.expects(:new).with { |key, options| key == "/my/file" }.returns(@fileset) @helper.path2instances(@request, "/my/file") end it "should support finding across multiple paths by merging the filesets" do first = stub 'fileset', :files => [], :path => "/first/file" Puppet::FileServing::Fileset.expects(:new).with { |path, options| path == "/first/file" }.returns(first) second = stub 'fileset', :files => [], :path => "/second/file" Puppet::FileServing::Fileset.expects(:new).with { |path, options| path == "/second/file" }.returns(second) Puppet::FileServing::Fileset.expects(:merge).with(first, second).returns({}) @helper.path2instances(@request, "/first/file", "/second/file") end it "should pass the indirection request to the Fileset at initialization" do Puppet::FileServing::Fileset.expects(:new).with { |path, options| options == @request }.returns @fileset @helper.path2instances(@request, "/my/file") end describe "when creating instances" do before do @request.stubs(:key).returns "puppet://host/mount/dir" @one = stub 'one', :links= => nil, :collect => nil @two = stub 'two', :links= => nil, :collect => nil @fileset = stub 'fileset', :files => %w{one two}, :path => "/my/file" Puppet::FileServing::Fileset.stubs(:new).returns(@fileset) end it "should set each returned instance's path to the original path" do @model.expects(:new).with { |key, options| key == "/my/file" }.returns(@one) @model.expects(:new).with { |key, options| key == "/my/file" }.returns(@two) @helper.path2instances(@request, "/my/file") end it "should set each returned instance's relative path to the file-specific path" do @model.expects(:new).with { |key, options| options[:relative_path] == "one" }.returns(@one) @model.expects(:new).with { |key, options| options[:relative_path] == "two" }.returns(@two) @helper.path2instances(@request, "/my/file") end it "should set the links value on each instance if one is provided" do @one.expects(:links=).with :manage @two.expects(:links=).with :manage @model.expects(:new).returns(@one) @model.expects(:new).returns(@two) @request.options[:links] = :manage @helper.path2instances(@request, "/my/file") end it "should set the request checksum_type if one is provided" do @one.expects(:checksum_type=).with :test @two.expects(:checksum_type=).with :test @model.expects(:new).returns(@one) @model.expects(:new).returns(@two) @request.options[:checksum_type] = :test @helper.path2instances(@request, "/my/file") end it "should collect the instance's attributes" do @one.expects(:collect) @two.expects(:collect) @model.expects(:new).returns(@one) @model.expects(:new).returns(@two) @helper.path2instances(@request, "/my/file") end end end diff --git a/spec/unit/indirector/active_record_spec.rb b/spec/unit/indirector/active_record_spec.rb index 376822c9d..2baef33fe 100755 --- a/spec/unit/indirector/active_record_spec.rb +++ b/spec/unit/indirector/active_record_spec.rb @@ -1,76 +1,75 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/rails' require 'puppet/indirector/active_record' describe Puppet::Indirector::ActiveRecord do before do Puppet::Rails.stubs(:init) Puppet::Indirector::Terminus.stubs(:register_terminus_class) @model = mock 'model' @indirection = stub 'indirection', :name => :mystuff, :register_terminus_type => nil, :model => @model Puppet::Indirector::Indirection.stubs(:instance).returns(@indirection) module Testing; end @active_record_class = class Testing::MyActiveRecord < Puppet::Indirector::ActiveRecord self end @ar_model = mock 'ar_model' @active_record_class.use_ar_model @ar_model @terminus = @active_record_class.new @name = "me" @instance = stub 'instance', :name => @name @request = stub 'request', :key => @name, :instance => @instance end it "should allow declaration of an ActiveRecord model to use" do @active_record_class.use_ar_model "foo" @active_record_class.ar_model.should == "foo" end describe "when initializing" do it "should init Rails" do Puppet::Rails.expects(:init) @active_record_class.new end end describe "when finding an instance" do it "should use the ActiveRecord model to find the instance" do @ar_model.expects(:find_by_name).with(@name) @terminus.find(@request) end it "should return nil if no instance is found" do @ar_model.expects(:find_by_name).with(@name).returns nil @terminus.find(@request).should be_nil end it "should convert the instance to a Puppet object if it is found" do instance = mock 'rails_instance' instance.expects(:to_puppet).returns "mypuppet" @ar_model.expects(:find_by_name).with(@name).returns instance @terminus.find(@request).should == "mypuppet" end end describe "when saving an instance" do it "should use the ActiveRecord model to convert the instance into a Rails object and then save that rails object" do rails_object = mock 'rails_object' @ar_model.expects(:from_puppet).with(@instance).returns rails_object rails_object.expects(:save) @terminus.save(@request) end end end diff --git a/spec/unit/indirector/catalog/active_record_spec.rb b/spec/unit/indirector/catalog/active_record_spec.rb index ddf6548fb..35d01179b 100755 --- a/spec/unit/indirector/catalog/active_record_spec.rb +++ b/spec/unit/indirector/catalog/active_record_spec.rb @@ -1,157 +1,156 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe "Puppet::Resource::Catalog::ActiveRecord", :if => Puppet.features.rails? do require 'puppet/rails' before :all do class Tableless < ActiveRecord::Base def self.columns @columns ||= [] end def self.column(name, sql_type=nil, default=nil, null=true) columns << ActiveRecord::ConnectionAdapters::Column.new(name.to_s, default, sql_type.to_s, null) end end class Host < Tableless column :name, :string, :null => false column :ip, :string column :environment, :string column :last_compile, :datetime end end before do require 'puppet/indirector/catalog/active_record' Puppet.features.stubs(:rails?).returns true Puppet::Rails.stubs(:init) @terminus = Puppet::Resource::Catalog::ActiveRecord.new end it "should be a subclass of the ActiveRecord terminus class" do Puppet::Resource::Catalog::ActiveRecord.ancestors.should be_include(Puppet::Indirector::ActiveRecord) end it "should use Puppet::Rails::Host as its ActiveRecord model" do Puppet::Resource::Catalog::ActiveRecord.ar_model.should equal(Puppet::Rails::Host) end describe "when finding an instance" do before do @request = stub 'request', :key => "foo", :options => {:cache_integration_hack => true} end # This hack is here because we don't want to look in the db unless we actually want # to look in the db, but our indirection architecture in 0.24.x isn't flexible # enough to tune that via configuration. it "should return nil unless ':cache_integration_hack' is set to true" do @request.options[:cache_integration_hack] = false Puppet::Rails::Host.expects(:find_by_name).never @terminus.find(@request).should be_nil end it "should use the Hosts ActiveRecord class to find the host" do Puppet::Rails::Host.expects(:find_by_name).with { |key, args| key == "foo" } @terminus.find(@request) end it "should return nil if no host instance can be found" do Puppet::Rails::Host.expects(:find_by_name).returns nil @terminus.find(@request).should be_nil end it "should return a catalog with the same name as the host if the host can be found" do host = stub 'host', :name => "foo", :resources => [] Puppet::Rails::Host.expects(:find_by_name).returns host result = @terminus.find(@request) result.should be_instance_of(Puppet::Resource::Catalog) result.name.should == "foo" end it "should set each of the host's resources as a transportable resource within the catalog" do host = stub 'host', :name => "foo" Puppet::Rails::Host.expects(:find_by_name).returns host res1 = mock 'res1', :to_transportable => "trans_res1" res2 = mock 'res2', :to_transportable => "trans_res2" host.expects(:resources).returns [res1, res2] catalog = stub 'catalog' Puppet::Resource::Catalog.expects(:new).returns catalog catalog.expects(:add_resource).with "trans_res1" catalog.expects(:add_resource).with "trans_res2" @terminus.find(@request) end end describe "when saving an instance" do before do @host = Host.new(:name => "foo") @host.stubs(:merge_resources) @host.stubs(:save) @host.stubs(:railsmark).yields @node = Puppet::Node.new("foo", :environment => "environment") Puppet::Node.indirection.stubs(:find).with("foo").returns(@node) Puppet::Rails::Host.stubs(:find_by_name).returns @host @catalog = Puppet::Resource::Catalog.new("foo") @request = Puppet::Indirector::Request.new(:active_record, :save, @catalog) end it "should find the Rails host with the same name" do Puppet::Rails::Host.expects(:find_by_name).with("foo").returns @host @terminus.save(@request) end it "should create a new Rails host if none can be found" do Puppet::Rails::Host.expects(:find_by_name).with("foo").returns nil Puppet::Rails::Host.expects(:create).with(:name => "foo").returns @host @terminus.save(@request) end it "should set the catalog vertices as resources on the Rails host instance" do @catalog.expects(:vertices).returns "foo" @host.expects(:merge_resources).with("foo") @terminus.save(@request) end it "should set host ip if we could find a matching node" do @node.stubs(:parameters).returns({"ipaddress" => "192.168.0.1"}) @terminus.save(@request) @host.ip.should == '192.168.0.1' end it "should set host environment if we could find a matching node" do @terminus.save(@request) @host.environment.should == "environment" end it "should set the last compile time on the host" do now = Time.now Time.expects(:now).returns now @terminus.save(@request) @host.last_compile.should == now end it "should save the Rails host instance" do @host.expects(:save) @terminus.save(@request) end end end diff --git a/spec/unit/indirector/catalog/compiler_spec.rb b/spec/unit/indirector/catalog/compiler_spec.rb index f6cb8f7bb..cd84031e5 100755 --- a/spec/unit/indirector/catalog/compiler_spec.rb +++ b/spec/unit/indirector/catalog/compiler_spec.rb @@ -1,283 +1,283 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Created by Luke Kanies on 2007-9-23. # Copyright (c) 2007. All rights reserved. require 'spec_helper' require 'puppet/indirector/catalog/compiler' require 'puppet/rails' describe Puppet::Resource::Catalog::Compiler do before do require 'puppet/rails' Puppet::Rails.stubs(:init) Facter.stubs(:to_hash).returns({}) Facter.stubs(:value).returns(Facter::Util::Fact.new("something")) end describe "when initializing" do before do Puppet.expects(:version).returns(1) Facter.expects(:value).with('fqdn').returns("my.server.com") Facter.expects(:value).with('ipaddress').returns("my.ip.address") end it "should gather data about itself" do Puppet::Resource::Catalog::Compiler.new end it "should cache the server metadata and reuse it" do compiler = Puppet::Resource::Catalog::Compiler.new node1 = stub 'node1', :merge => nil node2 = stub 'node2', :merge => nil compiler.stubs(:compile) Puppet::Node.indirection.stubs(:find).with('node1').returns(node1) Puppet::Node.indirection.stubs(:find).with('node2').returns(node2) compiler.find(stub('request', :key => 'node1', :node => 'node1', :options => {})) compiler.find(stub('node2request', :key => 'node2', :node => 'node2', :options => {})) end it "should provide a method for determining if the catalog is networked" do compiler = Puppet::Resource::Catalog::Compiler.new compiler.should respond_to(:networked?) end describe "and storeconfigs is enabled" do before do Puppet.settings.expects(:value).with(:storeconfigs).returns true end it "should initialize Rails if it is available" do Puppet.features.expects(:rails?).returns true Puppet::Rails.expects(:init) Puppet::Resource::Catalog::Compiler.new end it "should fail if Rails is unavailable" do Puppet.features.expects(:rails?).returns false Puppet::Rails.expects(:init).never lambda { Puppet::Resource::Catalog::Compiler.new }.should raise_error(Puppet::Error) end end end describe "when finding catalogs" do before do Facter.stubs(:value).returns("whatever") @compiler = Puppet::Resource::Catalog::Compiler.new @name = "me" @node = Puppet::Node.new @name @node.stubs(:merge) Puppet::Node.indirection.stubs(:find).returns @node @request = stub 'request', :key => @name, :node => @name, :options => {} end it "should directly use provided nodes" do Puppet::Node.indirection.expects(:find).never @compiler.expects(:compile).with(@node) @request.stubs(:options).returns(:use_node => @node) @compiler.find(@request) end it "should use the authenticated node name if no request key is provided" do @request.stubs(:key).returns(nil) Puppet::Node.indirection.expects(:find).with(@name).returns(@node) @compiler.expects(:compile).with(@node) @compiler.find(@request) end it "should use the provided node name by default" do @request.expects(:key).returns "my_node" Puppet::Node.indirection.expects(:find).with("my_node").returns @node @compiler.expects(:compile).with(@node) @compiler.find(@request) end it "should fail if no node is passed and none can be found" do Puppet::Node.indirection.stubs(:find).with(@name).returns(nil) proc { @compiler.find(@request) }.should raise_error(ArgumentError) end it "should fail intelligently when searching for a node raises an exception" do Puppet::Node.indirection.stubs(:find).with(@name).raises "eh" proc { @compiler.find(@request) }.should raise_error(Puppet::Error) end it "should pass the found node to the compiler for compiling" do Puppet::Node.indirection.expects(:find).with(@name).returns(@node) config = mock 'config' Puppet::Parser::Compiler.expects(:compile).with(@node) @compiler.find(@request) end it "should extract and save any facts from the request" do Puppet::Node.indirection.expects(:find).with(@name).returns @node @compiler.expects(:extract_facts_from_request).with(@request) Puppet::Parser::Compiler.stubs(:compile) @compiler.find(@request) end it "should return the results of compiling as the catalog" do Puppet::Node.indirection.stubs(:find).returns(@node) config = mock 'config' result = mock 'result' Puppet::Parser::Compiler.expects(:compile).returns result @compiler.find(@request).should equal(result) end it "should benchmark the compile process" do Puppet::Node.indirection.stubs(:find).returns(@node) @compiler.stubs(:networked?).returns(true) @compiler.expects(:benchmark).with do |level, message| level == :notice and message =~ /^Compiled catalog/ end Puppet::Parser::Compiler.stubs(:compile) @compiler.find(@request) end it "should log the benchmark result" do Puppet::Node.indirection.stubs(:find).returns(@node) @compiler.stubs(:networked?).returns(true) Puppet::Parser::Compiler.stubs(:compile) Puppet.expects(:notice).with { |msg| msg =~ /Compiled catalog/ } @compiler.find(@request) end end describe "when extracting facts from the request" do before do Facter.stubs(:value).returns "something" @compiler = Puppet::Resource::Catalog::Compiler.new @request = stub 'request', :options => {} @facts = Puppet::Node::Facts.new('hostname', "fact" => "value", "architecture" => "i386") Puppet::Node::Facts.indirection.stubs(:save).returns(nil) end it "should do nothing if no facts are provided" do Puppet::Node::Facts.indirection.expects(:convert_from).never @request.options[:facts] = nil @compiler.extract_facts_from_request(@request) end it "should use the Facts class to deserialize the provided facts and update the timestamp" do @request.options[:facts_format] = "foo" @request.options[:facts] = "bar" Puppet::Node::Facts.expects(:convert_from).returns @facts @facts.timestamp = Time.parse('2010-11-01') @now = Time.parse('2010-11-02') Time.expects(:now).returns(@now) @compiler.extract_facts_from_request(@request) @facts.timestamp.should == @now end it "should use the provided fact format" do @request.options[:facts_format] = "foo" @request.options[:facts] = "bar" Puppet::Node::Facts.expects(:convert_from).with { |format, text| format == "foo" }.returns @facts @compiler.extract_facts_from_request(@request) end it "should convert the facts into a fact instance and save it" do @request.options[:facts_format] = "foo" @request.options[:facts] = "bar" Puppet::Node::Facts.expects(:convert_from).returns @facts Puppet::Node::Facts.indirection.expects(:save).with(@facts) @compiler.extract_facts_from_request(@request) end end describe "when finding nodes" do before do Facter.stubs(:value).returns("whatever") @compiler = Puppet::Resource::Catalog::Compiler.new @name = "me" @node = mock 'node' @request = stub 'request', :key => @name, :options => {} @compiler.stubs(:compile) end it "should look node information up via the Node class with the provided key" do @node.stubs :merge Puppet::Node.indirection.expects(:find).with(@name).returns(@node) @compiler.find(@request) end end describe "after finding nodes" do before do Puppet.expects(:version).returns(1) Facter.expects(:value).with('fqdn').returns("my.server.com") Facter.expects(:value).with('ipaddress').returns("my.ip.address") @compiler = Puppet::Resource::Catalog::Compiler.new @name = "me" @node = mock 'node' @request = stub 'request', :key => @name, :options => {} @compiler.stubs(:compile) Puppet::Node.indirection.stubs(:find).with(@name).returns(@node) end it "should add the server's Puppet version to the node's parameters as 'serverversion'" do @node.expects(:merge).with { |args| args["serverversion"] == "1" } @compiler.find(@request) end it "should add the server's fqdn to the node's parameters as 'servername'" do @node.expects(:merge).with { |args| args["servername"] == "my.server.com" } @compiler.find(@request) end it "should add the server's IP address to the node's parameters as 'serverip'" do @node.expects(:merge).with { |args| args["serverip"] == "my.ip.address" } @compiler.find(@request) end end describe "when filtering resources" do before :each do Facter.stubs(:value) @compiler = Puppet::Resource::Catalog::Compiler.new @catalog = stub_everything 'catalog' @catalog.stubs(:respond_to?).with(:filter).returns(true) end it "should delegate to the catalog instance filtering" do @catalog.expects(:filter) @compiler.filter(@catalog) end it "should filter out virtual resources" do resource = mock 'resource', :virtual? => true @catalog.stubs(:filter).yields(resource) @compiler.filter(@catalog) end it "should return the same catalog if it doesn't support filtering" do @catalog.stubs(:respond_to?).with(:filter).returns(false) @compiler.filter(@catalog).should == @catalog end it "should return the filtered catalog" do catalog = stub 'filtered catalog' @catalog.stubs(:filter).returns(catalog) @compiler.filter(@catalog).should == catalog end end end diff --git a/spec/unit/indirector/catalog/queue_spec.rb b/spec/unit/indirector/catalog/queue_spec.rb index 5b24bee1a..d396ad897 100755 --- a/spec/unit/indirector/catalog/queue_spec.rb +++ b/spec/unit/indirector/catalog/queue_spec.rb @@ -1,20 +1,19 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/indirector/catalog/queue' describe Puppet::Resource::Catalog::Queue do it 'should be a subclass of the Queue terminus' do Puppet::Resource::Catalog::Queue.superclass.should equal(Puppet::Indirector::Queue) end it 'should be registered with the catalog store indirection' do indirection = Puppet::Indirector::Indirection.instance(:catalog) Puppet::Resource::Catalog::Queue.indirection.should equal(indirection) end it 'shall be dubbed ":queue"' do Puppet::Resource::Catalog::Queue.name.should == :queue end end diff --git a/spec/unit/indirector/catalog/rest_spec.rb b/spec/unit/indirector/catalog/rest_spec.rb index 498084dce..3e674dde9 100755 --- a/spec/unit/indirector/catalog/rest_spec.rb +++ b/spec/unit/indirector/catalog/rest_spec.rb @@ -1,11 +1,10 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/indirector/catalog/rest' describe Puppet::Resource::Catalog::Rest do it "should be a sublcass of Puppet::Indirector::REST" do Puppet::Resource::Catalog::Rest.superclass.should equal(Puppet::Indirector::REST) end end diff --git a/spec/unit/indirector/catalog/yaml_spec.rb b/spec/unit/indirector/catalog/yaml_spec.rb index 1c6fb7df3..ddaa173c6 100755 --- a/spec/unit/indirector/catalog/yaml_spec.rb +++ b/spec/unit/indirector/catalog/yaml_spec.rb @@ -1,25 +1,24 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/resource/catalog' require 'puppet/indirector/catalog/yaml' describe Puppet::Resource::Catalog::Yaml do it "should be a subclass of the Yaml terminus" do Puppet::Resource::Catalog::Yaml.superclass.should equal(Puppet::Indirector::Yaml) end it "should have documentation" do Puppet::Resource::Catalog::Yaml.doc.should_not be_nil end it "should be registered with the catalog store indirection" do indirection = Puppet::Indirector::Indirection.instance(:catalog) Puppet::Resource::Catalog::Yaml.indirection.should equal(indirection) end it "should have its name set to :yaml" do Puppet::Resource::Catalog::Yaml.name.should == :yaml end end diff --git a/spec/unit/indirector/certificate/ca_spec.rb b/spec/unit/indirector/certificate/ca_spec.rb index 2dc4f48e0..277d2209d 100755 --- a/spec/unit/indirector/certificate/ca_spec.rb +++ b/spec/unit/indirector/certificate/ca_spec.rb @@ -1,28 +1,28 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Created by Luke Kanies on 2008-3-7. # Copyright (c) 2007. All rights reserved. require 'spec_helper' require 'puppet/indirector/certificate/ca' describe Puppet::SSL::Certificate::Ca do it "should have documentation" do Puppet::SSL::Certificate::Ca.doc.should be_instance_of(String) end it "should use the :signeddir as the collection directory" do Puppet.settings.expects(:value).with(:signeddir).returns "/cert/dir" Puppet::SSL::Certificate::Ca.collection_directory.should == "/cert/dir" end it "should store the ca certificate at the :cacert location" do Puppet.settings.stubs(:use) Puppet.settings.stubs(:value).returns "whatever" Puppet.settings.stubs(:value).with(:cacert).returns "/ca/cert" file = Puppet::SSL::Certificate::Ca.new file.stubs(:ca?).returns true file.path("whatever").should == "/ca/cert" end end diff --git a/spec/unit/indirector/certificate/file_spec.rb b/spec/unit/indirector/certificate/file_spec.rb index e1960b8ec..f398e1115 100755 --- a/spec/unit/indirector/certificate/file_spec.rb +++ b/spec/unit/indirector/certificate/file_spec.rb @@ -1,28 +1,28 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Created by Luke Kanies on 2008-3-7. # Copyright (c) 2007. All rights reserved. require 'spec_helper' require 'puppet/indirector/certificate/file' describe Puppet::SSL::Certificate::File do it "should have documentation" do Puppet::SSL::Certificate::File.doc.should be_instance_of(String) end it "should use the :certdir as the collection directory" do Puppet.settings.expects(:value).with(:certdir).returns "/cert/dir" Puppet::SSL::Certificate::File.collection_directory.should == "/cert/dir" end it "should store the ca certificate at the :localcacert location" do Puppet.settings.stubs(:use) Puppet.settings.stubs(:value).returns "whatever" Puppet.settings.stubs(:value).with(:localcacert).returns "/ca/cert" file = Puppet::SSL::Certificate::File.new file.stubs(:ca?).returns true file.path("whatever").should == "/ca/cert" end end diff --git a/spec/unit/indirector/certificate/rest_spec.rb b/spec/unit/indirector/certificate/rest_spec.rb index 6efd50207..21e10e316 100755 --- a/spec/unit/indirector/certificate/rest_spec.rb +++ b/spec/unit/indirector/certificate/rest_spec.rb @@ -1,58 +1,57 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/indirector/certificate/rest' describe Puppet::SSL::Certificate::Rest do before do @searcher = Puppet::SSL::Certificate::Rest.new end it "should be a sublcass of Puppet::Indirector::REST" do Puppet::SSL::Certificate::Rest.superclass.should equal(Puppet::Indirector::REST) end it "should set server_setting to :ca_server" do Puppet::SSL::Certificate::Rest.server_setting.should == :ca_server end it "should set port_setting to :ca_port" do Puppet::SSL::Certificate::Rest.port_setting.should == :ca_port end it "should make sure found certificates have their names set to the search string" do terminus = Puppet::SSL::Certificate::Rest.new # This has 'boo.com' in the CN cert_string = "-----BEGIN CERTIFICATE----- MIICPzCCAaigAwIBAgIBBDANBgkqhkiG9w0BAQUFADAWMRQwEgYDVQQDDAtidWNr eS5sb2NhbDAeFw0wOTA5MTcxNzI1MzJaFw0xNDA5MTYxNzI1MzJaMBIxEDAOBgNV BAMMB2Jvby5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKG9B+DkTCNh F5xHchNDfnbC9NzWKM600oxrr84pgUVAG6B2wAZcdfoEtXszhsY9Jzpwqkvxk4Mx AbYqo9+TCi4UoiH6e+vAKOOJD3DHrlf+/RW4hGtyaI41DBhf4+B4/oFz5PH9mvKe NSfHFI/yPW+1IXYjxKLQNwF9E7q3JbnzAgMBAAGjgaAwgZ0wOAYJYIZIAYb4QgEN BCsWKVB1cHBldCBSdWJ5L09wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMAwG A1UdEwEB/wQCMAAwHQYDVR0OBBYEFJOxEUeyf4cNOBmf9zIaE1JTuNdLMAsGA1Ud DwQEAwIFoDAnBgNVHSUEIDAeBggrBgEFBQcDAQYIKwYBBQUHAwIGCCsGAQUFBwME MA0GCSqGSIb3DQEBBQUAA4GBAFTJxKprMg6tfhGnvEvURPmlJrINn9c2b5Y4AGYp tO86PFFkWw/EIJvvJzbj3s+Butr+eUo//+f1xxX7UCwwGqGxKqjtVS219oU/wkx8 h7rW4Xk7MrLl0auSS1p4wLcAMm+ZImf94+j8Cj+tkr8eGozZceRV13b8+EkdaE3S rn/G -----END CERTIFICATE----- " network = stub 'network' terminus.stubs(:network).returns network response = stub 'response', :code => "200", :body => cert_string response.stubs(:[]).with('content-type').returns "text/plain" response.stubs(:[]).with('content-encoding') network.expects(:get).returns response request = Puppet::Indirector::Request.new(:certificate, :find, "foo.com") result = terminus.find(request) result.should_not be_nil result.name.should == "foo.com" end end diff --git a/spec/unit/indirector/certificate_request/ca_spec.rb b/spec/unit/indirector/certificate_request/ca_spec.rb index 08055e08b..ebd64a2fb 100755 --- a/spec/unit/indirector/certificate_request/ca_spec.rb +++ b/spec/unit/indirector/certificate_request/ca_spec.rb @@ -1,64 +1,64 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Created by Luke Kanies on 2008-3-7. # Copyright (c) 2007. All rights reserved. require 'spec_helper' require 'puppet/ssl/host' require 'puppet/sslcertificates' require 'puppet/sslcertificates/ca' require 'puppet/indirector/certificate_request/ca' describe Puppet::SSL::CertificateRequest::Ca do include PuppetSpec::Files before :each do Puppet[:ssldir] = tmpdir('ssl') Puppet::SSL::Host.ca_location = :local Puppet[:localcacert] = Puppet[:cacert] Puppet::SSLCertificates::CA.new.mkrootcert @ca = Puppet::SSL::CertificateAuthority.new end after :all do Puppet::SSL::Host.ca_location = :none end it "should have documentation" do Puppet::SSL::CertificateRequest::Ca.doc.should be_instance_of(String) end it "should use the :csrdir as the collection directory" do Puppet.settings.expects(:value).with(:csrdir).returns "/request/dir" Puppet::SSL::CertificateRequest::Ca.collection_directory.should == "/request/dir" end it "should overwrite the previous certificate request if allow_duplicate_certs is true" do Puppet[:allow_duplicate_certs] = true host = Puppet::SSL::Host.new("foo") host.generate_certificate_request @ca.sign(host.name) Puppet::SSL::Host.indirection.find("foo").generate_certificate_request Puppet::SSL::Certificate.indirection.find("foo").name.should == "foo" Puppet::SSL::CertificateRequest.indirection.find("foo").name.should == "foo" Puppet::SSL::Host.indirection.find("foo").state.should == "requested" end it "should reject a new certificate request if allow_duplicate_certs is false" do Puppet[:allow_duplicate_certs] = false host = Puppet::SSL::Host.new("bar") host.generate_certificate_request @ca.sign(host.name) expect { Puppet::SSL::Host.indirection.find("bar").generate_certificate_request }.should raise_error(/ignoring certificate request/) Puppet::SSL::Certificate.indirection.find("bar").name.should == "bar" Puppet::SSL::CertificateRequest.indirection.find("bar").should be_nil Puppet::SSL::Host.indirection.find("bar").state.should == "signed" end end diff --git a/spec/unit/indirector/certificate_request/file_spec.rb b/spec/unit/indirector/certificate_request/file_spec.rb index c7a565491..69dc5eb9c 100755 --- a/spec/unit/indirector/certificate_request/file_spec.rb +++ b/spec/unit/indirector/certificate_request/file_spec.rb @@ -1,19 +1,19 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Created by Luke Kanies on 2008-3-7. # Copyright (c) 2007. All rights reserved. require 'spec_helper' require 'puppet/indirector/certificate_request/file' describe Puppet::SSL::CertificateRequest::File do it "should have documentation" do Puppet::SSL::CertificateRequest::File.doc.should be_instance_of(String) end it "should use the :requestdir as the collection directory" do Puppet.settings.expects(:value).with(:requestdir).returns "/request/dir" Puppet::SSL::CertificateRequest::File.collection_directory.should == "/request/dir" end end diff --git a/spec/unit/indirector/certificate_request/rest_spec.rb b/spec/unit/indirector/certificate_request/rest_spec.rb index 6e940b1f9..398b91b84 100755 --- a/spec/unit/indirector/certificate_request/rest_spec.rb +++ b/spec/unit/indirector/certificate_request/rest_spec.rb @@ -1,23 +1,22 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/indirector/certificate_request/rest' describe Puppet::SSL::CertificateRequest::Rest do before do @searcher = Puppet::SSL::CertificateRequest::Rest.new end it "should be a sublcass of Puppet::Indirector::REST" do Puppet::SSL::CertificateRequest::Rest.superclass.should equal(Puppet::Indirector::REST) end it "should set server_setting to :ca_server" do Puppet::SSL::CertificateRequest::Rest.server_setting.should == :ca_server end it "should set port_setting to :ca_port" do Puppet::SSL::CertificateRequest::Rest.port_setting.should == :ca_port end end diff --git a/spec/unit/indirector/certificate_revocation_list/ca_spec.rb b/spec/unit/indirector/certificate_revocation_list/ca_spec.rb index b6f814a9c..d76373b97 100755 --- a/spec/unit/indirector/certificate_revocation_list/ca_spec.rb +++ b/spec/unit/indirector/certificate_revocation_list/ca_spec.rb @@ -1,21 +1,21 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Created by Luke Kanies on 2008-3-7. # Copyright (c) 2007. All rights reserved. require 'spec_helper' require 'puppet/indirector/certificate_revocation_list/ca' describe Puppet::SSL::CertificateRevocationList::Ca do it "should have documentation" do Puppet::SSL::CertificateRevocationList::Ca.doc.should be_instance_of(String) end it "should use the :cacrl setting as the crl location" do Puppet.settings.stubs(:value).returns "whatever" Puppet.settings.stubs(:use) Puppet.settings.stubs(:value).with(:cacrl).returns "/request/dir" Puppet::SSL::CertificateRevocationList::Ca.new.path("whatever").should == "/request/dir" end end diff --git a/spec/unit/indirector/certificate_revocation_list/file_spec.rb b/spec/unit/indirector/certificate_revocation_list/file_spec.rb index cd047410c..f4b8c36d3 100755 --- a/spec/unit/indirector/certificate_revocation_list/file_spec.rb +++ b/spec/unit/indirector/certificate_revocation_list/file_spec.rb @@ -1,20 +1,20 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Created by Luke Kanies on 2008-3-7. # Copyright (c) 2007. All rights reserved. require 'spec_helper' require 'puppet/indirector/certificate_revocation_list/file' describe Puppet::SSL::CertificateRevocationList::File do it "should have documentation" do Puppet::SSL::CertificateRevocationList::File.doc.should be_instance_of(String) end it "should always store the file to :hostcrl location" do Puppet.settings.expects(:value).with(:hostcrl).returns "/host/crl" Puppet.settings.stubs(:use) Puppet::SSL::CertificateRevocationList::File.file_location.should == "/host/crl" end end diff --git a/spec/unit/indirector/certificate_revocation_list/rest_spec.rb b/spec/unit/indirector/certificate_revocation_list/rest_spec.rb index c77992182..238ba75ff 100755 --- a/spec/unit/indirector/certificate_revocation_list/rest_spec.rb +++ b/spec/unit/indirector/certificate_revocation_list/rest_spec.rb @@ -1,23 +1,22 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/indirector/certificate_revocation_list/rest' describe Puppet::SSL::CertificateRevocationList::Rest do before do @searcher = Puppet::SSL::CertificateRevocationList::Rest.new end it "should be a sublcass of Puppet::Indirector::REST" do Puppet::SSL::CertificateRevocationList::Rest.superclass.should equal(Puppet::Indirector::REST) end it "should set server_setting to :ca_server" do Puppet::SSL::CertificateRevocationList::Rest.server_setting.should == :ca_server end it "should set port_setting to :ca_port" do Puppet::SSL::CertificateRevocationList::Rest.port_setting.should == :ca_port end end diff --git a/spec/unit/indirector/certificate_status/file_spec.rb b/spec/unit/indirector/certificate_status/file_spec.rb index 72e9f5851..ae03aa9cb 100755 --- a/spec/unit/indirector/certificate_status/file_spec.rb +++ b/spec/unit/indirector/certificate_status/file_spec.rb @@ -1,188 +1,187 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/ssl/host' require 'puppet/indirector/certificate_status' require 'tempfile' describe "Puppet::Indirector::CertificateStatus::File" do include PuppetSpec::Files before do Puppet::SSL::CertificateAuthority.stubs(:ca?).returns true @terminus = Puppet::SSL::Host.indirection.terminus(:file) @tmpdir = tmpdir("certificate_status_ca_testing") Puppet[:confdir] = @tmpdir Puppet[:vardir] = @tmpdir # localcacert is where each client stores the CA certificate # cacert is where the master stores the CA certificate # Since we need to play the role of both for testing we need them to be the same and exist Puppet[:cacert] = Puppet[:localcacert] end def generate_csr(host) host.generate_key csr = Puppet::SSL::CertificateRequest.new(host.name) csr.generate(host.key.content) Puppet::SSL::CertificateRequest.indirection.save(csr) end def sign_csr(host) host.desired_state = "signed" @terminus.save(Puppet::Indirector::Request.new(:certificate_status, :save, host.name, host)) end def generate_signed_cert(host) generate_csr(host) sign_csr(host) @terminus.find(Puppet::Indirector::Request.new(:certificate_status, :find, host.name, host)) end def generate_revoked_cert(host) generate_signed_cert(host) host.desired_state = "revoked" @terminus.save(Puppet::Indirector::Request.new(:certificate_status, :save, host.name, host)) end it "should be a terminus on SSL::Host" do @terminus.should be_instance_of(Puppet::Indirector::CertificateStatus::File) end it "should create a CA instance if none is present" do @terminus.ca.should be_instance_of(Puppet::SSL::CertificateAuthority) end describe "when creating the CA" do it "should fail if it is not a valid CA" do Puppet::SSL::CertificateAuthority.expects(:ca?).returns false lambda { @terminus.ca }.should raise_error(ArgumentError, "This process is not configured as a certificate authority") end end it "should be indirected with the name 'certificate_status'" do Puppet::SSL::Host.indirection.name.should == :certificate_status end describe "when finding" do before do @host = Puppet::SSL::Host.new("foo") Puppet.settings.use(:main) end it "should return the Puppet::SSL::Host when a CSR exists for the host" do generate_csr(@host) request = Puppet::Indirector::Request.new(:certificate_status, :find, "foo", @host) retrieved_host = @terminus.find(request) retrieved_host.name.should == @host.name retrieved_host.certificate_request.content.to_s.chomp.should == @host.certificate_request.content.to_s.chomp end it "should return the Puppet::SSL::Host when a public key exist for the host" do generate_signed_cert(@host) request = Puppet::Indirector::Request.new(:certificate_status, :find, "foo", @host) retrieved_host = @terminus.find(request) retrieved_host.name.should == @host.name retrieved_host.certificate.content.to_s.chomp.should == @host.certificate.content.to_s.chomp end it "should return nil when neither a CSR nor public key exist for the host" do request = Puppet::Indirector::Request.new(:certificate_status, :find, "foo", @host) @terminus.find(request).should == nil end end describe "when saving" do before do @host = Puppet::SSL::Host.new("foobar") Puppet.settings.use(:main) end describe "when signing a cert" do before do @host.desired_state = "signed" @request = Puppet::Indirector::Request.new(:certificate_status, :save, "foobar", @host) end it "should fail if no CSR is on disk" do lambda { @terminus.save(@request) }.should raise_error(Puppet::Error, /certificate request/) end it "should sign the on-disk CSR when it is present" do signed_host = generate_signed_cert(@host) signed_host.state.should == "signed" Puppet::SSL::Certificate.indirection.find("foobar").should be_instance_of(Puppet::SSL::Certificate) end end describe "when revoking a cert" do before do @request = Puppet::Indirector::Request.new(:certificate_status, :save, "foobar", @host) end it "should fail if no certificate is on disk" do @host.desired_state = "revoked" lambda { @terminus.save(@request) }.should raise_error(Puppet::Error, /Cannot revoke/) end it "should revoke the certificate when it is present" do generate_revoked_cert(@host) @host.state.should == 'revoked' end end end describe "when deleting" do before do Puppet.settings.use(:main) end it "should not delete anything if no certificate, request, or key is on disk" do host = Puppet::SSL::Host.new("clean_me") request = Puppet::Indirector::Request.new(:certificate_status, :delete, "clean_me", host) @terminus.destroy(request).should == "Nothing was deleted" end it "should clean certs, cert requests, keys" do signed_host = Puppet::SSL::Host.new("clean_signed_cert") generate_signed_cert(signed_host) signed_request = Puppet::Indirector::Request.new(:certificate_status, :delete, "clean_signed_cert", signed_host) @terminus.destroy(signed_request).should == "Deleted for clean_signed_cert: Puppet::SSL::Certificate, Puppet::SSL::Key" requested_host = Puppet::SSL::Host.new("clean_csr") generate_csr(requested_host) csr_request = Puppet::Indirector::Request.new(:certificate_status, :delete, "clean_csr", requested_host) @terminus.destroy(csr_request).should == "Deleted for clean_csr: Puppet::SSL::CertificateRequest, Puppet::SSL::Key" end end describe "when searching" do it "should return a list of all hosts with certificate requests, signed certs, or revoked certs" do Puppet.settings.use(:main) signed_host = Puppet::SSL::Host.new("signed_host") generate_signed_cert(signed_host) requested_host = Puppet::SSL::Host.new("requested_host") generate_csr(requested_host) revoked_host = Puppet::SSL::Host.new("revoked_host") generate_revoked_cert(revoked_host) retrieved_hosts = @terminus.search(Puppet::Indirector::Request.new(:certificate_status, :search, "all", signed_host)) results = retrieved_hosts.map {|h| [h.name, h.state]}.sort{ |h,i| h[0] <=> i[0] } results.should == [["ca","signed"],["requested_host","requested"],["revoked_host","revoked"],["signed_host","signed"]] end end end diff --git a/spec/unit/indirector/certificate_status/rest_spec.rb b/spec/unit/indirector/certificate_status/rest_spec.rb index 5367c96c6..39fbb7024 100755 --- a/spec/unit/indirector/certificate_status/rest_spec.rb +++ b/spec/unit/indirector/certificate_status/rest_spec.rb @@ -1,15 +1,14 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/ssl/host' require 'puppet/indirector/certificate_status' describe "Puppet::CertificateStatus::Rest" do before do @terminus = Puppet::SSL::Host.indirection.terminus(:rest) end it "should be a terminus on Puppet::SSL::Host" do @terminus.should be_instance_of(Puppet::Indirector::CertificateStatus::Rest) end end diff --git a/spec/unit/indirector/code_spec.rb b/spec/unit/indirector/code_spec.rb index 7fe7e2fb2..29369bf5e 100755 --- a/spec/unit/indirector/code_spec.rb +++ b/spec/unit/indirector/code_spec.rb @@ -1,32 +1,31 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/indirector/code' describe Puppet::Indirector::Code do before :all do Puppet::Indirector::Terminus.stubs(:register_terminus_class) @model = mock 'model' @indirection = stub 'indirection', :name => :mystuff, :register_terminus_type => nil, :model => @model Puppet::Indirector::Indirection.stubs(:instance).returns(@indirection) module Testing; end @code_class = class Testing::MyCode < Puppet::Indirector::Code self end @searcher = @code_class.new end it "should not have a find() method defined" do @searcher.should_not respond_to(:find) end it "should not have a save() method defined" do @searcher.should_not respond_to(:save) end it "should not have a destroy() method defined" do @searcher.should_not respond_to(:destroy) end end diff --git a/spec/unit/indirector/direct_file_server_spec.rb b/spec/unit/indirector/direct_file_server_spec.rb index 41ec85ec7..abd7172b7 100755 --- a/spec/unit/indirector/direct_file_server_spec.rb +++ b/spec/unit/indirector/direct_file_server_spec.rb @@ -1,83 +1,83 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Created by Luke Kanies on 2007-10-24. # Copyright (c) 2007. All rights reserved. require 'spec_helper' require 'puppet/indirector/direct_file_server' describe Puppet::Indirector::DirectFileServer do before :all do Puppet::Indirector::Terminus.stubs(:register_terminus_class) @model = mock 'model' @indirection = stub 'indirection', :name => :mystuff, :register_terminus_type => nil, :model => @model Puppet::Indirector::Indirection.stubs(:instance).returns(@indirection) module Testing; end @direct_file_class = class Testing::Mytype < Puppet::Indirector::DirectFileServer self end @server = @direct_file_class.new @uri = "file:///my/local" @request = Puppet::Indirector::Request.new(:mytype, :find, @uri) end describe Puppet::Indirector::DirectFileServer, "when finding a single file" do it "should return nil if the file does not exist" do FileTest.expects(:exists?).with("/my/local").returns false @server.find(@request).should be_nil end it "should return a Content instance created with the full path to the file if the file exists" do FileTest.expects(:exists?).with("/my/local").returns true @model.expects(:new).returns(:mycontent) @server.find(@request).should == :mycontent end end describe Puppet::Indirector::DirectFileServer, "when creating the instance for a single found file" do before do @data = mock 'content' @data.stubs(:collect) FileTest.expects(:exists?).with("/my/local").returns true end it "should pass the full path to the instance" do @model.expects(:new).with { |key, options| key == "/my/local" }.returns(@data) @server.find(@request) end it "should pass the :links setting on to the created Content instance if the file exists and there is a value for :links" do @model.expects(:new).returns(@data) @data.expects(:links=).with(:manage) @request.stubs(:options).returns(:links => :manage) @server.find(@request) end end describe Puppet::Indirector::DirectFileServer, "when searching for multiple files" do it "should return nil if the file does not exist" do FileTest.expects(:exists?).with("/my/local").returns false @server.find(@request).should be_nil end it "should use :path2instances from the terminus_helper to return instances if the file exists" do FileTest.expects(:exists?).with("/my/local").returns true @server.expects(:path2instances) @server.search(@request) end it "should pass the original request to :path2instances" do FileTest.expects(:exists?).with("/my/local").returns true @server.expects(:path2instances).with(@request, "/my/local") @server.search(@request) end end end diff --git a/spec/unit/indirector/envelope_spec.rb b/spec/unit/indirector/envelope_spec.rb index 7f7540227..e056b768c 100755 --- a/spec/unit/indirector/envelope_spec.rb +++ b/spec/unit/indirector/envelope_spec.rb @@ -1,47 +1,46 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/indirector/envelope' describe Puppet::Indirector::Envelope do before do @instance = Object.new @instance.extend(Puppet::Indirector::Envelope) end it "should have an expiration accessor" do @instance.expiration = "testing" @instance.expiration.should == "testing" end it "should have an expiration setter" do @instance.should respond_to(:expiration=) end it "should have a means of testing whether it is expired" do @instance.should respond_to(:expired?) end describe "when testing if it is expired" do it "should return false if there is no expiration set" do @instance.should_not be_expired end it "should return true if the current date is after the expiration date" do @instance.expiration = Time.now - 10 @instance.should be_expired end it "should return false if the current date is prior to the expiration date" do @instance.expiration = Time.now + 10 @instance.should_not be_expired end it "should return false if the current date is equal to the expiration date" do now = Time.now Time.stubs(:now).returns(now) @instance.expiration = now @instance.should_not be_expired end end end diff --git a/spec/unit/indirector/exec_spec.rb b/spec/unit/indirector/exec_spec.rb index 147bb8a5c..1050ed4cc 100755 --- a/spec/unit/indirector/exec_spec.rb +++ b/spec/unit/indirector/exec_spec.rb @@ -1,55 +1,54 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/indirector/exec' describe Puppet::Indirector::Exec do before :all do @indirection = stub 'indirection', :name => :testing Puppet::Indirector::Indirection.expects(:instance).with(:testing).returns(@indirection) module Testing; end @exec_class = class Testing::MyTesting < Puppet::Indirector::Exec attr_accessor :command self end end before :each do @searcher = @exec_class.new @searcher.command = ["/echo"] @request = stub 'request', :key => "foo" end it "should throw an exception if the command is not an array" do @searcher.command = "/usr/bin/echo" proc { @searcher.find(@request) }.should raise_error(Puppet::DevError) end it "should throw an exception if the command is not fully qualified" do @searcher.command = ["mycommand"] proc { @searcher.find(@request) }.should raise_error(ArgumentError) end it "should execute the command with the object name as the only argument" do @searcher.expects(:execute).with(%w{/echo foo}) @searcher.find(@request) end it "should return the output of the script" do @searcher.expects(:execute).with(%w{/echo foo}).returns("whatever") @searcher.find(@request).should == "whatever" end it "should return nil when the command produces no output" do @searcher.expects(:execute).with(%w{/echo foo}).returns(nil) @searcher.find(@request).should be_nil end it "should raise an exception if there's an execution failure" do @searcher.expects(:execute).with(%w{/echo foo}).raises(Puppet::ExecutionFailure.new("message")) lambda {@searcher.find(@request)}.should raise_exception(Puppet::Error, 'Failed to find foo via exec: message') end end diff --git a/spec/unit/indirector/facts/active_record_spec.rb b/spec/unit/indirector/facts/active_record_spec.rb index cccf1352c..01a906716 100755 --- a/spec/unit/indirector/facts/active_record_spec.rb +++ b/spec/unit/indirector/facts/active_record_spec.rb @@ -1,103 +1,102 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/rails' require 'puppet/node/facts' describe "Puppet::Node::Facts::ActiveRecord", :if => Puppet.features.rails? do before do require 'puppet/indirector/facts/active_record' Puppet.features.stubs(:rails?).returns true Puppet::Rails.stubs(:init) @terminus = Puppet::Node::Facts::ActiveRecord.new end it "should be a subclass of the ActiveRecord terminus class" do Puppet::Node::Facts::ActiveRecord.ancestors.should be_include(Puppet::Indirector::ActiveRecord) end it "should use Puppet::Rails::Host as its ActiveRecord model" do Puppet::Node::Facts::ActiveRecord.ar_model.should equal(Puppet::Rails::Host) end describe "when finding an instance" do before do @request = stub 'request', :key => "foo" end it "should use the Hosts ActiveRecord class to find the host" do Puppet::Rails::Host.expects(:find_by_name).with { |key, args| key == "foo" } @terminus.find(@request) end it "should include the fact names and values when finding the host" do Puppet::Rails::Host.expects(:find_by_name).with { |key, args| args[:include] == {:fact_values => :fact_name} } @terminus.find(@request) end it "should return nil if no host instance can be found" do Puppet::Rails::Host.expects(:find_by_name).returns nil @terminus.find(@request).should be_nil end it "should convert the node's parameters into a Facts instance if a host instance is found" do host = stub 'host', :name => "foo" host.expects(:get_facts_hash).returns("one" => [mock("two_value", :value => "two")], "three" => [mock("three_value", :value => "four")]) Puppet::Rails::Host.expects(:find_by_name).returns host result = @terminus.find(@request) result.should be_instance_of(Puppet::Node::Facts) result.name.should == "foo" result.values.should == {"one" => "two", "three" => "four"} end it "should convert all single-member arrays into non-arrays" do host = stub 'host', :name => "foo" host.expects(:get_facts_hash).returns("one" => [mock("two_value", :value => "two")]) Puppet::Rails::Host.expects(:find_by_name).returns host @terminus.find(@request).values["one"].should == "two" end end describe "when saving an instance" do before do @host = stub 'host', :name => "foo", :save => nil, :merge_facts => nil Puppet::Rails::Host.stubs(:find_by_name).returns @host @facts = Puppet::Node::Facts.new("foo", "one" => "two", "three" => "four") @request = stub 'request', :key => "foo", :instance => @facts end it "should find the Rails host with the same name" do Puppet::Rails::Host.expects(:find_by_name).with("foo").returns @host @terminus.save(@request) end it "should create a new Rails host if none can be found" do Puppet::Rails::Host.expects(:find_by_name).with("foo").returns nil Puppet::Rails::Host.expects(:create).with(:name => "foo").returns @host @terminus.save(@request) end it "should set the facts as facts on the Rails host instance" do # There is other stuff added to the hash. @host.expects(:merge_facts).with { |args| args["one"] == "two" and args["three"] == "four" } @terminus.save(@request) end it "should save the Rails host instance" do @host.expects(:save) @terminus.save(@request) end end end diff --git a/spec/unit/indirector/facts/couch_spec.rb b/spec/unit/indirector/facts/couch_spec.rb index 3ac085251..d0862486c 100755 --- a/spec/unit/indirector/facts/couch_spec.rb +++ b/spec/unit/indirector/facts/couch_spec.rb @@ -1,103 +1,102 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/node/facts' require 'puppet/indirector/facts/couch' describe "Puppet::Node::Facts::Couch" do describe "when couchdb is not available", :unless => Puppet.features.couchdb? do it "should fail to initialize" do lambda { Puppet::Node::Facts::Couch.new }.should raise_error end end describe "when couchdb is available", :if => Puppet.features.couchdb? do before do @mock_db = mock('couch db') mock_document = CouchRest::Document.new(:_id => fake_request.key, :facts => fake_request.values) mock_document.stubs(:database).returns(@mock_db) @mock_db.stubs(:get).with(fake_request.key).returns(mock_document) Puppet::Node::Facts::Couch.stubs(:db).returns(@mock_db) end subject { Puppet::Node::Facts::Couch } describe "#find" do describe "when the node document exists" do it "should find the request by key" do @mock_db.expects(:get).with(fake_request.key).returns({'_id' => fake_request.key, 'facts' => fake_request.instance.values}) subject.new.find(fake_request).should == fake_request.instance end end describe "when the node document does not exist" do before do @mock_db.expects(:get). with(fake_request.key). raises(RestClient::ResourceNotFound) end it "should return nil" do subject.new.find(fake_request).should be_nil end it "should send Puppet a debug message" do Puppet.expects(:debug).with("No couchdb document with id: test.local") subject.new.find(fake_request).should be_nil end end end describe "#save" do describe "with options" do subject do lambda { Puppet::Node::Facts::Couch.new.save(fake_request([1])) } end it { should raise_error(ArgumentError, "PUT does not accept options") } end it "should save the json to the CouchDB database" do @mock_db.expects(:save_doc).at_least_once.returns({'ok' => true }) subject.new.save(fake_request) end describe "when the document exists" do before do @doc = CouchRest::Document.new(:_id => fake_request.key, :facts => fake_request.instance.values) @mock_db.expects(:get).with(fake_request.key).returns(@doc) end it "saves the document" do @doc.expects(:save) subject.new.save(fake_request) end end describe "when the document does not exist" do before do @mock_db.expects(:get). with(fake_request.key). raises(RestClient::ResourceNotFound) end it "saves the document" do @mock_db.expects(:save_doc) subject.new.save(fake_request) end end end def fake_request(options={}) facts = YAML.load_file(File.join(PuppetSpec::FIXTURE_DIR, 'yaml', 'test.local.yaml')) Struct.new(:instance, :key, :options).new(facts, facts.name, options) end private :fake_request end end diff --git a/spec/unit/indirector/facts/facter_spec.rb b/spec/unit/indirector/facts/facter_spec.rb index 76a1e29ce..9f5a0249b 100755 --- a/spec/unit/indirector/facts/facter_spec.rb +++ b/spec/unit/indirector/facts/facter_spec.rb @@ -1,143 +1,143 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Created by Luke Kanies on 2007-9-23. # Copyright (c) 2007. All rights reserved. require 'spec_helper' require 'puppet/indirector/facts/facter' describe Puppet::Node::Facts::Facter do it "should be a subclass of the Code terminus" do Puppet::Node::Facts::Facter.superclass.should equal(Puppet::Indirector::Code) end it "should have documentation" do Puppet::Node::Facts::Facter.doc.should_not be_nil end it "should be registered with the configuration store indirection" do indirection = Puppet::Indirector::Indirection.instance(:facts) Puppet::Node::Facts::Facter.indirection.should equal(indirection) end it "should have its name set to :facter" do Puppet::Node::Facts::Facter.name.should == :facter end it "should load facts on initialization" do Puppet::Node::Facts::Facter.expects(:load_fact_plugins) Puppet::Node::Facts::Facter.new end end describe Puppet::Node::Facts::Facter do before :each do @facter = Puppet::Node::Facts::Facter.new Facter.stubs(:to_hash).returns({}) @name = "me" @request = stub 'request', :key => @name end describe Puppet::Node::Facts::Facter, " when finding facts" do it "should return a Facts instance" do @facter.find(@request).should be_instance_of(Puppet::Node::Facts) end it "should return a Facts instance with the provided key as the name" do @facter.find(@request).name.should == @name end it "should return the Facter facts as the values in the Facts instance" do Facter.expects(:to_hash).returns("one" => "two") facts = @facter.find(@request) facts.values["one"].should == "two" end it "should add local facts" do facts = Puppet::Node::Facts.new("foo") Puppet::Node::Facts.expects(:new).returns facts facts.expects(:add_local_facts) @facter.find(@request) end it "should convert all facts into strings" do facts = Puppet::Node::Facts.new("foo") Puppet::Node::Facts.expects(:new).returns facts facts.expects(:stringify) @facter.find(@request) end it "should call the downcase hook" do facts = Puppet::Node::Facts.new("foo") Puppet::Node::Facts.expects(:new).returns facts facts.expects(:downcase_if_necessary) @facter.find(@request) end end describe Puppet::Node::Facts::Facter, " when saving facts" do it "should fail" do proc { @facter.save(@facts) }.should raise_error(Puppet::DevError) end end describe Puppet::Node::Facts::Facter, " when destroying facts" do it "should fail" do proc { @facter.destroy(@facts) }.should raise_error(Puppet::DevError) end end it "should skip files when asked to load a directory" do FileTest.expects(:directory?).with("myfile").returns false Puppet::Node::Facts::Facter.load_facts_in_dir("myfile") end it "should load each ruby file when asked to load a directory" do FileTest.expects(:directory?).with("mydir").returns true Dir.expects(:chdir).with("mydir").yields Dir.expects(:glob).with("*.rb").returns %w{a.rb b.rb} Puppet::Node::Facts::Facter.expects(:load).with("a.rb") Puppet::Node::Facts::Facter.expects(:load).with("b.rb") Puppet::Node::Facts::Facter.load_facts_in_dir("mydir") end describe Puppet::Node::Facts::Facter, "when loading fact plugins from disk" do it "should load each directory in the Fact path" do Puppet.settings.stubs(:value).returns "foo" Puppet.settings.expects(:value).with(:factpath).returns("one#{File::PATH_SEPARATOR}two") Puppet::Node::Facts::Facter.expects(:load_facts_in_dir).with("one") Puppet::Node::Facts::Facter.expects(:load_facts_in_dir).with("two") Puppet::Node::Facts::Facter.load_fact_plugins end it "should load all facts from the modules" do Puppet.settings.stubs(:value).returns "foo" Puppet::Node::Facts::Facter.stubs(:load_facts_in_dir) Puppet.settings.expects(:value).with(:modulepath).returns("one#{File::PATH_SEPARATOR}two") Dir.stubs(:glob).returns [] Dir.expects(:glob).with("one/*/lib/facter").returns %w{oneA oneB} Dir.expects(:glob).with("two/*/lib/facter").returns %w{twoA twoB} Puppet::Node::Facts::Facter.expects(:load_facts_in_dir).with("oneA") Puppet::Node::Facts::Facter.expects(:load_facts_in_dir).with("oneB") Puppet::Node::Facts::Facter.expects(:load_facts_in_dir).with("twoA") Puppet::Node::Facts::Facter.expects(:load_facts_in_dir).with("twoB") Puppet::Node::Facts::Facter.load_fact_plugins end end end diff --git a/spec/unit/indirector/facts/inventory_active_record_spec.rb b/spec/unit/indirector/facts/inventory_active_record_spec.rb index 0d5573999..edd03d8e4 100755 --- a/spec/unit/indirector/facts/inventory_active_record_spec.rb +++ b/spec/unit/indirector/facts/inventory_active_record_spec.rb @@ -1,168 +1,167 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' begin require 'sqlite3' rescue LoadError end require 'tempfile' require 'puppet/rails' describe "Puppet::Node::Facts::InventoryActiveRecord", :if => (Puppet.features.rails? and defined? SQLite3) do let(:terminus) { Puppet::Node::Facts::InventoryActiveRecord.new } before :all do require 'puppet/indirector/facts/inventory_active_record' @dbfile = Tempfile.new("testdb") @dbfile.close end after :all do Puppet::Node::Facts.indirection.reset_terminus_class @dbfile.unlink end before :each do Puppet::Node::Facts.indirection.terminus_class = :inventory_active_record Puppet[:dbadapter] = 'sqlite3' Puppet[:dblocation] = @dbfile.path Puppet[:railslog] = "/dev/null" Puppet::Rails.init end after :each do Puppet::Rails.teardown ActiveRecord::Base.remove_connection end describe "#save" do it "should use an existing node if possible" do node = Puppet::Rails::InventoryNode.new(:name => "foo", :timestamp => Time.now) node.save facts = Puppet::Node::Facts.new("foo", "uptime_days" => "60", "kernel" => "Darwin") Puppet::Node::Facts.indirection.save(facts) Puppet::Rails::InventoryNode.count.should == 1 Puppet::Rails::InventoryNode.first.should == node end it "should create a new node if one can't be found" do # This test isn't valid if there are nodes to begin with Puppet::Rails::InventoryNode.count.should == 0 facts = Puppet::Node::Facts.new("foo", "uptime_days" => "60", "kernel" => "Darwin") Puppet::Node::Facts.indirection.save(facts) Puppet::Rails::InventoryNode.count.should == 1 Puppet::Rails::InventoryNode.first.name.should == "foo" end it "should save the facts" do facts = Puppet::Node::Facts.new("foo", "uptime_days" => "60", "kernel" => "Darwin") Puppet::Node::Facts.indirection.save(facts) Puppet::Rails::InventoryFact.all.map{|f| [f.name,f.value]}.should =~ [["uptime_days","60"],["kernel","Darwin"]] end it "should remove the previous facts for an existing node" do facts = Puppet::Node::Facts.new("foo", "uptime_days" => "30", "kernel" => "Darwin") Puppet::Node::Facts.indirection.save(facts) bar_facts = Puppet::Node::Facts.new("bar", "uptime_days" => "35", "kernel" => "Linux") foo_facts = Puppet::Node::Facts.new("foo", "uptime_days" => "60", "is_virtual" => "false") Puppet::Node::Facts.indirection.save(bar_facts) Puppet::Node::Facts.indirection.save(foo_facts) Puppet::Node::Facts.indirection.find("bar").should == bar_facts Puppet::Node::Facts.indirection.find("foo").should == foo_facts Puppet::Rails::InventoryFact.all.map{|f| [f.name,f.value]}.should_not include(["uptime_days", "30"], ["kernel", "Darwin"]) end end describe "#find" do before do @foo_facts = Puppet::Node::Facts.new("foo", "uptime_days" => "60", "kernel" => "Darwin") @bar_facts = Puppet::Node::Facts.new("bar", "uptime_days" => "30", "kernel" => "Linux") Puppet::Node::Facts.indirection.save(@foo_facts) Puppet::Node::Facts.indirection.save(@bar_facts) end it "should identify facts by node name" do Puppet::Node::Facts.indirection.find("foo").should == @foo_facts end it "should return nil if no node instance can be found" do Puppet::Node::Facts.indirection.find("non-existent node").should == nil end end describe "#search" do def search_request(conditions) Puppet::Indirector::Request.new(:facts, :search, nil, conditions) end before :each do @now = Time.now @foo = Puppet::Node::Facts.new("foo", "fact1" => "value1", "fact2" => "value2", "uptime_days" => "30") @bar = Puppet::Node::Facts.new("bar", "fact1" => "value1", "uptime_days" => "60") @baz = Puppet::Node::Facts.new("baz", "fact1" => "value2", "fact2" => "value1", "uptime_days" => "90") @bat = Puppet::Node::Facts.new("bat") @foo.timestamp = @now - 3600*1 @bar.timestamp = @now - 3600*3 @baz.timestamp = @now - 3600*5 @bat.timestamp = @now - 3600*7 [@foo, @bar, @baz, @bat].each {|facts| Puppet::Node::Facts.indirection.save(facts)} end it "should return node names that match 'equal' constraints" do request = search_request('facts.fact1.eq' => 'value1', 'facts.fact2.eq' => 'value2') terminus.search(request).should == ["foo"] end it "should return node names that match 'not equal' constraints" do request = search_request('facts.fact1.ne' => 'value2') terminus.search(request).should == ["bar","foo"] end it "should return node names that match strict inequality constraints" do request = search_request('facts.uptime_days.gt' => '20', 'facts.uptime_days.lt' => '70') terminus.search(request).should == ["bar","foo"] end it "should return node names that match non-strict inequality constraints" do request = search_request('facts.uptime_days.ge' => '30', 'facts.uptime_days.le' => '60') terminus.search(request).should == ["bar","foo"] end it "should return node names whose facts are within a given timeframe" do request = search_request('meta.timestamp.ge' => @now - 3600*5, 'meta.timestamp.le' => @now - 3600*1) terminus.search(request).should == ["bar","baz","foo"] end it "should return node names whose facts are from a specific time" do request = search_request('meta.timestamp.eq' => @now - 3600*3) terminus.search(request).should == ["bar"] end it "should return node names whose facts are not from a specific time" do request = search_request('meta.timestamp.ne' => @now - 3600*1) terminus.search(request).should == ["bar","bat","baz"] end it "should perform strict searches on nodes by timestamp" do request = search_request('meta.timestamp.gt' => @now - 3600*5, 'meta.timestamp.lt' => @now - 3600*1) terminus.search(request).should == ["bar"] end it "should search nodes based on both facts and timestamp values" do request = search_request('facts.uptime_days.gt' => '45', 'meta.timestamp.lt' => @now - 3600*4) terminus.search(request).should == ["baz"] end end end diff --git a/spec/unit/indirector/facts/rest_spec.rb b/spec/unit/indirector/facts/rest_spec.rb index cf03d30bc..6a2a23f8b 100755 --- a/spec/unit/indirector/facts/rest_spec.rb +++ b/spec/unit/indirector/facts/rest_spec.rb @@ -1,11 +1,10 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/indirector/facts/rest' describe Puppet::Node::Facts::Rest do it "should be a sublcass of Puppet::Indirector::REST" do Puppet::Node::Facts::Rest.superclass.should equal(Puppet::Indirector::REST) end end diff --git a/spec/unit/indirector/facts/yaml_spec.rb b/spec/unit/indirector/facts/yaml_spec.rb index 45f5a1b67..a22d690b8 100755 --- a/spec/unit/indirector/facts/yaml_spec.rb +++ b/spec/unit/indirector/facts/yaml_spec.rb @@ -1,240 +1,239 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/node/facts' require 'puppet/indirector/facts/yaml' describe Puppet::Node::Facts::Yaml do it "should be a subclass of the Yaml terminus" do Puppet::Node::Facts::Yaml.superclass.should equal(Puppet::Indirector::Yaml) end it "should have documentation" do Puppet::Node::Facts::Yaml.doc.should_not be_nil Puppet::Node::Facts::Yaml.doc.should_not be_empty end it "should be registered with the facts indirection" do indirection = Puppet::Indirector::Indirection.instance(:facts) Puppet::Node::Facts::Yaml.indirection.should equal(indirection) end it "should have its name set to :yaml" do Puppet::Node::Facts::Yaml.name.should == :yaml end describe "#search" do def assert_search_matches(matching, nonmatching, query) request = Puppet::Indirector::Request.new(:inventory, :search, nil, query) Dir.stubs(:glob).returns(matching.keys + nonmatching.keys) [matching, nonmatching].each do |examples| examples.each do |key, value| YAML.stubs(:load_file).with(key).returns value end end Puppet::Node::Facts::Yaml.new.search(request).should =~ matching.values.map {|facts| facts.name} end it "should return node names that match the search query options" do assert_search_matches({ '/path/to/matching.yaml' => Puppet::Node::Facts.new("matchingnode", "architecture" => "i386", 'processor_count' => '4'), '/path/to/matching1.yaml' => Puppet::Node::Facts.new("matchingnode1", "architecture" => "i386", 'processor_count' => '4', 'randomfact' => 'foo') }, { "/path/to/nonmatching.yaml" => Puppet::Node::Facts.new("nonmatchingnode", "architecture" => "powerpc", 'processor_count' => '4'), "/path/to/nonmatching1.yaml" => Puppet::Node::Facts.new("nonmatchingnode1", "architecture" => "powerpc", 'processor_count' => '5'), "/path/to/nonmatching2.yaml" => Puppet::Node::Facts.new("nonmatchingnode2", "architecture" => "i386", 'processor_count' => '5'), "/path/to/nonmatching3.yaml" => Puppet::Node::Facts.new("nonmatchingnode3", 'processor_count' => '4'), }, {'facts.architecture' => 'i386', 'facts.processor_count' => '4'} ) end it "should return empty array when no nodes match the search query options" do assert_search_matches({}, { "/path/to/nonmatching.yaml" => Puppet::Node::Facts.new("nonmatchingnode", "architecture" => "powerpc", 'processor_count' => '10'), "/path/to/nonmatching1.yaml" => Puppet::Node::Facts.new("nonmatchingnode1", "architecture" => "powerpc", 'processor_count' => '5'), "/path/to/nonmatching2.yaml" => Puppet::Node::Facts.new("nonmatchingnode2", "architecture" => "i386", 'processor_count' => '5'), "/path/to/nonmatching3.yaml" => Puppet::Node::Facts.new("nonmatchingnode3", 'processor_count' => '4'), }, {'facts.processor_count.lt' => '4', 'facts.processor_count.gt' => '4'} ) end it "should return node names that match the search query options with the greater than operator" do assert_search_matches({ '/path/to/matching.yaml' => Puppet::Node::Facts.new("matchingnode", "architecture" => "i386", 'processor_count' => '5'), '/path/to/matching1.yaml' => Puppet::Node::Facts.new("matchingnode1", "architecture" => "powerpc", 'processor_count' => '10', 'randomfact' => 'foo') }, { "/path/to/nonmatching.yaml" => Puppet::Node::Facts.new("nonmatchingnode", "architecture" => "powerpc", 'processor_count' => '4'), "/path/to/nonmatching2.yaml" => Puppet::Node::Facts.new("nonmatchingnode2", "architecture" => "i386", 'processor_count' => '3'), "/path/to/nonmatching3.yaml" => Puppet::Node::Facts.new("nonmatchingnode3" ), }, {'facts.processor_count.gt' => '4'} ) end it "should return node names that match the search query options with the less than operator" do assert_search_matches({ '/path/to/matching.yaml' => Puppet::Node::Facts.new("matchingnode", "architecture" => "i386", 'processor_count' => '5'), '/path/to/matching1.yaml' => Puppet::Node::Facts.new("matchingnode1", "architecture" => "powerpc", 'processor_count' => '30', 'randomfact' => 'foo') }, { "/path/to/nonmatching.yaml" => Puppet::Node::Facts.new("nonmatchingnode", "architecture" => "powerpc", 'processor_count' => '50' ), "/path/to/nonmatching2.yaml" => Puppet::Node::Facts.new("nonmatchingnode2", "architecture" => "i386", 'processor_count' => '100'), "/path/to/nonmatching3.yaml" => Puppet::Node::Facts.new("nonmatchingnode3" ), }, {'facts.processor_count.lt' => '50'} ) end it "should return node names that match the search query options with the less than or equal to operator" do assert_search_matches({ '/path/to/matching.yaml' => Puppet::Node::Facts.new("matchingnode", "architecture" => "i386", 'processor_count' => '5'), '/path/to/matching1.yaml' => Puppet::Node::Facts.new("matchingnode1", "architecture" => "powerpc", 'processor_count' => '50', 'randomfact' => 'foo') }, { "/path/to/nonmatching.yaml" => Puppet::Node::Facts.new("nonmatchingnode", "architecture" => "powerpc", 'processor_count' => '100' ), "/path/to/nonmatching2.yaml" => Puppet::Node::Facts.new("nonmatchingnode2", "architecture" => "i386", 'processor_count' => '5000'), "/path/to/nonmatching3.yaml" => Puppet::Node::Facts.new("nonmatchingnode3" ), }, {'facts.processor_count.le' => '50'} ) end it "should return node names that match the search query options with the greater than or equal to operator" do assert_search_matches({ '/path/to/matching.yaml' => Puppet::Node::Facts.new("matchingnode", "architecture" => "i386", 'processor_count' => '100'), '/path/to/matching1.yaml' => Puppet::Node::Facts.new("matchingnode1", "architecture" => "powerpc", 'processor_count' => '50', 'randomfact' => 'foo') }, { "/path/to/nonmatching.yaml" => Puppet::Node::Facts.new("nonmatchingnode", "architecture" => "powerpc", 'processor_count' => '40'), "/path/to/nonmatching2.yaml" => Puppet::Node::Facts.new("nonmatchingnode2", "architecture" => "i386", 'processor_count' => '9' ), "/path/to/nonmatching3.yaml" => Puppet::Node::Facts.new("nonmatchingnode3" ), }, {'facts.processor_count.ge' => '50'} ) end it "should return node names that match the search query options with the not equal operator" do assert_search_matches({ '/path/to/matching.yaml' => Puppet::Node::Facts.new("matchingnode", "architecture" => 'arm' ), '/path/to/matching1.yaml' => Puppet::Node::Facts.new("matchingnode1", "architecture" => 'powerpc', 'randomfact' => 'foo') }, { "/path/to/nonmatching.yaml" => Puppet::Node::Facts.new("nonmatchingnode", "architecture" => "i386" ), "/path/to/nonmatching2.yaml" => Puppet::Node::Facts.new("nonmatchingnode2", "architecture" => "i386", 'processor_count' => '9' ), "/path/to/nonmatching3.yaml" => Puppet::Node::Facts.new("nonmatchingnode3" ), }, {'facts.architecture.ne' => 'i386'} ) end def apply_timestamp(facts, timestamp) facts.timestamp = timestamp facts end it "should be able to query based on meta.timestamp.gt" do assert_search_matches({ '/path/to/2010-11-01.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-11-01", {}), Time.parse("2010-11-01")), '/path/to/2010-11-10.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-11-10", {}), Time.parse("2010-11-10")), }, { '/path/to/2010-10-01.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-01", {}), Time.parse("2010-10-01")), '/path/to/2010-10-10.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-10", {}), Time.parse("2010-10-10")), '/path/to/2010-10-15.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-15", {}), Time.parse("2010-10-15")), }, {'meta.timestamp.gt' => '2010-10-15'} ) end it "should be able to query based on meta.timestamp.le" do assert_search_matches({ '/path/to/2010-10-01.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-01", {}), Time.parse("2010-10-01")), '/path/to/2010-10-10.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-10", {}), Time.parse("2010-10-10")), '/path/to/2010-10-15.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-15", {}), Time.parse("2010-10-15")), }, { '/path/to/2010-11-01.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-11-01", {}), Time.parse("2010-11-01")), '/path/to/2010-11-10.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-11-10", {}), Time.parse("2010-11-10")), }, {'meta.timestamp.le' => '2010-10-15'} ) end it "should be able to query based on meta.timestamp.lt" do assert_search_matches({ '/path/to/2010-10-01.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-01", {}), Time.parse("2010-10-01")), '/path/to/2010-10-10.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-10", {}), Time.parse("2010-10-10")), }, { '/path/to/2010-11-01.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-11-01", {}), Time.parse("2010-11-01")), '/path/to/2010-11-10.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-11-10", {}), Time.parse("2010-11-10")), '/path/to/2010-10-15.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-15", {}), Time.parse("2010-10-15")), }, {'meta.timestamp.lt' => '2010-10-15'} ) end it "should be able to query based on meta.timestamp.ge" do assert_search_matches({ '/path/to/2010-11-01.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-11-01", {}), Time.parse("2010-11-01")), '/path/to/2010-11-10.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-11-10", {}), Time.parse("2010-11-10")), '/path/to/2010-10-15.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-15", {}), Time.parse("2010-10-15")), }, { '/path/to/2010-10-01.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-01", {}), Time.parse("2010-10-01")), '/path/to/2010-10-10.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-10", {}), Time.parse("2010-10-10")), }, {'meta.timestamp.ge' => '2010-10-15'} ) end it "should be able to query based on meta.timestamp.eq" do assert_search_matches({ '/path/to/2010-10-15.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-15", {}), Time.parse("2010-10-15")), }, { '/path/to/2010-11-01.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-11-01", {}), Time.parse("2010-11-01")), '/path/to/2010-11-10.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-11-10", {}), Time.parse("2010-11-10")), '/path/to/2010-10-01.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-01", {}), Time.parse("2010-10-01")), '/path/to/2010-10-10.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-10", {}), Time.parse("2010-10-10")), }, {'meta.timestamp.eq' => '2010-10-15'} ) end it "should be able to query based on meta.timestamp" do assert_search_matches({ '/path/to/2010-10-15.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-15", {}), Time.parse("2010-10-15")), }, { '/path/to/2010-11-01.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-11-01", {}), Time.parse("2010-11-01")), '/path/to/2010-11-10.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-11-10", {}), Time.parse("2010-11-10")), '/path/to/2010-10-01.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-01", {}), Time.parse("2010-10-01")), '/path/to/2010-10-10.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-10", {}), Time.parse("2010-10-10")), }, {'meta.timestamp' => '2010-10-15'} ) end it "should be able to query based on meta.timestamp.ne" do assert_search_matches({ '/path/to/2010-11-01.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-11-01", {}), Time.parse("2010-11-01")), '/path/to/2010-11-10.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-11-10", {}), Time.parse("2010-11-10")), '/path/to/2010-10-01.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-01", {}), Time.parse("2010-10-01")), '/path/to/2010-10-10.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-10", {}), Time.parse("2010-10-10")), }, { '/path/to/2010-10-15.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-15", {}), Time.parse("2010-10-15")), }, {'meta.timestamp.ne' => '2010-10-15'} ) end end end diff --git a/spec/unit/indirector/file_bucket_file/file_spec.rb b/spec/unit/indirector/file_bucket_file/file_spec.rb index 242018882..e0612cb21 100755 --- a/spec/unit/indirector/file_bucket_file/file_spec.rb +++ b/spec/unit/indirector/file_bucket_file/file_spec.rb @@ -1,274 +1,273 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/indirector/file_bucket_file/file' describe Puppet::FileBucketFile::File do include PuppetSpec::Files it "should be a subclass of the Code terminus class" do Puppet::FileBucketFile::File.superclass.should equal(Puppet::Indirector::Code) end it "should have documentation" do Puppet::FileBucketFile::File.doc.should be_instance_of(String) end describe "non-stubbing tests" do include PuppetSpec::Files before do Puppet[:bucketdir] = tmpdir('bucketdir') end def save_bucket_file(contents, path = "/who_cares") bucket_file = Puppet::FileBucket::File.new(contents) Puppet::FileBucket::File.indirection.save(bucket_file, "md5/#{Digest::MD5.hexdigest(contents)}#{path}") bucket_file.checksum_data end describe "when servicing a save request" do describe "when supplying a path" do it "should store the path if not already stored" do checksum = save_bucket_file("stuff", "/foo/bar") dir_path = "#{Puppet[:bucketdir]}/c/1/3/d/8/8/c/b/c13d88cb4cb02003daedb8a84e5d272a" File.read("#{dir_path}/contents").should == "stuff" File.read("#{dir_path}/paths").should == "foo/bar\n" end it "should leave the paths file alone if the path is already stored" do checksum = save_bucket_file("stuff", "/foo/bar") checksum = save_bucket_file("stuff", "/foo/bar") dir_path = "#{Puppet[:bucketdir]}/c/1/3/d/8/8/c/b/c13d88cb4cb02003daedb8a84e5d272a" File.read("#{dir_path}/contents").should == "stuff" File.read("#{dir_path}/paths").should == "foo/bar\n" end it "should store an additional path if the new path differs from those already stored" do checksum = save_bucket_file("stuff", "/foo/bar") checksum = save_bucket_file("stuff", "/foo/baz") dir_path = "#{Puppet[:bucketdir]}/c/1/3/d/8/8/c/b/c13d88cb4cb02003daedb8a84e5d272a" File.read("#{dir_path}/contents").should == "stuff" File.read("#{dir_path}/paths").should == "foo/bar\nfoo/baz\n" end end describe "when not supplying a path" do it "should save the file and create an empty paths file" do checksum = save_bucket_file("stuff", "") dir_path = "#{Puppet[:bucketdir]}/c/1/3/d/8/8/c/b/c13d88cb4cb02003daedb8a84e5d272a" File.read("#{dir_path}/contents").should == "stuff" File.read("#{dir_path}/paths").should == "" end end end describe "when servicing a head/find request" do describe "when supplying a path" do it "should return false/nil if the file isn't bucketed" do Puppet::FileBucket::File.indirection.head("md5/0ae2ec1980410229885fe72f7b44fe55/foo/bar").should == false Puppet::FileBucket::File.indirection.find("md5/0ae2ec1980410229885fe72f7b44fe55/foo/bar").should == nil end it "should return false/nil if the file is bucketed but with a different path" do checksum = save_bucket_file("I'm the contents of a file", '/foo/bar') Puppet::FileBucket::File.indirection.head("md5/#{checksum}/foo/baz").should == false Puppet::FileBucket::File.indirection.find("md5/#{checksum}/foo/baz").should == nil end it "should return true/file if the file is already bucketed with the given path" do contents = "I'm the contents of a file" checksum = save_bucket_file(contents, '/foo/bar') Puppet::FileBucket::File.indirection.head("md5/#{checksum}/foo/bar").should == true find_result = Puppet::FileBucket::File.indirection.find("md5/#{checksum}/foo/bar") find_result.should be_a(Puppet::FileBucket::File) find_result.checksum.should == "{md5}#{checksum}" find_result.to_s.should == contents end end describe "when not supplying a path" do [false, true].each do |trailing_slash| describe "#{trailing_slash ? 'with' : 'without'} a trailing slash" do trailing_string = trailing_slash ? '/' : '' it "should return false/nil if the file isn't bucketed" do Puppet::FileBucket::File.indirection.head("md5/0ae2ec1980410229885fe72f7b44fe55#{trailing_string}").should == false Puppet::FileBucket::File.indirection.find("md5/0ae2ec1980410229885fe72f7b44fe55#{trailing_string}").should == nil end it "should return true/file if the file is already bucketed" do contents = "I'm the contents of a file" checksum = save_bucket_file(contents, '/foo/bar') Puppet::FileBucket::File.indirection.head("md5/#{checksum}#{trailing_string}").should == true find_result = Puppet::FileBucket::File.indirection.find("md5/#{checksum}#{trailing_string}") find_result.should be_a(Puppet::FileBucket::File) find_result.checksum.should == "{md5}#{checksum}" find_result.to_s.should == contents end end end end end describe "when diffing files" do it "should generate an empty string if there is no diff" do checksum = save_bucket_file("I'm the contents of a file") Puppet::FileBucket::File.indirection.find("md5/#{checksum}", :diff_with => checksum).should == '' end it "should generate a proper diff if there is a diff" do checksum1 = save_bucket_file("foo\nbar\nbaz") checksum2 = save_bucket_file("foo\nbiz\nbaz") diff = Puppet::FileBucket::File.indirection.find("md5/#{checksum1}", :diff_with => checksum2) diff.should == < biz HERE end it "should raise an exception if the hash to diff against isn't found" do checksum = save_bucket_file("whatever") bogus_checksum = "d1bf072d0e2c6e20e3fbd23f022089a1" lambda { Puppet::FileBucket::File.indirection.find("md5/#{checksum}", :diff_with => bogus_checksum) }.should raise_error "could not find diff_with #{bogus_checksum}" end it "should return nil if the hash to diff from isn't found" do checksum = save_bucket_file("whatever") bogus_checksum = "d1bf072d0e2c6e20e3fbd23f022089a1" Puppet::FileBucket::File.indirection.find("md5/#{bogus_checksum}", :diff_with => checksum).should == nil end end end describe "when initializing" do it "should use the filebucket settings section" do Puppet.settings.expects(:use).with(:filebucket) Puppet::FileBucketFile::File.new end end [true, false].each do |override_bucket_path| describe "when bucket path #{if override_bucket_path then 'is' else 'is not' end} overridden" do [true, false].each do |supply_path| describe "when #{supply_path ? 'supplying' : 'not supplying'} a path" do before :each do Puppet.settings.stubs(:use) @store = Puppet::FileBucketFile::File.new @contents = "my content" @digest = "f2bfa7fc155c4f42cb91404198dda01f" @digest.should == Digest::MD5.hexdigest(@contents) @bucket_dir = tmpdir("bucket") if override_bucket_path Puppet[:bucketdir] = "/bogus/path" # should not be used else Puppet[:bucketdir] = @bucket_dir end @dir = "#{@bucket_dir}/f/2/b/f/a/7/f/c/f2bfa7fc155c4f42cb91404198dda01f" @contents_path = "#{@dir}/contents" end describe "when retrieving files" do before :each do request_options = {} if override_bucket_path request_options[:bucket_path] = @bucket_dir end key = "md5/#{@digest}" if supply_path key += "/path/to/file" end @request = Puppet::Indirector::Request.new(:indirection_name, :find, key, request_options) end def make_bucketed_file FileUtils.mkdir_p(@dir) File.open(@contents_path, 'w') { |f| f.write @contents } end it "should return an instance of Puppet::FileBucket::File created with the content if the file exists" do make_bucketed_file if supply_path @store.find(@request).should == nil @store.head(@request).should == false # because path didn't match else bucketfile = @store.find(@request) bucketfile.should be_a(Puppet::FileBucket::File) bucketfile.contents.should == @contents @store.head(@request).should == true end end it "should return nil if no file is found" do @store.find(@request).should be_nil @store.head(@request).should == false end end describe "when saving files" do it "should save the contents to the calculated path" do options = {} if override_bucket_path options[:bucket_path] = @bucket_dir end key = "md5/#{@digest}" if supply_path key += "//path/to/file" end file_instance = Puppet::FileBucket::File.new(@contents, options) request = Puppet::Indirector::Request.new(:indirection_name, :save, key, file_instance) @store.save(request) File.read("#{@dir}/contents").should == @contents end end end end end end describe "when verifying identical files" do before do # this is the default from spec_helper, but it keeps getting reset at odd times Puppet[:bucketdir] = "/dev/null/bucket" @digest = "4a8ec4fa5f01b4ab1a0ab8cbccb709f0" @checksum = "{md5}4a8ec4fa5f01b4ab1a0ab8cbccb709f0" @dir = '/dev/null/bucket/4/a/8/e/c/4/f/a/4a8ec4fa5f01b4ab1a0ab8cbccb709f0' @contents = "file contents" @bucket = stub "bucket file" @bucket.stubs(:bucket_path) @bucket.stubs(:checksum).returns(@checksum) @bucket.stubs(:checksum_data).returns(@digest) @bucket.stubs(:path).returns(nil) @bucket.stubs(:contents).returns("file contents") end it "should raise an error if the files don't match" do File.expects(:read).with("#{@dir}/contents").returns("corrupt contents") lambda{ Puppet::FileBucketFile::File.new.send(:verify_identical_file!, @bucket) }.should raise_error(Puppet::FileBucket::BucketError) end it "should do nothing if the files match" do File.expects(:read).with("#{@dir}/contents").returns("file contents") Puppet::FileBucketFile::File.new.send(:verify_identical_file!, @bucket) end end end diff --git a/spec/unit/indirector/file_bucket_file/rest_spec.rb b/spec/unit/indirector/file_bucket_file/rest_spec.rb index 61dab2935..ae2e033c6 100755 --- a/spec/unit/indirector/file_bucket_file/rest_spec.rb +++ b/spec/unit/indirector/file_bucket_file/rest_spec.rb @@ -1,11 +1,10 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/indirector/file_bucket_file/rest' describe Puppet::FileBucketFile::Rest do it "should be a sublcass of Puppet::Indirector::REST" do Puppet::FileBucketFile::Rest.superclass.should equal(Puppet::Indirector::REST) end end diff --git a/spec/unit/indirector/file_content/file_server_spec.rb b/spec/unit/indirector/file_content/file_server_spec.rb index 6661e8786..99a535dc3 100755 --- a/spec/unit/indirector/file_content/file_server_spec.rb +++ b/spec/unit/indirector/file_content/file_server_spec.rb @@ -1,18 +1,18 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Created by Luke Kanies on 2007-10-18. # Copyright (c) 2007. All rights reserved. require 'spec_helper' require 'puppet/indirector/file_content/file_server' describe Puppet::Indirector::FileContent::FileServer do it "should be registered with the file_content indirection" do Puppet::Indirector::Terminus.terminus_class(:file_content, :file_server).should equal(Puppet::Indirector::FileContent::FileServer) end it "should be a subclass of the FileServer terminus" do Puppet::Indirector::FileContent::FileServer.superclass.should equal(Puppet::Indirector::FileServer) end end diff --git a/spec/unit/indirector/file_content/file_spec.rb b/spec/unit/indirector/file_content/file_spec.rb index 7ba01263f..b629981c5 100755 --- a/spec/unit/indirector/file_content/file_spec.rb +++ b/spec/unit/indirector/file_content/file_spec.rb @@ -1,18 +1,18 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Created by Luke Kanies on 2007-10-18. # Copyright (c) 2007. All rights reserved. require 'spec_helper' require 'puppet/indirector/file_content/file' describe Puppet::Indirector::FileContent::File do it "should be registered with the file_content indirection" do Puppet::Indirector::Terminus.terminus_class(:file_content, :file).should equal(Puppet::Indirector::FileContent::File) end it "should be a subclass of the DirectFileServer terminus" do Puppet::Indirector::FileContent::File.superclass.should equal(Puppet::Indirector::DirectFileServer) end end diff --git a/spec/unit/indirector/file_content/rest_spec.rb b/spec/unit/indirector/file_content/rest_spec.rb index dbcf7c2f8..06ad16e77 100755 --- a/spec/unit/indirector/file_content/rest_spec.rb +++ b/spec/unit/indirector/file_content/rest_spec.rb @@ -1,11 +1,10 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/indirector/file_content' describe "Puppet::Indirector::Content::Rest" do it "should add the node's cert name to the arguments" it "should set the content type to text/plain" end diff --git a/spec/unit/indirector/file_metadata/file_server_spec.rb b/spec/unit/indirector/file_metadata/file_server_spec.rb index 507da16ef..e16829035 100755 --- a/spec/unit/indirector/file_metadata/file_server_spec.rb +++ b/spec/unit/indirector/file_metadata/file_server_spec.rb @@ -1,18 +1,18 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Created by Luke Kanies on 2007-10-18. # Copyright (c) 2007. All rights reserved. require 'spec_helper' require 'puppet/indirector/file_metadata/file_server' describe Puppet::Indirector::FileMetadata::FileServer do it "should be registered with the file_metadata indirection" do Puppet::Indirector::Terminus.terminus_class(:file_metadata, :file_server).should equal(Puppet::Indirector::FileMetadata::FileServer) end it "should be a subclass of the FileServer terminus" do Puppet::Indirector::FileMetadata::FileServer.superclass.should equal(Puppet::Indirector::FileServer) end end diff --git a/spec/unit/indirector/file_metadata/file_spec.rb b/spec/unit/indirector/file_metadata/file_spec.rb index e3a766699..28a974290 100755 --- a/spec/unit/indirector/file_metadata/file_spec.rb +++ b/spec/unit/indirector/file_metadata/file_spec.rb @@ -1,52 +1,52 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Created by Luke Kanies on 2007-10-18. # Copyright (c) 2007. All rights reserved. require 'spec_helper' require 'puppet/indirector/file_metadata/file' describe Puppet::Indirector::FileMetadata::File do it "should be registered with the file_metadata indirection" do Puppet::Indirector::Terminus.terminus_class(:file_metadata, :file).should equal(Puppet::Indirector::FileMetadata::File) end it "should be a subclass of the DirectFileServer terminus" do Puppet::Indirector::FileMetadata::File.superclass.should equal(Puppet::Indirector::DirectFileServer) end describe "when creating the instance for a single found file" do before do @metadata = Puppet::Indirector::FileMetadata::File.new @uri = "file:///my/local" @data = mock 'metadata' @data.stubs(:collect) FileTest.expects(:exists?).with("/my/local").returns true @request = Puppet::Indirector::Request.new(:file_metadata, :find, @uri) end it "should collect its attributes when a file is found" do @data.expects(:collect) Puppet::FileServing::Metadata.expects(:new).returns(@data) @metadata.find(@request).should == @data end end describe "when searching for multiple files" do before do @metadata = Puppet::Indirector::FileMetadata::File.new @uri = "file:///my/local" @request = Puppet::Indirector::Request.new(:file_metadata, :find, @uri) end it "should collect the attributes of the instances returned" do FileTest.expects(:exists?).with("/my/local").returns true @metadata.expects(:path2instances).returns( [mock("one", :collect => nil), mock("two", :collect => nil)] ) @metadata.search(@request) end end end diff --git a/spec/unit/indirector/file_metadata/rest_spec.rb b/spec/unit/indirector/file_metadata/rest_spec.rb index 9cdd2ee06..511f7c758 100755 --- a/spec/unit/indirector/file_metadata/rest_spec.rb +++ b/spec/unit/indirector/file_metadata/rest_spec.rb @@ -1,9 +1,8 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/indirector/file_metadata' describe "Puppet::Indirector::Metadata::Rest" do it "should add the node's cert name to the arguments" end diff --git a/spec/unit/indirector/file_server_spec.rb b/spec/unit/indirector/file_server_spec.rb index 9f677399f..6df715fb1 100755 --- a/spec/unit/indirector/file_server_spec.rb +++ b/spec/unit/indirector/file_server_spec.rb @@ -1,267 +1,267 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Created by Luke Kanies on 2007-10-19. # Copyright (c) 2007. All rights reserved. require 'spec_helper' require 'puppet/indirector/file_server' require 'puppet/file_serving/configuration' describe Puppet::Indirector::FileServer do before :all do Puppet::Indirector::Terminus.stubs(:register_terminus_class) @model = mock 'model' @indirection = stub 'indirection', :name => :mystuff, :register_terminus_type => nil, :model => @model Puppet::Indirector::Indirection.stubs(:instance).returns(@indirection) module Testing; end @file_server_class = class Testing::MyFileServer < Puppet::Indirector::FileServer self end end before :each do @file_server = @file_server_class.new @uri = "puppet://host/my/local/file" @configuration = mock 'configuration' Puppet::FileServing::Configuration.stubs(:create).returns(@configuration) @request = Puppet::Indirector::Request.new(:myind, :mymethod, @uri, :environment => "myenv") end describe "when finding files" do before do @mount = stub 'mount', :find => nil @instance = stub('instance', :links= => nil, :collect => nil) end it "should use the configuration to find the mount and relative path" do @configuration.expects(:split_path).with(@request) @file_server.find(@request) end it "should return nil if it cannot find the mount" do @configuration.expects(:split_path).with(@request).returns(nil, nil) @file_server.find(@request).should be_nil end it "should use the mount to find the full path" do @configuration.expects(:split_path).with(@request).returns([@mount, "rel/path"]) @mount.expects(:find).with { |key, request| key == "rel/path" } @file_server.find(@request) end it "should pass the request when finding a file" do @configuration.expects(:split_path).with(@request).returns([@mount, "rel/path"]) @mount.expects(:find).with { |key, request| request == @request } @file_server.find(@request) end it "should return nil if it cannot find a full path" do @configuration.expects(:split_path).with(@request).returns([@mount, "rel/path"]) @mount.expects(:find).with { |key, request| key == "rel/path" }.returns nil @file_server.find(@request).should be_nil end it "should create an instance with the found path" do @configuration.expects(:split_path).with(@request).returns([@mount, "rel/path"]) @mount.expects(:find).with { |key, request| key == "rel/path" }.returns "/my/file" @model.expects(:new).with("/my/file").returns @instance @file_server.find(@request).should equal(@instance) end it "should set 'links' on the instance if it is set in the request options" do @request.options[:links] = true @configuration.expects(:split_path).with(@request).returns([@mount, "rel/path"]) @mount.expects(:find).with { |key, request| key == "rel/path" }.returns "/my/file" @model.expects(:new).with("/my/file").returns @instance @instance.expects(:links=).with(true) @file_server.find(@request).should equal(@instance) end it "should collect the instance" do @request.options[:links] = true @configuration.expects(:split_path).with(@request).returns([@mount, "rel/path"]) @mount.expects(:find).with { |key, request| key == "rel/path" }.returns "/my/file" @model.expects(:new).with("/my/file").returns @instance @instance.expects(:collect) @file_server.find(@request).should equal(@instance) end end describe "when searching for instances" do before do @mount = stub 'mount', :search => nil @instance = stub('instance', :links= => nil, :collect => nil) end it "should use the configuration to search the mount and relative path" do @configuration.expects(:split_path).with(@request) @file_server.search(@request) end it "should return nil if it cannot search the mount" do @configuration.expects(:split_path).with(@request).returns(nil, nil) @file_server.search(@request).should be_nil end it "should use the mount to search for the full paths" do @configuration.expects(:split_path).with(@request).returns([@mount, "rel/path"]) @mount.expects(:search).with { |key, request| key == "rel/path" } @file_server.search(@request) end it "should pass the request" do @configuration.stubs(:split_path).returns([@mount, "rel/path"]) @mount.expects(:search).with { |key, request| request == @request } @file_server.search(@request) end it "should return nil if searching does not find any full paths" do @configuration.expects(:split_path).with(@request).returns([@mount, "rel/path"]) @mount.expects(:search).with { |key, request| key == "rel/path" }.returns nil @file_server.search(@request).should be_nil end it "should create a fileset with each returned path and merge them" do @configuration.expects(:split_path).with(@request).returns([@mount, "rel/path"]) @mount.expects(:search).with { |key, request| key == "rel/path" }.returns %w{/one /two} FileTest.stubs(:exist?).returns true one = mock 'fileset_one' Puppet::FileServing::Fileset.expects(:new).with("/one", @request).returns(one) two = mock 'fileset_two' Puppet::FileServing::Fileset.expects(:new).with("/two", @request).returns(two) Puppet::FileServing::Fileset.expects(:merge).with(one, two).returns [] @file_server.search(@request) end it "should create an instance with each path resulting from the merger of the filesets" do @configuration.expects(:split_path).with(@request).returns([@mount, "rel/path"]) @mount.expects(:search).with { |key, request| key == "rel/path" }.returns [] FileTest.stubs(:exist?).returns true Puppet::FileServing::Fileset.expects(:merge).returns("one" => "/one", "two" => "/two") one = stub 'one', :collect => nil @model.expects(:new).with("/one", :relative_path => "one").returns one two = stub 'two', :collect => nil @model.expects(:new).with("/two", :relative_path => "two").returns two # order can't be guaranteed result = @file_server.search(@request) result.should be_include(one) result.should be_include(two) result.length.should == 2 end it "should set 'links' on the instances if it is set in the request options" do @configuration.expects(:split_path).with(@request).returns([@mount, "rel/path"]) @mount.expects(:search).with { |key, request| key == "rel/path" }.returns [] FileTest.stubs(:exist?).returns true Puppet::FileServing::Fileset.expects(:merge).returns("one" => "/one") one = stub 'one', :collect => nil @model.expects(:new).with("/one", :relative_path => "one").returns one one.expects(:links=).with true @request.options[:links] = true @file_server.search(@request) end it "should collect the instances" do @configuration.expects(:split_path).with(@request).returns([@mount, "rel/path"]) @mount.expects(:search).with { |key, options| key == "rel/path" }.returns [] FileTest.stubs(:exist?).returns true Puppet::FileServing::Fileset.expects(:merge).returns("one" => "/one") one = mock 'one' @model.expects(:new).with("/one", :relative_path => "one").returns one one.expects(:collect) @file_server.search(@request) end end describe "when checking authorization" do before do @request.method = :find @mount = stub 'mount' @configuration.stubs(:split_path).with(@request).returns([@mount, "rel/path"]) @request.stubs(:node).returns("mynode") @request.stubs(:ip).returns("myip") @mount.stubs(:allowed?).with("mynode", "myip").returns "something" end it "should return false when destroying" do @request.method = :destroy @file_server.should_not be_authorized(@request) end it "should return false when saving" do @request.method = :save @file_server.should_not be_authorized(@request) end it "should use the configuration to find the mount and relative path" do @configuration.expects(:split_path).with(@request) @file_server.authorized?(@request) end it "should return false if it cannot find the mount" do @configuration.expects(:split_path).with(@request).returns(nil, nil) @file_server.should_not be_authorized(@request) end it "should return the results of asking the mount whether the node and IP are authorized" do @file_server.authorized?(@request).should == "something" end end end diff --git a/spec/unit/indirector/file_spec.rb b/spec/unit/indirector/file_spec.rb index 50b1706bf..b72bf4d67 100755 --- a/spec/unit/indirector/file_spec.rb +++ b/spec/unit/indirector/file_spec.rb @@ -1,180 +1,179 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/indirector/file' describe Puppet::Indirector::File do before :all do Puppet::Indirector::Terminus.stubs(:register_terminus_class) @model = mock 'model' @indirection = stub 'indirection', :name => :mystuff, :register_terminus_type => nil, :model => @model Puppet::Indirector::Indirection.stubs(:instance).returns(@indirection) module Testing; end @file_class = class Testing::MyFile < Puppet::Indirector::File self end @searcher = @file_class.new @path = "/my/file" @dir = "/my" @request = stub 'request', :key => @path end describe "when finding files" do it "should provide a method to return file contents at a specified path" do @searcher.should respond_to(:find) end it "should use the server data directory plus the indirection name if the run_mode is master" do Puppet.run_mode.expects(:master?).returns true Puppet.settings.expects(:value).with(:server_datadir).returns "/my/dir" @searcher.data_directory.should == File.join("/my/dir", "mystuff") end it "should use the client data directory plus the indirection name if the run_mode is not master" do Puppet.run_mode.expects(:master?).returns false Puppet.settings.expects(:value).with(:client_datadir).returns "/my/dir" @searcher.data_directory.should == File.join("/my/dir", "mystuff") end it "should use the newest file in the data directory matching the indirection key without extension" do @searcher.expects(:data_directory).returns "/data/dir" @request.stubs(:key).returns "foo" Dir.expects(:glob).with("/data/dir/foo.*").returns %w{/data1.stuff /data2.stuff} stat1 = stub 'data1', :mtime => (Time.now - 5) stat2 = stub 'data2', :mtime => Time.now File.expects(:stat).with("/data1.stuff").returns stat1 File.expects(:stat).with("/data2.stuff").returns stat2 @searcher.latest_path(@request).should == "/data2.stuff" end it "should return nil when no files are found" do @searcher.stubs(:latest_path).returns nil @searcher.find(@request).should be_nil end it "should determine the file format from the file extension" do @searcher.file_format("/data2.pson").should == "pson" end it "should fail if the model does not support the file format" do @searcher.stubs(:latest_path).returns "/my/file.pson" @model.expects(:support_format?).with("pson").returns false lambda { @searcher.find(@request) }.should raise_error(ArgumentError) end end describe "when saving files" do before do @content = "my content" @file = stub 'file', :content => @content, :path => @path, :name => @path, :render => "mydata" @request.stubs(:instance).returns @file end it "should provide a method to save file contents at a specified path" do @searcher.should respond_to(:save) end it "should choose the file extension based on the default format of the model" do @model.expects(:default_format).returns "pson" @searcher.serialization_format.should == "pson" end it "should place the file in the data directory, named after the indirection, key, and format" do @searcher.stubs(:data_directory).returns "/my/dir" @searcher.stubs(:serialization_format).returns "pson" @request.stubs(:key).returns "foo" @searcher.file_path(@request).should == File.join("/my/dir", "foo.pson") end it "should fail intelligently if the file's parent directory does not exist" do @searcher.stubs(:file_path).returns "/my/dir/file.pson" @searcher.stubs(:serialization_format).returns "pson" @request.stubs(:key).returns "foo" File.expects(:directory?).with(File.join("/my/dir")).returns(false) proc { @searcher.save(@request) }.should raise_error(Puppet::Error) end it "should render the instance using the file format and print it to the file path" do @searcher.stubs(:file_path).returns "/my/file.pson" @searcher.stubs(:serialization_format).returns "pson" File.stubs(:directory?).returns true @request.instance.expects(:render).with("pson").returns "data" fh = mock 'filehandle' File.expects(:open).with("/my/file.pson", "w").yields fh fh.expects(:print).with("data") @searcher.save(@request) end it "should fail intelligently if a file cannot be written" do filehandle = mock 'file' File.stubs(:directory?).returns(true) File.stubs(:open).yields(filehandle) filehandle.expects(:print).raises(ArgumentError) @searcher.stubs(:file_path).returns "/my/file.pson" @model.stubs(:default_format).returns "pson" @instance.stubs(:render).returns "stuff" proc { @searcher.save(@request) }.should raise_error(Puppet::Error) end end describe "when removing files" do it "should provide a method to remove files" do @searcher.should respond_to(:destroy) end it "should remove files in all formats found in the data directory that match the request key" do @searcher.stubs(:data_directory).returns "/my/dir" @request.stubs(:key).returns "me" Dir.expects(:glob).with(File.join("/my/dir", "me.*")).returns %w{/one /two} File.expects(:unlink).with("/one") File.expects(:unlink).with("/two") @searcher.destroy(@request) end it "should throw an exception if no file is found" do @searcher.stubs(:data_directory).returns "/my/dir" @request.stubs(:key).returns "me" Dir.expects(:glob).with(File.join("/my/dir", "me.*")).returns [] proc { @searcher.destroy(@request) }.should raise_error(Puppet::Error) end it "should fail intelligently if a file cannot be removed" do @searcher.stubs(:data_directory).returns "/my/dir" @request.stubs(:key).returns "me" Dir.expects(:glob).with(File.join("/my/dir", "me.*")).returns %w{/one} File.expects(:unlink).with("/one").raises ArgumentError proc { @searcher.destroy(@request) }.should raise_error(Puppet::Error) end end end diff --git a/spec/unit/indirector/indirection_spec.rb b/spec/unit/indirector/indirection_spec.rb index 114062a20..4bbc855b1 100755 --- a/spec/unit/indirector/indirection_spec.rb +++ b/spec/unit/indirector/indirection_spec.rb @@ -1,861 +1,860 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/indirector/indirection' shared_examples_for "Indirection Delegator" do it "should create a request object with the appropriate method name and all of the passed arguments" do request = Puppet::Indirector::Request.new(:indirection, :find, "me") @indirection.expects(:request).with(@method, "mystuff", :one => :two).returns request @terminus.stubs(@method) @indirection.send(@method, "mystuff", :one => :two) end it "should let the :select_terminus method choose the terminus using the created request if the :select_terminus method is available" do # Define the method, so our respond_to? hook matches. class << @indirection def select_terminus(request) end end request = Puppet::Indirector::Request.new(:indirection, :find, "me") @indirection.stubs(:request).returns request @indirection.expects(:select_terminus).with(request).returns :test_terminus @indirection.stubs(:check_authorization) @terminus.expects(@method) @indirection.send(@method, "me") end it "should fail if the :select_terminus hook does not return a terminus name" do # Define the method, so our respond_to? hook matches. class << @indirection def select_terminus(request) end end request = stub 'request', :key => "me", :options => {} @indirection.stubs(:request).returns request @indirection.expects(:select_terminus).with(request).returns nil lambda { @indirection.send(@method, "me") }.should raise_error(ArgumentError) end it "should choose the terminus returned by the :terminus_class method if no :select_terminus method is available" do @indirection.expects(:terminus_class).returns :test_terminus @terminus.expects(@method) @indirection.send(@method, "me") end it "should let the appropriate terminus perform the lookup" do @terminus.expects(@method).with { |r| r.is_a?(Puppet::Indirector::Request) } @indirection.send(@method, "me") end end shared_examples_for "Delegation Authorizer" do before do # So the :respond_to? turns out correctly. class << @terminus def authorized? end end end it "should not check authorization if a node name is not provided" do @terminus.expects(:authorized?).never @terminus.stubs(@method) # The quotes are necessary here, else it looks like a block. @request.stubs(:options).returns({}) @indirection.send(@method, "/my/key") end it "should pass the request to the terminus's authorization method" do @terminus.expects(:authorized?).with { |r| r.is_a?(Puppet::Indirector::Request) }.returns(true) @terminus.stubs(@method) @indirection.send(@method, "/my/key", :node => "mynode") end it "should fail if authorization returns false" do @terminus.expects(:authorized?).returns(false) @terminus.stubs(@method) proc { @indirection.send(@method, "/my/key", :node => "mynode") }.should raise_error(ArgumentError) end it "should continue if authorization returns true" do @terminus.expects(:authorized?).returns(true) @terminus.stubs(@method) @indirection.send(@method, "/my/key", :node => "mynode") end end describe Puppet::Indirector::Indirection do after do Puppet::Util::Cacher.expire end describe "when initializing" do # (LAK) I've no idea how to test this, really. it "should store a reference to itself before it consumes its options" do proc { @indirection = Puppet::Indirector::Indirection.new(Object.new, :testingness, :not_valid_option) }.should raise_error Puppet::Indirector::Indirection.instance(:testingness).should be_instance_of(Puppet::Indirector::Indirection) Puppet::Indirector::Indirection.instance(:testingness).delete end it "should keep a reference to the indirecting model" do model = mock 'model' @indirection = Puppet::Indirector::Indirection.new(model, :myind) @indirection.model.should equal(model) end it "should set the name" do @indirection = Puppet::Indirector::Indirection.new(mock('model'), :myind) @indirection.name.should == :myind end it "should require indirections to have unique names" do @indirection = Puppet::Indirector::Indirection.new(mock('model'), :test) proc { Puppet::Indirector::Indirection.new(:test) }.should raise_error(ArgumentError) end it "should extend itself with any specified module" do mod = Module.new @indirection = Puppet::Indirector::Indirection.new(mock('model'), :test, :extend => mod) @indirection.singleton_class.included_modules.should include(mod) end after do @indirection.delete if defined?(@indirection) end end describe "when an instance" do before :each do @terminus_class = mock 'terminus_class' @terminus = mock 'terminus' @terminus_class.stubs(:new).returns(@terminus) @cache = stub 'cache', :name => "mycache" @cache_class = mock 'cache_class' Puppet::Indirector::Terminus.stubs(:terminus_class).with(:test, :cache_terminus).returns(@cache_class) Puppet::Indirector::Terminus.stubs(:terminus_class).with(:test, :test_terminus).returns(@terminus_class) @indirection = Puppet::Indirector::Indirection.new(mock('model'), :test) @indirection.terminus_class = :test_terminus @instance = stub 'instance', :expiration => nil, :expiration= => nil, :name => "whatever" @name = :mything #@request = stub 'instance', :key => "/my/key", :instance => @instance, :options => {} @request = mock 'instance' end it "should allow setting the ttl" do @indirection.ttl = 300 @indirection.ttl.should == 300 end it "should default to the :runinterval setting, converted to an integer, for its ttl" do Puppet.settings.expects(:value).returns "1800" @indirection.ttl.should == 1800 end it "should calculate the current expiration by adding the TTL to the current time" do @indirection.stubs(:ttl).returns(100) now = Time.now Time.stubs(:now).returns now @indirection.expiration.should == (Time.now + 100) end it "should have a method for creating an indirection request instance" do @indirection.should respond_to(:request) end describe "creates a request" do it "should create it with its name as the request's indirection name" do Puppet::Indirector::Request.expects(:new).with { |name, *other| @indirection.name == name } @indirection.request(:funtest, "yayness") end it "should require a method and key" do Puppet::Indirector::Request.expects(:new).with { |name, method, key, *other| method == :funtest and key == "yayness" } @indirection.request(:funtest, "yayness") end it "should support optional arguments" do Puppet::Indirector::Request.expects(:new).with { |name, method, key, other| other == {:one => :two} } @indirection.request(:funtest, "yayness", :one => :two) end it "should not pass options if none are supplied" do Puppet::Indirector::Request.expects(:new).with { |*args| args.length < 4 } @indirection.request(:funtest, "yayness") end it "should return the request" do request = mock 'request' Puppet::Indirector::Request.expects(:new).returns request @indirection.request(:funtest, "yayness").should equal(request) end end describe "and looking for a model instance" do before { @method = :find } it_should_behave_like "Indirection Delegator" it_should_behave_like "Delegation Authorizer" it "should return the results of the delegation" do @terminus.expects(:find).returns(@instance) @indirection.find("me").should equal(@instance) end it "should set the expiration date on any instances without one set" do @terminus.stubs(:find).returns(@instance) @indirection.expects(:expiration).returns :yay @instance.expects(:expiration).returns(nil) @instance.expects(:expiration=).with(:yay) @indirection.find("/my/key") end it "should not override an already-set expiration date on returned instances" do @terminus.stubs(:find).returns(@instance) @indirection.expects(:expiration).never @instance.expects(:expiration).returns(:yay) @instance.expects(:expiration=).never @indirection.find("/my/key") end it "should filter the result instance if the terminus supports it" do @terminus.stubs(:find).returns(@instance) @terminus.stubs(:respond_to?).with(:filter).returns(true) @terminus.expects(:filter).with(@instance) @indirection.find("/my/key") end describe "when caching is enabled" do before do @indirection.cache_class = :cache_terminus @cache_class.stubs(:new).returns(@cache) @instance.stubs(:expired?).returns false end it "should first look in the cache for an instance" do @terminus.stubs(:find).never @cache.expects(:find).returns @instance @indirection.find("/my/key") end it "should not look in the cache if the request specifies not to use the cache" do @terminus.expects(:find).returns @instance @cache.expects(:find).never @cache.stubs(:save) @indirection.find("/my/key", :ignore_cache => true) end it "should still save to the cache even if the cache is being ignored during readin" do @terminus.expects(:find).returns @instance @cache.expects(:save) @indirection.find("/my/key", :ignore_cache => true) end it "should only look in the cache if the request specifies not to use the terminus" do @terminus.expects(:find).never @cache.expects(:find) @indirection.find("/my/key", :ignore_terminus => true) end it "should use a request to look in the cache for cached objects" do @cache.expects(:find).with { |r| r.method == :find and r.key == "/my/key" }.returns @instance @cache.stubs(:save) @indirection.find("/my/key") end it "should return the cached object if it is not expired" do @instance.stubs(:expired?).returns false @cache.stubs(:find).returns @instance @indirection.find("/my/key").should equal(@instance) end it "should not fail if the cache fails" do @terminus.stubs(:find).returns @instance @cache.expects(:find).raises ArgumentError @cache.stubs(:save) lambda { @indirection.find("/my/key") }.should_not raise_error end it "should look in the main terminus if the cache fails" do @terminus.expects(:find).returns @instance @cache.expects(:find).raises ArgumentError @cache.stubs(:save) @indirection.find("/my/key").should equal(@instance) end it "should send a debug log if it is using the cached object" do Puppet.expects(:debug) @cache.stubs(:find).returns @instance @indirection.find("/my/key") end it "should not return the cached object if it is expired" do @instance.stubs(:expired?).returns true @cache.stubs(:find).returns @instance @terminus.stubs(:find).returns nil @indirection.find("/my/key").should be_nil end it "should send an info log if it is using the cached object" do Puppet.expects(:info) @instance.stubs(:expired?).returns true @cache.stubs(:find).returns @instance @terminus.stubs(:find).returns nil @indirection.find("/my/key") end it "should cache any objects not retrieved from the cache" do @cache.expects(:find).returns nil @terminus.expects(:find).returns(@instance) @cache.expects(:save) @indirection.find("/my/key") end it "should use a request to look in the cache for cached objects" do @cache.expects(:find).with { |r| r.method == :find and r.key == "/my/key" }.returns nil @terminus.stubs(:find).returns(@instance) @cache.stubs(:save) @indirection.find("/my/key") end it "should cache the instance using a request with the instance set to the cached object" do @cache.stubs(:find).returns nil @terminus.stubs(:find).returns(@instance) @cache.expects(:save).with { |r| r.method == :save and r.instance == @instance } @indirection.find("/my/key") end it "should send an info log that the object is being cached" do @cache.stubs(:find).returns nil @terminus.stubs(:find).returns(@instance) @cache.stubs(:save) Puppet.expects(:info) @indirection.find("/my/key") end end end describe "and doing a head operation" do before { @method = :head } it_should_behave_like "Indirection Delegator" it_should_behave_like "Delegation Authorizer" it "should return true if the head method returned true" do @terminus.expects(:head).returns(true) @indirection.head("me").should == true end it "should return false if the head method returned false" do @terminus.expects(:head).returns(false) @indirection.head("me").should == false end describe "when caching is enabled" do before do @indirection.cache_class = :cache_terminus @cache_class.stubs(:new).returns(@cache) @instance.stubs(:expired?).returns false end it "should first look in the cache for an instance" do @terminus.stubs(:find).never @terminus.stubs(:head).never @cache.expects(:find).returns @instance @indirection.head("/my/key").should == true end it "should not save to the cache" do @cache.expects(:find).returns nil @cache.expects(:save).never @terminus.expects(:head).returns true @indirection.head("/my/key").should == true end it "should not fail if the cache fails" do @terminus.stubs(:head).returns true @cache.expects(:find).raises ArgumentError lambda { @indirection.head("/my/key") }.should_not raise_error end it "should look in the main terminus if the cache fails" do @terminus.expects(:head).returns true @cache.expects(:find).raises ArgumentError @indirection.head("/my/key").should == true end it "should send a debug log if it is using the cached object" do Puppet.expects(:debug) @cache.stubs(:find).returns @instance @indirection.head("/my/key") end it "should not accept the cached object if it is expired" do @instance.stubs(:expired?).returns true @cache.stubs(:find).returns @instance @terminus.stubs(:head).returns false @indirection.head("/my/key").should == false end end end describe "and storing a model instance" do before { @method = :save } it "should return the result of the save" do @terminus.stubs(:save).returns "foo" @indirection.save(@instance).should == "foo" end describe "when caching is enabled" do before do @indirection.cache_class = :cache_terminus @cache_class.stubs(:new).returns(@cache) @instance.stubs(:expired?).returns false end it "should return the result of saving to the terminus" do request = stub 'request', :instance => @instance, :node => nil @indirection.expects(:request).returns request @cache.stubs(:save) @terminus.stubs(:save).returns @instance @indirection.save(@instance).should equal(@instance) end it "should use a request to save the object to the cache" do request = stub 'request', :instance => @instance, :node => nil @indirection.expects(:request).returns request @cache.expects(:save).with(request) @terminus.stubs(:save) @indirection.save(@instance) end it "should not save to the cache if the normal save fails" do request = stub 'request', :instance => @instance, :node => nil @indirection.expects(:request).returns request @cache.expects(:save).never @terminus.expects(:save).raises "eh" lambda { @indirection.save(@instance) }.should raise_error end end end describe "and removing a model instance" do before { @method = :destroy } it_should_behave_like "Indirection Delegator" it_should_behave_like "Delegation Authorizer" it "should return the result of removing the instance" do @terminus.stubs(:destroy).returns "yayness" @indirection.destroy("/my/key").should == "yayness" end describe "when caching is enabled" do before do @indirection.cache_class = :cache_terminus @cache_class.expects(:new).returns(@cache) @instance.stubs(:expired?).returns false end it "should use a request instance to search in and remove objects from the cache" do destroy = stub 'destroy_request', :key => "/my/key", :node => nil find = stub 'destroy_request', :key => "/my/key", :node => nil @indirection.expects(:request).with(:destroy, "/my/key").returns destroy @indirection.expects(:request).with(:find, "/my/key").returns find cached = mock 'cache' @cache.expects(:find).with(find).returns cached @cache.expects(:destroy).with(destroy) @terminus.stubs(:destroy) @indirection.destroy("/my/key") end end end describe "and searching for multiple model instances" do before { @method = :search } it_should_behave_like "Indirection Delegator" it_should_behave_like "Delegation Authorizer" it "should set the expiration date on any instances without one set" do @terminus.stubs(:search).returns([@instance]) @indirection.expects(:expiration).returns :yay @instance.expects(:expiration).returns(nil) @instance.expects(:expiration=).with(:yay) @indirection.search("/my/key") end it "should not override an already-set expiration date on returned instances" do @terminus.stubs(:search).returns([@instance]) @indirection.expects(:expiration).never @instance.expects(:expiration).returns(:yay) @instance.expects(:expiration=).never @indirection.search("/my/key") end it "should return the results of searching in the terminus" do @terminus.expects(:search).returns([@instance]) @indirection.search("/my/key").should == [@instance] end end describe "and expiring a model instance" do describe "when caching is not enabled" do it "should do nothing" do @cache_class.expects(:new).never @indirection.expire("/my/key") end end describe "when caching is enabled" do before do @indirection.cache_class = :cache_terminus @cache_class.expects(:new).returns(@cache) @instance.stubs(:expired?).returns false @cached = stub 'cached', :expiration= => nil, :name => "/my/key" end it "should use a request to find within the cache" do @cache.expects(:find).with { |r| r.is_a?(Puppet::Indirector::Request) and r.method == :find } @indirection.expire("/my/key") end it "should do nothing if no such instance is cached" do @cache.expects(:find).returns nil @indirection.expire("/my/key") end it "should log when expiring a found instance" do @cache.expects(:find).returns @cached @cache.stubs(:save) Puppet.expects(:info) @indirection.expire("/my/key") end it "should set the cached instance's expiration to a time in the past" do @cache.expects(:find).returns @cached @cache.stubs(:save) @cached.expects(:expiration=).with { |t| t < Time.now } @indirection.expire("/my/key") end it "should save the now expired instance back into the cache" do @cache.expects(:find).returns @cached @cached.expects(:expiration=).with { |t| t < Time.now } @cache.expects(:save) @indirection.expire("/my/key") end it "should use a request to save the expired resource to the cache" do @cache.expects(:find).returns @cached @cached.expects(:expiration=).with { |t| t < Time.now } @cache.expects(:save).with { |r| r.is_a?(Puppet::Indirector::Request) and r.instance == @cached and r.method == :save }.returns(@cached) @indirection.expire("/my/key") end end end after :each do @indirection.delete Puppet::Util::Cacher.expire end end describe "when managing indirection instances" do it "should allow an indirection to be retrieved by name" do @indirection = Puppet::Indirector::Indirection.new(mock('model'), :test) Puppet::Indirector::Indirection.instance(:test).should equal(@indirection) end it "should return nil when the named indirection has not been created" do Puppet::Indirector::Indirection.instance(:test).should be_nil end it "should allow an indirection's model to be retrieved by name" do mock_model = mock('model') @indirection = Puppet::Indirector::Indirection.new(mock_model, :test) Puppet::Indirector::Indirection.model(:test).should equal(mock_model) end it "should return nil when no model matches the requested name" do Puppet::Indirector::Indirection.model(:test).should be_nil end after do @indirection.delete if defined?(@indirection) end end describe "when routing to the correct the terminus class" do before do @indirection = Puppet::Indirector::Indirection.new(mock('model'), :test) @terminus = mock 'terminus' @terminus_class = stub 'terminus class', :new => @terminus Puppet::Indirector::Terminus.stubs(:terminus_class).with(:test, :default).returns(@terminus_class) end it "should fail if no terminus class can be picked" do proc { @indirection.terminus_class }.should raise_error(Puppet::DevError) end it "should choose the default terminus class if one is specified" do @indirection.terminus_class = :default @indirection.terminus_class.should equal(:default) end it "should use the provided Puppet setting if told to do so" do Puppet::Indirector::Terminus.stubs(:terminus_class).with(:test, :my_terminus).returns(mock("terminus_class2")) Puppet.settings.expects(:value).with(:my_setting).returns("my_terminus") @indirection.terminus_setting = :my_setting @indirection.terminus_class.should equal(:my_terminus) end it "should fail if the provided terminus class is not valid" do Puppet::Indirector::Terminus.stubs(:terminus_class).with(:test, :nosuchclass).returns(nil) proc { @indirection.terminus_class = :nosuchclass }.should raise_error(ArgumentError) end after do @indirection.delete if defined?(@indirection) end end describe "when specifying the terminus class to use" do before do @indirection = Puppet::Indirector::Indirection.new(mock('model'), :test) @terminus = mock 'terminus' @terminus_class = stub 'terminus class', :new => @terminus end it "should allow specification of a terminus type" do @indirection.should respond_to(:terminus_class=) end it "should fail to redirect if no terminus type has been specified" do proc { @indirection.find("blah") }.should raise_error(Puppet::DevError) end it "should fail when the terminus class name is an empty string" do proc { @indirection.terminus_class = "" }.should raise_error(ArgumentError) end it "should fail when the terminus class name is nil" do proc { @indirection.terminus_class = nil }.should raise_error(ArgumentError) end it "should fail when the specified terminus class cannot be found" do Puppet::Indirector::Terminus.expects(:terminus_class).with(:test, :foo).returns(nil) proc { @indirection.terminus_class = :foo }.should raise_error(ArgumentError) end it "should select the specified terminus class if a terminus class name is provided" do Puppet::Indirector::Terminus.expects(:terminus_class).with(:test, :foo).returns(@terminus_class) @indirection.terminus(:foo).should equal(@terminus) end it "should use the configured terminus class if no terminus name is specified" do Puppet::Indirector::Terminus.stubs(:terminus_class).with(:test, :foo).returns(@terminus_class) @indirection.terminus_class = :foo @indirection.terminus.should equal(@terminus) end after do @indirection.delete if defined?(@indirection) end end describe "when managing terminus instances" do before do @indirection = Puppet::Indirector::Indirection.new(mock('model'), :test) @terminus = mock 'terminus' @terminus_class = mock 'terminus class' Puppet::Indirector::Terminus.stubs(:terminus_class).with(:test, :foo).returns(@terminus_class) end it "should create an instance of the chosen terminus class" do @terminus_class.stubs(:new).returns(@terminus) @indirection.terminus(:foo).should equal(@terminus) end # Make sure it caches the terminus. it "should return the same terminus instance each time for a given name" do @terminus_class.stubs(:new).returns(@terminus) @indirection.terminus(:foo).should equal(@terminus) @indirection.terminus(:foo).should equal(@terminus) end it "should not create a terminus instance until one is actually needed" do Puppet::Indirector.expects(:terminus).never indirection = Puppet::Indirector::Indirection.new(mock('model'), :lazytest) end after do @indirection.delete end end describe "when deciding whether to cache" do before do @indirection = Puppet::Indirector::Indirection.new(mock('model'), :test) @terminus = mock 'terminus' @terminus_class = mock 'terminus class' @terminus_class.stubs(:new).returns(@terminus) Puppet::Indirector::Terminus.stubs(:terminus_class).with(:test, :foo).returns(@terminus_class) @indirection.terminus_class = :foo end it "should provide a method for setting the cache terminus class" do @indirection.should respond_to(:cache_class=) end it "should fail to cache if no cache type has been specified" do proc { @indirection.cache }.should raise_error(Puppet::DevError) end it "should fail to set the cache class when the cache class name is an empty string" do proc { @indirection.cache_class = "" }.should raise_error(ArgumentError) end it "should allow resetting the cache_class to nil" do @indirection.cache_class = nil @indirection.cache_class.should be_nil end it "should fail to set the cache class when the specified cache class cannot be found" do Puppet::Indirector::Terminus.expects(:terminus_class).with(:test, :foo).returns(nil) proc { @indirection.cache_class = :foo }.should raise_error(ArgumentError) end after do @indirection.delete end end describe "when using a cache" do before :each do Puppet.settings.stubs(:value).with("test_terminus").returns("test_terminus") @terminus_class = mock 'terminus_class' @terminus = mock 'terminus' @terminus_class.stubs(:new).returns(@terminus) @cache = mock 'cache' @cache_class = mock 'cache_class' Puppet::Indirector::Terminus.stubs(:terminus_class).with(:test, :cache_terminus).returns(@cache_class) Puppet::Indirector::Terminus.stubs(:terminus_class).with(:test, :test_terminus).returns(@terminus_class) @indirection = Puppet::Indirector::Indirection.new(mock('model'), :test) @indirection.terminus_class = :test_terminus end describe "and managing the cache terminus" do it "should not create a cache terminus at initialization" do # This is weird, because all of the code is in the setup. If we got # new called on the cache class, we'd get an exception here. end it "should reuse the cache terminus" do @cache_class.expects(:new).returns(@cache) Puppet.settings.stubs(:value).with("test_cache").returns("cache_terminus") @indirection.cache_class = :cache_terminus @indirection.cache.should equal(@cache) @indirection.cache.should equal(@cache) end end describe "and saving" do end describe "and finding" do end after :each do @indirection.delete end end end diff --git a/spec/unit/indirector/inventory/yaml_spec.rb b/spec/unit/indirector/inventory/yaml_spec.rb index fddbf9d33..54ab9c72c 100755 --- a/spec/unit/indirector/inventory/yaml_spec.rb +++ b/spec/unit/indirector/inventory/yaml_spec.rb @@ -1,221 +1,220 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/node/inventory' require 'puppet/indirector/inventory/yaml' require 'puppet/indirector/request' describe Puppet::Node::Inventory::Yaml do def assert_search_matches(matching, nonmatching, query) request = Puppet::Indirector::Request.new(:inventory, :search, nil, query) Dir.stubs(:glob).returns(matching.keys + nonmatching.keys) [matching, nonmatching].each do |examples| examples.each do |key, value| YAML.stubs(:load_file).with(key).returns value end end Puppet::Node::Inventory::Yaml.new.search(request).should =~ matching.values.map {|facts| facts.name} end it "should return node names that match the search query options" do assert_search_matches({ '/path/to/matching.yaml' => Puppet::Node::Facts.new("matchingnode", "architecture" => "i386", 'processor_count' => '4'), '/path/to/matching1.yaml' => Puppet::Node::Facts.new("matchingnode1", "architecture" => "i386", 'processor_count' => '4', 'randomfact' => 'foo') }, { "/path/to/nonmatching.yaml" => Puppet::Node::Facts.new("nonmatchingnode", "architecture" => "powerpc", 'processor_count' => '4'), "/path/to/nonmatching1.yaml" => Puppet::Node::Facts.new("nonmatchingnode1", "architecture" => "powerpc", 'processor_count' => '5'), "/path/to/nonmatching2.yaml" => Puppet::Node::Facts.new("nonmatchingnode2", "architecture" => "i386", 'processor_count' => '5'), "/path/to/nonmatching3.yaml" => Puppet::Node::Facts.new("nonmatchingnode3", 'processor_count' => '4'), }, {'facts.architecture' => 'i386', 'facts.processor_count' => '4'} ) end it "should return empty array when no nodes match the search query options" do assert_search_matches({}, { "/path/to/nonmatching.yaml" => Puppet::Node::Facts.new("nonmatchingnode", "architecture" => "powerpc", 'processor_count' => '10'), "/path/to/nonmatching1.yaml" => Puppet::Node::Facts.new("nonmatchingnode1", "architecture" => "powerpc", 'processor_count' => '5'), "/path/to/nonmatching2.yaml" => Puppet::Node::Facts.new("nonmatchingnode2", "architecture" => "i386", 'processor_count' => '5'), "/path/to/nonmatching3.yaml" => Puppet::Node::Facts.new("nonmatchingnode3", 'processor_count' => '4'), }, {'facts.processor_count.lt' => '4', 'facts.processor_count.gt' => '4'} ) end it "should return node names that match the search query options with the greater than operator" do assert_search_matches({ '/path/to/matching.yaml' => Puppet::Node::Facts.new("matchingnode", "architecture" => "i386", 'processor_count' => '5'), '/path/to/matching1.yaml' => Puppet::Node::Facts.new("matchingnode1", "architecture" => "powerpc", 'processor_count' => '10', 'randomfact' => 'foo') }, { "/path/to/nonmatching.yaml" => Puppet::Node::Facts.new("nonmatchingnode", "architecture" => "powerpc", 'processor_count' => '4'), "/path/to/nonmatching2.yaml" => Puppet::Node::Facts.new("nonmatchingnode2", "architecture" => "i386", 'processor_count' => '3'), "/path/to/nonmatching3.yaml" => Puppet::Node::Facts.new("nonmatchingnode3" ), }, {'facts.processor_count.gt' => '4'} ) end it "should return node names that match the search query options with the less than operator" do assert_search_matches({ '/path/to/matching.yaml' => Puppet::Node::Facts.new("matchingnode", "architecture" => "i386", 'processor_count' => '5'), '/path/to/matching1.yaml' => Puppet::Node::Facts.new("matchingnode1", "architecture" => "powerpc", 'processor_count' => '30', 'randomfact' => 'foo') }, { "/path/to/nonmatching.yaml" => Puppet::Node::Facts.new("nonmatchingnode", "architecture" => "powerpc", 'processor_count' => '50' ), "/path/to/nonmatching2.yaml" => Puppet::Node::Facts.new("nonmatchingnode2", "architecture" => "i386", 'processor_count' => '100'), "/path/to/nonmatching3.yaml" => Puppet::Node::Facts.new("nonmatchingnode3" ), }, {'facts.processor_count.lt' => '50'} ) end it "should return node names that match the search query options with the less than or equal to operator" do assert_search_matches({ '/path/to/matching.yaml' => Puppet::Node::Facts.new("matchingnode", "architecture" => "i386", 'processor_count' => '5'), '/path/to/matching1.yaml' => Puppet::Node::Facts.new("matchingnode1", "architecture" => "powerpc", 'processor_count' => '50', 'randomfact' => 'foo') }, { "/path/to/nonmatching.yaml" => Puppet::Node::Facts.new("nonmatchingnode", "architecture" => "powerpc", 'processor_count' => '100' ), "/path/to/nonmatching2.yaml" => Puppet::Node::Facts.new("nonmatchingnode2", "architecture" => "i386", 'processor_count' => '5000'), "/path/to/nonmatching3.yaml" => Puppet::Node::Facts.new("nonmatchingnode3" ), }, {'facts.processor_count.le' => '50'} ) end it "should return node names that match the search query options with the greater than or equal to operator" do assert_search_matches({ '/path/to/matching.yaml' => Puppet::Node::Facts.new("matchingnode", "architecture" => "i386", 'processor_count' => '100'), '/path/to/matching1.yaml' => Puppet::Node::Facts.new("matchingnode1", "architecture" => "powerpc", 'processor_count' => '50', 'randomfact' => 'foo') }, { "/path/to/nonmatching.yaml" => Puppet::Node::Facts.new("nonmatchingnode", "architecture" => "powerpc", 'processor_count' => '40'), "/path/to/nonmatching2.yaml" => Puppet::Node::Facts.new("nonmatchingnode2", "architecture" => "i386", 'processor_count' => '9' ), "/path/to/nonmatching3.yaml" => Puppet::Node::Facts.new("nonmatchingnode3" ), }, {'facts.processor_count.ge' => '50'} ) end it "should return node names that match the search query options with the not equal operator" do assert_search_matches({ '/path/to/matching.yaml' => Puppet::Node::Facts.new("matchingnode", "architecture" => 'arm' ), '/path/to/matching1.yaml' => Puppet::Node::Facts.new("matchingnode1", "architecture" => 'powerpc', 'randomfact' => 'foo') }, { "/path/to/nonmatching.yaml" => Puppet::Node::Facts.new("nonmatchingnode", "architecture" => "i386" ), "/path/to/nonmatching2.yaml" => Puppet::Node::Facts.new("nonmatchingnode2", "architecture" => "i386", 'processor_count' => '9' ), "/path/to/nonmatching3.yaml" => Puppet::Node::Facts.new("nonmatchingnode3" ), }, {'facts.architecture.ne' => 'i386'} ) end def apply_timestamp(facts, timestamp) facts.timestamp = timestamp facts end it "should be able to query based on meta.timestamp.gt" do assert_search_matches({ '/path/to/2010-11-01.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-11-01", {}), Time.parse("2010-11-01")), '/path/to/2010-11-10.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-11-10", {}), Time.parse("2010-11-10")), }, { '/path/to/2010-10-01.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-01", {}), Time.parse("2010-10-01")), '/path/to/2010-10-10.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-10", {}), Time.parse("2010-10-10")), '/path/to/2010-10-15.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-15", {}), Time.parse("2010-10-15")), }, {'meta.timestamp.gt' => '2010-10-15'} ) end it "should be able to query based on meta.timestamp.le" do assert_search_matches({ '/path/to/2010-10-01.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-01", {}), Time.parse("2010-10-01")), '/path/to/2010-10-10.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-10", {}), Time.parse("2010-10-10")), '/path/to/2010-10-15.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-15", {}), Time.parse("2010-10-15")), }, { '/path/to/2010-11-01.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-11-01", {}), Time.parse("2010-11-01")), '/path/to/2010-11-10.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-11-10", {}), Time.parse("2010-11-10")), }, {'meta.timestamp.le' => '2010-10-15'} ) end it "should be able to query based on meta.timestamp.lt" do assert_search_matches({ '/path/to/2010-10-01.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-01", {}), Time.parse("2010-10-01")), '/path/to/2010-10-10.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-10", {}), Time.parse("2010-10-10")), }, { '/path/to/2010-11-01.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-11-01", {}), Time.parse("2010-11-01")), '/path/to/2010-11-10.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-11-10", {}), Time.parse("2010-11-10")), '/path/to/2010-10-15.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-15", {}), Time.parse("2010-10-15")), }, {'meta.timestamp.lt' => '2010-10-15'} ) end it "should be able to query based on meta.timestamp.ge" do assert_search_matches({ '/path/to/2010-11-01.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-11-01", {}), Time.parse("2010-11-01")), '/path/to/2010-11-10.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-11-10", {}), Time.parse("2010-11-10")), '/path/to/2010-10-15.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-15", {}), Time.parse("2010-10-15")), }, { '/path/to/2010-10-01.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-01", {}), Time.parse("2010-10-01")), '/path/to/2010-10-10.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-10", {}), Time.parse("2010-10-10")), }, {'meta.timestamp.ge' => '2010-10-15'} ) end it "should be able to query based on meta.timestamp.eq" do assert_search_matches({ '/path/to/2010-10-15.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-15", {}), Time.parse("2010-10-15")), }, { '/path/to/2010-11-01.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-11-01", {}), Time.parse("2010-11-01")), '/path/to/2010-11-10.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-11-10", {}), Time.parse("2010-11-10")), '/path/to/2010-10-01.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-01", {}), Time.parse("2010-10-01")), '/path/to/2010-10-10.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-10", {}), Time.parse("2010-10-10")), }, {'meta.timestamp.eq' => '2010-10-15'} ) end it "should be able to query based on meta.timestamp" do assert_search_matches({ '/path/to/2010-10-15.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-15", {}), Time.parse("2010-10-15")), }, { '/path/to/2010-11-01.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-11-01", {}), Time.parse("2010-11-01")), '/path/to/2010-11-10.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-11-10", {}), Time.parse("2010-11-10")), '/path/to/2010-10-01.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-01", {}), Time.parse("2010-10-01")), '/path/to/2010-10-10.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-10", {}), Time.parse("2010-10-10")), }, {'meta.timestamp' => '2010-10-15'} ) end it "should be able to query based on meta.timestamp.ne" do assert_search_matches({ '/path/to/2010-11-01.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-11-01", {}), Time.parse("2010-11-01")), '/path/to/2010-11-10.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-11-10", {}), Time.parse("2010-11-10")), '/path/to/2010-10-01.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-01", {}), Time.parse("2010-10-01")), '/path/to/2010-10-10.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-10", {}), Time.parse("2010-10-10")), }, { '/path/to/2010-10-15.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-15", {}), Time.parse("2010-10-15")), }, {'meta.timestamp.ne' => '2010-10-15'} ) end end diff --git a/spec/unit/indirector/key/ca_spec.rb b/spec/unit/indirector/key/ca_spec.rb index 033a70c3f..ba3d1aae2 100755 --- a/spec/unit/indirector/key/ca_spec.rb +++ b/spec/unit/indirector/key/ca_spec.rb @@ -1,28 +1,28 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Created by Luke Kanies on 2008-3-7. # Copyright (c) 2007. All rights reserved. require 'spec_helper' require 'puppet/indirector/key/ca' describe Puppet::SSL::Key::Ca do it "should have documentation" do Puppet::SSL::Key::Ca.doc.should be_instance_of(String) end it "should use the :privatekeydir as the collection directory" do Puppet.settings.expects(:value).with(:privatekeydir).returns "/key/dir" Puppet::SSL::Key::Ca.collection_directory.should == "/key/dir" end it "should store the ca key at the :cakey location" do Puppet.settings.stubs(:use) Puppet.settings.stubs(:value).returns "whatever" Puppet.settings.stubs(:value).with(:cakey).returns "/ca/key" file = Puppet::SSL::Key::Ca.new file.stubs(:ca?).returns true file.path("whatever").should == "/ca/key" end end diff --git a/spec/unit/indirector/key/file_spec.rb b/spec/unit/indirector/key/file_spec.rb index a87c3b1d8..bf9b293d8 100755 --- a/spec/unit/indirector/key/file_spec.rb +++ b/spec/unit/indirector/key/file_spec.rb @@ -1,104 +1,104 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Created by Luke Kanies on 2008-3-7. # Copyright (c) 2007. All rights reserved. require 'spec_helper' require 'puppet/indirector/key/file' describe Puppet::SSL::Key::File do it "should have documentation" do Puppet::SSL::Key::File.doc.should be_instance_of(String) end it "should use the :privatekeydir as the collection directory" do Puppet.settings.expects(:value).with(:privatekeydir).returns "/key/dir" Puppet::SSL::Key::File.collection_directory.should == "/key/dir" end it "should store the ca key at the :cakey location" do Puppet.settings.stubs(:use) Puppet.settings.stubs(:value).returns "whatever" Puppet.settings.stubs(:value).with(:cakey).returns "/ca/key" file = Puppet::SSL::Key::File.new file.stubs(:ca?).returns true file.path("whatever").should == "/ca/key" end describe "when choosing the path for the public key" do it "should use the :capub setting location if the key is for the certificate authority" do Puppet.settings.stubs(:value).returns "/fake/dir" Puppet.settings.stubs(:value).with(:capub).returns "/ca/pubkey" Puppet.settings.stubs(:use) @searcher = Puppet::SSL::Key::File.new @searcher.stubs(:ca?).returns true @searcher.public_key_path("whatever").should == "/ca/pubkey" end it "should use the host name plus '.pem' in :publickeydir for normal hosts" do Puppet.settings.stubs(:value).with(:privatekeydir).returns "/private/key/dir" Puppet.settings.stubs(:value).with(:publickeydir).returns "/public/key/dir" Puppet.settings.stubs(:use) @searcher = Puppet::SSL::Key::File.new @searcher.stubs(:ca?).returns false @searcher.public_key_path("whatever").should == "/public/key/dir/whatever.pem" end end describe "when managing private keys" do before do @searcher = Puppet::SSL::Key::File.new @private_key_path = File.join("/fake/key/path") @public_key_path = File.join("/other/fake/key/path") @searcher.stubs(:public_key_path).returns @public_key_path @searcher.stubs(:path).returns @private_key_path FileTest.stubs(:directory?).returns true FileTest.stubs(:writable?).returns true @public_key = stub 'public_key' @real_key = stub 'sslkey', :public_key => @public_key @key = stub 'key', :name => "myname", :content => @real_key @request = stub 'request', :key => "myname", :instance => @key end it "should save the public key when saving the private key" do Puppet.settings.stubs(:writesub) fh = mock 'filehandle' Puppet.settings.expects(:writesub).with(:publickeydir, @public_key_path).yields fh @public_key.expects(:to_pem).returns "my pem" fh.expects(:print).with "my pem" @searcher.save(@request) end it "should destroy the public key when destroying the private key" do File.stubs(:unlink).with(@private_key_path) FileTest.stubs(:exist?).with(@private_key_path).returns true FileTest.expects(:exist?).with(@public_key_path).returns true File.expects(:unlink).with(@public_key_path) @searcher.destroy(@request) end it "should not fail if the public key does not exist when deleting the private key" do File.stubs(:unlink).with(@private_key_path) FileTest.stubs(:exist?).with(@private_key_path).returns true FileTest.expects(:exist?).with(@public_key_path).returns false File.expects(:unlink).with(@public_key_path).never @searcher.destroy(@request) end end end diff --git a/spec/unit/indirector/ldap_spec.rb b/spec/unit/indirector/ldap_spec.rb index 289d2fa0f..2b40325de 100755 --- a/spec/unit/indirector/ldap_spec.rb +++ b/spec/unit/indirector/ldap_spec.rb @@ -1,138 +1,137 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/indirector/ldap' describe Puppet::Indirector::Ldap do before do @indirection = stub 'indirection', :name => :testing Puppet::Indirector::Indirection.stubs(:instance).returns(@indirection) module Testing; end @ldap_class = class Testing::MyLdap < Puppet::Indirector::Ldap self end @connection = mock 'ldap' @searcher = @ldap_class.new end describe "when searching ldap" do before do # Stub everything, and we can selectively replace with an expect as # we need to for testing. @searcher.stubs(:connection).returns(@connection) @searcher.stubs(:search_filter).returns(:filter) @searcher.stubs(:search_base).returns(:base) @searcher.stubs(:process) @request = stub 'request', :key => "yay" end it "should call the ldapsearch method with the search filter" do @searcher.expects(:search_filter).with("yay").returns("yay's filter") @searcher.expects(:ldapsearch).with("yay's filter") @searcher.find @request end it "should fail if no block is passed to the ldapsearch method" do proc { @searcher.ldapsearch("blah") }.should raise_error(ArgumentError) end it "should use the results of the ldapbase method as the ldap search base" do @searcher.stubs(:search_base).returns("mybase") @connection.expects(:search).with do |*args| args[0].should == "mybase" true end @searcher.find @request end it "should default to the value of the :search_base setting as the result of the ldapbase method" do Puppet.expects(:[]).with(:ldapbase).returns("myldapbase") searcher = @ldap_class.new searcher.search_base.should == "myldapbase" end it "should use the results of the :search_attributes method as the list of attributes to return" do @searcher.stubs(:search_attributes).returns(:myattrs) @connection.expects(:search).with do |*args| args[3].should == :myattrs true end @searcher.find @request end it "should use depth 2 when searching" do @connection.expects(:search).with do |*args| args[1].should == 2 true end @searcher.find @request end it "should call process() on the first found entry" do @connection.expects(:search).yields("myresult") @searcher.expects(:process).with("myresult") @searcher.find @request end it "should reconnect and retry the search if there is a failure" do run = false @connection.stubs(:search).with do |*args| if run true else run = true raise "failed" end end.yields("myresult") @searcher.expects(:process).with("myresult") @searcher.find @request end it "should not reconnect on failure more than once" do count = 0 @connection.stubs(:search).with do |*args| count += 1 raise ArgumentError, "yay" end proc { @searcher.find(@request) }.should raise_error(Puppet::Error) count.should == 2 end it "should return true if an entry is found" do @connection.expects(:search).yields("result") @searcher.ldapsearch("whatever") { |r| }.should be_true end end describe "when connecting to ldap", :if => Puppet.features.ldap? do it "should create and start a Util::Ldap::Connection instance" do conn = mock 'connection', :connection => "myconn", :start => nil Puppet::Util::Ldap::Connection.expects(:instance).returns conn @searcher.connection.should == "myconn" end it "should only create the ldap connection when asked for it the first time" do conn = mock 'connection', :connection => "myconn", :start => nil Puppet::Util::Ldap::Connection.expects(:instance).returns conn @searcher.connection end it "should cache the connection" do conn = mock 'connection', :connection => "myconn", :start => nil Puppet::Util::Ldap::Connection.expects(:instance).returns conn @searcher.connection.should equal(@searcher.connection) end end describe "when reconnecting to ldap", :if => (Puppet.features.root? and Facter.value("hostname") == "culain") do it "should reconnect to ldap when connections are lost" end end diff --git a/spec/unit/indirector/memory_spec.rb b/spec/unit/indirector/memory_spec.rb index 4f0e6e9fe..676acfcca 100755 --- a/spec/unit/indirector/memory_spec.rb +++ b/spec/unit/indirector/memory_spec.rb @@ -1,28 +1,27 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/indirector/memory' require 'shared_behaviours/memory_terminus' describe Puppet::Indirector::Memory do it_should_behave_like "A Memory Terminus" before do Puppet::Indirector::Terminus.stubs(:register_terminus_class) @model = mock 'model' @indirection = stub 'indirection', :name => :mystuff, :register_terminus_type => nil, :model => @model Puppet::Indirector::Indirection.stubs(:instance).returns(@indirection) module Testing; end @memory_class = class Testing::MyMemory < Puppet::Indirector::Memory self end @searcher = @memory_class.new @name = "me" @instance = stub 'instance', :name => @name @request = stub 'request', :key => @name, :instance => @instance end end diff --git a/spec/unit/indirector/node/active_record_spec.rb b/spec/unit/indirector/node/active_record_spec.rb index ac53419ca..6fed940b9 100755 --- a/spec/unit/indirector/node/active_record_spec.rb +++ b/spec/unit/indirector/node/active_record_spec.rb @@ -1,38 +1,37 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/node' describe "Puppet::Node::ActiveRecord", :if => Puppet.features.rails? && Puppet.features.sqlite? do include PuppetSpec::Files before do require 'puppet/indirector/node/active_record' end it "should be a subclass of the ActiveRecord terminus class" do Puppet::Node::ActiveRecord.ancestors.should be_include(Puppet::Indirector::ActiveRecord) end it "should use Puppet::Rails::Host as its ActiveRecord model" do Puppet::Node::ActiveRecord.ar_model.should equal(Puppet::Rails::Host) end it "should call fact_merge when a node is found" do db_instance = stub 'db_instance' Puppet::Node::ActiveRecord.ar_model.expects(:find_by_name).returns db_instance node = Puppet::Node.new("foo") db_instance.expects(:to_puppet).returns node Puppet[:statedir] = tmpdir('active_record_tmp') Puppet[:railslog] = '$statedir/rails.log' ar = Puppet::Node::ActiveRecord.new node.expects(:fact_merge) request = Puppet::Indirector::Request.new(:node, :find, "what.ever") ar.find(request) end end diff --git a/spec/unit/indirector/node/exec_spec.rb b/spec/unit/indirector/node/exec_spec.rb index 372b2df9b..f14990cd5 100755 --- a/spec/unit/indirector/node/exec_spec.rb +++ b/spec/unit/indirector/node/exec_spec.rb @@ -1,70 +1,69 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/indirector/node/exec' describe Puppet::Node::Exec do before do @indirection = mock 'indirection' Puppet.settings.stubs(:value).with(:external_nodes).returns("/echo") @searcher = Puppet::Node::Exec.new end describe "when constructing the command to run" do it "should use the external_node script as the command" do Puppet.expects(:[]).with(:external_nodes).returns("/bin/echo") @searcher.command.should == %w{/bin/echo} end it "should throw an exception if no external node command is set" do Puppet.expects(:[]).with(:external_nodes).returns("none") proc { @searcher.find(stub('request', :key => "foo")) }.should raise_error(ArgumentError) end end describe "when handling the results of the command" do before do @name = "yay" @node = Puppet::Node.new(@name) @node.stubs(:fact_merge) Puppet::Node.expects(:new).with(@name).returns(@node) @result = {} # Use a local variable so the reference is usable in the execute definition. result = @result @searcher.meta_def(:execute) do |command| return YAML.dump(result) end @request = stub 'request', :key => @name end it "should translate the YAML into a Node instance" do # Use an empty hash @searcher.find(@request).should equal(@node) end it "should set the resulting parameters as the node parameters" do @result[:parameters] = {"a" => "b", "c" => "d"} @searcher.find(@request) @node.parameters.should == {"a" => "b", "c" => "d"} end it "should set the resulting classes as the node classes" do @result[:classes] = %w{one two} @searcher.find(@request) @node.classes.should == [ 'one', 'two' ] end it "should merge the node's facts with its parameters" do @node.expects(:fact_merge) @searcher.find(@request) end it "should set the node's environment if one is provided" do @result[:environment] = "yay" @searcher.find(@request) @node.environment.to_s.should == 'yay' end end end diff --git a/spec/unit/indirector/node/ldap_spec.rb b/spec/unit/indirector/node/ldap_spec.rb index 710951e9c..5e57db3c4 100755 --- a/spec/unit/indirector/node/ldap_spec.rb +++ b/spec/unit/indirector/node/ldap_spec.rb @@ -1,454 +1,453 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/indirector/node/ldap' describe Puppet::Node::Ldap do describe "when searching for a single node" do before :each do @searcher = Puppet::Node::Ldap.new @name = "mynode.domain.com" @node = stub 'node', :name => @name, :name= => nil @node.stub_everything Puppet::Node.stubs(:new).returns(@node) @request = stub 'request', :key => @name end it "should convert the hostname into a search filter" do entry = stub 'entry', :dn => 'cn=mynode.domain.com,ou=hosts,dc=madstop,dc=com', :vals => %w{}, :to_hash => {} @searcher.expects(:ldapsearch).with("(&(objectclass=puppetClient)(cn=#{@name}))").yields entry @searcher.name2hash(@name) end it "should convert any found entry into a hash" do entry = stub 'entry', :dn => 'cn=mynode.domain.com,ou=hosts,dc=madstop,dc=com', :vals => %w{}, :to_hash => {} @searcher.expects(:ldapsearch).with("(&(objectclass=puppetClient)(cn=#{@name}))").yields entry myhash = {"myhash" => true} @searcher.expects(:entry2hash).with(entry).returns myhash @searcher.name2hash(@name).should == myhash end # This heavily tests our entry2hash method, so we don't have to stub out the stupid entry information any more. describe "when an ldap entry is found" do before do @entry = stub 'entry', :dn => 'cn=mynode,ou=hosts,dc=madstop,dc=com', :vals => %w{}, :to_hash => {} @searcher.stubs(:ldapsearch).yields @entry end it "should convert the entry to a hash" do @searcher.entry2hash(@entry).should be_instance_of(Hash) end it "should add the entry's common name to the hash if fqdn if false" do @searcher.entry2hash(@entry,fqdn = false)[:name].should == "mynode" end it "should add the entry's fqdn name to the hash if fqdn if true" do @searcher.entry2hash(@entry,fqdn = true)[:name].should == "mynode.madstop.com" end it "should add all of the entry's classes to the hash" do @entry.stubs(:vals).with("puppetclass").returns %w{one two} @searcher.entry2hash(@entry)[:classes].should == %w{one two} end it "should deduplicate class values" do @entry.stubs(:to_hash).returns({}) @searcher.stubs(:class_attributes).returns(%w{one two}) @entry.stubs(:vals).with("one").returns(%w{a b}) @entry.stubs(:vals).with("two").returns(%w{b c}) @searcher.entry2hash(@entry)[:classes].should == %w{a b c} end it "should add the entry's environment to the hash" do @entry.stubs(:to_hash).returns("environment" => %w{production}) @searcher.entry2hash(@entry)[:environment].should == "production" end it "should add all stacked parameters as parameters in the hash" do @entry.stubs(:vals).with("puppetvar").returns(%w{one=two three=four}) result = @searcher.entry2hash(@entry) result[:parameters]["one"].should == "two" result[:parameters]["three"].should == "four" end it "should not add the stacked parameter as a normal parameter" do @entry.stubs(:vals).with("puppetvar").returns(%w{one=two three=four}) @entry.stubs(:to_hash).returns("puppetvar" => %w{one=two three=four}) @searcher.entry2hash(@entry)[:parameters]["puppetvar"].should be_nil end it "should add all other attributes as parameters in the hash" do @entry.stubs(:to_hash).returns("foo" => %w{one two}) @searcher.entry2hash(@entry)[:parameters]["foo"].should == %w{one two} end it "should return single-value parameters as strings, not arrays" do @entry.stubs(:to_hash).returns("foo" => %w{one}) @searcher.entry2hash(@entry)[:parameters]["foo"].should == "one" end it "should convert 'true' values to the boolean 'true'" do @entry.stubs(:to_hash).returns({"one" => ["true"]}) @searcher.entry2hash(@entry)[:parameters]["one"].should == true end it "should convert 'false' values to the boolean 'false'" do @entry.stubs(:to_hash).returns({"one" => ["false"]}) @searcher.entry2hash(@entry)[:parameters]["one"].should == false end it "should convert 'true' values to the boolean 'true' inside an array" do @entry.stubs(:to_hash).returns({"one" => ["true", "other"]}) @searcher.entry2hash(@entry)[:parameters]["one"].should == [true, "other"] end it "should convert 'false' values to the boolean 'false' inside an array" do @entry.stubs(:to_hash).returns({"one" => ["false", "other"]}) @searcher.entry2hash(@entry)[:parameters]["one"].should == [false, "other"] end it "should add the parent's name if present" do @entry.stubs(:vals).with("parentnode").returns(%w{foo}) @searcher.entry2hash(@entry)[:parent].should == "foo" end it "should fail if more than one parent is specified" do @entry.stubs(:vals).with("parentnode").returns(%w{foo}) @searcher.entry2hash(@entry)[:parent].should == "foo" end end it "should search first for the provided key" do @searcher.expects(:name2hash).with("mynode.domain.com").returns({}) @searcher.find(@request) end it "should search for the short version of the provided key if the key looks like a hostname and no results are found for the key itself" do @searcher.expects(:name2hash).with("mynode.domain.com").returns(nil) @searcher.expects(:name2hash).with("mynode").returns({}) @searcher.find(@request) end it "should search for default information if no information can be found for the key" do @searcher.expects(:name2hash).with("mynode.domain.com").returns(nil) @searcher.expects(:name2hash).with("mynode").returns(nil) @searcher.expects(:name2hash).with("default").returns({}) @searcher.find(@request) end it "should return nil if no results are found in ldap" do @searcher.stubs(:name2hash).returns nil @searcher.find(@request).should be_nil end it "should return a node object if results are found in ldap" do @searcher.stubs(:name2hash).returns({}) @searcher.find(@request).should equal(@node) end describe "and node information is found in LDAP" do before do @result = {} @searcher.stubs(:name2hash).returns @result end it "should create the node with the correct name, even if it was found by a different name" do @searcher.expects(:name2hash).with("mynode.domain.com").returns nil @searcher.expects(:name2hash).with("mynode").returns @result Puppet::Node.expects(:new).with("mynode.domain.com").returns @node @searcher.find(@request) end it "should add any classes from ldap" do @result[:classes] = %w{a b c d} @node.expects(:classes=).with(%w{a b c d}) @searcher.find(@request) end it "should add all entry attributes as node parameters" do @result[:parameters] = {"one" => "two", "three" => "four"} @node.expects(:parameters=).with("one" => "two", "three" => "four") @searcher.find(@request) end it "should set the node's environment to the environment of the results" do @result[:environment] = "test" @node.expects(:environment=).with("test") @searcher.find(@request) end it "should retain false parameter values" do @result[:parameters] = {} @result[:parameters]["one"] = false @node.expects(:parameters=).with("one" => false) @searcher.find(@request) end it "should merge the node's facts after the parameters from ldap are assigned" do # Make sure we've got data to start with, so the parameters are actually set. @result[:parameters] = {} @result[:parameters]["one"] = "yay" # A hackish way to enforce order. set = false @node.expects(:parameters=).with { |*args| set = true } @node.expects(:fact_merge).with { |*args| raise "Facts were merged before parameters were set" unless set; true } @searcher.find(@request) end describe "and a parent node is specified" do before do @entry = {:classes => [], :parameters => {}} @parent = {:classes => [], :parameters => {}} @parent_parent = {:classes => [], :parameters => {}} @searcher.stubs(:name2hash).with(@name).returns(@entry) @searcher.stubs(:name2hash).with('parent').returns(@parent) @searcher.stubs(:name2hash).with('parent_parent').returns(@parent_parent) @searcher.stubs(:parent_attribute).returns(:parent) end it "should search for the parent node" do @entry[:parent] = "parent" @searcher.expects(:name2hash).with(@name).returns @entry @searcher.expects(:name2hash).with('parent').returns @parent @searcher.find(@request) end it "should fail if the parent cannot be found" do @entry[:parent] = "parent" @searcher.expects(:name2hash).with('parent').returns nil proc { @searcher.find(@request) }.should raise_error(Puppet::Error) end it "should add any parent classes to the node's classes" do @entry[:parent] = "parent" @entry[:classes] = %w{a b} @parent[:classes] = %w{c d} @node.expects(:classes=).with(%w{a b c d}) @searcher.find(@request) end it "should add any parent parameters to the node's parameters" do @entry[:parent] = "parent" @entry[:parameters]["one"] = "two" @parent[:parameters]["three"] = "four" @node.expects(:parameters=).with("one" => "two", "three" => "four") @searcher.find(@request) end it "should prefer node parameters over parent parameters" do @entry[:parent] = "parent" @entry[:parameters]["one"] = "two" @parent[:parameters]["one"] = "three" @node.expects(:parameters=).with("one" => "two") @searcher.find(@request) end it "should use the parent's environment if the node has none" do @entry[:parent] = "parent" @parent[:environment] = "parent" @node.stubs(:parameters=) @node.expects(:environment=).with("parent") @searcher.find(@request) end it "should prefer the node's environment to the parent's" do @entry[:parent] = "parent" @entry[:environment] = "child" @parent[:environment] = "parent" @node.stubs(:parameters=) @node.expects(:environment=).with("child") @searcher.find(@request) end it "should recursively look up parent information" do @entry[:parent] = "parent" @entry[:parameters]["one"] = "two" @parent[:parent] = "parent_parent" @parent[:parameters]["three"] = "four" @parent_parent[:parameters]["five"] = "six" @node.expects(:parameters=).with("one" => "two", "three" => "four", "five" => "six") @searcher.find(@request) end it "should not allow loops in parent declarations" do @entry[:parent] = "parent" @parent[:parent] = @name proc { @searcher.find(@request) }.should raise_error(ArgumentError) end end end end describe "when searching for multiple nodes" do before :each do @searcher = Puppet::Node::Ldap.new @options = {} @request = stub 'request', :key => "foo", :options => @options Puppet::Node::Facts.indirection.stubs(:terminus_class).returns :yaml end it "should find all nodes if no arguments are provided" do @searcher.expects(:ldapsearch).with("(objectclass=puppetClient)") # LAK:NOTE The search method requires an essentially bogus key. It's # an API problem that I don't really know how to fix. @searcher.search @request end describe "and a class is specified" do it "should find all nodes that are members of that class" do @searcher.expects(:ldapsearch).with("(&(objectclass=puppetClient)(puppetclass=one))") @options[:class] = "one" @searcher.search @request end end describe "multiple classes are specified" do it "should find all nodes that are members of all classes" do @searcher.expects(:ldapsearch).with("(&(objectclass=puppetClient)(puppetclass=one)(puppetclass=two))") @options[:class] = %w{one two} @searcher.search @request end end it "should process each found entry" do # .yields can't be used to yield multiple values :/ @searcher.expects(:ldapsearch).yields("one") @searcher.expects(:entry2hash).with("one",nil).returns(:name => "foo") @searcher.search @request end it "should return a node for each processed entry with the name from the entry" do @searcher.expects(:ldapsearch).yields("whatever") @searcher.expects(:entry2hash).with("whatever",nil).returns(:name => "foo") result = @searcher.search(@request) result[0].should be_instance_of(Puppet::Node) result[0].name.should == "foo" end it "should merge each node's facts" do node = mock 'node' Puppet::Node.expects(:new).with("foo").returns node node.expects(:fact_merge) @searcher.stubs(:ldapsearch).yields("one") @searcher.stubs(:entry2hash).with("one",nil).returns(:name => "foo") @searcher.search(@request) end it "should pass the request's fqdn option to entry2hash" do node = mock 'node' @options[:fqdn] = :hello Puppet::Node.stubs(:new).with("foo").returns node node.stubs(:fact_merge) @searcher.stubs(:ldapsearch).yields("one") @searcher.expects(:entry2hash).with("one",:hello).returns(:name => "foo") @searcher.search(@request) end end end describe Puppet::Node::Ldap, " when developing the search query" do before do @searcher = Puppet::Node::Ldap.new end it "should return the value of the :ldapclassattrs split on commas as the class attributes" do Puppet.stubs(:[]).with(:ldapclassattrs).returns("one,two") @searcher.class_attributes.should == %w{one two} end it "should return nil as the parent attribute if the :ldapparentattr is set to an empty string" do Puppet.stubs(:[]).with(:ldapparentattr).returns("") @searcher.parent_attribute.should be_nil end it "should return the value of the :ldapparentattr as the parent attribute" do Puppet.stubs(:[]).with(:ldapparentattr).returns("pere") @searcher.parent_attribute.should == "pere" end it "should use the value of the :ldapstring as the search filter" do Puppet.stubs(:[]).with(:ldapstring).returns("mystring") @searcher.search_filter("testing").should == "mystring" end it "should replace '%s' with the node name in the search filter if it is present" do Puppet.stubs(:[]).with(:ldapstring).returns("my%sstring") @searcher.search_filter("testing").should == "mytestingstring" end it "should not modify the global :ldapstring when replacing '%s' in the search filter" do filter = mock 'filter' filter.expects(:include?).with("%s").returns(true) filter.expects(:gsub).with("%s", "testing").returns("mynewstring") Puppet.stubs(:[]).with(:ldapstring).returns(filter) @searcher.search_filter("testing").should == "mynewstring" end end describe Puppet::Node::Ldap, " when deciding attributes to search for" do before do @searcher = Puppet::Node::Ldap.new end it "should use 'nil' if the :ldapattrs setting is 'all'" do Puppet.stubs(:[]).with(:ldapattrs).returns("all") @searcher.search_attributes.should be_nil end it "should split the value of :ldapattrs on commas and use the result as the attribute list" do Puppet.stubs(:[]).with(:ldapattrs).returns("one,two") @searcher.stubs(:class_attributes).returns([]) @searcher.stubs(:parent_attribute).returns(nil) @searcher.search_attributes.should == %w{one two} end it "should add the class attributes to the search attributes if not returning all attributes" do Puppet.stubs(:[]).with(:ldapattrs).returns("one,two") @searcher.stubs(:class_attributes).returns(%w{three four}) @searcher.stubs(:parent_attribute).returns(nil) # Sort them so i don't have to care about return order @searcher.search_attributes.sort.should == %w{one two three four}.sort end it "should add the parent attribute to the search attributes if not returning all attributes" do Puppet.stubs(:[]).with(:ldapattrs).returns("one,two") @searcher.stubs(:class_attributes).returns([]) @searcher.stubs(:parent_attribute).returns("parent") @searcher.search_attributes.sort.should == %w{one two parent}.sort end it "should not add nil parent attributes to the search attributes" do Puppet.stubs(:[]).with(:ldapattrs).returns("one,two") @searcher.stubs(:class_attributes).returns([]) @searcher.stubs(:parent_attribute).returns(nil) @searcher.search_attributes.should == %w{one two} end end diff --git a/spec/unit/indirector/node/memory_spec.rb b/spec/unit/indirector/node/memory_spec.rb index 77cfa4af7..8b26a47c1 100755 --- a/spec/unit/indirector/node/memory_spec.rb +++ b/spec/unit/indirector/node/memory_spec.rb @@ -1,19 +1,18 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/indirector/node/memory' require 'shared_behaviours/memory_terminus' describe Puppet::Node::Memory do before do @name = "me" @searcher = Puppet::Node::Memory.new @instance = stub 'instance', :name => @name @request = stub 'request', :key => @name, :instance => @instance end it_should_behave_like "A Memory Terminus" end diff --git a/spec/unit/indirector/node/plain_spec.rb b/spec/unit/indirector/node/plain_spec.rb index 9cdd8f35b..c6ba84e67 100755 --- a/spec/unit/indirector/node/plain_spec.rb +++ b/spec/unit/indirector/node/plain_spec.rb @@ -1,19 +1,18 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/indirector/node/plain' describe Puppet::Node::Plain do before do @searcher = Puppet::Node::Plain.new end it "should call node_merge() on the returned node" do node = mock 'node' Puppet::Node.expects(:new).with("mynode").returns(node) node.expects(:fact_merge) request = stub 'request', :key => "mynode" @searcher.find(request) end end diff --git a/spec/unit/indirector/node/rest_spec.rb b/spec/unit/indirector/node/rest_spec.rb index 8c91297d6..fa5d1baf7 100755 --- a/spec/unit/indirector/node/rest_spec.rb +++ b/spec/unit/indirector/node/rest_spec.rb @@ -1,13 +1,12 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/indirector/node/rest' describe Puppet::Node::Rest do before do @searcher = Puppet::Node::Rest.new end end diff --git a/spec/unit/indirector/node/yaml_spec.rb b/spec/unit/indirector/node/yaml_spec.rb index ce196c221..db9ffe435 100755 --- a/spec/unit/indirector/node/yaml_spec.rb +++ b/spec/unit/indirector/node/yaml_spec.rb @@ -1,25 +1,24 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/node' require 'puppet/indirector/node/yaml' describe Puppet::Node::Yaml do it "should be a subclass of the Yaml terminus" do Puppet::Node::Yaml.superclass.should equal(Puppet::Indirector::Yaml) end it "should have documentation" do Puppet::Node::Yaml.doc.should_not be_nil end it "should be registered with the configuration store indirection" do indirection = Puppet::Indirector::Indirection.instance(:node) Puppet::Node::Yaml.indirection.should equal(indirection) end it "should have its name set to :node" do Puppet::Node::Yaml.name.should == :yaml end end diff --git a/spec/unit/indirector/plain_spec.rb b/spec/unit/indirector/plain_spec.rb index 8efdc7894..0894f70f0 100755 --- a/spec/unit/indirector/plain_spec.rb +++ b/spec/unit/indirector/plain_spec.rb @@ -1,28 +1,27 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/indirector/plain' describe Puppet::Indirector::Plain do before do Puppet::Indirector::Terminus.stubs(:register_terminus_class) @model = mock 'model' @indirection = stub 'indirection', :name => :mystuff, :register_terminus_type => nil, :model => @model Puppet::Indirector::Indirection.stubs(:instance).returns(@indirection) module Testing; end @plain_class = class Testing::MyPlain < Puppet::Indirector::Plain self end @searcher = @plain_class.new @request = stub 'request', :key => "yay" end it "should return return an instance of the indirected model" do object = mock 'object' @model.expects(:new).with(@request.key).returns object @searcher.find(@request).should equal(object) end end diff --git a/spec/unit/indirector/queue_spec.rb b/spec/unit/indirector/queue_spec.rb index 40c87e248..b84ed2aea 100755 --- a/spec/unit/indirector/queue_spec.rb +++ b/spec/unit/indirector/queue_spec.rb @@ -1,122 +1,121 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/indirector/queue' class Puppet::Indirector::Queue::TestClient end class FooExampleData attr_accessor :name def self.pson_create(pson) new(pson['data'].to_sym) end def initialize(name = nil) @name = name if name end def render(format = :pson) to_pson end def to_pson(*args) {:type => self.class.to_s, :data => name}.to_pson(*args) end end describe Puppet::Indirector::Queue, :if => Puppet.features.pson? do before :each do @model = mock 'model' @indirection = stub 'indirection', :name => :my_queue, :register_terminus_type => nil, :model => @model Puppet::Indirector::Indirection.stubs(:instance).with(:my_queue).returns(@indirection) module MyQueue; end @store_class = class MyQueue::MyType < Puppet::Indirector::Queue self end @store = @store_class.new @subject_class = FooExampleData @subject = @subject_class.new @subject.name = :me Puppet[:queue_type] = :test_client Puppet::Util::Queue.stubs(:queue_type_to_class).with(:test_client).returns(Puppet::Indirector::Queue::TestClient) @request = stub 'request', :key => :me, :instance => @subject end it "should require PSON" do Puppet.features.expects(:pson?).returns false lambda { @store_class.new }.should raise_error(ArgumentError) end it 'should use the correct client type and queue' do @store.queue.should == :my_queue @store.client.should be_an_instance_of(Puppet::Indirector::Queue::TestClient) end describe "when saving" do it 'should render the instance using pson' do @subject.expects(:render).with(:pson) @store.client.stubs(:send_message) @store.save(@request) end it "should send the rendered message to the appropriate queue on the client" do @subject.expects(:render).returns "mypson" @store.client.expects(:send_message).with(:my_queue, "mypson") @store.save(@request) end it "should catch any exceptions raised" do @store.client.expects(:send_message).raises ArgumentError lambda { @store.save(@request) }.should raise_error(Puppet::Error) end end describe "when subscribing to the queue" do before do @store_class.stubs(:model).returns @model end it "should use the model's Format support to intern the message from pson" do @model.expects(:convert_from).with(:pson, "mymessage") @store_class.client.expects(:subscribe).yields("mymessage") @store_class.subscribe {|o| o } end it "should yield each interned received message" do @model.stubs(:convert_from).returns "something" @subject_two = @subject_class.new @subject_two.name = :too @store_class.client.expects(:subscribe).with(:my_queue).multiple_yields(@subject, @subject_two) received = [] @store_class.subscribe do |obj| received.push(obj) end received.should == %w{something something} end it "should log but not propagate errors" do @store_class.client.expects(:subscribe).yields("foo") @store_class.expects(:intern).raises(ArgumentError) expect { @store_class.subscribe {|o| o } }.should_not raise_error @logs.length.should == 1 @logs.first.message.should =~ /Error occured with subscription to queue my_queue for indirection my_queue: ArgumentError/ @logs.first.level.should == :err end end end diff --git a/spec/unit/indirector/report/processor_spec.rb b/spec/unit/indirector/report/processor_spec.rb index 545294644..bafbe6ee7 100755 --- a/spec/unit/indirector/report/processor_spec.rb +++ b/spec/unit/indirector/report/processor_spec.rb @@ -1,81 +1,81 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Created by Luke Kanies on 2007-9-23. # Copyright (c) 2007. All rights reserved. require 'spec_helper' require 'puppet/indirector/report/processor' describe Puppet::Transaction::Report::Processor do before do Puppet.settings.stubs(:use).returns(true) end it "should provide a method for saving reports" do Puppet::Transaction::Report::Processor.new.should respond_to(:save) end end describe Puppet::Transaction::Report::Processor, " when saving a report" do before do Puppet.settings.stubs(:use) @reporter = Puppet::Transaction::Report::Processor.new end it "should not process the report if reports are set to 'none'" do Puppet::Reports.expects(:report).never Puppet.settings.expects(:value).with(:reports).returns("none") request = stub 'request', :instance => mock("report") @reporter.save(request) end it "should process the report with each configured report type" do Puppet.settings.stubs(:value).with(:reports).returns("one,two") @reporter.send(:reports).should == %w{one two} end end describe Puppet::Transaction::Report::Processor, " when processing a report" do before do Puppet.settings.stubs(:value).with(:reports).returns("one") Puppet.settings.stubs(:use) @reporter = Puppet::Transaction::Report::Processor.new @report_type = mock 'one' @dup_report = mock 'dupe report' @dup_report.stubs(:process) @report = mock 'report' @report.expects(:dup).returns(@dup_report) @request = stub 'request', :instance => @report Puppet::Reports.expects(:report).with("one").returns(@report_type) @dup_report.expects(:extend).with(@report_type) end # LAK:NOTE This is stupid, because the code is so short it doesn't # make sense to split it out, which means I just do the same test # three times so the spec looks right. it "should process a duplicate of the report, not the original" do @reporter.save(@request) end it "should extend the report with the report type's module" do @reporter.save(@request) end it "should call the report type's :process method" do @dup_report.expects(:process) @reporter.save(@request) end it "should not raise exceptions" do Puppet.settings.stubs(:value).with(:trace).returns(false) @dup_report.expects(:process).raises(ArgumentError) proc { @reporter.save(@request) }.should_not raise_error end end diff --git a/spec/unit/indirector/report/rest_spec.rb b/spec/unit/indirector/report/rest_spec.rb index 1e7ac7732..806ae6efd 100755 --- a/spec/unit/indirector/report/rest_spec.rb +++ b/spec/unit/indirector/report/rest_spec.rb @@ -1,28 +1,27 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/indirector/report/rest' describe Puppet::Transaction::Report::Rest do it "should be a subclass of Puppet::Indirector::REST" do Puppet::Transaction::Report::Rest.superclass.should equal(Puppet::Indirector::REST) end it "should use the :report_server setting in preference to :reportserver" do Puppet.settings[:reportserver] = "reportserver" Puppet.settings[:report_server] = "report_server" Puppet::Transaction::Report::Rest.server.should == "report_server" end it "should use the :report_server setting in preference to :server" do Puppet.settings[:server] = "server" Puppet.settings[:report_server] = "report_server" Puppet::Transaction::Report::Rest.server.should == "report_server" end it "should have a value for report_server and report_port" do Puppet::Transaction::Report::Rest.server.should_not be_nil Puppet::Transaction::Report::Rest.port.should_not be_nil end end diff --git a/spec/unit/indirector/report/yaml_spec.rb b/spec/unit/indirector/report/yaml_spec.rb index d164bea54..7df4bb2e9 100755 --- a/spec/unit/indirector/report/yaml_spec.rb +++ b/spec/unit/indirector/report/yaml_spec.rb @@ -1,38 +1,37 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/transaction/report' require 'puppet/indirector/report/yaml' describe Puppet::Transaction::Report::Yaml do it "should be a subclass of the Yaml terminus" do Puppet::Transaction::Report::Yaml.superclass.should equal(Puppet::Indirector::Yaml) end it "should have documentation" do Puppet::Transaction::Report::Yaml.doc.should_not be_nil end it "should be registered with the report indirection" do indirection = Puppet::Indirector::Indirection.instance(:report) Puppet::Transaction::Report::Yaml.indirection.should equal(indirection) end it "should have its name set to :yaml" do Puppet::Transaction::Report::Yaml.name.should == :yaml end it "should inconditionnally save/load from the --lastrunreport setting" do indirection = stub 'indirection', :name => :my_yaml, :register_terminus_type => nil Puppet::Indirector::Indirection.stubs(:instance).with(:my_yaml).returns(indirection) store_class = Class.new(Puppet::Transaction::Report::Yaml) do def self.to_s "MyYaml::MyType" end end store = store_class.new store.path(:me).should == Puppet[:lastrunreport] end end diff --git a/spec/unit/indirector/request_spec.rb b/spec/unit/indirector/request_spec.rb index c1718bf11..965d54188 100755 --- a/spec/unit/indirector/request_spec.rb +++ b/spec/unit/indirector/request_spec.rb @@ -1,304 +1,303 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/indirector/request' describe Puppet::Indirector::Request do describe "when initializing" do it "should require an indirection name, a key, and a method" do lambda { Puppet::Indirector::Request.new }.should raise_error(ArgumentError) end it "should always convert the indirection name to a symbol" do Puppet::Indirector::Request.new("ind", :method, "mykey").indirection_name.should == :ind end it "should use provided value as the key if it is a string" do Puppet::Indirector::Request.new(:ind, :method, "mykey").key.should == "mykey" end it "should use provided value as the key if it is a symbol" do Puppet::Indirector::Request.new(:ind, :method, :mykey).key.should == :mykey end it "should use the name of the provided instance as its key if an instance is provided as the key instead of a string" do instance = mock 'instance', :name => "mykey" request = Puppet::Indirector::Request.new(:ind, :method, instance) request.key.should == "mykey" request.instance.should equal(instance) end it "should support options specified as a hash" do lambda { Puppet::Indirector::Request.new(:ind, :method, :key, :one => :two) }.should_not raise_error(ArgumentError) end it "should support nil options" do lambda { Puppet::Indirector::Request.new(:ind, :method, :key, nil) }.should_not raise_error(ArgumentError) end it "should support unspecified options" do lambda { Puppet::Indirector::Request.new(:ind, :method, :key) }.should_not raise_error(ArgumentError) end it "should use an empty options hash if nil was provided" do Puppet::Indirector::Request.new(:ind, :method, :key, nil).options.should == {} end it "should default to a nil node" do Puppet::Indirector::Request.new(:ind, :method, :key, nil).node.should be_nil end it "should set its node attribute if provided in the options" do Puppet::Indirector::Request.new(:ind, :method, :key, :node => "foo.com").node.should == "foo.com" end it "should default to a nil ip" do Puppet::Indirector::Request.new(:ind, :method, :key, nil).ip.should be_nil end it "should set its ip attribute if provided in the options" do Puppet::Indirector::Request.new(:ind, :method, :key, :ip => "192.168.0.1").ip.should == "192.168.0.1" end it "should default to being unauthenticated" do Puppet::Indirector::Request.new(:ind, :method, :key, nil).should_not be_authenticated end it "should set be marked authenticated if configured in the options" do Puppet::Indirector::Request.new(:ind, :method, :key, :authenticated => "eh").should be_authenticated end it "should keep its options as a hash even if a node is specified" do Puppet::Indirector::Request.new(:ind, :method, :key, :node => "eh").options.should be_instance_of(Hash) end it "should keep its options as a hash even if another option is specified" do Puppet::Indirector::Request.new(:ind, :method, :key, :foo => "bar").options.should be_instance_of(Hash) end it "should treat options other than :ip, :node, and :authenticated as options rather than attributes" do Puppet::Indirector::Request.new(:ind, :method, :key, :server => "bar").options[:server].should == "bar" end it "should normalize options to use symbols as keys" do Puppet::Indirector::Request.new(:ind, :method, :key, "foo" => "bar").options[:foo].should == "bar" end describe "and the request key is a URI" do describe "and the URI is a 'file' URI" do before do @request = Puppet::Indirector::Request.new(:ind, :method, "file:///my/file with spaces") end it "should set the request key to the unescaped full file path" do @request.key.should == "/my/file with spaces" end it "should not set the protocol" do @request.protocol.should be_nil end it "should not set the port" do @request.port.should be_nil end it "should not set the server" do @request.server.should be_nil end end it "should set the protocol to the URI scheme" do Puppet::Indirector::Request.new(:ind, :method, "http://host/stuff").protocol.should == "http" end it "should set the server if a server is provided" do Puppet::Indirector::Request.new(:ind, :method, "http://host/stuff").server.should == "host" end it "should set the server and port if both are provided" do Puppet::Indirector::Request.new(:ind, :method, "http://host:543/stuff").port.should == 543 end it "should default to the masterport if the URI scheme is 'puppet'" do Puppet.settings.expects(:value).with(:masterport).returns "321" Puppet::Indirector::Request.new(:ind, :method, "puppet://host/stuff").port.should == 321 end it "should use the provided port if the URI scheme is not 'puppet'" do Puppet::Indirector::Request.new(:ind, :method, "http://host/stuff").port.should == 80 end it "should set the request key to the unescaped key part path from the URI" do Puppet::Indirector::Request.new(:ind, :method, "http://host/environment/terminus/stuff with spaces").key.should == "stuff with spaces" end it "should set the :uri attribute to the full URI" do Puppet::Indirector::Request.new(:ind, :method, "http:///stuff").uri.should == "http:///stuff" end end it "should allow indication that it should not read a cached instance" do Puppet::Indirector::Request.new(:ind, :method, :key, :ignore_cache => true).should be_ignore_cache end it "should default to not ignoring the cache" do Puppet::Indirector::Request.new(:ind, :method, :key).should_not be_ignore_cache end it "should allow indication that it should not not read an instance from the terminus" do Puppet::Indirector::Request.new(:ind, :method, :key, :ignore_terminus => true).should be_ignore_terminus end it "should default to not ignoring the terminus" do Puppet::Indirector::Request.new(:ind, :method, :key).should_not be_ignore_terminus end end it "should look use the Indirection class to return the appropriate indirection" do ind = mock 'indirection' Puppet::Indirector::Indirection.expects(:instance).with(:myind).returns ind request = Puppet::Indirector::Request.new(:myind, :method, :key) request.indirection.should equal(ind) end it "should use its indirection to look up the appropriate model" do ind = mock 'indirection' Puppet::Indirector::Indirection.expects(:instance).with(:myind).returns ind request = Puppet::Indirector::Request.new(:myind, :method, :key) ind.expects(:model).returns "mymodel" request.model.should == "mymodel" end it "should fail intelligently when asked to find a model but the indirection cannot be found" do Puppet::Indirector::Indirection.expects(:instance).with(:myind).returns nil request = Puppet::Indirector::Request.new(:myind, :method, :key) lambda { request.model }.should raise_error(ArgumentError) end it "should have a method for determining if the request is plural or singular" do Puppet::Indirector::Request.new(:myind, :method, :key).should respond_to(:plural?) end it "should be considered plural if the method is 'search'" do Puppet::Indirector::Request.new(:myind, :search, :key).should be_plural end it "should not be considered plural if the method is not 'search'" do Puppet::Indirector::Request.new(:myind, :find, :key).should_not be_plural end it "should use its uri, if it has one, as its string representation" do Puppet::Indirector::Request.new(:myind, :find, "foo://bar/baz").to_s.should == "foo://bar/baz" end it "should use its indirection name and key, if it has no uri, as its string representation" do Puppet::Indirector::Request.new(:myind, :find, "key") == "/myind/key" end it "should be able to return the URI-escaped key" do Puppet::Indirector::Request.new(:myind, :find, "my key").escaped_key.should == URI.escape("my key") end it "should have an environment accessor" do Puppet::Indirector::Request.new(:myind, :find, "my key", :environment => "foo").should respond_to(:environment) end it "should set its environment to an environment instance when a string is specified as its environment" do Puppet::Indirector::Request.new(:myind, :find, "my key", :environment => "foo").environment.should == Puppet::Node::Environment.new("foo") end it "should use any passed in environment instances as its environment" do env = Puppet::Node::Environment.new("foo") Puppet::Indirector::Request.new(:myind, :find, "my key", :environment => env).environment.should equal(env) end it "should use the default environment when none is provided" do Puppet::Indirector::Request.new(:myind, :find, "my key" ).environment.should equal(Puppet::Node::Environment.new) end it "should support converting its options to a hash" do Puppet::Indirector::Request.new(:myind, :find, "my key" ).should respond_to(:to_hash) end it "should include all of its attributes when its options are converted to a hash" do Puppet::Indirector::Request.new(:myind, :find, "my key", :node => 'foo').to_hash[:node].should == 'foo' end describe "when building a query string from its options" do before do @request = Puppet::Indirector::Request.new(:myind, :find, "my key") end it "should return an empty query string if there are no options" do @request.stubs(:options).returns nil @request.query_string.should == "" end it "should return an empty query string if the options are empty" do @request.stubs(:options).returns({}) @request.query_string.should == "" end it "should prefix the query string with '?'" do @request.stubs(:options).returns(:one => "two") @request.query_string.should =~ /^\?/ end it "should include all options in the query string, separated by '&'" do @request.stubs(:options).returns(:one => "two", :three => "four") @request.query_string.sub(/^\?/, '').split("&").sort.should == %w{one=two three=four}.sort end it "should ignore nil options" do @request.stubs(:options).returns(:one => "two", :three => nil) @request.query_string.should_not be_include("three") end it "should convert 'true' option values into strings" do @request.stubs(:options).returns(:one => true) @request.query_string.should == "?one=true" end it "should convert 'false' option values into strings" do @request.stubs(:options).returns(:one => false) @request.query_string.should == "?one=false" end it "should convert to a string all option values that are integers" do @request.stubs(:options).returns(:one => 50) @request.query_string.should == "?one=50" end it "should convert to a string all option values that are floating point numbers" do @request.stubs(:options).returns(:one => 1.2) @request.query_string.should == "?one=1.2" end it "should CGI-escape all option values that are strings" do escaping = CGI.escape("one two") @request.stubs(:options).returns(:one => "one two") @request.query_string.should == "?one=#{escaping}" end it "should YAML-dump and CGI-escape arrays" do escaping = CGI.escape(YAML.dump(%w{one two})) @request.stubs(:options).returns(:one => %w{one two}) @request.query_string.should == "?one=#{escaping}" end it "should convert to a string and CGI-escape all option values that are symbols" do escaping = CGI.escape("sym bol") @request.stubs(:options).returns(:one => :"sym bol") @request.query_string.should == "?one=#{escaping}" end it "should fail if options other than booleans or strings are provided" do @request.stubs(:options).returns(:one => {:one => :two}) lambda { @request.query_string }.should raise_error(ArgumentError) end end end diff --git a/spec/unit/indirector/resource/ral_spec.rb b/spec/unit/indirector/resource/ral_spec.rb index 74acec536..61290f7a7 100755 --- a/spec/unit/indirector/resource/ral_spec.rb +++ b/spec/unit/indirector/resource/ral_spec.rb @@ -1,129 +1,128 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe "Puppet::Resource::Ral" do describe "find" do before do @request = stub 'request', :key => "user/root" end it "should find an existing instance" do my_resource = stub "my user resource" wrong_instance = stub "wrong user", :name => "bob" my_instance = stub "my user", :name => "root", :to_resource => my_resource require 'puppet/type/user' Puppet::Type::User.expects(:instances).returns([ wrong_instance, my_instance, wrong_instance ]) Puppet::Resource::Ral.new.find(@request).should == my_resource end it "if there is no instance, it should create one" do wrong_instance = stub "wrong user", :name => "bob" require 'puppet/type/user' Puppet::Type::User.expects(:instances).returns([ wrong_instance, wrong_instance ]) result = Puppet::Resource::Ral.new.find(@request) result.should be_is_a(Puppet::Resource) result.title.should == "root" end end describe "search" do before do @request = stub 'request', :key => "user/", :options => {} end it "should convert ral resources into regular resources" do my_resource = stub "my user resource" my_instance = stub "my user", :name => "root", :to_resource => my_resource require 'puppet/type/user' Puppet::Type::User.expects(:instances).returns([ my_instance ]) Puppet::Resource::Ral.new.search(@request).should == [my_resource] end it "should filter results by name if there's a name in the key" do my_resource = stub "my user resource" my_resource.stubs(:to_resource).returns(my_resource) my_resource.stubs(:[]).with(:name).returns("root") wrong_resource = stub "wrong resource" wrong_resource.stubs(:to_resource).returns(wrong_resource) wrong_resource.stubs(:[]).with(:name).returns("bad") my_instance = stub "my user", :to_resource => my_resource wrong_instance = stub "wrong user", :to_resource => wrong_resource @request = stub 'request', :key => "user/root", :options => {} require 'puppet/type/user' Puppet::Type::User.expects(:instances).returns([ my_instance, wrong_instance ]) Puppet::Resource::Ral.new.search(@request).should == [my_resource] end it "should filter results by query parameters" do wrong_resource = stub "my user resource" wrong_resource.stubs(:to_resource).returns(wrong_resource) wrong_resource.stubs(:[]).with(:name).returns("root") my_resource = stub "wrong resource" my_resource.stubs(:to_resource).returns(my_resource) my_resource.stubs(:[]).with(:name).returns("bob") my_instance = stub "my user", :to_resource => my_resource wrong_instance = stub "wrong user", :to_resource => wrong_resource @request = stub 'request', :key => "user/", :options => {:name => "bob"} require 'puppet/type/user' Puppet::Type::User.expects(:instances).returns([ my_instance, wrong_instance ]) Puppet::Resource::Ral.new.search(@request).should == [my_resource] end it "should return sorted results" do a_resource = stub "alice resource" a_resource.stubs(:to_resource).returns(a_resource) a_resource.stubs(:title).returns("alice") b_resource = stub "bob resource" b_resource.stubs(:to_resource).returns(b_resource) b_resource.stubs(:title).returns("bob") a_instance = stub "alice user", :to_resource => a_resource b_instance = stub "bob user", :to_resource => b_resource @request = stub 'request', :key => "user/", :options => {} require 'puppet/type/user' Puppet::Type::User.expects(:instances).returns([ b_instance, a_instance ]) Puppet::Resource::Ral.new.search(@request).should == [a_resource, b_resource] end end describe "save" do before do @rebuilt_res = stub 'rebuilt instance' @ral_res = stub 'ral resource', :to_resource => @rebuilt_res @instance = stub 'instance', :to_ral => @ral_res @request = stub 'request', :key => "user/", :instance => @instance @catalog = stub 'catalog' Puppet::Resource::Catalog.stubs(:new).returns(@catalog) @catalog.stubs(:apply) @catalog.stubs(:add_resource) end it "should apply a new catalog with a ral object in it" do Puppet::Resource::Catalog.expects(:new).returns(@catalog) @catalog.expects(:add_resource).with(@ral_res) @catalog.expects(:apply) Puppet::Resource::Ral.new.save(@request) end it "should return a regular resource that used to be the ral resource" do Puppet::Resource::Ral.new.save(@request).should == @rebuilt_res end end end diff --git a/spec/unit/indirector/resource/rest_spec.rb b/spec/unit/indirector/resource/rest_spec.rb index 8857c552e..70c9a7f11 100755 --- a/spec/unit/indirector/resource/rest_spec.rb +++ b/spec/unit/indirector/resource/rest_spec.rb @@ -1,11 +1,10 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/indirector/resource/rest' describe Puppet::Resource::Rest do it "should be a sublcass of Puppet::Indirector::REST" do Puppet::Resource::Rest.superclass.should equal(Puppet::Indirector::REST) end end diff --git a/spec/unit/indirector/resource_type/parser_spec.rb b/spec/unit/indirector/resource_type/parser_spec.rb index 4eaf680a2..c4fc455a0 100755 --- a/spec/unit/indirector/resource_type/parser_spec.rb +++ b/spec/unit/indirector/resource_type/parser_spec.rb @@ -1,150 +1,149 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/indirector/resource_type/parser' require 'puppet_spec/files' describe Puppet::Indirector::ResourceType::Parser do include PuppetSpec::Files before do @terminus = Puppet::Indirector::ResourceType::Parser.new @request = Puppet::Indirector::Request.new(:resource_type, :find, "foo") @krt = @request.environment.known_resource_types end it "should be registered with the resource_type indirection" do Puppet::Indirector::Terminus.terminus_class(:resource_type, :parser).should equal(Puppet::Indirector::ResourceType::Parser) end describe "when finding" do it "should return any found type from the request's environment" do type = Puppet::Resource::Type.new(:hostclass, "foo") @request.environment.known_resource_types.add(type) @terminus.find(@request).should == type end it "should attempt to load the type if none is found in memory" do dir = tmpdir("find_a_type") FileUtils.mkdir_p(dir) Puppet[:modulepath] = dir # Make a new request, since we've reset the env @request = Puppet::Indirector::Request.new(:resource_type, :find, "foo::bar") manifest_path = File.join(dir, "foo", "manifests") FileUtils.mkdir_p(manifest_path) File.open(File.join(manifest_path, "bar.pp"), "w") { |f| f.puts "class foo::bar {}" } result = @terminus.find(@request) result.should be_instance_of(Puppet::Resource::Type) result.name.should == "foo::bar" end it "should return nil if no type can be found" do @terminus.find(@request).should be_nil end it "should prefer definitions to nodes" do type = @krt.add(Puppet::Resource::Type.new(:hostclass, "foo")) node = @krt.add(Puppet::Resource::Type.new(:node, "foo")) @terminus.find(@request).should == type end end describe "when searching" do before do @request.key = "*" end it "should use the request's environment's list of known resource types" do @request.environment.known_resource_types.expects(:hostclasses).returns({}) @terminus.search(@request) end it "should return all results if '*' is provided as the search string" do @request.key = "*" type = @krt.add(Puppet::Resource::Type.new(:hostclass, "foo")) node = @krt.add(Puppet::Resource::Type.new(:node, "bar")) define = @krt.add(Puppet::Resource::Type.new(:definition, "baz")) result = @terminus.search(@request) result.should be_include(type) result.should be_include(node) result.should be_include(define) end it "should treat any search string not '*' as a regex" do @request.key = "a" foo = @krt.add(Puppet::Resource::Type.new(:hostclass, "foo")) bar = @krt.add(Puppet::Resource::Type.new(:hostclass, "bar")) baz = @krt.add(Puppet::Resource::Type.new(:hostclass, "baz")) result = @terminus.search(@request) result.should be_include(bar) result.should be_include(baz) result.should_not be_include(foo) end it "should fail if a provided search string is not '*' and is not a valid regex" do @request.key = "*foo*" # Add one instance so we don't just get an empty array" @krt.add(Puppet::Resource::Type.new(:hostclass, "foo")) lambda { @terminus.search(@request) }.should raise_error(ArgumentError) end it "should return all known types" do type = @krt.add(Puppet::Resource::Type.new(:hostclass, "foo")) node = @krt.add(Puppet::Resource::Type.new(:node, "bar")) define = @krt.add(Puppet::Resource::Type.new(:definition, "baz")) result = @terminus.search(@request) result.should be_include(type) result.should be_include(node) result.should be_include(define) end it "should not return the 'main' class" do main = @krt.add(Puppet::Resource::Type.new(:hostclass, "")) # So there is a return value foo = @krt.add(Puppet::Resource::Type.new(:hostclass, "foo")) @terminus.search(@request).should_not be_include(main) end it "should return nil if no types can be found" do @terminus.search(@request).should be_nil end it "should load all resource types from all search paths" do dir = tmpdir("searching_in_all") first = File.join(dir, "first") second = File.join(dir, "second") FileUtils.mkdir_p(first) FileUtils.mkdir_p(second) Puppet[:modulepath] = "#{first}:#{second}" # Make a new request, since we've reset the env @request = Puppet::Indirector::Request.new(:resource_type, :search, "*") onepath = File.join(first, "one", "manifests") FileUtils.mkdir_p(onepath) twopath = File.join(first, "two", "manifests") FileUtils.mkdir_p(twopath) File.open(File.join(onepath, "oneklass.pp"), "w") { |f| f.puts "class one::oneklass {}" } File.open(File.join(twopath, "twoklass.pp"), "w") { |f| f.puts "class two::twoklass {}" } result = @terminus.search(@request) result.find { |t| t.name == "one::oneklass" }.should be_instance_of(Puppet::Resource::Type) result.find { |t| t.name == "two::twoklass" }.should be_instance_of(Puppet::Resource::Type) end end end diff --git a/spec/unit/indirector/resource_type/rest_spec.rb b/spec/unit/indirector/resource_type/rest_spec.rb index 11071107a..3d8ddf44c 100755 --- a/spec/unit/indirector/resource_type/rest_spec.rb +++ b/spec/unit/indirector/resource_type/rest_spec.rb @@ -1,15 +1,14 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/indirector/resource_type/rest' describe Puppet::Indirector::ResourceType::Rest do it "should be registered with the resource_type indirection" do Puppet::Indirector::Terminus.terminus_class(:resource_type, :rest).should equal(Puppet::Indirector::ResourceType::Rest) end it "should be a subclass of Puppet::Indirector::Rest" do Puppet::Indirector::ResourceType::Rest.superclass.should == Puppet::Indirector::REST end end diff --git a/spec/unit/indirector/rest_spec.rb b/spec/unit/indirector/rest_spec.rb index 29d00f1eb..513eb8352 100755 --- a/spec/unit/indirector/rest_spec.rb +++ b/spec/unit/indirector/rest_spec.rb @@ -1,516 +1,515 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/indirector/rest' shared_examples_for "a REST http call" do it "should accept a path" do lambda { @search.send(@method, *@arguments) }.should_not raise_error(ArgumentError) end it "should require a path" do lambda { @searcher.send(@method) }.should raise_error(ArgumentError) end it "should return the results of deserializing the response to the request" do conn = mock 'connection' conn.stubs(:put).returns @response conn.stubs(:delete).returns @response conn.stubs(:get).returns @response Puppet::Network::HttpPool.stubs(:http_instance).returns conn @searcher.expects(:deserialize).with(@response).returns "myobject" @searcher.send(@method, *@arguments).should == 'myobject' end end describe Puppet::Indirector::REST do before :all do Puppet::Indirector::Terminus.stubs(:register_terminus_class) @model = stub('model', :supported_formats => %w{}, :convert_from => nil) @instance = stub('model instance', :name= => nil) @indirection = stub('indirection', :name => :mystuff, :register_terminus_type => nil, :model => @model) Puppet::Indirector::Indirection.expects(:instance).returns(@indirection) module This module Is module A module Test end end end end @rest_class = class This::Is::A::Test::Class < Puppet::Indirector::REST self end end before :each do @response = stub('mock response', :body => 'result', :code => "200") @response.stubs(:[]).with('content-type').returns "text/plain" @response.stubs(:[]).with('content-encoding').returns nil @searcher = @rest_class.new @searcher.stubs(:model).returns @model end it "should include the v1 REST API module" do Puppet::Indirector::REST.ancestors.should be_include(Puppet::Network::HTTP::API::V1) end it "should have a method for specifying what setting a subclass should use to retrieve its server" do @rest_class.should respond_to(:use_server_setting) end it "should use any specified setting to pick the server" do @rest_class.expects(:server_setting).returns :servset Puppet.settings.expects(:value).with(:servset).returns "myserver" @rest_class.server.should == "myserver" end it "should default to :server for the server setting" do @rest_class.expects(:server_setting).returns nil Puppet.settings.expects(:value).with(:server).returns "myserver" @rest_class.server.should == "myserver" end it "should have a method for specifying what setting a subclass should use to retrieve its port" do @rest_class.should respond_to(:use_port_setting) end it "should use any specified setting to pick the port" do @rest_class.expects(:port_setting).returns :servset Puppet.settings.expects(:value).with(:servset).returns "321" @rest_class.port.should == 321 end it "should default to :port for the port setting" do @rest_class.expects(:port_setting).returns nil Puppet.settings.expects(:value).with(:masterport).returns "543" @rest_class.port.should == 543 end describe "when deserializing responses" do it "should return nil if the response code is 404" do response = mock 'response' response.expects(:code).returns "404" @searcher.deserialize(response).should be_nil end [300,400,403,405,500,501,502,503,504].each { |rc| describe "when the response code is #{rc}" do before :each do @model.expects(:convert_from).never @response = mock 'response' @response.stubs(:code).returns rc.to_s @response.stubs(:[]).with('content-encoding').returns nil @response.stubs(:message).returns "There was a problem (header)" end it "should fail" do @response.stubs(:body).returns nil lambda { @searcher.deserialize(@response) }.should raise_error(Net::HTTPError) end it "should take the error message from the body, if present" do @response.stubs(:body).returns "There was a problem (body)" lambda { @searcher.deserialize(@response) }.should raise_error(Net::HTTPError,"Error #{rc} on SERVER: There was a problem (body)") end it "should take the error message from the response header if the body is empty" do @response.stubs(:body).returns "" lambda { @searcher.deserialize(@response) }.should raise_error(Net::HTTPError,"Error #{rc} on SERVER: There was a problem (header)") end it "should take the error message from the response header if the body is absent" do @response.stubs(:body).returns nil lambda { @searcher.deserialize(@response) }.should raise_error(Net::HTTPError,"Error #{rc} on SERVER: There was a problem (header)") end describe "and with http compression" do it "should uncompress the body" do @response.stubs(:body).returns("compressed body") @searcher.expects(:uncompress_body).with(@response).returns("uncompressed") lambda { @searcher.deserialize(@response) }.should raise_error { |e| e.message =~ /uncompressed/ } end end end } it "should return the results of converting from the format specified by the content-type header if the response code is in the 200s" do @model.expects(:convert_from).with("myformat", "mydata").returns "myobject" response = mock 'response' response.stubs(:[]).with("content-type").returns "myformat" response.stubs(:[]).with("content-encoding").returns nil response.stubs(:body).returns "mydata" response.stubs(:code).returns "200" @searcher.deserialize(response).should == "myobject" end it "should convert and return multiple instances if the return code is in the 200s and 'multiple' is specified" do @model.expects(:convert_from_multiple).with("myformat", "mydata").returns "myobjects" response = mock 'response' response.stubs(:[]).with("content-type").returns "myformat" response.stubs(:[]).with("content-encoding").returns nil response.stubs(:body).returns "mydata" response.stubs(:code).returns "200" @searcher.deserialize(response, true).should == "myobjects" end it "should strip the content-type header to keep only the mime-type" do @model.expects(:convert_from).with("text/plain", "mydata").returns "myobject" response = mock 'response' response.stubs(:[]).with("content-type").returns "text/plain; charset=utf-8" response.stubs(:[]).with("content-encoding").returns nil response.stubs(:body).returns "mydata" response.stubs(:code).returns "200" @searcher.deserialize(response) end it "should uncompress the body" do @model.expects(:convert_from).with("myformat", "uncompressed mydata").returns "myobject" response = mock 'response' response.stubs(:[]).with("content-type").returns "myformat" response.stubs(:body).returns "compressed mydata" response.stubs(:code).returns "200" @searcher.expects(:uncompress_body).with(response).returns("uncompressed mydata") @searcher.deserialize(response).should == "myobject" end end describe "when creating an HTTP client" do before do Puppet.settings.stubs(:value).returns("rest_testing") end it "should use the class's server and port if the indirection request provides neither" do @request = stub 'request', :key => "foo", :server => nil, :port => nil @searcher.class.expects(:port).returns 321 @searcher.class.expects(:server).returns "myserver" Puppet::Network::HttpPool.expects(:http_instance).with("myserver", 321).returns "myconn" @searcher.network(@request).should == "myconn" end it "should use the server from the indirection request if one is present" do @request = stub 'request', :key => "foo", :server => "myserver", :port => nil @searcher.class.stubs(:port).returns 321 Puppet::Network::HttpPool.expects(:http_instance).with("myserver", 321).returns "myconn" @searcher.network(@request).should == "myconn" end it "should use the port from the indirection request if one is present" do @request = stub 'request', :key => "foo", :server => nil, :port => 321 @searcher.class.stubs(:server).returns "myserver" Puppet::Network::HttpPool.expects(:http_instance).with("myserver", 321).returns "myconn" @searcher.network(@request).should == "myconn" end end describe "when doing a find" do before :each do @connection = stub('mock http connection', :get => @response) @searcher.stubs(:network).returns(@connection) # neuter the network connection # Use a key with spaces, so we can test escaping @request = Puppet::Indirector::Request.new(:foo, :find, "foo bar", :environment => "myenv") end describe "with a large body" do it "should use the POST http method" do params = {} 'aa'.upto('zz') do |s| params[s] = 'foo' end @request = Puppet::Indirector::Request.new(:foo, :find, "foo bar", params.merge(:environment => "myenv")) @connection.expects(:post).with do |uri, body| uri == "/myenv/foo/foo%20bar" and body.split("&").sort == params.map {|key,value| "#{key}=#{value}"}.sort end.returns(@response) @searcher.find(@request) end end describe "with a small body" do it "should use the GET http method" do @searcher.expects(:network).returns @connection @connection.expects(:get).returns @response @searcher.find(@request) end end it "should deserialize and return the http response, setting name" do @connection.expects(:get).returns @response instance = stub 'object' instance.expects(:name=) @searcher.expects(:deserialize).with(@response).returns instance @searcher.find(@request).should == instance end it "should deserialize and return the http response, and not require name=" do @connection.expects(:get).returns @response instance = stub 'object' @searcher.expects(:deserialize).with(@response).returns instance @searcher.find(@request).should == instance end it "should use the URI generated by the Handler module" do @connection.expects(:get).with { |path, args| path == "/myenv/foo/foo%20bar?" }.returns(@response) @searcher.find(@request) end it "should provide an Accept header containing the list of supported formats joined with commas" do @connection.expects(:get).with { |path, args| args["Accept"] == "supported, formats" }.returns(@response) @searcher.model.expects(:supported_formats).returns %w{supported formats} @searcher.find(@request) end it "should add Accept-Encoding header" do @searcher.expects(:add_accept_encoding).returns({"accept-encoding" => "gzip"}) @connection.expects(:get).with { |path, args| args["accept-encoding"] == "gzip" }.returns(@response) @searcher.find(@request) end it "should deserialize and return the network response" do @searcher.expects(:deserialize).with(@response).returns @instance @searcher.find(@request).should equal(@instance) end it "should set the name of the resulting instance to the asked-for name" do @searcher.expects(:deserialize).with(@response).returns @instance @instance.expects(:name=).with "foo bar" @searcher.find(@request) end it "should generate an error when result data deserializes fails" do @searcher.expects(:deserialize).raises(ArgumentError) lambda { @searcher.find(@request) }.should raise_error(ArgumentError) end end describe "when doing a head" do before :each do @connection = stub('mock http connection', :head => @response) @searcher.stubs(:network).returns(@connection) # Use a key with spaces, so we can test escaping @request = Puppet::Indirector::Request.new(:foo, :head, "foo bar") end it "should call the HEAD http method on a network connection" do @searcher.expects(:network).returns @connection @connection.expects(:head).returns @response @searcher.head(@request) end it "should return true if there was a successful http response" do @connection.expects(:head).returns @response @response.stubs(:code).returns "200" @searcher.head(@request).should == true end it "should return false if there was a successful http response" do @connection.expects(:head).returns @response @response.stubs(:code).returns "404" @searcher.head(@request).should == false end it "should use the URI generated by the Handler module" do @searcher.expects(:indirection2uri).with(@request).returns "/my/uri" @connection.expects(:head).with { |path, args| path == "/my/uri" }.returns(@response) @searcher.head(@request) end end describe "when doing a search" do before :each do @connection = stub('mock http connection', :get => @response) @searcher.stubs(:network).returns(@connection) # neuter the network connection @model.stubs(:convert_from_multiple) @request = Puppet::Indirector::Request.new(:foo, :search, "foo bar") end it "should call the GET http method on a network connection" do @searcher.expects(:network).returns @connection @connection.expects(:get).returns @response @searcher.search(@request) end it "should deserialize as multiple instances and return the http response" do @connection.expects(:get).returns @response @searcher.expects(:deserialize).with(@response, true).returns "myobject" @searcher.search(@request).should == 'myobject' end it "should use the URI generated by the Handler module" do @searcher.expects(:indirection2uri).with(@request).returns "/mys/uri" @connection.expects(:get).with { |path, args| path == "/mys/uri" }.returns(@response) @searcher.search(@request) end it "should provide an Accept header containing the list of supported formats joined with commas" do @connection.expects(:get).with { |path, args| args["Accept"] == "supported, formats" }.returns(@response) @searcher.model.expects(:supported_formats).returns %w{supported formats} @searcher.search(@request) end it "should return an empty array if serialization returns nil" do @model.stubs(:convert_from_multiple).returns nil @searcher.search(@request).should == [] end it "should generate an error when result data deserializes fails" do @searcher.expects(:deserialize).raises(ArgumentError) lambda { @searcher.search(@request) }.should raise_error(ArgumentError) end end describe "when doing a destroy" do before :each do @connection = stub('mock http connection', :delete => @response) @searcher.stubs(:network).returns(@connection) # neuter the network connection @request = Puppet::Indirector::Request.new(:foo, :destroy, "foo bar") end it "should call the DELETE http method on a network connection" do @searcher.expects(:network).returns @connection @connection.expects(:delete).returns @response @searcher.destroy(@request) end it "should fail if any options are provided, since DELETE apparently does not support query options" do @request.stubs(:options).returns(:one => "two", :three => "four") lambda { @searcher.destroy(@request) }.should raise_error(ArgumentError) end it "should deserialize and return the http response" do @connection.expects(:delete).returns @response @searcher.expects(:deserialize).with(@response).returns "myobject" @searcher.destroy(@request).should == 'myobject' end it "should use the URI generated by the Handler module" do @searcher.expects(:indirection2uri).with(@request).returns "/my/uri" @connection.expects(:delete).with { |path, args| path == "/my/uri" }.returns(@response) @searcher.destroy(@request) end it "should not include the query string" do @connection.stubs(:delete).returns @response @searcher.destroy(@request) end it "should provide an Accept header containing the list of supported formats joined with commas" do @connection.expects(:delete).with { |path, args| args["Accept"] == "supported, formats" }.returns(@response) @searcher.model.expects(:supported_formats).returns %w{supported formats} @searcher.destroy(@request) end it "should deserialize and return the network response" do @searcher.expects(:deserialize).with(@response).returns @instance @searcher.destroy(@request).should equal(@instance) end it "should generate an error when result data deserializes fails" do @searcher.expects(:deserialize).raises(ArgumentError) lambda { @searcher.destroy(@request) }.should raise_error(ArgumentError) end end describe "when doing a save" do before :each do @connection = stub('mock http connection', :put => @response) @searcher.stubs(:network).returns(@connection) # neuter the network connection @instance = stub 'instance', :render => "mydata", :mime => "mime" @request = Puppet::Indirector::Request.new(:foo, :save, "foo bar") @request.instance = @instance end it "should call the PUT http method on a network connection" do @searcher.expects(:network).returns @connection @connection.expects(:put).returns @response @searcher.save(@request) end it "should fail if any options are provided, since DELETE apparently does not support query options" do @request.stubs(:options).returns(:one => "two", :three => "four") lambda { @searcher.save(@request) }.should raise_error(ArgumentError) end it "should use the URI generated by the Handler module" do @searcher.expects(:indirection2uri).with(@request).returns "/my/uri" @connection.expects(:put).with { |path, args| path == "/my/uri" }.returns(@response) @searcher.save(@request) end it "should serialize the instance using the default format and pass the result as the body of the request" do @instance.expects(:render).returns "serial_instance" @connection.expects(:put).with { |path, data, args| data == "serial_instance" }.returns @response @searcher.save(@request) end it "should deserialize and return the http response" do @connection.expects(:put).returns @response @searcher.expects(:deserialize).with(@response).returns "myobject" @searcher.save(@request).should == 'myobject' end it "should provide an Accept header containing the list of supported formats joined with commas" do @connection.expects(:put).with { |path, data, args| args["Accept"] == "supported, formats" }.returns(@response) @searcher.model.expects(:supported_formats).returns %w{supported formats} @searcher.save(@request) end it "should provide a Content-Type header containing the mime-type of the sent object" do @connection.expects(:put).with { |path, data, args| args['Content-Type'] == "mime" }.returns(@response) @instance.expects(:mime).returns "mime" @searcher.save(@request) end it "should deserialize and return the network response" do @searcher.expects(:deserialize).with(@response).returns @instance @searcher.save(@request).should equal(@instance) end it "should generate an error when result data deserializes fails" do @searcher.expects(:deserialize).raises(ArgumentError) lambda { @searcher.save(@request) }.should raise_error(ArgumentError) end end end diff --git a/spec/unit/indirector/run/local_spec.rb b/spec/unit/indirector/run/local_spec.rb index 1fbda7f34..8fb61d962 100755 --- a/spec/unit/indirector/run/local_spec.rb +++ b/spec/unit/indirector/run/local_spec.rb @@ -1,20 +1,19 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/indirector/run/local' describe Puppet::Run::Local do it "should be a sublcass of Puppet::Indirector::Code" do Puppet::Run::Local.superclass.should equal(Puppet::Indirector::Code) end it "should call runner.run on save and return the runner" do runner = Puppet::Run.new runner.stubs(:run).returns(runner) request = Puppet::Indirector::Request.new(:indirection, :save, "anything") request.instance = runner = Puppet::Run.new Puppet::Run::Local.new.save(request).should == runner end end diff --git a/spec/unit/indirector/run/rest_spec.rb b/spec/unit/indirector/run/rest_spec.rb index 3997d9c2f..4b80962d1 100755 --- a/spec/unit/indirector/run/rest_spec.rb +++ b/spec/unit/indirector/run/rest_spec.rb @@ -1,11 +1,10 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/indirector/run/rest' describe Puppet::Run::Rest do it "should be a sublcass of Puppet::Indirector::REST" do Puppet::Run::Rest.superclass.should equal(Puppet::Indirector::REST) end end diff --git a/spec/unit/indirector/ssl_file_spec.rb b/spec/unit/indirector/ssl_file_spec.rb index 011bdfa9c..5d0859598 100755 --- a/spec/unit/indirector/ssl_file_spec.rb +++ b/spec/unit/indirector/ssl_file_spec.rb @@ -1,282 +1,282 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Created by Luke Kanies on 2008-3-10. # Copyright (c) 2007. All rights reserved. require 'spec_helper' require 'puppet/indirector/ssl_file' describe Puppet::Indirector::SslFile do before :all do @indirection = stub 'indirection', :name => :testing, :model => @model Puppet::Indirector::Indirection.expects(:instance).with(:testing).returns(@indirection) module Testing; end @file_class = class Testing::MyType < Puppet::Indirector::SslFile self end end before :each do @model = mock 'model' @setting = :certdir @file_class.store_in @setting @path = "/tmp/my_directory" Puppet[:noop] = false Puppet[@setting] = @path Puppet[:trace] = false end it "should use :main and :ssl upon initialization" do Puppet.settings.expects(:use).with(:main, :ssl) @file_class.new end it "should return a nil collection directory if no directory setting has been provided" do @file_class.store_in nil @file_class.collection_directory.should be_nil end it "should return a nil file location if no location has been provided" do @file_class.store_at nil @file_class.file_location.should be_nil end it "should fail if no store directory or file location has been set" do @file_class.store_in nil @file_class.store_at nil lambda { @file_class.new }.should raise_error(Puppet::DevError) end describe "when managing ssl files" do before do Puppet.settings.stubs(:use) @searcher = @file_class.new @cert = stub 'certificate', :name => "myname" @certpath = File.join(@path, "myname.pem") @request = stub 'request', :key => @cert.name, :instance => @cert end it "should consider the file a ca file if the name is equal to what the SSL::Host class says is the CA name" do Puppet::SSL::Host.expects(:ca_name).returns "amaca" @searcher.should be_ca("amaca") end describe "when choosing the location for certificates" do it "should set them at the ca setting's path if a ca setting is available and the name resolves to the CA name" do @file_class.store_in nil @file_class.store_at :mysetting @file_class.store_ca_at :casetting Puppet.settings.stubs(:value).with(:casetting).returns "/ca/file" @searcher.expects(:ca?).with(@cert.name).returns true @searcher.path(@cert.name).should == "/ca/file" end it "should set them at the file location if a file setting is available" do @file_class.store_in nil @file_class.store_at :mysetting Puppet.settings.stubs(:value).with(:mysetting).returns "/some/file" @searcher.path(@cert.name).should == "/some/file" end it "should set them in the setting directory, with the certificate name plus '.pem', if a directory setting is available" do @searcher.path(@cert.name).should == @certpath end end describe "when finding certificates on disk" do describe "and no certificate is present" do before do # Stub things so the case management bits work. FileTest.stubs(:exist?).with(File.dirname(@certpath)).returns false FileTest.expects(:exist?).with(@certpath).returns false end it "should return nil" do @searcher.find(@request).should be_nil end end describe "and a certificate is present" do before do FileTest.expects(:exist?).with(@certpath).returns true end it "should return an instance of the model, which it should use to read the certificate" do cert = mock 'cert' model = mock 'model' @file_class.stubs(:model).returns model model.expects(:new).with("myname").returns cert cert.expects(:read).with(@certpath) @searcher.find(@request).should equal(cert) end end describe "and a certificate is present but has uppercase letters" do before do @request = stub 'request', :key => "myhost" end # This is kind of more an integration test; it's for #1382, until # the support for upper-case certs can be removed around mid-2009. it "should rename the existing file to the lower-case path" do @path = @searcher.path("myhost") FileTest.expects(:exist?).with(@path).returns(false) dir, file = File.split(@path) FileTest.expects(:exist?).with(dir).returns true Dir.expects(:entries).with(dir).returns [".", "..", "something.pem", file.upcase] File.expects(:rename).with(File.join(dir, file.upcase), @path) cert = mock 'cert' model = mock 'model' @searcher.stubs(:model).returns model @searcher.model.expects(:new).with("myhost").returns cert cert.expects(:read).with(@path) @searcher.find(@request) end end end describe "when saving certificates to disk" do before do FileTest.stubs(:directory?).returns true FileTest.stubs(:writable?).returns true end it "should fail if the directory is absent" do FileTest.expects(:directory?).with(File.dirname(@certpath)).returns false lambda { @searcher.save(@request) }.should raise_error(Puppet::Error) end it "should fail if the directory is not writeable" do FileTest.stubs(:directory?).returns true FileTest.expects(:writable?).with(File.dirname(@certpath)).returns false lambda { @searcher.save(@request) }.should raise_error(Puppet::Error) end it "should save to the path the output of converting the certificate to a string" do fh = mock 'filehandle' fh.expects(:print).with("mycert") @searcher.stubs(:write).yields fh @cert.expects(:to_s).returns "mycert" @searcher.save(@request) end describe "and a directory setting is set" do it "should use the Settings class to write the file" do @searcher.class.store_in @setting fh = mock 'filehandle' fh.stubs :print Puppet.settings.expects(:writesub).with(@setting, @certpath).yields fh @searcher.save(@request) end end describe "and a file location is set" do it "should use the filehandle provided by the Settings" do @searcher.class.store_at @setting fh = mock 'filehandle' fh.stubs :print Puppet.settings.expects(:write).with(@setting).yields fh @searcher.save(@request) end end describe "and the name is the CA name and a ca setting is set" do it "should use the filehandle provided by the Settings" do @searcher.class.store_at @setting @searcher.class.store_ca_at :castuff Puppet.settings.stubs(:value).with(:castuff).returns "castuff stub" fh = mock 'filehandle' fh.stubs :print Puppet.settings.expects(:write).with(:castuff).yields fh @searcher.stubs(:ca?).returns true @searcher.save(@request) end end end describe "when destroying certificates" do describe "that do not exist" do before do FileTest.expects(:exist?).with(@certpath).returns false end it "should return false" do @searcher.destroy(@request).should be_false end end describe "that exist" do before do FileTest.expects(:exist?).with(@certpath).returns true end it "should unlink the certificate file" do File.expects(:unlink).with(@certpath) @searcher.destroy(@request) end it "should log that is removing the file" do File.stubs(:exist?).returns true File.stubs(:unlink) Puppet.expects(:notice) @searcher.destroy(@request) end end end describe "when searching for certificates" do before do @model = mock 'model' @file_class.stubs(:model).returns @model end it "should return a certificate instance for all files that exist" do Dir.expects(:entries).with(@path).returns %w{one.pem two.pem} one = stub 'one', :read => nil two = stub 'two', :read => nil @model.expects(:new).with("one").returns one @model.expects(:new).with("two").returns two @searcher.search(@request).should == [one, two] end it "should read each certificate in using the model's :read method" do Dir.expects(:entries).with(@path).returns %w{one.pem} one = stub 'one' one.expects(:read).with(File.join(@path, "one.pem")) @model.expects(:new).with("one").returns one @searcher.search(@request) end it "should skip any files that do not match /\.pem$/" do Dir.expects(:entries).with(@path).returns %w{. .. one.pem} one = stub 'one', :read => nil @model.expects(:new).with("one").returns one @searcher.search(@request) end end end end diff --git a/spec/unit/indirector/status/rest_spec.rb b/spec/unit/indirector/status/rest_spec.rb index 24b10df07..b203e6e20 100755 --- a/spec/unit/indirector/status/rest_spec.rb +++ b/spec/unit/indirector/status/rest_spec.rb @@ -1,11 +1,10 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/indirector/status/rest' describe Puppet::Indirector::Status::Rest do it "should be a sublcass of Puppet::Indirector::REST" do Puppet::Indirector::Status::Rest.superclass.should equal(Puppet::Indirector::REST) end end diff --git a/spec/unit/indirector/terminus_spec.rb b/spec/unit/indirector/terminus_spec.rb index 2abdab4f6..41770e1e3 100755 --- a/spec/unit/indirector/terminus_spec.rb +++ b/spec/unit/indirector/terminus_spec.rb @@ -1,245 +1,244 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/defaults' require 'puppet/indirector' require 'puppet/indirector/file' describe Puppet::Indirector::Terminus do before :each do Puppet::Indirector::Terminus.stubs(:register_terminus_class) @indirection = stub 'indirection', :name => :my_stuff, :register_terminus_type => nil Puppet::Indirector::Indirection.stubs(:instance).with(:my_stuff).returns(@indirection) @abstract_terminus = Class.new(Puppet::Indirector::Terminus) do def self.to_s "Testing::Abstract" end end @terminus_class = Class.new(@abstract_terminus) do def self.to_s "MyStuff::TermType" end end @terminus = @terminus_class.new end describe Puppet::Indirector::Terminus do it "should provide a method for setting terminus class documentation" do @terminus_class.should respond_to(:desc) end it "should support a class-level name attribute" do @terminus_class.should respond_to(:name) end it "should support a class-level indirection attribute" do @terminus_class.should respond_to(:indirection) end it "should support a class-level terminus-type attribute" do @terminus_class.should respond_to(:terminus_type) end it "should support a class-level model attribute" do @terminus_class.should respond_to(:model) end it "should accept indirection instances as its indirection" do indirection = stub 'indirection', :is_a? => true, :register_terminus_type => nil proc { @terminus_class.indirection = indirection }.should_not raise_error @terminus_class.indirection.should equal(indirection) end it "should look up indirection instances when only a name has been provided" do indirection = mock 'indirection' Puppet::Indirector::Indirection.expects(:instance).with(:myind).returns(indirection) @terminus_class.indirection = :myind @terminus_class.indirection.should equal(indirection) end it "should fail when provided a name that does not resolve to an indirection" do Puppet::Indirector::Indirection.expects(:instance).with(:myind).returns(nil) proc { @terminus_class.indirection = :myind }.should raise_error(ArgumentError) # It shouldn't overwrite our existing one (or, more normally, it shouldn't set # anything). @terminus_class.indirection.should equal(@indirection) end end describe Puppet::Indirector::Terminus, " when creating terminus classes" do it "should associate the subclass with an indirection based on the subclass constant" do @terminus.indirection.should equal(@indirection) end it "should set the subclass's type to the abstract terminus name" do @terminus.terminus_type.should == :abstract end it "should set the subclass's name to the indirection name" do @terminus.name.should == :term_type end it "should set the subclass's model to the indirection model" do @indirection.expects(:model).returns :yay @terminus.model.should == :yay end end describe Puppet::Indirector::Terminus, " when a terminus instance" do it "should return the class's name as its name" do @terminus.name.should == :term_type end it "should return the class's indirection as its indirection" do @terminus.indirection.should equal(@indirection) end it "should set the instances's type to the abstract terminus type's name" do @terminus.terminus_type.should == :abstract end it "should set the instances's model to the indirection's model" do @indirection.expects(:model).returns :yay @terminus.model.should == :yay end end end # LAK: This could reasonably be in the Indirection instances, too. It doesn't make # a whole heckuva lot of difference, except that with the instance loading in # the Terminus base class, we have to have a check to see if we're already # instance-loading a given terminus class type. describe Puppet::Indirector::Terminus, " when managing terminus classes" do it "should provide a method for registering terminus classes" do Puppet::Indirector::Terminus.should respond_to(:register_terminus_class) end it "should provide a method for returning terminus classes by name and type" do terminus = stub 'terminus_type', :name => :abstract, :indirection_name => :whatever Puppet::Indirector::Terminus.register_terminus_class(terminus) Puppet::Indirector::Terminus.terminus_class(:whatever, :abstract).should equal(terminus) end it "should set up autoloading for any terminus class types requested" do Puppet::Indirector::Terminus.expects(:instance_load).with(:test2, "puppet/indirector/test2") Puppet::Indirector::Terminus.terminus_class(:test2, :whatever) end it "should load terminus classes that are not found" do # Set up instance loading; it would normally happen automatically Puppet::Indirector::Terminus.instance_load :test1, "puppet/indirector/test1" Puppet::Indirector::Terminus.instance_loader(:test1).expects(:load).with(:yay) Puppet::Indirector::Terminus.terminus_class(:test1, :yay) end it "should fail when no indirection can be found" do Puppet::Indirector::Indirection.expects(:instance).with(:my_indirection).returns(nil) @abstract_terminus = Class.new(Puppet::Indirector::Terminus) do def self.to_s "Abstract" end end proc { @terminus = Class.new(@abstract_terminus) do def self.to_s "MyIndirection::TestType" end end }.should raise_error(ArgumentError) end it "should register the terminus class with the terminus base class" do Puppet::Indirector::Terminus.expects(:register_terminus_class).with do |type| type.indirection_name == :my_indirection and type.name == :test_terminus end @indirection = stub 'indirection', :name => :my_indirection, :register_terminus_type => nil Puppet::Indirector::Indirection.expects(:instance).with(:my_indirection).returns(@indirection) @abstract_terminus = Class.new(Puppet::Indirector::Terminus) do def self.to_s "Abstract" end end @terminus = Class.new(@abstract_terminus) do def self.to_s "MyIndirection::TestTerminus" end end end end describe Puppet::Indirector::Terminus, " when parsing class constants for indirection and terminus names" do before do @subclass = mock 'subclass' @subclass.stubs(:to_s).returns("TestInd::OneTwo") @subclass.stubs(:mark_as_abstract_terminus) Puppet::Indirector::Terminus.stubs(:register_terminus_class) end it "should fail when anonymous classes are used" do proc { Puppet::Indirector::Terminus.inherited(Class.new) }.should raise_error(Puppet::DevError) end it "should use the last term in the constant for the terminus class name" do @subclass.expects(:name=).with(:one_two) @subclass.stubs(:indirection=) Puppet::Indirector::Terminus.inherited(@subclass) end it "should convert the terminus name to a downcased symbol" do @subclass.expects(:name=).with(:one_two) @subclass.stubs(:indirection=) Puppet::Indirector::Terminus.inherited(@subclass) end it "should use the second to last term in the constant for the indirection name" do @subclass.expects(:indirection=).with(:test_ind) @subclass.stubs(:name=) @subclass.stubs(:terminus_type=) Puppet::Indirector::File.inherited(@subclass) end it "should convert the indirection name to a downcased symbol" do @subclass.expects(:indirection=).with(:test_ind) @subclass.stubs(:name=) @subclass.stubs(:terminus_type=) Puppet::Indirector::File.inherited(@subclass) end it "should convert camel case to lower case with underscores as word separators" do @subclass.expects(:name=).with(:one_two) @subclass.stubs(:indirection=) Puppet::Indirector::Terminus.inherited(@subclass) end end describe Puppet::Indirector::Terminus, " when creating terminus class types" do before do Puppet::Indirector::Terminus.stubs(:register_terminus_class) @subclass = Class.new(Puppet::Indirector::Terminus) do def self.to_s "Puppet::Indirector::Terminus::MyTermType" end end end it "should set the name of the abstract subclass to be its class constant" do @subclass.name.should equal(:my_term_type) end it "should mark abstract terminus types as such" do @subclass.should be_abstract_terminus end it "should not allow instances of abstract subclasses to be created" do proc { @subclass.new }.should raise_error(Puppet::DevError) end end diff --git a/spec/unit/indirector/yaml_spec.rb b/spec/unit/indirector/yaml_spec.rb index d2d12e74f..c43dbcaf6 100755 --- a/spec/unit/indirector/yaml_spec.rb +++ b/spec/unit/indirector/yaml_spec.rb @@ -1,159 +1,158 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/indirector/yaml' describe Puppet::Indirector::Yaml, " when choosing file location" do before :all do @indirection = stub 'indirection', :name => :my_yaml, :register_terminus_type => nil Puppet::Indirector::Indirection.expects(:instance).with(:my_yaml).returns(@indirection) module MyYaml; end @store_class = class MyYaml::MyType < Puppet::Indirector::Yaml self end end before :each do @store = @store_class.new @subject = Object.new @subject.singleton_class.send(:attr_accessor, :name) @subject.name = :me @dir = "/what/ever" Puppet.settings.stubs(:value).returns("fakesettingdata") Puppet.settings.stubs(:value).with(:clientyamldir).returns(@dir) Puppet.run_mode.stubs(:master?).returns false @request = stub 'request', :key => :me, :instance => @subject end describe Puppet::Indirector::Yaml, " when choosing file location" do it "should use the server_datadir if the run_mode is master" do Puppet.run_mode.expects(:master?).returns true Puppet.settings.expects(:value).with(:yamldir).returns "/server/yaml/dir" @store.path(:me).should =~ %r{^/server/yaml/dir} end it "should use the client yamldir if the run_mode is not master" do Puppet.run_mode.expects(:master?).returns false Puppet.settings.expects(:value).with(:clientyamldir).returns "/client/yaml/dir" @store.path(:me).should =~ %r{^/client/yaml/dir} end it "should use the extension if one is specified" do Puppet.run_mode.expects(:master?).returns true Puppet.settings.expects(:value).with(:yamldir).returns "/server/yaml/dir" @store.path(:me,'.farfignewton').should =~ %r{\.farfignewton$} end it "should assume an extension of .yaml if none is specified" do Puppet.run_mode.expects(:master?).returns true Puppet.settings.expects(:value).with(:yamldir).returns "/server/yaml/dir" @store.path(:me).should =~ %r{\.yaml$} end it "should store all files in a single file root set in the Puppet defaults" do @store.path(:me).should =~ %r{^#{@dir}} end it "should use the terminus name for choosing the subdirectory" do @store.path(:me).should =~ %r{^#{@dir}/my_yaml} end it "should use the object's name to determine the file name" do @store.path(:me).should =~ %r{me.yaml$} end end describe Puppet::Indirector::Yaml, " when storing objects as YAML" do it "should only store objects that respond to :name" do @request.stubs(:instance).returns Object.new proc { @store.save(@request) }.should raise_error(ArgumentError) end it "should convert Ruby objects to YAML and write them to disk using a write lock" do yaml = @subject.to_yaml file = mock 'file' path = @store.send(:path, @subject.name) FileTest.expects(:exist?).with(File.dirname(path)).returns(true) @store.expects(:writelock).with(path, 0660).yields(file) file.expects(:print).with(yaml) @store.save(@request) end it "should create the indirection subdirectory if it does not exist" do yaml = @subject.to_yaml file = mock 'file' path = @store.send(:path, @subject.name) dir = File.dirname(path) FileTest.expects(:exist?).with(dir).returns(false) Dir.expects(:mkdir).with(dir) @store.expects(:writelock).yields(file) file.expects(:print).with(yaml) @store.save(@request) end end describe Puppet::Indirector::Yaml, " when retrieving YAML" do it "should read YAML in from disk using a read lock and convert it to Ruby objects" do path = @store.send(:path, @subject.name) yaml = @subject.to_yaml FileTest.expects(:exist?).with(path).returns(true) fh = mock 'filehandle' @store.expects(:readlock).with(path).yields fh fh.expects(:read).returns yaml @store.find(@request).instance_variable_get("@name").should == :me end it "should fail coherently when the stored YAML is invalid" do path = @store.send(:path, @subject.name) FileTest.expects(:exist?).with(path).returns(true) # Something that will fail in yaml yaml = "--- !ruby/object:Hash" fh = mock 'filehandle' @store.expects(:readlock).yields fh fh.expects(:read).returns yaml proc { @store.find(@request) }.should raise_error(Puppet::Error) end end describe Puppet::Indirector::Yaml, " when searching" do it "should return an array of fact instances with one instance for each file when globbing *" do @request = stub 'request', :key => "*", :instance => @subject @one = mock 'one' @two = mock 'two' @store.expects(:path).with(@request.key,'').returns :glob Dir.expects(:glob).with(:glob).returns(%w{one.yaml two.yaml}) YAML.expects(:load_file).with("one.yaml").returns @one; YAML.expects(:load_file).with("two.yaml").returns @two; @store.search(@request).should == [@one, @two] end it "should return an array containing a single instance of fact when globbing 'one*'" do @request = stub 'request', :key => "one*", :instance => @subject @one = mock 'one' @store.expects(:path).with(@request.key,'').returns :glob Dir.expects(:glob).with(:glob).returns(%w{one.yaml}) YAML.expects(:load_file).with("one.yaml").returns @one; @store.search(@request).should == [@one] end it "should return an empty array when the glob doesn't match anything" do @request = stub 'request', :key => "f*ilglobcanfail*", :instance => @subject @store.expects(:path).with(@request.key,'').returns :glob Dir.expects(:glob).with(:glob).returns [] @store.search(@request).should == [] end end end diff --git a/spec/unit/indirector_spec.rb b/spec/unit/indirector_spec.rb index cca86e218..0c09831db 100755 --- a/spec/unit/indirector_spec.rb +++ b/spec/unit/indirector_spec.rb @@ -1,145 +1,144 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/defaults' require 'puppet/indirector' describe Puppet::Indirector, "when configuring routes" do before :each do Puppet::Node.indirection.reset_terminus_class Puppet::Node.indirection.cache_class = nil end after :each do Puppet::Node.indirection.reset_terminus_class Puppet::Node.indirection.cache_class = nil end it "should configure routes as requested" do routes = { "node" => { "terminus" => "exec", "cache" => "plain" } } Puppet::Indirector.configure_routes(routes) Puppet::Node.indirection.terminus_class.should == "exec" Puppet::Node.indirection.cache_class.should == "plain" end it "should fail when given an invalid indirection" do routes = { "fake_indirection" => { "terminus" => "exec", "cache" => "plain" } } expect { Puppet::Indirector.configure_routes(routes) }.should raise_error(/fake_indirection does not exist/) end it "should fail when given an invalid terminus" do routes = { "node" => { "terminus" => "fake_terminus", "cache" => "plain" } } expect { Puppet::Indirector.configure_routes(routes) }.should raise_error(/Could not find terminus fake_terminus/) end it "should fail when given an invalid cache" do routes = { "node" => { "terminus" => "exec", "cache" => "fake_cache" } } expect { Puppet::Indirector.configure_routes(routes) }.should raise_error(/Could not find terminus fake_cache/) end end describe Puppet::Indirector, " when available to a model" do before do @thingie = Class.new do extend Puppet::Indirector end end it "should provide a way for the model to register an indirection under a name" do @thingie.should respond_to(:indirects) end end describe Puppet::Indirector, "when registering an indirection" do before do @thingie = Class.new do extend Puppet::Indirector attr_reader :name def initialize(name) @name = name end end end it "should require a name when registering a model" do Proc.new {@thingie.send(:indirects) }.should raise_error(ArgumentError) end it "should create an indirection instance to manage each indirecting model" do @indirection = @thingie.indirects(:test) @indirection.should be_instance_of(Puppet::Indirector::Indirection) end it "should not allow a model to register under multiple names" do # Keep track of the indirection instance so we can delete it on cleanup @indirection = @thingie.indirects :first Proc.new { @thingie.indirects :second }.should raise_error(ArgumentError) end it "should make the indirection available via an accessor" do @indirection = @thingie.indirects :first @thingie.indirection.should equal(@indirection) end it "should pass any provided options to the indirection during initialization" do klass = mock 'terminus class' Puppet::Indirector::Indirection.expects(:new).with(@thingie, :first, {:some => :options}) @indirection = @thingie.indirects :first, :some => :options end it "should extend the class with the Format Handler" do @indirection = @thingie.indirects :first @thingie.singleton_class.ancestors.should be_include(Puppet::Network::FormatHandler) end after do @indirection.delete if @indirection end end describe Puppet::Indirector, "when redirecting a model" do before do @thingie = Class.new do extend Puppet::Indirector attr_reader :name def initialize(name) @name = name end end @indirection = @thingie.send(:indirects, :test) end it "should include the Envelope module in the model" do @thingie.ancestors.should be_include(Puppet::Indirector::Envelope) end after do @indirection.delete end end diff --git a/spec/unit/interface/action_builder_spec.rb b/spec/unit/interface/action_builder_spec.rb index 666575605..5b04df900 100755 --- a/spec/unit/interface/action_builder_spec.rb +++ b/spec/unit/interface/action_builder_spec.rb @@ -1,70 +1,69 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/interface/action_builder' describe Puppet::Interface::ActionBuilder do describe "::build" do it "should build an action" do action = Puppet::Interface::ActionBuilder.build(nil, :foo) do end action.should be_a(Puppet::Interface::Action) action.name.should == :foo end it "should define a method on the face which invokes the action" do face = Puppet::Interface.new(:action_builder_test_interface, '0.0.1') action = Puppet::Interface::ActionBuilder.build(face, :foo) do when_invoked do "invoked the method" end end face.foo.should == "invoked the method" end it "should require a block" do expect { Puppet::Interface::ActionBuilder.build(nil, :foo) }. should raise_error("Action :foo must specify a block") end describe "when handling options" do let :face do Puppet::Interface.new(:option_handling, '0.0.1') end it "should have a #option DSL function" do method = nil Puppet::Interface::ActionBuilder.build(face, :foo) do method = self.method(:option) end method.should be end it "should define an option without a block" do action = Puppet::Interface::ActionBuilder.build(face, :foo) do option "--bar" end action.should be_option :bar end it "should accept an empty block" do action = Puppet::Interface::ActionBuilder.build(face, :foo) do option "--bar" do # This space left deliberately blank. end end action.should be_option :bar end end context "inline documentation" do let :face do Puppet::Interface.new(:inline_action_docs, '0.0.1') end it "should set the summary" do action = Puppet::Interface::ActionBuilder.build(face, :foo) do summary "this is some text" end action.summary.should == "this is some text" end end end end diff --git a/spec/unit/interface/action_manager_spec.rb b/spec/unit/interface/action_manager_spec.rb index 42daf763e..c4b21eaac 100755 --- a/spec/unit/interface/action_manager_spec.rb +++ b/spec/unit/interface/action_manager_spec.rb @@ -1,233 +1,232 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' # This is entirely an internal class for Interface, so we have to load it instead of our class. require 'puppet/interface' class ActionManagerTester include Puppet::Interface::ActionManager end describe Puppet::Interface::ActionManager do subject { ActionManagerTester.new } describe "when included in a class" do it "should be able to define an action" do subject.action(:foo) do when_invoked { "something "} end end it "should be able to define a 'script' style action" do subject.script :bar do "a bar is where beer is found" end end it "should be able to list defined actions" do subject.action(:foo) do when_invoked { "something" } end subject.action(:bar) do when_invoked { "something" } end subject.actions.should =~ [:foo, :bar] end it "should list 'script' actions" do subject.script :foo do "foo" end subject.actions.should =~ [:foo] end it "should list both script and normal actions" do subject.action :foo do when_invoked do "foo" end end subject.script :bar do "a bar is where beer is found" end subject.actions.should =~ [:foo, :bar] end it "should be able to indicate when an action is defined" do subject.action(:foo) do when_invoked { "something" } end subject.should be_action(:foo) end it "should indicate an action is defined for script actions" do subject.script :foo do "foo" end subject.should be_action :foo end it "should correctly treat action names specified as strings" do subject.action(:foo) do when_invoked { "something" } end subject.should be_action("foo") end end describe "when used to extend a class" do subject { Class.new.extend(Puppet::Interface::ActionManager) } it "should be able to define an action" do subject.action(:foo) do when_invoked { "something "} end end it "should be able to list defined actions" do subject.action(:foo) do when_invoked { "something" } end subject.action(:bar) do when_invoked { "something" } end subject.actions.should include(:bar) subject.actions.should include(:foo) end it "should be able to indicate when an action is defined" do subject.action(:foo) { "something" } subject.should be_action(:foo) end end describe "when used both at the class and instance level" do before do @klass = Class.new do include Puppet::Interface::ActionManager extend Puppet::Interface::ActionManager end @instance = @klass.new end it "should be able to define an action at the class level" do @klass.action(:foo) do when_invoked { "something "} end end it "should create an instance method when an action is defined at the class level" do @klass.action(:foo) do when_invoked { "something" } end @instance.foo.should == "something" end it "should be able to define an action at the instance level" do @instance.action(:foo) do when_invoked { "something "} end end it "should create an instance method when an action is defined at the instance level" do @instance.action(:foo) do when_invoked { "something" } end @instance.foo.should == "something" end it "should be able to list actions defined at the class level" do @klass.action(:foo) do when_invoked { "something" } end @klass.action(:bar) do when_invoked { "something" } end @klass.actions.should include(:bar) @klass.actions.should include(:foo) end it "should be able to list actions defined at the instance level" do @instance.action(:foo) do when_invoked { "something" } end @instance.action(:bar) do when_invoked { "something" } end @instance.actions.should include(:bar) @instance.actions.should include(:foo) end it "should be able to list actions defined at both instance and class level" do @klass.action(:foo) do when_invoked { "something" } end @instance.action(:bar) do when_invoked { "something" } end @instance.actions.should include(:bar) @instance.actions.should include(:foo) end it "should be able to indicate when an action is defined at the class level" do @klass.action(:foo) do when_invoked { "something" } end @instance.should be_action(:foo) end it "should be able to indicate when an action is defined at the instance level" do @klass.action(:foo) do when_invoked { "something" } end @instance.should be_action(:foo) end it "should list actions defined in superclasses" do @subclass = Class.new(@klass) @instance = @subclass.new @klass.action(:parent) do when_invoked { "a" } end @subclass.action(:sub) do when_invoked { "a" } end @instance.action(:instance) do when_invoked { "a" } end @instance.should be_action(:parent) @instance.should be_action(:sub) @instance.should be_action(:instance) end it "should create an instance method when an action is defined in a superclass" do @subclass = Class.new(@klass) @instance = @subclass.new @klass.action(:foo) do when_invoked { "something" } end @instance.foo.should == "something" end end describe "#get_action" do let :parent_class do parent_class = Class.new(Puppet::Interface) parent_class.action(:foo) {} parent_class end it "should check that we can find inherited actions when we are a class" do Class.new(parent_class).get_action(:foo).name.should == :foo end it "should check that we can find inherited actions when we are an instance" do instance = parent_class.new(:foo, '0.0.0') instance.get_action(:foo).name.should == :foo end end end diff --git a/spec/unit/interface/action_spec.rb b/spec/unit/interface/action_spec.rb index 957198427..8c6782976 100755 --- a/spec/unit/interface/action_spec.rb +++ b/spec/unit/interface/action_spec.rb @@ -1,173 +1,172 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/interface/action' describe Puppet::Interface::Action do describe "when validating the action name" do [nil, '', 'foo bar', '-foobar'].each do |input| it "should treat #{input.inspect} as an invalid name" do expect { Puppet::Interface::Action.new(nil, input) }. should raise_error(/is an invalid action name/) end end end describe "when invoking" do it "should be able to call other actions on the same object" do face = Puppet::Interface.new(:my_face, '0.0.1') do action(:foo) do when_invoked { 25 } end action(:bar) do when_invoked { "the value of foo is '#{foo}'" } end end face.foo.should == 25 face.bar.should == "the value of foo is '25'" end # bar is a class action calling a class action # quux is a class action calling an instance action # baz is an instance action calling a class action # qux is an instance action calling an instance action it "should be able to call other actions on the same object when defined on a class" do class Puppet::Interface::MyInterfaceBaseClass < Puppet::Interface action(:foo) do when_invoked { 25 } end action(:bar) do when_invoked { "the value of foo is '#{foo}'" } end action(:quux) do when_invoked { "qux told me #{qux}" } end end face = Puppet::Interface::MyInterfaceBaseClass.new(:my_inherited_face, '0.0.1') do action(:baz) do when_invoked { "the value of foo in baz is '#{foo}'" } end action(:qux) do when_invoked { baz } end end face.foo.should == 25 face.bar.should == "the value of foo is '25'" face.quux.should == "qux told me the value of foo in baz is '25'" face.baz.should == "the value of foo in baz is '25'" face.qux.should == "the value of foo in baz is '25'" end context "when calling the Ruby API" do let :face do Puppet::Interface.new(:ruby_api, '1.0.0') do action :bar do when_invoked do |options| options end end end end it "should work when no options are supplied" do options = face.bar options.should == {} end it "should work when options are supplied" do options = face.bar :bar => "beer" options.should == { :bar => "beer" } end end end describe "with action-level options" do it "should support options with an empty block" do face = Puppet::Interface.new(:action_level_options, '0.0.1') do action :foo do option "--bar" do # this line left deliberately blank end end end face.should_not be_option :bar face.get_action(:foo).should be_option :bar end it "should return only action level options when there are no face options" do face = Puppet::Interface.new(:action_level_options, '0.0.1') do action :foo do option "--bar" end end face.get_action(:foo).options.should =~ [:bar] end describe "with both face and action options" do let :face do Puppet::Interface.new(:action_level_options, '0.0.1') do action :foo do option "--bar" end action :baz do option "--bim" end option "--quux" end end it "should return combined face and action options" do face.get_action(:foo).options.should =~ [:bar, :quux] end it "should fetch options that the face inherited" do parent = Class.new(Puppet::Interface) parent.option "--foo" child = parent.new(:inherited_options, '0.0.1') do option "--bar" action :action do option "--baz" end end action = child.get_action(:action) action.should be [:baz, :bar, :foo].each do |name| action.get_option(name).should be_an_instance_of Puppet::Interface::Option end end it "should get an action option when asked" do face.get_action(:foo).get_option(:bar). should be_an_instance_of Puppet::Interface::Option end it "should get a face option when asked" do face.get_action(:foo).get_option(:quux). should be_an_instance_of Puppet::Interface::Option end it "should return options only for this action" do face.get_action(:baz).options.should =~ [:bim, :quux] end end it_should_behave_like "things that declare options" do def add_options_to(&block) face = Puppet::Interface.new(:with_options, '0.0.1') do action(:foo, &block) end face.get_action(:foo) end end it "should fail when a face option duplicates an action option" do expect { Puppet::Interface.new(:action_level_options, '0.0.1') do option "--foo" action :bar do option "--foo" end end }.should raise_error ArgumentError, /Option foo conflicts with existing option foo/i end end end diff --git a/spec/unit/interface/face_collection_spec.rb b/spec/unit/interface/face_collection_spec.rb index 752871035..d1114dde7 100755 --- a/spec/unit/interface/face_collection_spec.rb +++ b/spec/unit/interface/face_collection_spec.rb @@ -1,181 +1,170 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec require 'spec_helper' require 'tmpdir' require 'puppet/interface/face_collection' describe Puppet::Interface::FaceCollection do # To avoid cross-pollution we have to save and restore both the hash # containing all the interface data, and the array used by require. Restoring # both means that we don't leak side-effects across the code. --daniel 2011-04-06 # # Worse luck, we *also* need to flush $" of anything defining a face, # because otherwise we can cross-pollute from other test files and end up # with no faces loaded, but the require value set true. --daniel 2011-04-10 before :each do @original_faces = subject.instance_variable_get("@faces").dup @original_required = $".dup - $".delete_if do |path| path =~ %r{/faces/.*\.rb$} end + $".delete_if do |path| path =~ %r{/face/.*\.rb$} end subject.instance_variable_get("@faces").clear end after :each do subject.instance_variable_set("@faces", @original_faces) $".clear ; @original_required.each do |item| $" << item end end describe "::faces" do it "REVISIT: should have some tests here, if we describe it" end describe "::validate_version" do it 'should permit three number versions' do subject.validate_version('10.10.10').should == true end it 'should permit versions with appended descriptions' do subject.validate_version('10.10.10beta').should == true end it 'should not permit versions with more than three numbers' do subject.validate_version('1.2.3.4').should == false end it 'should not permit versions with only two numbers' do subject.validate_version('10.10').should == false end it 'should not permit versions with only one number' do subject.validate_version('123').should == false end it 'should not permit versions with text in any position but at the end' do subject.validate_version('v1.1.1').should == false end end describe "::[]" do before :each do subject.instance_variable_get("@faces")[:foo]['0.0.1'] = 10 end - before :each do - @dir = Dir.mktmpdir - @lib = FileUtils.mkdir_p(File.join @dir, 'puppet', 'faces') - $LOAD_PATH.push(@dir) - end - - after :each do - FileUtils.remove_entry_secure @dir - $LOAD_PATH.pop - end - - it "should return the faces with the given name" do + it "should return the face with the given name" do subject["foo", '0.0.1'].should == 10 end - it "should attempt to load the faces if it isn't found" do - subject.expects(:require).with('puppet/faces/bar') + it "should attempt to load the face if it isn't found" do + subject.expects(:require).with('puppet/face/bar') subject["bar", '0.0.1'] end - it "should attempt to load the default faces for the specified version :current" do - subject.expects(:require).with('puppet/faces/fozzie') + it "should attempt to load the default face for the specified version :current" do + subject.expects(:require).with('puppet/face/fozzie') subject['fozzie', :current] end end describe "::face?" do - it "should return true if the faces specified is registered" do + it "should return true if the face specified is registered" do subject.instance_variable_get("@faces")[:foo]['0.0.1'] = 10 subject.face?("foo", '0.0.1').should == true end - it "should attempt to require the faces if it is not registered" do + it "should attempt to require the face if it is not registered" do subject.expects(:require).with do |file| subject.instance_variable_get("@faces")[:bar]['0.0.1'] = true - file == 'puppet/faces/bar' + file == 'puppet/face/bar' end subject.face?("bar", '0.0.1').should == true end - it "should return true if requiring the faces registered it" do + it "should return true if requiring the face registered it" do subject.stubs(:require).with do subject.instance_variable_get("@faces")[:bar]['0.0.1'] = 20 end end - it "should return false if the faces is not registered" do + it "should return false if the face is not registered" do subject.stubs(:require).returns(true) subject.face?("bar", '0.0.1').should be_false end - it "should return false if the faces file itself is missing" do + it "should return false if the face file itself is missing" do subject.stubs(:require). - raises(LoadError, 'no such file to load -- puppet/faces/bar') + raises(LoadError, 'no such file to load -- puppet/face/bar') subject.face?("bar", '0.0.1').should be_false end it "should register the version loaded by `:current` as `:current`" do subject.expects(:require).with do |file| - subject.instance_variable_get("@faces")[:huzzah]['2.0.1'] = :huzzah_faces - file == 'puppet/faces/huzzah' + subject.instance_variable_get("@faces")[:huzzah]['2.0.1'] = :huzzah_face + file == 'puppet/face/huzzah' end subject.face?("huzzah", :current) - subject.instance_variable_get("@faces")[:huzzah][:current].should == :huzzah_faces + subject.instance_variable_get("@faces")[:huzzah][:current].should == :huzzah_face end context "with something on disk" do - it "should register the version loaded from `puppet/faces/{name}` as `:current`" do + it "should register the version loaded from `puppet/face/{name}` as `:current`" do subject.should be_face "huzzah", '2.0.1' subject.should be_face "huzzah", :current - Puppet::Faces[:huzzah, '2.0.1'].should == Puppet::Faces[:huzzah, :current] + Puppet::Face[:huzzah, '2.0.1'].should == Puppet::Face[:huzzah, :current] end it "should index :current when the code was pre-required" do subject.instance_variable_get("@faces")[:huzzah].should_not be_key :current - require 'puppet/faces/huzzah' + require 'puppet/face/huzzah' subject.face?(:huzzah, :current).should be_true end end it "should not cause an invalid face to be enumerated later" do subject.face?(:there_is_no_face, :current).should be_false subject.faces.should_not include :there_is_no_face end end describe "::register" do - it "should store the faces by name" do - faces = Puppet::Faces.new(:my_faces, '0.0.1') - subject.register(faces) - subject.instance_variable_get("@faces").should == {:my_faces => {'0.0.1' => faces}} + it "should store the face by name" do + face = Puppet::Face.new(:my_face, '0.0.1') + subject.register(face) + subject.instance_variable_get("@faces").should == {:my_face => {'0.0.1' => face}} end end describe "::underscorize" do faulty = [1, "#foo", "$bar", "sturm und drang", :"sturm und drang"] valid = { "Foo" => :foo, :Foo => :foo, "foo_bar" => :foo_bar, :foo_bar => :foo_bar, "foo-bar" => :foo_bar, :"foo-bar" => :foo_bar, } valid.each do |input, expect| it "should map #{input.inspect} to #{expect.inspect}" do result = subject.underscorize(input) result.should == expect end end faulty.each do |input| it "should fail when presented with #{input.inspect} (#{input.class})" do expect { subject.underscorize(input) }. should raise_error ArgumentError, /not a valid face name/ end end end end diff --git a/spec/unit/interface/option_builder_spec.rb b/spec/unit/interface/option_builder_spec.rb old mode 100644 new mode 100755 diff --git a/spec/unit/interface/option_spec.rb b/spec/unit/interface/option_spec.rb old mode 100644 new mode 100755 diff --git a/spec/unit/interface_spec.rb b/spec/unit/interface_spec.rb index 7e6b7de77..2365d5cac 100755 --- a/spec/unit/interface_spec.rb +++ b/spec/unit/interface_spec.rb @@ -1,185 +1,185 @@ require 'spec_helper' -require 'puppet/faces' +require 'puppet/face' require 'puppet/interface' describe Puppet::Interface do subject { Puppet::Interface } before :all do @faces = Puppet::Interface::FaceCollection.instance_variable_get("@faces").dup end before :each do Puppet::Interface::FaceCollection.instance_variable_get("@faces").clear end after :all do Puppet::Interface::FaceCollection.instance_variable_set("@faces", @faces) end describe "#[]" do it "should fail when no version is requested" do expect { subject[:huzzah] }.should raise_error ArgumentError end it "should raise an exception when the requested version is unavailable" do expect { subject[:huzzah, '17.0.0'] }.should raise_error, Puppet::Error end it "should raise an exception when the requested face doesn't exist" do expect { subject[:burrble_toot, :current] }.should raise_error, Puppet::Error end end describe "#define" do it "should register the face" do face = subject.define(:face_test_register, '0.0.1') face.should == subject[:face_test_register, '0.0.1'] end it "should load actions" do subject.any_instance.expects(:load_actions) subject.define(:face_test_load_actions, '0.0.1') end it "should require a version number" do expect { subject.define(:no_version) }.to raise_error ArgumentError end it "should support summary builder and accessor methods" do subject.new(:foo, '1.0.0').should respond_to(:summary).with(0).arguments subject.new(:foo, '1.0.0').should respond_to(:summary=).with(1).arguments end it "should set the summary text" do text = "hello, freddy, my little pal" subject.define(:face_test_summary, '1.0.0') do summary text end subject[:face_test_summary, '1.0.0'].summary.should == text end it "should support mutating the summary" do text = "hello, freddy, my little pal" subject.define(:face_test_summary, '1.0.0') do summary text end subject[:face_test_summary, '1.0.0'].summary.should == text subject[:face_test_summary, '1.0.0'].summary = text + text subject[:face_test_summary, '1.0.0'].summary.should == text + text end end describe "#initialize" do it "should require a version number" do expect { subject.new(:no_version) }.to raise_error ArgumentError end it "should require a valid version number" do expect { subject.new(:bad_version, 'Rasins') }. should raise_error ArgumentError end it "should instance-eval any provided block" do face = subject.new(:face_test_block, '0.0.1') do action(:something) do when_invoked { "foo" } end end face.something.should == "foo" end end it "should have a name" do subject.new(:me, '0.0.1').name.should == :me end it "should stringify with its own name" do subject.new(:me, '0.0.1').to_s.should =~ /\bme\b/ end it "should allow overriding of the default format" do face = subject.new(:me, '0.0.1') face.set_default_format :foo face.default_format.should == :foo end it "should default to :pson for its format" do subject.new(:me, '0.0.1').default_format.should == :pson end # Why? it "should create a class-level autoloader" do subject.autoloader.should be_instance_of(Puppet::Util::Autoload) end it "should try to require faces that are not known" do pending "mocking require causes random stack overflow" - subject::FaceCollection.expects(:require).with "puppet/faces/foo" + subject::FaceCollection.expects(:require).with "puppet/face/foo" subject[:foo, '0.0.1'] end it "should be able to load all actions in all search paths" it_should_behave_like "things that declare options" do def add_options_to(&block) subject.new(:with_options, '0.0.1', &block) end end describe "with face-level options" do it "should not return any action-level options" do face = subject.new(:with_options, '0.0.1') do option "--foo" option "--bar" action :baz do option "--quux" end end face.options.should =~ [:foo, :bar] end it "should fail when a face option duplicates an action option" do expect { subject.new(:action_level_options, '0.0.1') do action :bar do option "--foo" end option "--foo" end }.should raise_error ArgumentError, /Option foo conflicts with existing option foo on/i end it "should work when two actions have the same option" do face = subject.new(:with_options, '0.0.1') do action :foo do option "--quux" end action :bar do option "--quux" end end face.get_action(:foo).options.should =~ [:quux] face.get_action(:bar).options.should =~ [:quux] end end describe "with inherited options" do let :face do parent = Class.new(subject) parent.option("--inherited") face = parent.new(:example, '0.2.1') face.option("--local") face end describe "#options" do it "should list inherited options" do face.options.should =~ [:inherited, :local] end end describe "#get_option" do it "should return an inherited option object" do face.get_option(:inherited).should be_an_instance_of subject::Option end end end end diff --git a/spec/unit/module_spec.rb b/spec/unit/module_spec.rb index 2daf85347..8d38657f9 100755 --- a/spec/unit/module_spec.rb +++ b/spec/unit/module_spec.rb @@ -1,570 +1,569 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet_spec/files' describe Puppet::Module do include PuppetSpec::Files before do # This is necessary because of the extra checks we have for the deprecated # 'plugins' directory FileTest.stubs(:exist?).returns false end it "should have a class method that returns a named module from a given environment" do env = mock 'module' env.expects(:module).with("mymod").returns "yep" Puppet::Node::Environment.expects(:new).with("myenv").returns env Puppet::Module.find("mymod", "myenv").should == "yep" end it "should return nil if asked for a named module that doesn't exist" do env = mock 'module' env.expects(:module).with("mymod").returns nil Puppet::Node::Environment.expects(:new).with("myenv").returns env Puppet::Module.find("mymod", "myenv").should be_nil end it "should support a 'version' attribute" do mod = Puppet::Module.new("mymod") mod.version = 1.09 mod.version.should == 1.09 end it "should support a 'source' attribute" do mod = Puppet::Module.new("mymod") mod.source = "http://foo/bar" mod.source.should == "http://foo/bar" end it "should support a 'project_page' attribute" do mod = Puppet::Module.new("mymod") mod.project_page = "http://foo/bar" mod.project_page.should == "http://foo/bar" end it "should support an 'author' attribute" do mod = Puppet::Module.new("mymod") mod.author = "Luke Kanies " mod.author.should == "Luke Kanies " end it "should support a 'license' attribute" do mod = Puppet::Module.new("mymod") mod.license = "GPL2" mod.license.should == "GPL2" end it "should support a 'summary' attribute" do mod = Puppet::Module.new("mymod") mod.summary = "GPL2" mod.summary.should == "GPL2" end it "should support a 'description' attribute" do mod = Puppet::Module.new("mymod") mod.description = "GPL2" mod.description.should == "GPL2" end it "should support specifying a compatible puppet version" do mod = Puppet::Module.new("mymod") mod.puppetversion = "0.25" mod.puppetversion.should == "0.25" end it "should validate that the puppet version is compatible" do mod = Puppet::Module.new("mymod") mod.puppetversion = "0.25" Puppet.expects(:version).returns "0.25" mod.validate_puppet_version end it "should fail if the specified puppet version is not compatible" do mod = Puppet::Module.new("mymod") mod.puppetversion = "0.25" Puppet.stubs(:version).returns "0.24" lambda { mod.validate_puppet_version }.should raise_error(Puppet::Module::IncompatibleModule) end describe "when specifying required modules" do it "should support specifying a required module" do mod = Puppet::Module.new("mymod") mod.requires "foobar" end it "should support specifying multiple required modules" do mod = Puppet::Module.new("mymod") mod.requires "foobar" mod.requires "baz" end it "should support specifying a required module and version" do mod = Puppet::Module.new("mymod") mod.requires "foobar", 1.0 end it "should fail when required modules are missing" do mod = Puppet::Module.new("mymod") mod.requires "foobar" mod.environment.expects(:module).with("foobar").returns nil lambda { mod.validate_dependencies }.should raise_error(Puppet::Module::MissingModule) end it "should fail when required modules are present but of the wrong version" do mod = Puppet::Module.new("mymod") mod.requires "foobar", 1.0 foobar = Puppet::Module.new("foobar") foobar.version = 2.0 mod.environment.expects(:module).with("foobar").returns foobar lambda { mod.validate_dependencies }.should raise_error(Puppet::Module::IncompatibleModule) end it "should have valid dependencies when no dependencies have been specified" do mod = Puppet::Module.new("mymod") lambda { mod.validate_dependencies }.should_not raise_error end it "should fail when some dependencies are present but others aren't" do mod = Puppet::Module.new("mymod") mod.requires "foobar" mod.requires "baz" mod.environment.expects(:module).with("foobar").returns Puppet::Module.new("foobar") mod.environment.expects(:module).with("baz").returns nil lambda { mod.validate_dependencies }.should raise_error(Puppet::Module::MissingModule) end it "should have valid dependencies when all dependencies are met" do mod = Puppet::Module.new("mymod") mod.requires "foobar", 1.0 mod.requires "baz" foobar = Puppet::Module.new("foobar") foobar.version = 1.0 baz = Puppet::Module.new("baz") mod.environment.expects(:module).with("foobar").returns foobar mod.environment.expects(:module).with("baz").returns baz lambda { mod.validate_dependencies }.should_not raise_error end it "should validate its dependendencies on initialization" do Puppet::Module.any_instance.expects(:validate_dependencies) Puppet::Module.new("mymod") end end describe "when managing supported platforms" do it "should support specifying a supported platform" do mod = Puppet::Module.new("mymod") mod.supports "solaris" end it "should support specifying a supported platform and version" do mod = Puppet::Module.new("mymod") mod.supports "solaris", 1.0 end it "should fail when not running on a supported platform" do pending "Not sure how to send client platform to the module" mod = Puppet::Module.new("mymod") Facter.expects(:value).with("operatingsystem").returns "Solaris" mod.supports "hpux" lambda { mod.validate_supported_platform }.should raise_error(Puppet::Module::UnsupportedPlatform) end it "should fail when supported platforms are present but of the wrong version" do pending "Not sure how to send client platform to the module" mod = Puppet::Module.new("mymod") Facter.expects(:value).with("operatingsystem").returns "Solaris" Facter.expects(:value).with("operatingsystemrelease").returns 2.0 mod.supports "Solaris", 1.0 lambda { mod.validate_supported_platform }.should raise_error(Puppet::Module::IncompatiblePlatform) end it "should be considered supported when no supported platforms have been specified" do pending "Not sure how to send client platform to the module" mod = Puppet::Module.new("mymod") lambda { mod.validate_supported_platform }.should_not raise_error end it "should be considered supported when running on a supported platform" do pending "Not sure how to send client platform to the module" mod = Puppet::Module.new("mymod") Facter.expects(:value).with("operatingsystem").returns "Solaris" Facter.expects(:value).with("operatingsystemrelease").returns 2.0 mod.supports "Solaris", 1.0 lambda { mod.validate_supported_platform }.should raise_error(Puppet::Module::IncompatiblePlatform) end it "should be considered supported when running on any of multiple supported platforms" do pending "Not sure how to send client platform to the module" end it "should validate its platform support on initialization" do pending "Not sure how to send client platform to the module" end end it "should return nil if asked for a module whose name is 'nil'" do Puppet::Module.find(nil, "myenv").should be_nil end it "should provide support for logging" do Puppet::Module.ancestors.should be_include(Puppet::Util::Logging) end it "should be able to be converted to a string" do Puppet::Module.new("foo").to_s.should == "Module foo" end it "should add the path to its string form if the module is found" do mod = Puppet::Module.new("foo") mod.stubs(:path).returns "/a" mod.to_s.should == "Module foo(/a)" end it "should fail if its name is not alphanumeric" do lambda { Puppet::Module.new(".something") }.should raise_error(Puppet::Module::InvalidName) end it "should require a name at initialization" do lambda { Puppet::Module.new }.should raise_error(ArgumentError) end it "should convert an environment name into an Environment instance" do Puppet::Module.new("foo", "prod").environment.should be_instance_of(Puppet::Node::Environment) end it "should accept an environment at initialization" do Puppet::Module.new("foo", :prod).environment.name.should == :prod end it "should use the default environment if none is provided" do env = Puppet::Node::Environment.new Puppet::Module.new("foo").environment.should equal(env) end it "should use any provided Environment instance" do env = Puppet::Node::Environment.new Puppet::Module.new("foo", env).environment.should equal(env) end it "should return the path to the first found instance in its environment's module paths as its path" do dir = tmpdir("deep_path") first = File.join(dir, "first") second = File.join(dir, "second") FileUtils.mkdir_p(first) FileUtils.mkdir_p(second) Puppet[:modulepath] = "#{first}:#{second}" modpath = File.join(first, "foo") FileUtils.mkdir_p(modpath) # Make a second one, which we shouldn't find FileUtils.mkdir_p(File.join(second, "foo")) mod = Puppet::Module.new("foo") mod.path.should == modpath end it "should be able to find itself in a directory other than the first directory in the module path" do dir = tmpdir("deep_path") first = File.join(dir, "first") second = File.join(dir, "second") FileUtils.mkdir_p(first) FileUtils.mkdir_p(second) Puppet[:modulepath] = "#{first}:#{second}" modpath = File.join(second, "foo") FileUtils.mkdir_p(modpath) mod = Puppet::Module.new("foo") mod.should be_exist mod.path.should == modpath end it "should be considered existent if it exists in at least one module path" do mod = Puppet::Module.new("foo") mod.expects(:path).returns "/a/foo" mod.should be_exist end it "should be considered nonexistent if it does not exist in any of the module paths" do mod = Puppet::Module.new("foo") mod.expects(:path).returns nil mod.should_not be_exist end [:plugins, :templates, :files, :manifests].each do |filetype| dirname = filetype == :plugins ? "lib" : filetype.to_s it "should be able to return individual #{filetype}" do mod = Puppet::Module.new("foo") mod.stubs(:path).returns "/a/foo" path = File.join("/a/foo", dirname, "my/file") FileTest.expects(:exist?).with(path).returns true mod.send(filetype.to_s.sub(/s$/, ''), "my/file").should == path end it "should consider #{filetype} to be present if their base directory exists" do mod = Puppet::Module.new("foo") mod.stubs(:path).returns "/a/foo" path = File.join("/a/foo", dirname) FileTest.expects(:exist?).with(path).returns true mod.send(filetype.to_s + "?").should be_true end it "should consider #{filetype} to be absent if their base directory does not exist" do mod = Puppet::Module.new("foo") mod.stubs(:path).returns "/a/foo" path = File.join("/a/foo", dirname) FileTest.expects(:exist?).with(path).returns false mod.send(filetype.to_s + "?").should be_false end it "should consider #{filetype} to be absent if the module base directory does not exist" do mod = Puppet::Module.new("foo") mod.stubs(:path).returns nil mod.send(filetype.to_s + "?").should be_false end it "should return nil if asked to return individual #{filetype} that don't exist" do mod = Puppet::Module.new("foo") mod.stubs(:path).returns "/a/foo" path = File.join("/a/foo", dirname, "my/file") FileTest.expects(:exist?).with(path).returns false mod.send(filetype.to_s.sub(/s$/, ''), "my/file").should be_nil end it "should return nil when asked for individual #{filetype} if the module does not exist" do mod = Puppet::Module.new("foo") mod.stubs(:path).returns nil mod.send(filetype.to_s.sub(/s$/, ''), "my/file").should be_nil end it "should return the base directory if asked for a nil path" do mod = Puppet::Module.new("foo") mod.stubs(:path).returns "/a/foo" base = File.join("/a/foo", dirname) FileTest.expects(:exist?).with(base).returns true mod.send(filetype.to_s.sub(/s$/, ''), nil).should == base end end %w{plugins files}.each do |filetype| short = filetype.sub(/s$/, '') dirname = filetype == "plugins" ? "lib" : filetype.to_s it "should be able to return the #{short} directory" do Puppet::Module.new("foo").should respond_to(short + "_directory") end it "should return the path to the #{short} directory" do mod = Puppet::Module.new("foo") mod.stubs(:path).returns "/a/foo" mod.send(short + "_directory").should == "/a/foo/#{dirname}" end end it "should throw a warning if plugins are in a 'plugins' directory rather than a 'lib' directory" do mod = Puppet::Module.new("foo") mod.stubs(:path).returns "/a/foo" FileTest.expects(:exist?).with("/a/foo/plugins").returns true mod.plugin_directory.should == "/a/foo/plugins" @logs.first.message.should == "using the deprecated 'plugins' directory for ruby extensions; please move to 'lib'" @logs.first.level.should == :warning end it "should default to 'lib' for the plugins directory" do mod = Puppet::Module.new("foo") mod.stubs(:path).returns "/a/foo" mod.plugin_directory.should == "/a/foo/lib" end end describe Puppet::Module, " when building its search path" do it "should use the current environment's search path if no environment is specified" do env = mock 'env' env.expects(:modulepath).returns "eh" Puppet::Node::Environment.expects(:new).with(nil).returns env Puppet::Module.modulepath.should == "eh" end it "should use the specified environment's search path if an environment is specified" do env = mock 'env' env.expects(:modulepath).returns "eh" Puppet::Node::Environment.expects(:new).with("foo").returns env Puppet::Module.modulepath("foo").should == "eh" end end describe Puppet::Module, "when finding matching manifests" do before do @mod = Puppet::Module.new("mymod") @mod.stubs(:path).returns "/a" @pq_glob_with_extension = "yay/*.xx" @fq_glob_with_extension = "/a/manifests/#{@pq_glob_with_extension}" end it "should return all manifests matching the glob pattern" do Dir.expects(:glob).with(@fq_glob_with_extension).returns(%w{foo bar}) FileTest.stubs(:directory?).returns false @mod.match_manifests(@pq_glob_with_extension).should == %w{foo bar} end it "should not return directories" do Dir.expects(:glob).with(@fq_glob_with_extension).returns(%w{foo bar}) FileTest.expects(:directory?).with("foo").returns false FileTest.expects(:directory?).with("bar").returns true @mod.match_manifests(@pq_glob_with_extension).should == %w{foo} end it "should default to the 'init' file if no glob pattern is specified" do Dir.expects(:glob).with("/a/manifests/init.{pp,rb}").returns(%w{/a/manifests/init.pp}) @mod.match_manifests(nil).should == %w{/a/manifests/init.pp} end it "should return all manifests matching the glob pattern in all existing paths" do Dir.expects(:glob).with(@fq_glob_with_extension).returns(%w{a b}) @mod.match_manifests(@pq_glob_with_extension).should == %w{a b} end it "should match the glob pattern plus '.{pp,rb}' if no extention is specified" do Dir.expects(:glob).with("/a/manifests/yay/foo.{pp,rb}").returns(%w{yay}) @mod.match_manifests("yay/foo").should == %w{yay} end it "should return an empty array if no manifests matched" do Dir.expects(:glob).with(@fq_glob_with_extension).returns([]) @mod.match_manifests(@pq_glob_with_extension).should == [] end end describe Puppet::Module do before do Puppet::Module.any_instance.stubs(:path).returns "/my/mod/path" @module = Puppet::Module.new("foo") end it "should use 'License' in its current path as its metadata file" do @module.license_file.should == "/my/mod/path/License" end it "should return nil as its license file when the module has no path" do Puppet::Module.any_instance.stubs(:path).returns nil Puppet::Module.new("foo").license_file.should be_nil end it "should cache the license file" do Puppet::Module.any_instance.expects(:path).once.returns nil mod = Puppet::Module.new("foo") mod.license_file.should == mod.license_file end it "should use 'metadata.json' in its current path as its metadata file" do @module.metadata_file.should == "/my/mod/path/metadata.json" end it "should return nil as its metadata file when the module has no path" do Puppet::Module.any_instance.stubs(:path).returns nil Puppet::Module.new("foo").metadata_file.should be_nil end it "should cache the metadata file" do Puppet::Module.any_instance.expects(:path).once.returns nil mod = Puppet::Module.new("foo") mod.metadata_file.should == mod.metadata_file end it "should know if it has a metadata file" do FileTest.expects(:exist?).with(@module.metadata_file).returns true @module.should be_has_metadata end it "should know if it is missing a metadata file" do FileTest.expects(:exist?).with(@module.metadata_file).returns false @module.should_not be_has_metadata end it "should be able to parse its metadata file" do @module.should respond_to(:load_metadata) end it "should parse its metadata file on initialization if it is present" do Puppet::Module.any_instance.expects(:has_metadata?).returns true Puppet::Module.any_instance.expects(:load_metadata) Puppet::Module.new("yay") end describe "when loading the medatada file", :if => Puppet.features.json? do before do @data = { :license => "GPL2", :author => "luke", :version => "1.0", :source => "http://foo/", :puppetversion => "0.25" } @text = @data.to_json @module = Puppet::Module.new("foo") @module.stubs(:metadata_file).returns "/my/file" File.stubs(:read).with("/my/file").returns @text end %w{source author version license}.each do |attr| it "should set #{attr} if present in the metadata file" do @module.load_metadata @module.send(attr).should == @data[attr.to_sym] end it "should fail if #{attr} is not present in the metadata file" do @data.delete(attr.to_sym) @text = @data.to_json File.stubs(:read).with("/my/file").returns @text lambda { @module.load_metadata }.should raise_error(Puppet::Module::MissingMetadata) end end it "should set puppetversion if present in the metadata file" do @module.load_metadata @module.puppetversion.should == @data[:puppetversion] end it "should fail if the discovered name is different than the metadata name" end end diff --git a/spec/unit/network/authconfig_spec.rb b/spec/unit/network/authconfig_spec.rb index 99accefb2..c47b2e0c5 100755 --- a/spec/unit/network/authconfig_spec.rb +++ b/spec/unit/network/authconfig_spec.rb @@ -1,292 +1,291 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/network/authconfig' describe Puppet::Network::AuthConfig do before do @rights = stubs 'rights' Puppet::Network::Rights.stubs(:new).returns(@rights) @rights.stubs(:each).returns([]) FileTest.stubs(:exists?).returns(true) File.stubs(:stat).returns(stub('stat', :ctime => :now)) Time.stubs(:now).returns Time.now @authconfig = Puppet::Network::AuthConfig.new("dummy", false) end describe "when initializing" do before :each do Puppet::Network::AuthConfig.any_instance.stubs(:read) end it "should use the authconfig default pathname if none provided" do Puppet.expects(:[]).with(:authconfig).returns("dummy") Puppet::Network::AuthConfig.new end it "should raise an error if no file is defined finally" do Puppet.stubs(:[]).with(:authconfig).returns(nil) lambda { Puppet::Network::AuthConfig.new }.should raise_error(Puppet::DevError) end it "should read and parse the file if parsenow is true" do Puppet::Network::AuthConfig.any_instance.expects(:read) Puppet::Network::AuthConfig.new("dummy", true) end end describe "when checking authorization" do before :each do @authconfig.stubs(:read) @call = stub 'call', :intern => "name" @handler = stub 'handler', :intern => "handler" @method = stub_everything 'method' @request = stub 'request', :call => @call, :handler => @handler, :method => @method, :name => "me", :ip => "1.2.3.4" end it "should attempt to read the authconfig file" do @rights.stubs(:include?) @authconfig.expects(:read) @authconfig.allowed?(@request) end it "should use a name right if it exists" do right = stub 'right' @rights.stubs(:include?).with("name").returns(true) @rights.stubs(:[]).with("name").returns(right) right.expects(:allowed?).with("me", "1.2.3.4") @authconfig.allowed?(@request) end it "should use a namespace right otherwise" do right = stub 'right' @rights.stubs(:include?).with("name").returns(false) @rights.stubs(:include?).with("handler").returns(true) @rights.stubs(:[]).with("handler").returns(right) right.expects(:allowed?).with("me", "1.2.3.4") @authconfig.allowed?(@request) end it "should return whatever the found rights returns" do right = stub 'right' @rights.stubs(:include?).with("name").returns(true) @rights.stubs(:[]).with("name").returns(right) right.stubs(:allowed?).with("me", "1.2.3.4").returns(:returned) @authconfig.allowed?(@request).should == :returned end end describe "when parsing authconfig file" do before :each do @fd = stub 'fd' File.stubs(:open).yields(@fd) @rights.stubs(:include?).returns(false) @rights.stubs(:[]) end it "should skip comments" do @fd.stubs(:each).yields(' # comment') @rights.expects(:newright).never @authconfig.read end it "should increment line number even on commented lines" do @fd.stubs(:each).multiple_yields(' # comment','[puppetca]') @rights.expects(:newright).with('[puppetca]', 2, 'dummy') @authconfig.read end it "should skip blank lines" do @fd.stubs(:each).yields(' ') @rights.expects(:newright).never @authconfig.read end it "should increment line number even on blank lines" do @fd.stubs(:each).multiple_yields(' ','[puppetca]') @rights.expects(:newright).with('[puppetca]', 2, 'dummy') @authconfig.read end it "should throw an error if the current namespace right already exist" do @fd.stubs(:each).yields('[puppetca]') @rights.stubs(:include?).with("puppetca").returns(true) lambda { @authconfig.read }.should raise_error end it "should not throw an error if the current path right already exist" do @fd.stubs(:each).yields('path /hello') @rights.stubs(:newright).with("/hello",1, 'dummy') @rights.stubs(:include?).with("/hello").returns(true) lambda { @authconfig.read }.should_not raise_error end it "should create a new right for found namespaces" do @fd.stubs(:each).yields('[puppetca]') @rights.expects(:newright).with("[puppetca]", 1, 'dummy') @authconfig.read end it "should create a new right for each found namespace line" do @fd.stubs(:each).multiple_yields('[puppetca]', '[fileserver]') @rights.expects(:newright).with("[puppetca]", 1, 'dummy') @rights.expects(:newright).with("[fileserver]", 2, 'dummy') @authconfig.read end it "should create a new right for each found path line" do @fd.stubs(:each).multiple_yields('path /certificates') @rights.expects(:newright).with("/certificates", 1, 'dummy') @authconfig.read end it "should create a new right for each found regex line" do @fd.stubs(:each).multiple_yields('path ~ .rb$') @rights.expects(:newright).with("~ .rb$", 1, 'dummy') @authconfig.read end it "should create an allow ACE on each subsequent allow" do acl = stub 'acl', :info @fd.stubs(:each).multiple_yields('[puppetca]', 'allow 127.0.0.1') @rights.stubs(:newright).with("[puppetca]", 1, 'dummy').returns(acl) acl.expects(:allow).with('127.0.0.1') @authconfig.read end it "should create a deny ACE on each subsequent deny" do acl = stub 'acl', :info @fd.stubs(:each).multiple_yields('[puppetca]', 'deny 127.0.0.1') @rights.stubs(:newright).with("[puppetca]", 1, 'dummy').returns(acl) acl.expects(:deny).with('127.0.0.1') @authconfig.read end it "should inform the current ACL if we get the 'method' directive" do acl = stub 'acl', :info acl.stubs(:acl_type).returns(:regex) @fd.stubs(:each).multiple_yields('path /certificates', 'method search,find') @rights.stubs(:newright).with("/certificates", 1, 'dummy').returns(acl) acl.expects(:restrict_method).with('search') acl.expects(:restrict_method).with('find') @authconfig.read end it "should raise an error if the 'method' directive is used in a right different than a path/regex one" do acl = stub 'acl', :info acl.stubs(:acl_type).returns(:regex) @fd.stubs(:each).multiple_yields('[puppetca]', 'method search,find') @rights.stubs(:newright).with("puppetca", 1, 'dummy').returns(acl) lambda { @authconfig.read }.should raise_error end it "should inform the current ACL if we get the 'environment' directive" do acl = stub 'acl', :info acl.stubs(:acl_type).returns(:regex) @fd.stubs(:each).multiple_yields('path /certificates', 'environment production,development') @rights.stubs(:newright).with("/certificates", 1, 'dummy').returns(acl) acl.expects(:restrict_environment).with('production') acl.expects(:restrict_environment).with('development') @authconfig.read end it "should raise an error if the 'environment' directive is used in a right different than a path/regex one" do acl = stub 'acl', :info acl.stubs(:acl_type).returns(:regex) @fd.stubs(:each).multiple_yields('[puppetca]', 'environment env') @rights.stubs(:newright).with("puppetca", 1, 'dummy').returns(acl) lambda { @authconfig.read }.should raise_error end it "should inform the current ACL if we get the 'auth' directive" do acl = stub 'acl', :info acl.stubs(:acl_type).returns(:regex) @fd.stubs(:each).multiple_yields('path /certificates', 'auth yes') @rights.stubs(:newright).with("/certificates", 1, 'dummy').returns(acl) acl.expects(:restrict_authenticated).with('yes') @authconfig.read end it "should also allow the longest 'authenticated' directive" do acl = stub 'acl', :info acl.stubs(:acl_type).returns(:regex) @fd.stubs(:each).multiple_yields('path /certificates', 'authenticated yes') @rights.stubs(:newright).with("/certificates", 1, 'dummy').returns(acl) acl.expects(:restrict_authenticated).with('yes') @authconfig.read end it "should raise an error if the 'auth' directive is used in a right different than a path/regex one" do acl = stub 'acl', :info acl.stubs(:acl_type).returns(:regex) @fd.stubs(:each).multiple_yields('[puppetca]', 'auth yes') @rights.stubs(:newright).with("puppetca", 1, 'dummy').returns(acl) lambda { @authconfig.read }.should raise_error end end end diff --git a/spec/unit/network/authstore_spec.rb b/spec/unit/network/authstore_spec.rb index 535e1bdff..d62c8abaa 100755 --- a/spec/unit/network/authstore_spec.rb +++ b/spec/unit/network/authstore_spec.rb @@ -1,370 +1,369 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/network/authconfig' describe Puppet::Network::AuthStore do describe "when checking if the acl has some entries" do before :each do @authstore = Puppet::Network::AuthStore.new end it "should be empty if no ACE have been entered" do @authstore.should be_empty end it "should not be empty if it is a global allow" do @authstore.allow('*') @authstore.should_not be_empty end it "should not be empty if at least one allow has been entered" do @authstore.allow('1.1.1.*') @authstore.should_not be_empty end it "should not be empty if at least one deny has been entered" do @authstore.deny('1.1.1.*') @authstore.should_not be_empty end end end describe Puppet::Network::AuthStore::Declaration do ['100.101.99.98','100.100.100.100','1.2.3.4','11.22.33.44'].each { |ip| describe "when the pattern is a simple numeric IP such as #{ip}" do before :each do @declaration = Puppet::Network::AuthStore::Declaration.new(:allow,ip) end it "should match the specified IP" do @declaration.should be_match('www.testsite.org',ip) end it "should not match other IPs" do @declaration.should_not be_match('www.testsite.org','200.101.99.98') end end (1..3).each { |n| describe "when the pattern is a IP mask with #{n} numeric segments and a *" do before :each do @ip_pattern = ip.split('.')[0,n].join('.')+'.*' @declaration = Puppet::Network::AuthStore::Declaration.new(:allow,@ip_pattern) end it "should match an IP in the range" do @declaration.should be_match('www.testsite.org',ip) end it "should not match other IPs" do @declaration.should_not be_match('www.testsite.org','200.101.99.98') end it "should not match IPs that differ in the last non-wildcard segment" do other = ip.split('.') other[n-1].succ! @declaration.should_not be_match('www.testsite.org',other.join('.')) end end } } describe "when the pattern is a numeric IP with a back reference" do before :each do @ip = '100.101.$1' @declaration = Puppet::Network::AuthStore::Declaration.new(:allow,@ip).interpolate('12.34'.match(/(.*)/)) end it "should match an IP with the appropriate interpolation" do @declaration.should be_match('www.testsite.org',@ip.sub(/\$1/,'12.34')) end it "should not match other IPs" do @declaration.should_not be_match('www.testsite.org',@ip.sub(/\$1/,'66.34')) end end [ "02001:0000:1234:0000:0000:C1C0:ABCD:0876", "2001:0000:1234:0000:00001:C1C0:ABCD:0876", " 2001:0000:1234:0000:0000:C1C0:ABCD:0876 0", "2001:0000:1234: 0000:0000:C1C0:ABCD:0876", "3ffe:0b00:0000:0001:0000:0000:000a", "FF02:0000:0000:0000:0000:0000:0000:0000:0001", "3ffe:b00::1::a", "1:2:3::4:5::7:8", "12345::6:7:8", "1::5:400.2.3.4", "1::5:260.2.3.4", "1::5:256.2.3.4", "1::5:1.256.3.4", "1::5:1.2.256.4", "1::5:1.2.3.256", "1::5:300.2.3.4", "1::5:1.300.3.4", "1::5:1.2.300.4", "1::5:1.2.3.300", "1::5:900.2.3.4", "1::5:1.900.3.4", "1::5:1.2.900.4", "1::5:1.2.3.900", "1::5:300.300.300.300", "1::5:3000.30.30.30", "1::400.2.3.4", "1::260.2.3.4", "1::256.2.3.4", "1::1.256.3.4", "1::1.2.256.4", "1::1.2.3.256", "1::300.2.3.4", "1::1.300.3.4", "1::1.2.300.4", "1::1.2.3.300", "1::900.2.3.4", "1::1.900.3.4", "1::1.2.900.4", "1::1.2.3.900", "1::300.300.300.300", "1::3000.30.30.30", "::400.2.3.4", "::260.2.3.4", "::256.2.3.4", "::1.256.3.4", "::1.2.256.4", "::1.2.3.256", "::300.2.3.4", "::1.300.3.4", "::1.2.300.4", "::1.2.3.300", "::900.2.3.4", "::1.900.3.4", "::1.2.900.4", "::1.2.3.900", "::300.300.300.300", "::3000.30.30.30", "2001:DB8:0:0:8:800:200C:417A:221", # unicast, full "FF01::101::2" # multicast, compressed ].each { |invalid_ip| describe "when the pattern is an invalid IPv6 address such as #{invalid_ip}" do it "should raise an exception" do lambda { Puppet::Network::AuthStore::Declaration.new(:allow,invalid_ip) }.should raise_error end end } [ "1.2.3.4", "2001:0000:1234:0000:0000:C1C0:ABCD:0876", "3ffe:0b00:0000:0000:0001:0000:0000:000a", "FF02:0000:0000:0000:0000:0000:0000:0001", "0000:0000:0000:0000:0000:0000:0000:0001", "0000:0000:0000:0000:0000:0000:0000:0000", "::ffff:192.168.1.26", "2::10", "ff02::1", "fe80::", "2002::", "2001:db8::", "2001:0db8:1234::", "::ffff:0:0", "::1", "::ffff:192.168.1.1", "1:2:3:4:5:6:7:8", "1:2:3:4:5:6::8", "1:2:3:4:5::8", "1:2:3:4::8", "1:2:3::8", "1:2::8", "1::8", "1::2:3:4:5:6:7", "1::2:3:4:5:6", "1::2:3:4:5", "1::2:3:4", "1::2:3", "1::8", "::2:3:4:5:6:7:8", "::2:3:4:5:6:7", "::2:3:4:5:6", "::2:3:4:5", "::2:3:4", "::2:3", "::8", "1:2:3:4:5:6::", "1:2:3:4:5::", "1:2:3:4::", "1:2:3::", "1:2::", "1::", "1:2:3:4:5::7:8", "1:2:3:4::7:8", "1:2:3::7:8", "1:2::7:8", "1::7:8", "1:2:3:4:5:6:1.2.3.4", "1:2:3:4:5::1.2.3.4", "1:2:3:4::1.2.3.4", "1:2:3::1.2.3.4", "1:2::1.2.3.4", "1::1.2.3.4", "1:2:3:4::5:1.2.3.4", "1:2:3::5:1.2.3.4", "1:2::5:1.2.3.4", "1::5:1.2.3.4", "1::5:11.22.33.44", "fe80::217:f2ff:254.7.237.98", "fe80::217:f2ff:fe07:ed62", "2001:DB8:0:0:8:800:200C:417A", # unicast, full "FF01:0:0:0:0:0:0:101", # multicast, full "0:0:0:0:0:0:0:1", # loopback, full "0:0:0:0:0:0:0:0", # unspecified, full "2001:DB8::8:800:200C:417A", # unicast, compressed "FF01::101", # multicast, compressed "::1", # loopback, compressed, non-routable "::", # unspecified, compressed, non-routable "0:0:0:0:0:0:13.1.68.3", # IPv4-compatible IPv6 address, full, deprecated "0:0:0:0:0:FFFF:129.144.52.38", # IPv4-mapped IPv6 address, full "::13.1.68.3", # IPv4-compatible IPv6 address, compressed, deprecated "::FFFF:129.144.52.38", # IPv4-mapped IPv6 address, compressed "2001:0DB8:0000:CD30:0000:0000:0000:0000/60", # full, with prefix "2001:0DB8::CD30:0:0:0:0/60", # compressed, with prefix "2001:0DB8:0:CD30::/60", # compressed, with prefix #2 "::/128", # compressed, unspecified address type, non-routable "::1/128", # compressed, loopback address type, non-routable "FF00::/8", # compressed, multicast address type "FE80::/10", # compressed, link-local unicast, non-routable "FEC0::/10", # compressed, site-local unicast, deprecated "127.0.0.1", # standard IPv4, loopback, non-routable "0.0.0.0", # standard IPv4, unspecified, non-routable "255.255.255.255", # standard IPv4 "fe80:0000:0000:0000:0204:61ff:fe9d:f156", "fe80:0:0:0:204:61ff:fe9d:f156", "fe80::204:61ff:fe9d:f156", "fe80:0000:0000:0000:0204:61ff:254.157.241.086", "fe80:0:0:0:204:61ff:254.157.241.86", "fe80::204:61ff:254.157.241.86", "::1", "fe80::", "fe80::1" ].each { |ip| describe "when the pattern is a valid IP such as #{ip}" do before :each do @declaration = Puppet::Network::AuthStore::Declaration.new(:allow,ip) end it "should match the specified IP" do @declaration.should be_match('www.testsite.org',ip) end it "should not match other IPs" do @declaration.should_not be_match('www.testsite.org','200.101.99.98') end end unless ip =~ /:.*\./ # Hybrid IPs aren't supported by ruby's ipaddr } { 'spirit.mars.nasa.gov' => 'a PQDN', 'ratchet.2ndsiteinc.com' => 'a PQDN with digits', 'a.c.ru' => 'a PQDN with short segments', }.each {|pqdn,desc| describe "when the pattern is #{desc}" do before :each do @host = pqdn @declaration = Puppet::Network::AuthStore::Declaration.new(:allow,@host) end it "should match the specified PQDN" do @declaration.should be_match(@host,'200.101.99.98') end it "should not match a similar FQDN" do pending "FQDN consensus" @declaration.should_not be_match(@host+'.','200.101.99.98') end end } ['abc.12seps.edu.phisher.biz','www.google.com','slashdot.org'].each { |host| (1...(host.split('.').length)).each { |n| describe "when the pattern is #{"*."+host.split('.')[-n,n].join('.')}" do before :each do @pattern = "*."+host.split('.')[-n,n].join('.') @declaration = Puppet::Network::AuthStore::Declaration.new(:allow,@pattern) end it "should match #{host}" do @declaration.should be_match(host,'1.2.3.4') end it "should not match www.testsite.gov" do @declaration.should_not be_match('www.testsite.gov','200.101.99.98') end it "should not match hosts that differ in the first non-wildcard segment" do other = host.split('.') other[-n].succ! @declaration.should_not be_match(other.join('.'),'1.2.3.4') end end } } describe "when the pattern is a FQDN" do before :each do @host = 'spirit.mars.nasa.gov.' @declaration = Puppet::Network::AuthStore::Declaration.new(:allow,@host) end it "should match the specified FQDN" do pending "FQDN consensus" @declaration.should be_match(@host,'200.101.99.98') end it "should not match a similar PQDN" do @declaration.should_not be_match(@host[0..-2],'200.101.99.98') end end describe "when the pattern is an opaque string with a back reference" do before :each do @host = 'c216f41a-f902-4bfb-a222-850dd957bebb' @item = "/catalog/#{@host}" @pattern = %{^/catalog/([^/]+)$} @declaration = Puppet::Network::AuthStore::Declaration.new(:allow,'$1') end it "should match an IP with the appropriate interpolation" do @declaration.interpolate(@item.match(@pattern)).should be_match(@host,'10.0.0.5') end end describe "when the pattern is an opaque string with a back reference and the matched data contains dots" do before :each do @host = 'admin.mgmt.nym1' @item = "/catalog/#{@host}" @pattern = %{^/catalog/([^/]+)$} @declaration = Puppet::Network::AuthStore::Declaration.new(:allow,'$1') end it "should match a name with the appropriate interpolation" do @declaration.interpolate(@item.match(@pattern)).should be_match(@host,'10.0.0.5') end end describe "when the pattern is an opaque string with a back reference and the matched data contains dots with an initial prefix that looks like an IP address" do before :each do @host = '01.admin.mgmt.nym1' @item = "/catalog/#{@host}" @pattern = %{^/catalog/([^/]+)$} @declaration = Puppet::Network::AuthStore::Declaration.new(:allow,'$1') end it "should match a name with the appropriate interpolation" do @declaration.interpolate(@item.match(@pattern)).should be_match(@host,'10.0.0.5') end end describe "when comparing patterns" do before :each do @ip = Puppet::Network::AuthStore::Declaration.new(:allow,'127.0.0.1') @host_name = Puppet::Network::AuthStore::Declaration.new(:allow,'www.hard_knocks.edu') @opaque = Puppet::Network::AuthStore::Declaration.new(:allow,'hey_dude') end it "should consider ip addresses before host names" do (@ip < @host_name).should be_true end it "should consider ip addresses before opaque strings" do (@ip < @opaque).should be_true end it "should consider host_names before opaque strings" do (@host_name < @opaque).should be_true end end end diff --git a/spec/unit/network/client_spec.rb b/spec/unit/network/client_spec.rb index 75825879f..102a053c0 100755 --- a/spec/unit/network/client_spec.rb +++ b/spec/unit/network/client_spec.rb @@ -1,45 +1,45 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Created by Luke Kanies on 2008-3-24. # Copyright (c) 2008. All rights reserved. require 'spec_helper' require 'puppet/network/client' describe Puppet::Network::Client do before do Puppet.settings.stubs(:use).returns(true) Puppet::Network::HttpPool.stubs(:cert_setup) end describe "when keep-alive is enabled" do before do Puppet::Network::HttpPool.stubs(:keep_alive?).returns true end it "should start the http client up on creation" do http = mock 'http' http.stub_everything http.expects(:start) Net::HTTP.stubs(:new).returns http # Pick a random subclass... Puppet::Network::Client.runner.new :Server => Puppet[:server] end end describe "when keep-alive is disabled" do before do Puppet::Network::HttpPool.stubs(:keep_alive?).returns false end it "should not start the http client up on creation" do http = mock 'http' http.stub_everything http.expects(:start).never Net::HTTP.stubs(:new).returns http # Pick a random subclass... Puppet::Network::Client.runner.new :Server => Puppet[:server] end end end diff --git a/spec/unit/network/format_handler_spec.rb b/spec/unit/network/format_handler_spec.rb index 25a988dbc..8b535c3ab 100755 --- a/spec/unit/network/format_handler_spec.rb +++ b/spec/unit/network/format_handler_spec.rb @@ -1,336 +1,335 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/network/format_handler' class FormatTester extend Puppet::Network::FormatHandler end describe Puppet::Network::FormatHandler do after do formats = Puppet::Network::FormatHandler.instance_variable_get("@formats") formats.each do |name, format| formats.delete(name) unless format.is_a?(Puppet::Network::Format) end end it "should be able to list supported formats" do FormatTester.should respond_to(:supported_formats) end it "should include all supported formats" do one = stub 'supported', :supported? => true, :name => :one, :weight => 1 two = stub 'supported', :supported? => false, :name => :two, :weight => 1 three = stub 'supported', :supported? => true, :name => :three, :weight => 1 four = stub 'supported', :supported? => false, :name => :four, :weight => 1 Puppet::Network::FormatHandler.stubs(:formats).returns [:one, :two, :three, :four] Puppet::Network::FormatHandler.stubs(:format).with(:one).returns one Puppet::Network::FormatHandler.stubs(:format).with(:two).returns two Puppet::Network::FormatHandler.stubs(:format).with(:three).returns three Puppet::Network::FormatHandler.stubs(:format).with(:four).returns four result = FormatTester.supported_formats result.length.should == 2 result.should be_include(:one) result.should be_include(:three) end it "should return the supported formats in decreasing order of weight" do one = stub 'supported', :supported? => true, :name => :one, :weight => 1 two = stub 'supported', :supported? => true, :name => :two, :weight => 6 three = stub 'supported', :supported? => true, :name => :three, :weight => 2 four = stub 'supported', :supported? => true, :name => :four, :weight => 8 Puppet::Network::FormatHandler.stubs(:formats).returns [:one, :two, :three, :four] Puppet::Network::FormatHandler.stubs(:format).with(:one).returns one Puppet::Network::FormatHandler.stubs(:format).with(:two).returns two Puppet::Network::FormatHandler.stubs(:format).with(:three).returns three Puppet::Network::FormatHandler.stubs(:format).with(:four).returns four FormatTester.supported_formats.should == [:four, :two, :three, :one] end describe "with a preferred serialization format setting" do before do one = stub 'supported', :supported? => true, :name => :one, :weight => 1 two = stub 'supported', :supported? => true, :name => :two, :weight => 6 Puppet::Network::FormatHandler.stubs(:formats).returns [:one, :two] Puppet::Network::FormatHandler.stubs(:format).with(:one).returns one Puppet::Network::FormatHandler.stubs(:format).with(:two).returns two end describe "that is supported" do before do Puppet.settings.expects(:value).with(:preferred_serialization_format).returns :one end it "should return the preferred serialization format first" do FormatTester.supported_formats.should == [:one, :two] end end describe "that is not supported" do before do Puppet.settings.expects(:value).with(:preferred_serialization_format).returns :unsupported end it "should still return the default format first" do FormatTester.supported_formats.should == [:two, :one] end it "should log a debug message" do Puppet.expects(:debug).with("Value of 'preferred_serialization_format' (unsupported) is invalid for FormatTester, using default (two)") Puppet.expects(:debug).with("FormatTester supports formats: one two; using two") FormatTester.supported_formats end end end it "should return the first format as the default format" do FormatTester.expects(:supported_formats).returns [:one, :two] FormatTester.default_format.should == :one end it "should be able to use a protected format for better logging on errors" do Puppet::Network::FormatHandler.should respond_to(:protected_format) end it "should delegate all methods from the informative format to the specified format" do format = mock 'format' format.stubs(:name).returns(:myformat) Puppet::Network::FormatHandler.expects(:format).twice.with(:myformat).returns format format.expects(:render).with("foo").returns "yay" Puppet::Network::FormatHandler.protected_format(:myformat).render("foo").should == "yay" end it "should provide better logging if a failure is encountered when delegating from the informative format to the real format" do format = mock 'format' format.stubs(:name).returns(:myformat) Puppet::Network::FormatHandler.expects(:format).twice.with(:myformat).returns format format.expects(:render).with("foo").raises "foo" lambda { Puppet::Network::FormatHandler.protected_format(:myformat).render("foo") }.should raise_error(Puppet::Network::FormatHandler::FormatError) end it "should raise an error if we couldn't find a format by name or mime-type" do Puppet::Network::FormatHandler.stubs(:format).with(:myformat).returns nil lambda { Puppet::Network::FormatHandler.protected_format(:myformat) }.should raise_error end describe "when using formats" do before do @format = mock 'format' @format.stubs(:supported?).returns true @format.stubs(:name).returns :my_format Puppet::Network::FormatHandler.stubs(:format).with(:my_format).returns @format Puppet::Network::FormatHandler.stubs(:mime).with("text/myformat").returns @format Puppet::Network::Format.stubs(:===).returns false Puppet::Network::Format.stubs(:===).with(@format).returns true end it "should be able to test whether a format is supported" do FormatTester.should respond_to(:support_format?) end it "should use the Format to determine whether a given format is supported" do @format.expects(:supported?).with(FormatTester) FormatTester.support_format?(:my_format) end it "should be able to convert from a given format" do FormatTester.should respond_to(:convert_from) end it "should call the format-specific converter when asked to convert from a given format" do @format.expects(:intern).with(FormatTester, "mydata") FormatTester.convert_from(:my_format, "mydata") end it "should call the format-specific converter when asked to convert from a given format by mime-type" do @format.expects(:intern).with(FormatTester, "mydata") FormatTester.convert_from("text/myformat", "mydata") end it "should call the format-specific converter when asked to convert from a given format by format instance" do @format.expects(:intern).with(FormatTester, "mydata") FormatTester.convert_from(@format, "mydata") end it "should raise a FormatError when an exception is encountered when converting from a format" do @format.expects(:intern).with(FormatTester, "mydata").raises "foo" lambda { FormatTester.convert_from(:my_format, "mydata") }.should raise_error(Puppet::Network::FormatHandler::FormatError) end it "should be able to use a specific hook for converting into multiple instances" do @format.expects(:intern_multiple).with(FormatTester, "mydata") FormatTester.convert_from_multiple(:my_format, "mydata") end it "should raise a FormatError when an exception is encountered when converting multiple items from a format" do @format.expects(:intern_multiple).with(FormatTester, "mydata").raises "foo" lambda { FormatTester.convert_from_multiple(:my_format, "mydata") }.should raise_error(Puppet::Network::FormatHandler::FormatError) end it "should be able to use a specific hook for rendering multiple instances" do @format.expects(:render_multiple).with("mydata") FormatTester.render_multiple(:my_format, "mydata") end it "should raise a FormatError when an exception is encountered when rendering multiple items into a format" do @format.expects(:render_multiple).with("mydata").raises "foo" lambda { FormatTester.render_multiple(:my_format, "mydata") }.should raise_error(Puppet::Network::FormatHandler::FormatError) end end describe "when managing formats" do it "should have a method for defining a new format" do Puppet::Network::FormatHandler.should respond_to(:create) end it "should create a format instance when asked" do format = stub 'format', :name => :foo Puppet::Network::Format.expects(:new).with(:foo).returns format Puppet::Network::FormatHandler.create(:foo) end it "should instance_eval any block provided when creating a format" do format = stub 'format', :name => :instance_eval format.expects(:yayness) Puppet::Network::Format.expects(:new).returns format Puppet::Network::FormatHandler.create(:instance_eval) do yayness end end it "should be able to retrieve a format by name" do format = Puppet::Network::FormatHandler.create(:by_name) Puppet::Network::FormatHandler.format(:by_name).should equal(format) end it "should be able to retrieve a format by extension" do format = Puppet::Network::FormatHandler.create(:by_extension, :extension => "foo") Puppet::Network::FormatHandler.format_by_extension("foo").should equal(format) end it "should return nil if asked to return a format by an unknown extension" do Puppet::Network::FormatHandler.format_by_extension("yayness").should be_nil end it "should be able to retrieve formats by name irrespective of case and class" do format = Puppet::Network::FormatHandler.create(:by_name) Puppet::Network::FormatHandler.format(:By_Name).should equal(format) end it "should be able to retrieve a format by mime type" do format = Puppet::Network::FormatHandler.create(:by_name, :mime => "foo/bar") Puppet::Network::FormatHandler.mime("foo/bar").should equal(format) end it "should be able to retrieve a format by mime type irrespective of case" do format = Puppet::Network::FormatHandler.create(:by_name, :mime => "foo/bar") Puppet::Network::FormatHandler.mime("Foo/Bar").should equal(format) end it "should be able to return all formats" do one = stub 'one', :name => :one two = stub 'two', :name => :two Puppet::Network::Format.expects(:new).with(:one).returns(one) Puppet::Network::Format.expects(:new).with(:two).returns(two) Puppet::Network::FormatHandler.create(:one) Puppet::Network::FormatHandler.create(:two) list = Puppet::Network::FormatHandler.formats list.should be_include(:one) list.should be_include(:two) end end describe "when an instance" do it "should be able to test whether a format is supported" do FormatTester.new.should respond_to(:support_format?) end it "should be able to convert to a given format" do FormatTester.new.should respond_to(:render) end it "should be able to get a format mime-type" do FormatTester.new.should respond_to(:mime) end it "should raise a FormatError when a rendering error is encountered" do format = stub 'rendering format', :supported? => true, :name => :foo Puppet::Network::FormatHandler.stubs(:format).with(:foo).returns format tester = FormatTester.new format.expects(:render).with(tester).raises "eh" lambda { tester.render(:foo) }.should raise_error(Puppet::Network::FormatHandler::FormatError) end it "should call the format-specific converter when asked to convert to a given format" do format = stub 'rendering format', :supported? => true, :name => :foo Puppet::Network::FormatHandler.stubs(:format).with(:foo).returns format tester = FormatTester.new format.expects(:render).with(tester).returns "foo" tester.render(:foo).should == "foo" end it "should call the format-specific converter when asked to convert to a given format by mime-type" do format = stub 'rendering format', :supported? => true, :name => :foo Puppet::Network::FormatHandler.stubs(:mime).with("text/foo").returns format Puppet::Network::FormatHandler.stubs(:format).with(:foo).returns format tester = FormatTester.new format.expects(:render).with(tester).returns "foo" tester.render("text/foo").should == "foo" end it "should call the format converter when asked to convert to a given format instance" do format = stub 'rendering format', :supported? => true, :name => :foo Puppet::Network::Format.stubs(:===).with(format).returns(true) Puppet::Network::FormatHandler.stubs(:format).with(:foo).returns format tester = FormatTester.new format.expects(:render).with(tester).returns "foo" tester.render(format).should == "foo" end it "should render to the default format if no format is provided when rendering" do format = stub 'rendering format', :supported? => true, :name => :foo Puppet::Network::FormatHandler.stubs(:format).with(:foo).returns format FormatTester.expects(:default_format).returns :foo tester = FormatTester.new format.expects(:render).with(tester) tester.render end it "should call the format-specific converter when asked for the mime-type of a given format" do format = stub 'rendering format', :supported? => true, :name => :foo Puppet::Network::FormatHandler.stubs(:format).with(:foo).returns format tester = FormatTester.new format.expects(:mime).returns "text/foo" tester.mime(:foo).should == "text/foo" end it "should return the default format mime-type if no format is provided" do format = stub 'rendering format', :supported? => true, :name => :foo Puppet::Network::FormatHandler.stubs(:format).with(:foo).returns format FormatTester.expects(:default_format).returns :foo tester = FormatTester.new format.expects(:mime).returns "text/foo" tester.mime.should == "text/foo" end end end diff --git a/spec/unit/network/format_spec.rb b/spec/unit/network/format_spec.rb index c54fdfd31..f59593479 100755 --- a/spec/unit/network/format_spec.rb +++ b/spec/unit/network/format_spec.rb @@ -1,198 +1,197 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/network/format' # A class with all of the necessary # hooks. class FormatRenderer def self.to_multiple_my_format(list) end def self.from_multiple_my_format(text) end def self.from_my_format(text) end def to_my_format end end describe Puppet::Network::Format do describe "when initializing" do it "should require a name" do lambda { Puppet::Network::Format.new }.should raise_error(ArgumentError) end it "should be able to provide its name" do Puppet::Network::Format.new(:my_format).name.should == :my_format end it "should always convert its name to a downcased symbol" do Puppet::Network::Format.new(:My_Format).name.should == :my_format end it "should be able to set its downcased mime type at initialization" do format = Puppet::Network::Format.new(:my_format, :mime => "Foo/Bar") format.mime.should == "foo/bar" end it "should default to text plus the name of the format as the mime type" do Puppet::Network::Format.new(:my_format).mime.should == "text/my_format" end it "should fail if unsupported options are provided" do lambda { Puppet::Network::Format.new(:my_format, :foo => "bar") }.should raise_error(ArgumentError) end end describe "instances" do before do @format = Puppet::Network::Format.new(:my_format) end it "should support being confined" do @format.should respond_to(:confine) end it "should not be considered suitable if confinement conditions are not met" do @format.confine :true => false @format.should_not be_suitable end it "should be able to determine if a class is supported" do @format.should respond_to(:supported?) end it "should consider a class to be supported if it has the individual and multiple methods for rendering and interning" do @format.should be_supported(FormatRenderer) end it "should default to its required methods being the individual and multiple methods for rendering and interning" do Puppet::Network::Format.new(:foo).required_methods.sort { |a,b| a.to_s <=> b.to_s }.should == [:intern_method, :intern_multiple_method, :render_multiple_method, :render_method].sort { |a,b| a.to_s <=> b.to_s } end it "should consider a class supported if the provided class has all required methods present" do format = Puppet::Network::Format.new(:foo) [:intern_method, :intern_multiple_method, :render_multiple_method, :render_method].each do |method| format.expects(:required_method_present?).with { |name, klass, type| name == method and klass == String }.returns true end format.should be_required_methods_present(String) end it "should consider a class not supported if any required methods are missing from the provided class" do format = Puppet::Network::Format.new(:foo) format.stubs(:required_method_present?).returns true format.expects(:required_method_present?).with { |name, *args| name == :intern_method }.returns false format.should_not be_required_methods_present(String) end it "should be able to specify the methods required for support" do Puppet::Network::Format.new(:foo, :required_methods => [:render_method, :intern_method]).required_methods.should == [:render_method, :intern_method] end it "should only test for required methods if specific methods are specified as required" do format = Puppet::Network::Format.new(:foo, :required_methods => [:intern_method]) format.expects(:required_method_present?).with { |name, klass, type| name == :intern_method } format.required_methods_present?(String) end it "should not consider a class supported unless the format is suitable" do @format.expects(:suitable?).returns false @format.should_not be_supported(FormatRenderer) end it "should always downcase mimetypes" do @format.mime = "Foo/Bar" @format.mime.should == "foo/bar" end it "should support having a weight" do @format.should respond_to(:weight) end it "should default to a weight of of 5" do @format.weight.should == 5 end it "should be able to override its weight at initialization" do Puppet::Network::Format.new(:foo, :weight => 1).weight.should == 1 end it "should default to its extension being equal to its name" do Puppet::Network::Format.new(:foo).extension.should == "foo" end it "should support overriding the extension" do Puppet::Network::Format.new(:foo, :extension => "bar").extension.should == "bar" end [:intern_method, :intern_multiple_method, :render_multiple_method, :render_method].each do |method| it "should allow assignment of the #{method}" do Puppet::Network::Format.new(:foo, method => :foo).send(method).should == :foo end end end describe "when converting between instances and formatted text" do before do @format = Puppet::Network::Format.new(:my_format) @instance = FormatRenderer.new end it "should have a method for rendering a single instance" do @format.should respond_to(:render) end it "should have a method for rendering multiple instances" do @format.should respond_to(:render_multiple) end it "should have a method for interning text" do @format.should respond_to(:intern) end it "should have a method for interning text into multiple instances" do @format.should respond_to(:intern_multiple) end it "should return the results of calling the instance-specific render method if the method is present" do @instance.expects(:to_my_format).returns "foo" @format.render(@instance).should == "foo" end it "should return the results of calling the class-specific render_multiple method if the method is present" do @instance.class.expects(:to_multiple_my_format).returns ["foo"] @format.render_multiple([@instance]).should == ["foo"] end it "should return the results of calling the class-specific intern method if the method is present" do FormatRenderer.expects(:from_my_format).with("foo").returns @instance @format.intern(FormatRenderer, "foo").should equal(@instance) end it "should return the results of calling the class-specific intern_multiple method if the method is present" do FormatRenderer.expects(:from_multiple_my_format).with("foo").returns [@instance] @format.intern_multiple(FormatRenderer, "foo").should == [@instance] end it "should fail if asked to render and the instance does not respond to 'to_'" do lambda { @format.render("foo") }.should raise_error(NotImplementedError) end it "should fail if asked to intern and the class does not respond to 'from_'" do lambda { @format.intern(String, "foo") }.should raise_error(NotImplementedError) end it "should fail if asked to intern multiple and the class does not respond to 'from_multiple_'" do lambda { @format.intern_multiple(String, "foo") }.should raise_error(NotImplementedError) end it "should fail if asked to render multiple and the instance does not respond to 'to_multiple_'" do lambda { @format.render_multiple(["foo", "bar"]) }.should raise_error(NotImplementedError) end end end diff --git a/spec/unit/network/formats_spec.rb b/spec/unit/network/formats_spec.rb index 34b83f3ed..72d355192 100755 --- a/spec/unit/network/formats_spec.rb +++ b/spec/unit/network/formats_spec.rb @@ -1,334 +1,333 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/network/formats' class PsonTest attr_accessor :string def ==(other) string == other.string end def self.from_pson(data) new(data) end def initialize(string) @string = string end def to_pson(*args) { 'type' => self.class.name, 'data' => @string }.to_pson(*args) end end describe "Puppet Network Format" do it "should include a yaml format" do Puppet::Network::FormatHandler.format(:yaml).should_not be_nil end describe "yaml" do before do @yaml = Puppet::Network::FormatHandler.format(:yaml) end it "should have its mime type set to text/yaml" do @yaml.mime.should == "text/yaml" end it "should be supported on Strings" do @yaml.should be_supported(String) end it "should render by calling 'to_yaml' on the instance" do instance = mock 'instance' instance.expects(:to_yaml).returns "foo" @yaml.render(instance).should == "foo" end it "should render multiple instances by calling 'to_yaml' on the array" do instances = [mock('instance')] instances.expects(:to_yaml).returns "foo" @yaml.render_multiple(instances).should == "foo" end it "should intern by calling 'YAML.load'" do text = "foo" YAML.expects(:load).with("foo").returns "bar" @yaml.intern(String, text).should == "bar" end it "should intern multiples by calling 'YAML.load'" do text = "foo" YAML.expects(:load).with("foo").returns "bar" @yaml.intern_multiple(String, text).should == "bar" end end describe "base64 compressed yaml", :if => Puppet.features.zlib? do yaml = Puppet::Network::FormatHandler.format(:b64_zlib_yaml) before do @yaml = Puppet::Network::FormatHandler.format(:b64_zlib_yaml) end it "should have its mime type set to text/b64_zlib_yaml" do @yaml.mime.should == "text/b64_zlib_yaml" end it "should render by calling 'to_yaml' on the instance" do instance = mock 'instance' instance.expects(:to_yaml).returns "foo" @yaml.render(instance) end it "should encode generated yaml on render" do instance = mock 'instance', :to_yaml => "foo" @yaml.expects(:encode).with("foo").returns "bar" @yaml.render(instance).should == "bar" end it "should render multiple instances by calling 'to_yaml' on the array" do instances = [mock('instance')] instances.expects(:to_yaml).returns "foo" @yaml.render_multiple(instances) end it "should encode generated yaml on render" do instances = [mock('instance')] instances.stubs(:to_yaml).returns "foo" @yaml.expects(:encode).with("foo").returns "bar" @yaml.render(instances).should == "bar" end it "should intern by calling decode" do text = "foo" @yaml.expects(:decode).with("foo").returns "bar" @yaml.intern(String, text).should == "bar" end it "should intern multiples by calling 'decode'" do text = "foo" @yaml.expects(:decode).with("foo").returns "bar" @yaml.intern_multiple(String, text).should == "bar" end it "should decode by base64 decoding, uncompressing and Yaml loading" do Base64.expects(:decode64).with("zorg").returns "foo" Zlib::Inflate.expects(:inflate).with("foo").returns "baz" YAML.expects(:load).with("baz").returns "bar" @yaml.decode("zorg").should == "bar" end it "should encode by compressing and base64 encoding" do Zlib::Deflate.expects(:deflate).with("foo", Zlib::BEST_COMPRESSION).returns "bar" Base64.expects(:encode64).with("bar").returns "baz" @yaml.encode("foo").should == "baz" end describe "when zlib is disabled" do before do Puppet[:zlib] = false end it "use_zlib? should return false" do @yaml.use_zlib?.should == false end it "should refuse to encode" do lambda{ @yaml.encode("foo") }.should raise_error end it "should refuse to decode" do lambda{ @yaml.decode("foo") }.should raise_error end end describe "when zlib is not installed" do it "use_zlib? should return false" do Puppet[:zlib] = true Puppet.features.expects(:zlib?).returns(false) @yaml.use_zlib?.should == false end end end it "should include a marshal format" do Puppet::Network::FormatHandler.format(:marshal).should_not be_nil end describe "marshal" do before do @marshal = Puppet::Network::FormatHandler.format(:marshal) end it "should have its mime type set to text/marshal" do Puppet::Network::FormatHandler.format(:marshal).mime.should == "text/marshal" end it "should be supported on Strings" do @marshal.should be_supported(String) end it "should render by calling 'Marshal.dump' on the instance" do instance = mock 'instance' Marshal.expects(:dump).with(instance).returns "foo" @marshal.render(instance).should == "foo" end it "should render multiple instances by calling 'to_marshal' on the array" do instances = [mock('instance')] Marshal.expects(:dump).with(instances).returns "foo" @marshal.render_multiple(instances).should == "foo" end it "should intern by calling 'Marshal.load'" do text = "foo" Marshal.expects(:load).with("foo").returns "bar" @marshal.intern(String, text).should == "bar" end it "should intern multiples by calling 'Marshal.load'" do text = "foo" Marshal.expects(:load).with("foo").returns "bar" @marshal.intern_multiple(String, text).should == "bar" end end describe "plaintext" do before do @text = Puppet::Network::FormatHandler.format(:s) end it "should have its mimetype set to text/plain" do @text.mime.should == "text/plain" end it "should use 'txt' as its extension" do @text.extension.should == "txt" end end describe "dot" do before do @dot = Puppet::Network::FormatHandler.format(:dot) end it "should have its mimetype set to text/dot" do @dot.mime.should == "text/dot" end end describe Puppet::Network::FormatHandler.format(:raw) do before do @format = Puppet::Network::FormatHandler.format(:raw) end it "should exist" do @format.should_not be_nil end it "should have its mimetype set to application/x-raw" do @format.mime.should == "application/x-raw" end it "should always be supported" do @format.should be_supported(String) end it "should fail if its multiple_render method is used" do lambda { @format.render_multiple("foo") }.should raise_error(NotImplementedError) end it "should fail if its multiple_intern method is used" do lambda { @format.intern_multiple(String, "foo") }.should raise_error(NotImplementedError) end it "should have a weight of 1" do @format.weight.should == 1 end end it "should include a pson format" do Puppet::Network::FormatHandler.format(:pson).should_not be_nil end describe "pson", :if => Puppet.features.pson? do before do @pson = Puppet::Network::FormatHandler.format(:pson) end it "should have its mime type set to text/pson" do Puppet::Network::FormatHandler.format(:pson).mime.should == "text/pson" end it "should require the :render_method" do Puppet::Network::FormatHandler.format(:pson).required_methods.should be_include(:render_method) end it "should require the :intern_method" do Puppet::Network::FormatHandler.format(:pson).required_methods.should be_include(:intern_method) end it "should have a weight of 10" do @pson.weight.should == 10 end describe "when supported" do it "should render by calling 'to_pson' on the instance" do instance = PsonTest.new("foo") instance.expects(:to_pson).returns "foo" @pson.render(instance).should == "foo" end it "should render multiple instances by calling 'to_pson' on the array" do instances = [mock('instance')] instances.expects(:to_pson).returns "foo" @pson.render_multiple(instances).should == "foo" end it "should intern by calling 'PSON.parse' on the text and then using from_pson to convert the data into an instance" do text = "foo" PSON.expects(:parse).with("foo").returns("type" => "PsonTest", "data" => "foo") PsonTest.expects(:from_pson).with("foo").returns "parsed_pson" @pson.intern(PsonTest, text).should == "parsed_pson" end it "should not render twice if 'PSON.parse' creates the appropriate instance" do text = "foo" instance = PsonTest.new("foo") PSON.expects(:parse).with("foo").returns(instance) PsonTest.expects(:from_pson).never @pson.intern(PsonTest, text).should equal(instance) end it "should intern by calling 'PSON.parse' on the text and then using from_pson to convert the actual into an instance if the pson has no class/data separation" do text = "foo" PSON.expects(:parse).with("foo").returns("foo") PsonTest.expects(:from_pson).with("foo").returns "parsed_pson" @pson.intern(PsonTest, text).should == "parsed_pson" end it "should intern multiples by parsing the text and using 'class.intern' on each resulting data structure" do text = "foo" PSON.expects(:parse).with("foo").returns ["bar", "baz"] PsonTest.expects(:from_pson).with("bar").returns "BAR" PsonTest.expects(:from_pson).with("baz").returns "BAZ" @pson.intern_multiple(PsonTest, text).should == %w{BAR BAZ} end end end end diff --git a/spec/unit/network/handler/fileserver_spec.rb b/spec/unit/network/handler/fileserver_spec.rb index 5d88edbf2..52c4a71f5 100755 --- a/spec/unit/network/handler/fileserver_spec.rb +++ b/spec/unit/network/handler/fileserver_spec.rb @@ -1,170 +1,169 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/network/handler/fileserver' describe Puppet::Network::Handler::FileServer do include PuppetSpec::Files def create_file(filename) File.open(filename, "w") { |f| f.puts filename} end def create_nested_file dirname = File.join(@basedir, "nested_dir") Dir.mkdir(dirname) file = File.join(dirname, "nested_dir_file") create_file(file) end before do @basedir = tmpdir("test_network_handler") @file = File.join(@basedir, "aFile") @link = File.join(@basedir, "aLink") create_file(@file) @mount = Puppet::Network::Handler::FileServer::Mount.new("some_path", @basedir) end it "should list a single directory" do @mount.list("/", false, false).should == [["/", "directory"]] end it "should list a file within a directory when given the file path" do @mount.list("/aFile", false, "false").should == [["/", "file"]] end it "should list a file within a directory when given the file path with recursion" do @mount.list("/aFile", true, "false").should == [["/", "file"]] end it "should return nil for a non-existent path" do @mount.list("/no_such_file", false, false).should be(nil) end it "should list a symbolic link as a file when given the link path" do File.symlink(@file, @link) @mount.list("/aLink", false, false).should == [["/", "file"]] end it "should return nil for a dangling symbolic link when given the link path" do File.symlink("/some/where", @link) @mount.list("/aLink", false, false).should be(nil) end it "should list directory contents of a flat directory structure when asked to recurse" do list = @mount.list("/", true, false) list.should include(["/aFile", "file"]) list.should include(["/", "directory"]) list.should have(2).items end it "should list the contents of a nested directory" do create_nested_file list = @mount.list("/", true, false) list.sort.should == [ ["/aFile", "file"], ["/", "directory"] , ["/nested_dir", "directory"], ["/nested_dir/nested_dir_file", "file"]].sort end it "should list the contents of a directory ignoring files that match" do create_nested_file list = @mount.list("/", true, "*File") list.sort.should == [ ["/", "directory"] , ["/nested_dir", "directory"], ["/nested_dir/nested_dir_file", "file"]].sort end it "should list the contents of a directory ignoring directories that match" do create_nested_file list = @mount.list("/", true, "*nested_dir") list.sort.should == [ ["/aFile", "file"], ["/", "directory"] ].sort end it "should list the contents of a directory ignoring all ignore patterns that match" do create_nested_file list = @mount.list("/", true, ["*File" , "*nested_dir"]) list.should == [ ["/", "directory"] ] end it "should list the directory when recursing to a depth of zero" do create_nested_file list = @mount.list("/", 0, false) list.should == [["/", "directory"]] end it "should list the base directory and files and nested directory to a depth of one" do create_nested_file list = @mount.list("/", 1, false) list.sort.should == [ ["/aFile", "file"], ["/nested_dir", "directory"], ["/", "directory"] ].sort end it "should list the base directory and files and nested directory to a depth of two" do create_nested_file list = @mount.list("/", 2, false) list.sort.should == [ ["/aFile", "file"], ["/", "directory"] , ["/nested_dir", "directory"], ["/nested_dir/nested_dir_file", "file"]].sort end it "should list the base directory and files and nested directory to a depth greater than the directory structure" do create_nested_file list = @mount.list("/", 42, false) list.sort.should == [ ["/aFile", "file"], ["/", "directory"] , ["/nested_dir", "directory"], ["/nested_dir/nested_dir_file", "file"]].sort end it "should list a valid symbolic link as a file when recursing base dir" do File.symlink(@file, @link) list = @mount.list("/", true, false) list.sort.should == [ ["/", "directory"], ["/aFile", "file"], ["/aLink", "file"] ].sort end it "should not error when a dangling symlink is present" do File.symlink("/some/where", @link) lambda { @mount.list("/", true, false) }.should_not raise_error end it "should return the directory contents of valid entries when a dangling symlink is present" do File.symlink("/some/where", @link) list = @mount.list("/", true, false) list.sort.should == [ ["/aFile", "file"], ["/", "directory"] ].sort end describe Puppet::Network::Handler::FileServer::PluginMount do PLUGINS = Puppet::Network::Handler::FileServer::PLUGINS # create a module plugin hierarchy def create_plugin(mod, plugin) dirname = File.join(@basedir, mod) Dir.mkdir(dirname) plugins = File.join(dirname, PLUGINS) Dir.mkdir(plugins) facter = File.join(plugins, plugin) Dir.mkdir(facter) create_file(File.join(facter,"fact.rb")) end before :each do @modules = ["one","two"] @modules.each { |m| create_plugin(m, "facter") } Puppet::Node::Environment.new.stubs(:modulepath).returns @basedir @mount = Puppet::Network::Handler::FileServer::PluginMount.new(PLUGINS) @mount.allow("*") end it "should list a file within a directory when given the file path with recursion" do @mount.list("facter/fact.rb", true, "false").should == [["/", "file"], ["/", "file"]] end it "should return a merged view of all plugins for all modules" do list = @mount.list("facter",true,false) list.should == [["/", "directory"], ["/fact.rb", "file"], ["/", "directory"], ["/fact.rb", "file"]] end it "should not fail for inexistant plugins type" do @mount.list("puppet/parser",true,false) end end after do FileUtils.rm_rf(@basedir) end end diff --git a/spec/unit/network/http/api/v1_spec.rb b/spec/unit/network/http/api/v1_spec.rb index d16ff122a..bd95071c1 100755 --- a/spec/unit/network/http/api/v1_spec.rb +++ b/spec/unit/network/http/api/v1_spec.rb @@ -1,193 +1,192 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/network/http/api/v1' class V1RestApiTester include Puppet::Network::HTTP::API::V1 end describe Puppet::Network::HTTP::API::V1 do before do @tester = V1RestApiTester.new end it "should be able to convert a URI into a request" do @tester.should respond_to(:uri2indirection) end it "should be able to convert a request into a URI" do @tester.should respond_to(:indirection2uri) end describe "when converting a URI into a request" do before do @tester.stubs(:handler).returns "foo" end it "should require the http method, the URI, and the query parameters" do # Not a terribly useful test, but an important statement for the spec lambda { @tester.uri2indirection("/foo") }.should raise_error(ArgumentError) end it "should use the first field of the URI as the environment" do @tester.uri2indirection("GET", "/env/foo/bar", {})[3][:environment].should == "env" end it "should fail if the environment is not alphanumeric" do lambda { @tester.uri2indirection("GET", "/env ness/foo/bar", {}) }.should raise_error(ArgumentError) end it "should use the environment from the URI even if one is specified in the parameters" do @tester.uri2indirection("GET", "/env/foo/bar", {:environment => "otherenv"})[3][:environment].should == "env" end it "should use the second field of the URI as the indirection name" do @tester.uri2indirection("GET", "/env/foo/bar", {})[0].should == "foo" end it "should fail if the indirection name is not alphanumeric" do lambda { @tester.uri2indirection("GET", "/env/foo ness/bar", {}) }.should raise_error(ArgumentError) end it "should use the remainder of the URI as the indirection key" do @tester.uri2indirection("GET", "/env/foo/bar", {})[2].should == "bar" end it "should support the indirection key being a /-separated file path" do @tester.uri2indirection("GET", "/env/foo/bee/baz/bomb", {})[2].should == "bee/baz/bomb" end it "should fail if no indirection key is specified" do lambda { @tester.uri2indirection("GET", "/env/foo/", {}) }.should raise_error(ArgumentError) lambda { @tester.uri2indirection("GET", "/env/foo", {}) }.should raise_error(ArgumentError) end it "should choose 'find' as the indirection method if the http method is a GET and the indirection name is singular" do @tester.uri2indirection("GET", "/env/foo/bar", {})[1].should == :find end it "should choose 'find' as the indirection method if the http method is a POST and the indirection name is singular" do @tester.uri2indirection("POST", "/env/foo/bar", {})[1].should == :find end it "should choose 'head' as the indirection method if the http method is a HEAD and the indirection name is singular" do @tester.uri2indirection("HEAD", "/env/foo/bar", {})[1].should == :head end it "should choose 'search' as the indirection method if the http method is a GET and the indirection name is plural" do @tester.uri2indirection("GET", "/env/foos/bar", {})[1].should == :search end it "should choose 'find' as the indirection method if the http method is a GET and the indirection name is facts" do @tester.uri2indirection("GET", "/env/facts/bar", {})[1].should == :find end it "should choose 'save' as the indirection method if the http method is a PUT and the indirection name is facts" do @tester.uri2indirection("PUT", "/env/facts/bar", {})[1].should == :save end it "should choose 'search' as the indirection method if the http method is a GET and the indirection name is inventory" do @tester.uri2indirection("GET", "/env/inventory/search", {})[1].should == :search end it "should choose 'find' as the indirection method if the http method is a GET and the indirection name is facts" do @tester.uri2indirection("GET", "/env/facts/bar", {})[1].should == :find end it "should choose 'save' as the indirection method if the http method is a PUT and the indirection name is facts" do @tester.uri2indirection("PUT", "/env/facts/bar", {})[1].should == :save end it "should choose 'search' as the indirection method if the http method is a GET and the indirection name is inventory" do @tester.uri2indirection("GET", "/env/inventory/search", {})[1].should == :search end it "should choose 'search' as the indirection method if the http method is a GET and the indirection name is facts_search" do @tester.uri2indirection("GET", "/env/facts_search/bar", {})[1].should == :search end it "should change indirection name to 'facts' if the http method is a GET and the indirection name is facts_search" do @tester.uri2indirection("GET", "/env/facts_search/bar", {})[0].should == 'facts' end it "should not change indirection name from 'facts' if the http method is a GET and the indirection name is facts" do @tester.uri2indirection("GET", "/env/facts/bar", {})[0].should == 'facts' end it "should change indirection name to 'status' if the http method is a GET and the indirection name is statuses" do @tester.uri2indirection("GET", "/env/statuses/bar", {})[0].should == 'status' end it "should choose 'delete' as the indirection method if the http method is a DELETE and the indirection name is singular" do @tester.uri2indirection("DELETE", "/env/foo/bar", {})[1].should == :destroy end it "should choose 'save' as the indirection method if the http method is a PUT and the indirection name is singular" do @tester.uri2indirection("PUT", "/env/foo/bar", {})[1].should == :save end it "should fail if an indirection method cannot be picked" do lambda { @tester.uri2indirection("UPDATE", "/env/foo/bar", {}) }.should raise_error(ArgumentError) end it "should URI unescape the indirection key" do escaped = URI.escape("foo bar") indirection_name, method, key, params = @tester.uri2indirection("GET", "/env/foo/#{escaped}", {}) key.should == "foo bar" end end describe "when converting a request into a URI" do before do @request = Puppet::Indirector::Request.new(:foo, :find, "with spaces", :foo => :bar, :environment => "myenv") end it "should use the environment as the first field of the URI" do @tester.indirection2uri(@request).split("/")[1].should == "myenv" end it "should use the indirection as the second field of the URI" do @tester.indirection2uri(@request).split("/")[2].should == "foo" end it "should pluralize the indirection name if the method is 'search'" do @request.stubs(:method).returns :search @tester.indirection2uri(@request).split("/")[2].should == "foos" end it "should use the escaped key as the remainder of the URI" do escaped = URI.escape("with spaces") @tester.indirection2uri(@request).split("/")[3].sub(/\?.+/, '').should == escaped end it "should add the query string to the URI" do @request.expects(:query_string).returns "?query" @tester.indirection2uri(@request).should =~ /\?query$/ end end describe "when converting a request into a URI with body" do before :each do @request = Puppet::Indirector::Request.new(:foo, :find, "with spaces", :foo => :bar, :environment => "myenv") end it "should use the environment as the first field of the URI" do @tester.request_to_uri_and_body(@request).first.split("/")[1].should == "myenv" end it "should use the indirection as the second field of the URI" do @tester.request_to_uri_and_body(@request).first.split("/")[2].should == "foo" end it "should use the escaped key as the remainder of the URI" do escaped = URI.escape("with spaces") @tester.request_to_uri_and_body(@request).first.split("/")[3].sub(/\?.+/, '').should == escaped end it "should return the URI and body separately" do @tester.request_to_uri_and_body(@request).should == ["/myenv/foo/with%20spaces", "foo=bar"] end end end diff --git a/spec/unit/network/http/compression_spec.rb b/spec/unit/network/http/compression_spec.rb index 32ffd6a72..5c919c6c5 100755 --- a/spec/unit/network/http/compression_spec.rb +++ b/spec/unit/network/http/compression_spec.rb @@ -1,197 +1,196 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe "http compression" do describe "when zlib is not available" do before(:each) do Puppet.features.stubs(:zlib?).returns false require 'puppet/network/http/compression' class HttpUncompressor include Puppet::Network::HTTP::Compression::None end @uncompressor = HttpUncompressor.new end it "should have a module function that returns the None underlying module" do Puppet::Network::HTTP::Compression.module.should == Puppet::Network::HTTP::Compression::None end it "should not add any Accept-Encoding header" do @uncompressor.add_accept_encoding({}).should == {} end it "should not tamper the body" do response = stub 'response', :body => "data" @uncompressor.uncompress_body(response).should == "data" end it "should yield an identity uncompressor" do response = stub 'response' @uncompressor.uncompress(response) { |u| u.should be_instance_of(Puppet::Network::HTTP::Compression::IdentityAdapter) } end end describe "when zlib is available", :if => Puppet.features.zlib? do before(:each) do Puppet.features.stubs(:zlib?).returns true require 'puppet/network/http/compression' class HttpUncompressor include Puppet::Network::HTTP::Compression::Active end @uncompressor = HttpUncompressor.new end it "should have a module function that returns the Active underlying module" do Puppet::Network::HTTP::Compression.module.should == Puppet::Network::HTTP::Compression::Active end it "should add an Accept-Encoding header when http compression is available" do Puppet.settings.expects(:[]).with(:http_compression).returns(true) headers = @uncompressor.add_accept_encoding({}) headers.should have_key('accept-encoding') headers['accept-encoding'].should =~ /gzip/ headers['accept-encoding'].should =~ /deflate/ headers['accept-encoding'].should =~ /identity/ end it "should not add Accept-Encoding header if http compression is not available" do Puppet.settings.stubs(:[]).with(:http_compression).returns(false) @uncompressor.add_accept_encoding({}).should == {} end describe "when uncompressing response body" do before do @response = stub 'response' @response.stubs(:[]).with('content-encoding') @response.stubs(:body).returns("mydata") end it "should return untransformed response body with no content-encoding" do @uncompressor.uncompress_body(@response).should == "mydata" end it "should return untransformed response body with 'identity' content-encoding" do @response.stubs(:[]).with('content-encoding').returns('identity') @uncompressor.uncompress_body(@response).should == "mydata" end it "should use a Zlib inflater with 'deflate' content-encoding" do @response.stubs(:[]).with('content-encoding').returns('deflate') inflater = stub 'inflater' Zlib::Inflate.expects(:new).returns(inflater) inflater.expects(:inflate).with("mydata").returns "uncompresseddata" @uncompressor.uncompress_body(@response).should == "uncompresseddata" end it "should use a GzipReader with 'gzip' content-encoding" do @response.stubs(:[]).with('content-encoding').returns('gzip') io = stub 'io' StringIO.expects(:new).with("mydata").returns io reader = stub 'gzip reader' Zlib::GzipReader.expects(:new).with(io).returns(reader) reader.expects(:read).returns "uncompresseddata" @uncompressor.uncompress_body(@response).should == "uncompresseddata" end end describe "when uncompressing by chunk" do before do @response = stub 'response' @response.stubs(:[]).with('content-encoding') @inflater = stub_everything 'inflater' Zlib::Inflate.stubs(:new).returns(@inflater) end it "should yield an identity uncompressor with no content-encoding" do @uncompressor.uncompress(@response) { |u| u.should be_instance_of(Puppet::Network::HTTP::Compression::IdentityAdapter) } end it "should yield an identity uncompressor with 'identity' content-encoding" do @response.stubs(:[]).with('content-encoding').returns 'identity' @uncompressor.uncompress(@response) { |u| u.should be_instance_of(Puppet::Network::HTTP::Compression::IdentityAdapter) } end %w{gzip deflate}.each do |c| it "should yield a Zlib uncompressor with '#{c}' content-encoding" do @response.stubs(:[]).with('content-encoding').returns c @uncompressor.uncompress(@response) { |u| u.should be_instance_of(Puppet::Network::HTTP::Compression::Active::ZlibAdapter) } end end it "should close the underlying adapter" do adapter = stub_everything 'adapter' Puppet::Network::HTTP::Compression::IdentityAdapter.expects(:new).returns(adapter) adapter.expects(:close) @uncompressor.uncompress(@response) { |u| } end end describe "zlib adapter" do before do @inflater = stub_everything 'inflater' Zlib::Inflate.stubs(:new).returns(@inflater) @adapter = Puppet::Network::HTTP::Compression::Active::ZlibAdapter.new end it "should initialize the underlying inflater with gzip/zlib header parsing" do Zlib::Inflate.expects(:new).with(15+32) Puppet::Network::HTTP::Compression::Active::ZlibAdapter.new end it "should inflate the given chunk" do @inflater.expects(:inflate).with("chunk") @adapter.uncompress("chunk") end it "should return the inflated chunk" do @inflater.stubs(:inflate).with("chunk").returns("uncompressed") @adapter.uncompress("chunk").should == "uncompressed" end it "should try a 'regular' inflater on Zlib::DataError" do @inflater.expects(:inflate).raises(Zlib::DataError.new("not a zlib stream")) inflater = stub_everything 'inflater2' inflater.expects(:inflate).with("chunk").returns("uncompressed") Zlib::Inflate.expects(:new).with.returns(inflater) @adapter.uncompress("chunk") end it "should raise the error the second time" do @inflater.stubs(:inflate).raises(Zlib::DataError.new("not a zlib stream")) Zlib::Inflate.expects(:new).with.returns(@inflater) lambda { @adapter.uncompress("chunk") }.should raise_error end it "should finish the stream on close" do @inflater.expects(:finish) @adapter.close end it "should close the stream on close" do @inflater.expects(:close) @adapter.close end end end end diff --git a/spec/unit/network/http/handler_spec.rb b/spec/unit/network/http/handler_spec.rb index 868efa72b..83969c504 100755 --- a/spec/unit/network/http/handler_spec.rb +++ b/spec/unit/network/http/handler_spec.rb @@ -1,472 +1,471 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/network/http/handler' require 'puppet/network/rest_authorization' class HttpHandled include Puppet::Network::HTTP::Handler end describe Puppet::Network::HTTP::Handler do before do @handler = HttpHandled.new end it "should include the v1 REST API" do Puppet::Network::HTTP::Handler.ancestors.should be_include(Puppet::Network::HTTP::API::V1) end it "should include the Rest Authorization system" do Puppet::Network::HTTP::Handler.ancestors.should be_include(Puppet::Network::RestAuthorization) end it "should have a method for initializing" do @handler.should respond_to(:initialize_for_puppet) end describe "when initializing" do it "should fail when no server type has been provided" do lambda { @handler.initialize_for_puppet }.should raise_error(ArgumentError) end it "should set server type" do @handler.initialize_for_puppet("foo") @handler.server.should == "foo" end end it "should be able to process requests" do @handler.should respond_to(:process) end describe "when processing a request" do before do @request = stub('http request') @request.stubs(:[]).returns "foo" @response = stub('http response') @model_class = stub('indirected model class') @indirection = stub('indirection') @model_class.stubs(:indirection).returns(@indirection) @result = stub 'result', :render => "mytext" @handler.stubs(:check_authorization) stub_server_interface end # Stub out the interface we require our including classes to # implement. def stub_server_interface @handler.stubs(:accept_header ).returns "format_one,format_two" @handler.stubs(:content_type_header).returns "text/yaml" @handler.stubs(:set_content_type ).returns "my_result" @handler.stubs(:set_response ).returns "my_result" @handler.stubs(:path ).returns "/my_handler/my_result" @handler.stubs(:http_method ).returns("GET") @handler.stubs(:params ).returns({}) @handler.stubs(:content_type ).returns("text/plain") end it "should create an indirection request from the path, parameters, and http method" do @handler.expects(:path).with(@request).returns "mypath" @handler.expects(:http_method).with(@request).returns "mymethod" @handler.expects(:params).with(@request).returns "myparams" @handler.expects(:uri2indirection).with("mymethod", "mypath", "myparams").returns stub("request", :method => :find) @handler.stubs(:do_find) @handler.process(@request, @response) end it "should call the 'do' method and delegate authorization to the RestAuthorization layer" do @handler.expects(:uri2indirection).returns(["facts", :mymethod, "key", {:node => "name"}]) @handler.expects(:do_mymethod).with("facts", "key", {:node => "name"}, @request, @response) @handler.expects(:check_authorization).with("facts", :mymethod, "key", {:node => "name"}) @handler.process(@request, @response) end it "should return 403 if the request is not authorized" do @handler.expects(:uri2indirection).returns(["facts", :mymethod, "key", {:node => "name"}]) @handler.expects(:do_mymethod).never @handler.expects(:check_authorization).with("facts", :mymethod, "key", {:node => "name"}).raises(Puppet::Network::AuthorizationError.new("forbidden")) @handler.expects(:set_response).with { |response, body, status| status == 403 } @handler.process(@request, @response) end it "should serialize a controller exception when an exception is thrown while finding the model instance" do @handler.expects(:uri2indirection).returns(["facts", :find, "key", {:node => "name"}]) @handler.expects(:do_find).raises(ArgumentError, "The exception") @handler.expects(:set_response).with { |response, body, status| body == "The exception" and status == 400 } @handler.process(@request, @response) end it "should set the format to text/plain when serializing an exception" do @handler.expects(:set_content_type).with(@response, "text/plain") @handler.do_exception(@response, "A test", 404) end it "should raise an error if the request is formatted in an unknown format" do @handler.stubs(:content_type_header).returns "unknown format" lambda { @handler.request_format(@request) }.should raise_error end it "should still find the correct format if content type contains charset information" do @handler.stubs(:content_type_header).returns "text/plain; charset=UTF-8" @handler.request_format(@request).should == "s" end describe "when finding a model instance" do before do @indirection.stubs(:find).returns @result Puppet::Indirector::Indirection.expects(:instance).with(:my_handler).returns( stub "indirection", :model => @model_class ) @format = stub 'format', :suitable? => true, :mime => "text/format", :name => "format" Puppet::Network::FormatHandler.stubs(:format).returns @format @oneformat = stub 'one', :suitable? => true, :mime => "text/one", :name => "one" Puppet::Network::FormatHandler.stubs(:format).with("one").returns @oneformat end it "should use the indirection request to find the model class" do @handler.do_find("my_handler", "my_result", {}, @request, @response) end it "should use the escaped request key" do @indirection.expects(:find).with do |key, args| key == "my_result" end.returns @result @handler.do_find("my_handler", "my_result", {}, @request, @response) end it "should use a common method for determining the request parameters" do @indirection.expects(:find).with do |key, args| args[:foo] == :baz and args[:bar] == :xyzzy end.returns @result @handler.do_find("my_handler", "my_result", {:foo => :baz, :bar => :xyzzy}, @request, @response) end it "should set the content type to the first format specified in the accept header" do @handler.expects(:accept_header).with(@request).returns "one,two" @handler.expects(:set_content_type).with(@response, @oneformat) @handler.do_find("my_handler", "my_result", {}, @request, @response) end it "should fail if no accept header is provided" do @handler.expects(:accept_header).with(@request).returns nil lambda { @handler.do_find("my_handler", "my_result", {}, @request, @response) }.should raise_error(ArgumentError) end it "should fail if the accept header does not contain a valid format" do @handler.expects(:accept_header).with(@request).returns "" lambda { @handler.do_find("my_handler", "my_result", {}, @request, @response) }.should raise_error(RuntimeError) end it "should not use an unsuitable format" do @handler.expects(:accept_header).with(@request).returns "foo,bar" foo = mock 'foo', :suitable? => false bar = mock 'bar', :suitable? => true Puppet::Network::FormatHandler.expects(:format).with("foo").returns foo Puppet::Network::FormatHandler.expects(:format).with("bar").returns bar @handler.expects(:set_content_type).with(@response, bar) # the suitable one @handler.do_find("my_handler", "my_result", {}, @request, @response) end it "should render the result using the first format specified in the accept header" do @handler.expects(:accept_header).with(@request).returns "one,two" @result.expects(:render).with(@oneformat) @handler.do_find("my_handler", "my_result", {}, @request, @response) end it "should pass the result through without rendering it if the result is a string" do @indirection.stubs(:find).returns "foo" @handler.expects(:set_response).with(@response, "foo") @handler.do_find("my_handler", "my_result", {}, @request, @response) end it "should use the default status when a model find call succeeds" do @handler.expects(:set_response).with { |response, body, status| status.nil? } @handler.do_find("my_handler", "my_result", {}, @request, @response) end it "should return a serialized object when a model find call succeeds" do @model_instance = stub('model instance') @model_instance.expects(:render).returns "my_rendered_object" @handler.expects(:set_response).with { |response, body, status| body == "my_rendered_object" } @indirection.stubs(:find).returns(@model_instance) @handler.do_find("my_handler", "my_result", {}, @request, @response) end it "should return a 404 when no model instance can be found" do @model_class.stubs(:name).returns "my name" @handler.expects(:set_response).with { |response, body, status| status == 404 } @indirection.stubs(:find).returns(nil) @handler.do_find("my_handler", "my_result", {}, @request, @response) end it "should write a log message when no model instance can be found" do @model_class.stubs(:name).returns "my name" @indirection.stubs(:find).returns(nil) Puppet.expects(:info).with("Could not find my_handler for 'my_result'") @handler.do_find("my_handler", "my_result", {}, @request, @response) end it "should serialize the result in with the appropriate format" do @model_instance = stub('model instance') @handler.expects(:format_to_use).returns(@oneformat) @model_instance.expects(:render).with(@oneformat).returns "my_rendered_object" @indirection.stubs(:find).returns(@model_instance) @handler.do_find("my_handler", "my_result", {}, @request, @response) end end describe "when performing head operation" do before do @irequest = stub 'indirection_request', :method => :head, :indirection_name => "my_handler", :to_hash => {}, :key => "my_result", :model => @model_class @model_class.stubs(:head).returns true end it "should use the indirection request to find the model class" do @irequest.expects(:model).returns @model_class @handler.do_head(@irequest, @request, @response) end it "should use the escaped request key" do @model_class.expects(:head).with do |key, args| key == "my_result" end.returns true @handler.do_head(@irequest, @request, @response) end it "should not generate a response when a model head call succeeds" do @handler.expects(:set_response).never @handler.do_head(@irequest, @request, @response) end it "should return a 404 when the model head call returns false" do @model_class.stubs(:name).returns "my name" @handler.expects(:set_response).with { |response, body, status| status == 404 } @model_class.stubs(:head).returns(false) @handler.do_head(@irequest, @request, @response) end end describe "when searching for model instances" do before do Puppet::Indirector::Indirection.expects(:instance).with(:my_handler).returns( stub "indirection", :model => @model_class ) @result1 = mock 'result1' @result2 = mock 'results' @result = [@result1, @result2] @model_class.stubs(:render_multiple).returns "my rendered instances" @indirection.stubs(:search).returns(@result) @format = stub 'format', :suitable? => true, :mime => "text/format", :name => "format" Puppet::Network::FormatHandler.stubs(:format).returns @format @oneformat = stub 'one', :suitable? => true, :mime => "text/one", :name => "one" Puppet::Network::FormatHandler.stubs(:format).with("one").returns @oneformat end it "should use the indirection request to find the model" do @handler.do_search("my_handler", "my_result", {}, @request, @response) end it "should use a common method for determining the request parameters" do @indirection.expects(:search).with do |key, args| args[:foo] == :baz and args[:bar] == :xyzzy end.returns @result @handler.do_search("my_handler", "my_result", {:foo => :baz, :bar => :xyzzy}, @request, @response) end it "should use the default status when a model search call succeeds" do @indirection.stubs(:search).returns(@result) @handler.do_search("my_handler", "my_result", {}, @request, @response) end it "should set the content type to the first format returned by the accept header" do @handler.expects(:accept_header).with(@request).returns "one,two" @handler.expects(:set_content_type).with(@response, @oneformat) @handler.do_search("my_handler", "my_result", {}, @request, @response) end it "should return a list of serialized objects when a model search call succeeds" do @handler.expects(:accept_header).with(@request).returns "one,two" @indirection.stubs(:search).returns(@result) @model_class.expects(:render_multiple).with(@oneformat, @result).returns "my rendered instances" @handler.expects(:set_response).with { |response, data| data == "my rendered instances" } @handler.do_search("my_handler", "my_result", {}, @request, @response) end it "should return [] when searching returns an empty array" do @handler.expects(:accept_header).with(@request).returns "one,two" @indirection.stubs(:search).returns([]) @model_class.expects(:render_multiple).with(@oneformat, []).returns "[]" @handler.expects(:set_response).with { |response, data| data == "[]" } @handler.do_search("my_handler", "my_result", {}, @request, @response) end it "should return a 404 when searching returns nil" do @model_class.stubs(:name).returns "my name" @handler.expects(:set_response).with { |response, body, status| status == 404 } @indirection.stubs(:search).returns(nil) @handler.do_search("my_handler", "my_result", {}, @request, @response) end end describe "when destroying a model instance" do before do Puppet::Indirector::Indirection.expects(:instance).with(:my_handler).returns( stub "indirection", :model => @model_class ) @result = stub 'result', :render => "the result" @indirection.stubs(:destroy).returns @result end it "should use the indirection request to find the model" do @handler.do_destroy("my_handler", "my_result", {}, @request, @response) end it "should use the escaped request key to destroy the instance in the model" do @indirection.expects(:destroy).with do |key, args| key == "foo bar" end @handler.do_destroy("my_handler", "foo bar", {}, @request, @response) end it "should use a common method for determining the request parameters" do @indirection.expects(:destroy).with do |key, args| args[:foo] == :baz and args[:bar] == :xyzzy end @handler.do_destroy("my_handler", "my_result", {:foo => :baz, :bar => :xyzzy}, @request, @response) end it "should use the default status code a model destroy call succeeds" do @handler.expects(:set_response).with { |response, body, status| status.nil? } @handler.do_destroy("my_handler", "my_result", {}, @request, @response) end it "should return a yaml-encoded result when a model destroy call succeeds" do @result = stub 'result', :to_yaml => "the result" @indirection.expects(:destroy).returns(@result) @handler.expects(:set_response).with { |response, body, status| body == "the result" } @handler.do_destroy("my_handler", "my_result", {}, @request, @response) end end describe "when saving a model instance" do before do Puppet::Indirector::Indirection.stubs(:instance).with(:my_handler).returns( stub "indirection", :model => @model_class ) @handler.stubs(:body).returns('my stuff') @handler.stubs(:content_type_header).returns("text/yaml") @result = stub 'result', :render => "the result" @model_instance = stub('indirected model instance') @model_class.stubs(:convert_from).returns(@model_instance) @indirection.stubs(:save) @format = stub 'format', :suitable? => true, :name => "format", :mime => "text/format" Puppet::Network::FormatHandler.stubs(:format).returns @format @yamlformat = stub 'yaml', :suitable? => true, :name => "yaml", :mime => "text/yaml" Puppet::Network::FormatHandler.stubs(:format).with("yaml").returns @yamlformat end it "should use the indirection request to find the model" do @handler.do_save("my_handler", "my_result", {}, @request, @response) end it "should use the 'body' hook to retrieve the body of the request" do @handler.expects(:body).returns "my body" @model_class.expects(:convert_from).with { |format, body| body == "my body" }.returns @model_instance @handler.do_save("my_handler", "my_result", {}, @request, @response) end it "should fail to save model if data is not specified" do @handler.stubs(:body).returns('') lambda { @handler.do_save("my_handler", "my_result", {}, @request, @response) }.should raise_error(ArgumentError) end it "should use a common method for determining the request parameters" do @indirection.expects(:save).with(@model_instance, 'key').once @handler.do_save("my_handler", "key", {}, @request, @response) end it "should use the default status when a model save call succeeds" do @handler.expects(:set_response).with { |response, body, status| status.nil? } @handler.do_save("my_handler", "my_result", {}, @request, @response) end it "should return the yaml-serialized result when a model save call succeeds" do @indirection.stubs(:save).returns(@model_instance) @model_instance.expects(:to_yaml).returns('foo') @handler.do_save("my_handler", "my_result", {}, @request, @response) end it "should set the content to yaml" do @handler.expects(:set_content_type).with(@response, @yamlformat) @handler.do_save("my_handler", "my_result", {}, @request, @response) end it "should use the content-type header to know the body format" do @handler.expects(:content_type_header).returns("text/format") Puppet::Network::FormatHandler.stubs(:mime).with("text/format").returns @format @model_class.expects(:convert_from).with { |format, body| format == "format" }.returns @model_instance @handler.do_save("my_handler", "my_result", {}, @request, @response) end end end describe "when resolving node" do it "should use a look-up from the ip address" do Resolv.expects(:getname).with("1.2.3.4").returns("host.domain.com") @handler.resolve_node(:ip => "1.2.3.4") end it "should return the look-up result" do Resolv.stubs(:getname).with("1.2.3.4").returns("host.domain.com") @handler.resolve_node(:ip => "1.2.3.4").should == "host.domain.com" end it "should return the ip address if resolving fails" do Resolv.stubs(:getname).with("1.2.3.4").raises(RuntimeError, "no such host") @handler.resolve_node(:ip => "1.2.3.4").should == "1.2.3.4" end end end diff --git a/spec/unit/network/http/mongrel/rest_spec.rb b/spec/unit/network/http/mongrel/rest_spec.rb index cd3a59994..3e454cf8f 100755 --- a/spec/unit/network/http/mongrel/rest_spec.rb +++ b/spec/unit/network/http/mongrel/rest_spec.rb @@ -1,248 +1,247 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/network/http' describe "Puppet::Network::HTTP::MongrelREST", :if => Puppet.features.mongrel? do before do require 'puppet/network/http/mongrel/rest' end it "should include the Puppet::Network::HTTP::Handler module" do Puppet::Network::HTTP::MongrelREST.ancestors.should be_include(Puppet::Network::HTTP::Handler) end describe "when initializing" do it "should call the Handler's initialization hook with its provided arguments as the server and handler" do Puppet::Network::HTTP::MongrelREST.any_instance.expects(:initialize_for_puppet).with(:server => "my", :handler => "arguments") Puppet::Network::HTTP::MongrelREST.new(:server => "my", :handler => "arguments") end end describe "when receiving a request" do before do @params = {} @request = stub('mongrel http request', :params => @params) @head = stub('response head') @body = stub('response body', :write => true) @response = stub('mongrel http response') @response.stubs(:start).yields(@head, @body) @model_class = stub('indirected model class') @mongrel = stub('mongrel http server', :register => true) Puppet::Indirector::Indirection.stubs(:model).with(:foo).returns(@model_class) @handler = Puppet::Network::HTTP::MongrelREST.new(:server => @mongrel, :handler => :foo) end describe "and using the HTTP Handler interface" do it "should return the HTTP_ACCEPT parameter as the accept header" do @params.expects(:[]).with("HTTP_ACCEPT").returns "myaccept" @handler.accept_header(@request).should == "myaccept" end it "should return the Content-Type parameter as the Content-Type header" do @params.expects(:[]).with("HTTP_CONTENT_TYPE").returns "mycontent" @handler.content_type_header(@request).should == "mycontent" end it "should use the REQUEST_METHOD as the http method" do @params.expects(:[]).with(Mongrel::Const::REQUEST_METHOD).returns "mymethod" @handler.http_method(@request).should == "mymethod" end it "should return the request path as the path" do @params.expects(:[]).with(Mongrel::Const::REQUEST_PATH).returns "/foo/bar" @handler.path(@request).should == "/foo/bar" end it "should return the request body as the body" do @request.expects(:body).returns StringIO.new("mybody") @handler.body(@request).should == "mybody" end it "should set the response's content-type header when setting the content type" do @header = mock 'header' @response.expects(:header).returns @header @header.expects(:[]=).with('Content-Type', "mytype") @handler.set_content_type(@response, "mytype") end it "should set the status and write the body when setting the response for a successful request" do head = mock 'head' body = mock 'body' @response.expects(:start).with(200).yields(head, body) body.expects(:write).with("mybody") @handler.set_response(@response, "mybody", 200) end describe "when the result is a File" do it "should use response send_file" do head = mock 'head' body = mock 'body' stat = stub 'stat', :size => 100 file = stub 'file', :stat => stat, :path => "/tmp/path" file.stubs(:is_a?).with(File).returns(true) @response.expects(:start).with(200).yields(head, body) @response.expects(:send_status).with(100) @response.expects(:send_header) @response.expects(:send_file).with("/tmp/path") @handler.set_response(@response, file, 200) end end it "should set the status and reason and write the body when setting the response for a successful request" do head = mock 'head' body = mock 'body' @response.expects(:start).with(400, false, "mybody").yields(head, body) body.expects(:write).with("mybody") @handler.set_response(@response, "mybody", 400) end end describe "and determining the request parameters" do before do @request.stubs(:params).returns({}) end it "should skip empty parameter values" do @request.expects(:params).returns('QUERY_STRING' => "&=") lambda { @handler.params(@request) }.should_not raise_error end it "should include the HTTP request parameters, with the keys as symbols" do @request.expects(:params).returns('QUERY_STRING' => 'foo=baz&bar=xyzzy') result = @handler.params(@request) result[:foo].should == "baz" result[:bar].should == "xyzzy" end it "should CGI-decode the HTTP parameters" do encoding = CGI.escape("foo bar") @request.expects(:params).returns('QUERY_STRING' => "foo=#{encoding}") result = @handler.params(@request) result[:foo].should == "foo bar" end it "should convert the string 'true' to the boolean" do @request.expects(:params).returns('QUERY_STRING' => 'foo=true') result = @handler.params(@request) result[:foo].should be_true end it "should convert the string 'false' to the boolean" do @request.expects(:params).returns('QUERY_STRING' => 'foo=false') result = @handler.params(@request) result[:foo].should be_false end it "should convert integer arguments to Integers" do @request.expects(:params).returns('QUERY_STRING' => 'foo=15') result = @handler.params(@request) result[:foo].should == 15 end it "should convert floating point arguments to Floats" do @request.expects(:params).returns('QUERY_STRING' => 'foo=1.5') result = @handler.params(@request) result[:foo].should == 1.5 end it "should YAML-load and URI-decode values that are YAML-encoded" do escaping = CGI.escape(YAML.dump(%w{one two})) @request.expects(:params).returns('QUERY_STRING' => "foo=#{escaping}") result = @handler.params(@request) result[:foo].should == %w{one two} end it "should not allow the client to set the node via the query string" do @request.stubs(:params).returns('QUERY_STRING' => "node=foo") @handler.params(@request)[:node].should be_nil end it "should not allow the client to set the IP address via the query string" do @request.stubs(:params).returns('QUERY_STRING' => "ip=foo") @handler.params(@request)[:ip].should be_nil end it "should pass the client's ip address to model find" do @request.stubs(:params).returns("REMOTE_ADDR" => "ipaddress") @handler.params(@request)[:ip].should == "ipaddress" end it "should pass the client's provided X-Forwared-For value as the ip" do @request.stubs(:params).returns("HTTP_X_FORWARDED_FOR" => "ipaddress") @handler.params(@request)[:ip].should == "ipaddress" end it "should pass the client's provided X-Forwared-For first value as the ip" do @request.stubs(:params).returns("HTTP_X_FORWARDED_FOR" => "ipproxy1,ipproxy2,ipaddress") @handler.params(@request)[:ip].should == "ipaddress" end it "should pass the client's provided X-Forwared-For value as the ip instead of the REMOTE_ADDR" do @request.stubs(:params).returns("REMOTE_ADDR" => "remote_addr") @request.stubs(:params).returns("HTTP_X_FORWARDED_FOR" => "ipaddress") @handler.params(@request)[:ip].should == "ipaddress" end it "should use the :ssl_client_header to determine the parameter when looking for the certificate" do Puppet.settings.stubs(:value).returns "eh" Puppet.settings.expects(:value).with(:ssl_client_header).returns "myheader" @request.stubs(:params).returns("myheader" => "/CN=host.domain.com") @handler.params(@request) end it "should retrieve the hostname by matching the certificate parameter" do Puppet.settings.stubs(:value).returns "eh" Puppet.settings.expects(:value).with(:ssl_client_header).returns "myheader" @request.stubs(:params).returns("myheader" => "/CN=host.domain.com") @handler.params(@request)[:node].should == "host.domain.com" end it "should use the :ssl_client_header to determine the parameter for checking whether the host certificate is valid" do Puppet.settings.stubs(:value).with(:ssl_client_header).returns "certheader" Puppet.settings.expects(:value).with(:ssl_client_verify_header).returns "myheader" @request.stubs(:params).returns("myheader" => "SUCCESS", "certheader" => "/CN=host.domain.com") @handler.params(@request) end it "should consider the host authenticated if the validity parameter contains 'SUCCESS'" do Puppet.settings.stubs(:value).with(:ssl_client_header).returns "certheader" Puppet.settings.stubs(:value).with(:ssl_client_verify_header).returns "myheader" @request.stubs(:params).returns("myheader" => "SUCCESS", "certheader" => "/CN=host.domain.com") @handler.params(@request)[:authenticated].should be_true end it "should consider the host unauthenticated if the validity parameter does not contain 'SUCCESS'" do Puppet.settings.stubs(:value).with(:ssl_client_header).returns "certheader" Puppet.settings.stubs(:value).with(:ssl_client_verify_header).returns "myheader" @request.stubs(:params).returns("myheader" => "whatever", "certheader" => "/CN=host.domain.com") @handler.params(@request)[:authenticated].should be_false end it "should consider the host unauthenticated if no certificate information is present" do Puppet.settings.stubs(:value).with(:ssl_client_header).returns "certheader" Puppet.settings.stubs(:value).with(:ssl_client_verify_header).returns "myheader" @request.stubs(:params).returns("myheader" => nil, "certheader" => "SUCCESS") @handler.params(@request)[:authenticated].should be_false end it "should resolve the node name with an ip address look-up if no certificate is present" do Puppet.settings.stubs(:value).returns "eh" Puppet.settings.expects(:value).with(:ssl_client_header).returns "myheader" @request.stubs(:params).returns("myheader" => nil) @handler.expects(:resolve_node).returns("host.domain.com") @handler.params(@request)[:node].should == "host.domain.com" end end end end diff --git a/spec/unit/network/http/mongrel_spec.rb b/spec/unit/network/http/mongrel_spec.rb index a200de384..56d0afbed 100755 --- a/spec/unit/network/http/mongrel_spec.rb +++ b/spec/unit/network/http/mongrel_spec.rb @@ -1,125 +1,125 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Created by Rick Bradley on 2007-10-15. # Copyright (c) 2007. All rights reserved. require 'spec_helper' require 'puppet/network/http' describe "Puppet::Network::HTTP::Mongrel", "after initializing", :if => Puppet.features.mongrel? do it "should not be listening" do require 'puppet/network/http/mongrel' Puppet::Network::HTTP::Mongrel.new.should_not be_listening end end describe "Puppet::Network::HTTP::Mongrel", "when turning on listening", :if => Puppet.features.mongrel? do before do require 'puppet/network/http/mongrel' @server = Puppet::Network::HTTP::Mongrel.new @mock_mongrel = mock('mongrel') @mock_mongrel.stubs(:run) @mock_mongrel.stubs(:register) Mongrel::HttpServer.stubs(:new).returns(@mock_mongrel) @mock_puppet_mongrel = mock('puppet_mongrel') Puppet::Network::HTTPServer::Mongrel.stubs(:new).returns(@mock_puppet_mongrel) @listen_params = { :address => "127.0.0.1", :port => 31337, :protocols => [ :rest, :xmlrpc ], :xmlrpc_handlers => [ :status, :fileserver ] } end it "should fail if already listening" do @server.listen(@listen_params) Proc.new { @server.listen(@listen_params) }.should raise_error(RuntimeError) end it "should require at least one protocol" do Proc.new { @server.listen(@listen_params.delete_if {|k,v| :protocols == k}) }.should raise_error(ArgumentError) end it "should require a listening address to be specified" do Proc.new { @server.listen(@listen_params.delete_if {|k,v| :address == k})}.should raise_error(ArgumentError) end it "should require a listening port to be specified" do Proc.new { @server.listen(@listen_params.delete_if {|k,v| :port == k})}.should raise_error(ArgumentError) end it "should order a mongrel server to start" do @mock_mongrel.expects(:run) @server.listen(@listen_params) end it "should tell mongrel to listen on the specified address and port" do Mongrel::HttpServer.expects(:new).with("127.0.0.1", 31337).returns(@mock_mongrel) @server.listen(@listen_params) end it "should be listening" do Mongrel::HttpServer.expects(:new).returns(@mock_mongrel) @server.listen(@listen_params) @server.should be_listening end describe "when providing REST services" do it "should instantiate a handler at / for handling REST calls" do Puppet::Network::HTTP::MongrelREST.expects(:new).returns "myhandler" @mock_mongrel.expects(:register).with("/", "myhandler") @server.listen(@listen_params) end it "should use a Mongrel + REST class to configure Mongrel when REST services are requested" do @server.expects(:class_for_protocol).with(:rest).at_least_once.returns(Puppet::Network::HTTP::MongrelREST) @server.listen(@listen_params) end end describe "when providing XMLRPC services" do it "should do nothing if no xmlrpc handlers have been provided" do Puppet::Network::HTTPServer::Mongrel.expects(:new).never @server.listen(@listen_params.merge(:xmlrpc_handlers => [])) end it "should create an instance of the existing Mongrel http server with the right handlers" do Puppet::Network::HTTPServer::Mongrel.expects(:new).with([:status, :master]).returns(@mock_puppet_mongrel) @server.listen(@listen_params.merge(:xmlrpc_handlers => [:status, :master])) end it "should register the Mongrel server instance at /RPC2" do @mock_mongrel.expects(:register).with("/RPC2", @mock_puppet_mongrel) @server.listen(@listen_params.merge(:xmlrpc_handlers => [:status, :master])) end end end describe "Puppet::Network::HTTP::Mongrel", "when turning off listening", :if => Puppet.features.mongrel? do before do @mock_mongrel = mock('mongrel httpserver') @mock_mongrel.stubs(:run) @mock_mongrel.stubs(:register) Mongrel::HttpServer.stubs(:new).returns(@mock_mongrel) @server = Puppet::Network::HTTP::Mongrel.new @listen_params = { :address => "127.0.0.1", :port => 31337, :handlers => [ :node, :catalog ], :protocols => [ :rest ] } end it "should fail unless listening" do Proc.new { @server.unlisten }.should raise_error(RuntimeError) end it "should order mongrel server to stop" do @server.listen(@listen_params) @mock_mongrel.expects(:stop) @server.unlisten end it "should not be listening" do @server.listen(@listen_params) @mock_mongrel.stubs(:stop) @server.unlisten @server.should_not be_listening end end diff --git a/spec/unit/network/http/rack/rest_spec.rb b/spec/unit/network/http/rack/rest_spec.rb index daa3af351..8a5666f56 100755 --- a/spec/unit/network/http/rack/rest_spec.rb +++ b/spec/unit/network/http/rack/rest_spec.rb @@ -1,247 +1,246 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/network/http/rack' if Puppet.features.rack? require 'puppet/network/http/rack/rest' describe "Puppet::Network::HTTP::RackREST", :if => Puppet.features.rack? do it "should include the Puppet::Network::HTTP::Handler module" do Puppet::Network::HTTP::RackREST.ancestors.should be_include(Puppet::Network::HTTP::Handler) end describe "when initializing" do it "should call the Handler's initialization hook with its provided arguments" do Puppet::Network::HTTP::RackREST.any_instance.expects(:initialize_for_puppet).with(:server => "my", :handler => "arguments") Puppet::Network::HTTP::RackREST.new(:server => "my", :handler => "arguments") end end describe "when serving a request" do before :all do @model_class = stub('indirected model class') Puppet::Indirector::Indirection.stubs(:model).with(:foo).returns(@model_class) @handler = Puppet::Network::HTTP::RackREST.new(:handler => :foo) end before :each do @response = Rack::Response.new end def mk_req(uri, opts = {}) env = Rack::MockRequest.env_for(uri, opts) Rack::Request.new(env) end describe "and using the HTTP Handler interface" do it "should return the HTTP_ACCEPT parameter as the accept header" do req = mk_req('/', 'HTTP_ACCEPT' => 'myaccept') @handler.accept_header(req).should == "myaccept" end it "should return the CONTENT_TYPE parameter as the content type header" do req = mk_req('/', 'CONTENT_TYPE' => 'mycontent') @handler.content_type_header(req).should == "mycontent" end it "should use the REQUEST_METHOD as the http method" do req = mk_req('/', :method => 'MYMETHOD') @handler.http_method(req).should == "MYMETHOD" end it "should return the request path as the path" do req = mk_req('/foo/bar') @handler.path(req).should == "/foo/bar" end it "should return the request body as the body" do req = mk_req('/foo/bar', :input => 'mybody') @handler.body(req).should == "mybody" end it "should set the response's content-type header when setting the content type" do @header = mock 'header' @response.expects(:header).returns @header @header.expects(:[]=).with('Content-Type', "mytype") @handler.set_content_type(@response, "mytype") end it "should set the status and write the body when setting the response for a request" do @response.expects(:status=).with(400) @response.expects(:write).with("mybody") @handler.set_response(@response, "mybody", 400) end describe "when result is a File" do before :each do stat = stub 'stat', :size => 100 @file = stub 'file', :stat => stat, :path => "/tmp/path" @file.stubs(:is_a?).with(File).returns(true) end it "should set the Content-Length header as a string" do @response.expects(:[]=).with("Content-Length", '100') @handler.set_response(@response, @file, 200) end it "should return a RackFile adapter as body" do @response.expects(:body=).with { |val| val.is_a?(Puppet::Network::HTTP::RackREST::RackFile) } @handler.set_response(@response, @file, 200) end end end describe "and determining the request parameters" do it "should include the HTTP request parameters, with the keys as symbols" do req = mk_req('/?foo=baz&bar=xyzzy') result = @handler.params(req) result[:foo].should == "baz" result[:bar].should == "xyzzy" end it "should CGI-decode the HTTP parameters" do encoding = CGI.escape("foo bar") req = mk_req("/?foo=#{encoding}") result = @handler.params(req) result[:foo].should == "foo bar" end it "should convert the string 'true' to the boolean" do req = mk_req("/?foo=true") result = @handler.params(req) result[:foo].should be_true end it "should convert the string 'false' to the boolean" do req = mk_req("/?foo=false") result = @handler.params(req) result[:foo].should be_false end it "should convert integer arguments to Integers" do req = mk_req("/?foo=15") result = @handler.params(req) result[:foo].should == 15 end it "should convert floating point arguments to Floats" do req = mk_req("/?foo=1.5") result = @handler.params(req) result[:foo].should == 1.5 end it "should YAML-load and CGI-decode values that are YAML-encoded" do escaping = CGI.escape(YAML.dump(%w{one two})) req = mk_req("/?foo=#{escaping}") result = @handler.params(req) result[:foo].should == %w{one two} end it "should not allow the client to set the node via the query string" do req = mk_req("/?node=foo") @handler.params(req)[:node].should be_nil end it "should not allow the client to set the IP address via the query string" do req = mk_req("/?ip=foo") @handler.params(req)[:ip].should be_nil end it "should pass the client's ip address to model find" do req = mk_req("/", 'REMOTE_ADDR' => 'ipaddress') @handler.params(req)[:ip].should == "ipaddress" end it "should set 'authenticated' to false if no certificate is present" do req = mk_req('/') @handler.params(req)[:authenticated].should be_false end end describe "with pre-validated certificates" do it "should use the :ssl_client_header to determine the parameter when looking for the certificate" do Puppet.settings.stubs(:value).returns "eh" Puppet.settings.expects(:value).with(:ssl_client_header).returns "myheader" req = mk_req('/', "myheader" => "/CN=host.domain.com") @handler.params(req) end it "should retrieve the hostname by matching the certificate parameter" do Puppet.settings.stubs(:value).returns "eh" Puppet.settings.expects(:value).with(:ssl_client_header).returns "myheader" req = mk_req('/', "myheader" => "/CN=host.domain.com") @handler.params(req)[:node].should == "host.domain.com" end it "should use the :ssl_client_header to determine the parameter for checking whether the host certificate is valid" do Puppet.settings.stubs(:value).with(:ssl_client_header).returns "certheader" Puppet.settings.expects(:value).with(:ssl_client_verify_header).returns "myheader" req = mk_req('/', "myheader" => "SUCCESS", "certheader" => "/CN=host.domain.com") @handler.params(req) end it "should consider the host authenticated if the validity parameter contains 'SUCCESS'" do Puppet.settings.stubs(:value).with(:ssl_client_header).returns "certheader" Puppet.settings.stubs(:value).with(:ssl_client_verify_header).returns "myheader" req = mk_req('/', "myheader" => "SUCCESS", "certheader" => "/CN=host.domain.com") @handler.params(req)[:authenticated].should be_true end it "should consider the host unauthenticated if the validity parameter does not contain 'SUCCESS'" do Puppet.settings.stubs(:value).with(:ssl_client_header).returns "certheader" Puppet.settings.stubs(:value).with(:ssl_client_verify_header).returns "myheader" req = mk_req('/', "myheader" => "whatever", "certheader" => "/CN=host.domain.com") @handler.params(req)[:authenticated].should be_false end it "should consider the host unauthenticated if no certificate information is present" do Puppet.settings.stubs(:value).with(:ssl_client_header).returns "certheader" Puppet.settings.stubs(:value).with(:ssl_client_verify_header).returns "myheader" req = mk_req('/', "myheader" => nil, "certheader" => "/CN=host.domain.com") @handler.params(req)[:authenticated].should be_false end it "should resolve the node name with an ip address look-up if no certificate is present" do Puppet.settings.stubs(:value).returns "eh" Puppet.settings.expects(:value).with(:ssl_client_header).returns "myheader" req = mk_req('/', "myheader" => nil) @handler.expects(:resolve_node).returns("host.domain.com") @handler.params(req)[:node].should == "host.domain.com" end end end end describe Puppet::Network::HTTP::RackREST::RackFile do before(:each) do stat = stub 'stat', :size => 100 @file = stub 'file', :stat => stat, :path => "/tmp/path" @rackfile = Puppet::Network::HTTP::RackREST::RackFile.new(@file) end it "should have an each method" do @rackfile.should be_respond_to(:each) end it "should yield file chunks by chunks" do @file.expects(:read).times(3).with(8192).returns("1", "2", nil) i = 1 @rackfile.each do |chunk| chunk.to_i.should == i i += 1 end end it "should have a close method" do @rackfile.should be_respond_to(:close) end it "should delegate close to File close" do @file.expects(:close) @rackfile.close end end diff --git a/spec/unit/network/http/rack/xmlrpc_spec.rb b/spec/unit/network/http/rack/xmlrpc_spec.rb index 4b3023a36..9173438a6 100755 --- a/spec/unit/network/http/rack/xmlrpc_spec.rb +++ b/spec/unit/network/http/rack/xmlrpc_spec.rb @@ -1,156 +1,155 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/network/handler' require 'puppet/network/http/rack' if Puppet.features.rack? require 'puppet/network/http/rack/xmlrpc' if Puppet.features.rack? describe "Puppet::Network::HTTP::RackXMLRPC", :if => Puppet.features.rack? do describe "when initializing" do it "should create an Puppet::Network::XMLRPCServer" do Puppet::Network::XMLRPCServer.expects(:new).returns stub_everything Puppet::Network::HTTP::RackXMLRPC.new([]) end it "should create each handler" do handler = stub_everything 'handler' Puppet::Network::XMLRPCServer.any_instance.stubs(:add_handler) Puppet::Network::Handler.expects(:handler).returns(handler).times(2) Puppet::Network::HTTP::RackXMLRPC.new([:foo, :bar]) end it "should add each handler to the XMLRPCserver" do handler = stub_everything 'handler' Puppet::Network::Handler.stubs(:handler).returns(handler) Puppet::Network::XMLRPCServer.any_instance.expects(:add_handler).times(2) Puppet::Network::HTTP::RackXMLRPC.new([:foo, :bar]) end end describe "when serving a request" do before :each do foo_handler = stub_everything 'foo_handler' Puppet::Network::Handler.stubs(:handler).with(:foo).returns foo_handler Puppet::Network::XMLRPCServer.any_instance.stubs(:add_handler) Puppet::Network::XMLRPCServer.any_instance.stubs(:process).returns('') @handler = Puppet::Network::HTTP::RackXMLRPC.new([:foo]) end before :each do @response = Rack::Response.new end def mk_req(opts = {}) opts[:method] = 'POST' if !opts[:method] opts['CONTENT_TYPE'] = 'text/xml; foo=bar' if !opts['CONTENT_TYPE'] env = Rack::MockRequest.env_for('/RPC2', opts) Rack::Request.new(env) end it "should reject non-POST requests" do req = mk_req :method => 'PUT' @handler.process(req, @response) @response.status.should == 405 end it "should reject non text/xml requests" do req = mk_req 'CONTENT_TYPE' => 'yadda/plain' end it "should create a ClientRequest" do cr = Puppet::Network::ClientRequest.new(nil, '127.0.0.1', false) Puppet::Network::ClientRequest.expects(:new).returns cr req = mk_req @handler.process(req, @response) end it "should let xmlrpcserver process the request" do Puppet::Network::XMLRPCServer.any_instance.expects(:process).returns('yay') req = mk_req @handler.process(req, @response) end it "should report the response as OK" do req = mk_req @handler.process(req, @response) @response.status.should == 200 end it "should report the response with the correct content type" do req = mk_req @handler.process(req, @response) @response['Content-Type'].should == 'text/xml; charset=utf-8' end it "should set 'authenticated' to false if no certificate is present" do req = mk_req Puppet::Network::ClientRequest.expects(:new).with { |node,ip,authenticated| authenticated == false } @handler.process(req, @response) end it "should use the client's ip address" do req = mk_req 'REMOTE_ADDR' => 'ipaddress' Puppet::Network::ClientRequest.expects(:new).with { |node,ip,authenticated| ip == 'ipaddress' } @handler.process(req, @response) end describe "with pre-validated certificates" do it "should use the :ssl_client_header to determine the parameter when looking for the certificate" do Puppet.settings.stubs(:value).returns "eh" Puppet.settings.expects(:value).with(:ssl_client_header).returns "myheader" req = mk_req "myheader" => "/CN=host.domain.com" @handler.process(req, @response) end it "should retrieve the hostname by matching the certificate parameter" do Puppet.settings.stubs(:value).returns "eh" Puppet.settings.expects(:value).with(:ssl_client_header).returns "myheader" Puppet::Network::ClientRequest.expects(:new).with { |node,ip,authenticated| node == "host.domain.com" } req = mk_req "myheader" => "/CN=host.domain.com" @handler.process(req, @response) end it "should use the :ssl_client_header to determine the parameter for checking whether the host certificate is valid" do Puppet.settings.stubs(:value).with(:ssl_client_header).returns "certheader" Puppet.settings.expects(:value).with(:ssl_client_verify_header).returns "myheader" req = mk_req "myheader" => "SUCCESS", "certheader" => "/CN=host.domain.com" @handler.process(req, @response) end it "should consider the host authenticated if the validity parameter contains 'SUCCESS'" do Puppet.settings.stubs(:value).with(:ssl_client_header).returns "certheader" Puppet.settings.stubs(:value).with(:ssl_client_verify_header).returns "myheader" Puppet::Network::ClientRequest.expects(:new).with { |node,ip,authenticated| authenticated == true } req = mk_req "myheader" => "SUCCESS", "certheader" => "/CN=host.domain.com" @handler.process(req, @response) end it "should consider the host unauthenticated if the validity parameter does not contain 'SUCCESS'" do Puppet.settings.stubs(:value).with(:ssl_client_header).returns "certheader" Puppet.settings.stubs(:value).with(:ssl_client_verify_header).returns "myheader" Puppet::Network::ClientRequest.expects(:new).with { |node,ip,authenticated| authenticated == false } req = mk_req "myheader" => "whatever", "certheader" => "/CN=host.domain.com" @handler.process(req, @response) end it "should consider the host unauthenticated if no certificate information is present" do Puppet.settings.stubs(:value).with(:ssl_client_header).returns "certheader" Puppet.settings.stubs(:value).with(:ssl_client_verify_header).returns "myheader" Puppet::Network::ClientRequest.expects(:new).with { |node,ip,authenticated| authenticated == false } req = mk_req "myheader" => nil, "certheader" => "/CN=host.domain.com" @handler.process(req, @response) end it "should resolve the node name with an ip address look-up if no certificate is present" do Puppet.settings.stubs(:value).returns "eh" Puppet.settings.expects(:value).with(:ssl_client_header).returns "myheader" Resolv.any_instance.expects(:getname).returns("host.domain.com") Puppet::Network::ClientRequest.expects(:new).with { |node,ip,authenticated| node == "host.domain.com" } req = mk_req "myheader" => nil @handler.process(req, @response) end end end end diff --git a/spec/unit/network/http/rack_spec.rb b/spec/unit/network/http/rack_spec.rb index bf61a1355..9e1ee3d1e 100755 --- a/spec/unit/network/http/rack_spec.rb +++ b/spec/unit/network/http/rack_spec.rb @@ -1,101 +1,100 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/network/handler' require 'puppet/network/http/rack' if Puppet.features.rack? describe "Puppet::Network::HTTP::Rack", :if => Puppet.features.rack? do describe "while initializing" do it "should require a protocol specification" do Proc.new { Puppet::Network::HTTP::Rack.new({}) }.should raise_error(ArgumentError) end it "should not accept imaginary protocols" do Proc.new { Puppet::Network::HTTP::Rack.new({:protocols => [:foo]}) }.should raise_error(ArgumentError) end it "should accept the REST protocol" do Proc.new { Puppet::Network::HTTP::Rack.new({:protocols => [:rest]}) }.should_not raise_error(ArgumentError) end it "should create a RackREST instance" do Puppet::Network::HTTP::RackREST.expects(:new) Puppet::Network::HTTP::Rack.new({:protocols => [:rest]}) end describe "with XMLRPC enabled" do it "should require XMLRPC handlers" do Proc.new { Puppet::Network::HTTP::Rack.new({:protocols => [:xmlrpc]}) }.should raise_error(ArgumentError) end it "should create a RackXMLRPC instance" do Puppet::Network::HTTP::RackXMLRPC.expects(:new) Puppet::Network::HTTP::Rack.new({:protocols => [:xmlrpc], :xmlrpc_handlers => [:Status]}) end end end describe "when called" do before :all do @app = Puppet::Network::HTTP::Rack.new({:protocols => [:rest]}) # let's use Rack::Lint to verify that we're OK with the rack specification @linted = Rack::Lint.new(@app) end before :each do @env = Rack::MockRequest.env_for('/') end it "should create a Request object" do request = Rack::Request.new(@env) Rack::Request.expects(:new).returns request @linted.call(@env) end it "should create a Response object" do Rack::Response.expects(:new).returns stub_everything @app.call(@env) # can't lint when Rack::Response is a stub end it "should let RackREST process the request" do Puppet::Network::HTTP::RackREST.any_instance.expects(:process).once @linted.call(@env) end it "should catch unhandled exceptions from RackREST" do Puppet::Network::HTTP::RackREST.any_instance.expects(:process).raises(ArgumentError, 'test error') Proc.new { @linted.call(@env) }.should_not raise_error end it "should finish() the Response" do Rack::Response.any_instance.expects(:finish).once @app.call(@env) # can't lint when finish is a stub end end describe "when serving XMLRPC" do before :all do @app = Puppet::Network::HTTP::Rack.new({:protocols => [:rest, :xmlrpc], :xmlrpc_handlers => [:Status]}) @linted = Rack::Lint.new(@app) end before :each do @env = Rack::MockRequest.env_for('/RPC2', :method => 'POST') end it "should use RackXMLRPC to serve /RPC2 requests" do Puppet::Network::HTTP::RackXMLRPC.any_instance.expects(:process).once @linted.call(@env) end end end diff --git a/spec/unit/network/http/webrick/rest_spec.rb b/spec/unit/network/http/webrick/rest_spec.rb index c582ac046..267ddcc72 100755 --- a/spec/unit/network/http/webrick/rest_spec.rb +++ b/spec/unit/network/http/webrick/rest_spec.rb @@ -1,181 +1,180 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/network/http' require 'webrick' require 'puppet/network/http/webrick/rest' describe Puppet::Network::HTTP::WEBrickREST do it "should include the Puppet::Network::HTTP::Handler module" do Puppet::Network::HTTP::WEBrickREST.ancestors.should be_include(Puppet::Network::HTTP::Handler) end describe "when initializing" do it "should call the Handler's initialization hook with its provided arguments as the server and handler" do Puppet::Network::HTTP::WEBrickREST.any_instance.expects(:initialize_for_puppet).with(:server => "my", :handler => "arguments") Puppet::Network::HTTP::WEBrickREST.new("my", "arguments") end end describe "when receiving a request" do before do @request = stub('webrick http request', :query => {}, :peeraddr => %w{eh boo host ip}, :client_cert => nil) @response = stub('webrick http response', :status= => true, :body= => true) @model_class = stub('indirected model class') @webrick = stub('webrick http server', :mount => true, :[] => {}) Puppet::Indirector::Indirection.stubs(:model).with(:foo).returns(@model_class) @handler = Puppet::Network::HTTP::WEBrickREST.new(@webrick, :foo) end it "should delegate its :service method to its :process method" do @handler.expects(:process).with(@request, @response).returns "stuff" @handler.service(@request, @response).should == "stuff" end describe "when using the Handler interface" do it "should use the 'accept' request parameter as the Accept header" do @request.expects(:[]).with("accept").returns "foobar" @handler.accept_header(@request).should == "foobar" end it "should use the 'content-type' request header as the Content-Type header" do @request.expects(:[]).with("content-type").returns "foobar" @handler.content_type_header(@request).should == "foobar" end it "should use the request method as the http method" do @request.expects(:request_method).returns "FOO" @handler.http_method(@request).should == "FOO" end it "should return the request path as the path" do @request.expects(:path).returns "/foo/bar" @handler.path(@request).should == "/foo/bar" end it "should return the request body as the body" do @request.expects(:body).returns "my body" @handler.body(@request).should == "my body" end it "should set the response's 'content-type' header when setting the content type" do @response.expects(:[]=).with("content-type", "text/html") @handler.set_content_type(@response, "text/html") end it "should set the status and body on the response when setting the response for a successful query" do @response.expects(:status=).with 200 @response.expects(:body=).with "mybody" @handler.set_response(@response, "mybody", 200) end describe "when the result is a File" do before(:each) do stat = stub 'stat', :size => 100 @file = stub 'file', :stat => stat, :path => "/tmp/path" @file.stubs(:is_a?).with(File).returns(true) end it "should serve it" do @response.stubs(:[]=) @response.expects(:status=).with 200 @response.expects(:body=).with @file @handler.set_response(@response, @file, 200) end it "should set the Content-Length header" do @response.expects(:[]=).with('content-length', 100) @handler.set_response(@response, @file, 200) end end it "should set the status and message on the response when setting the response for a failed query" do @response.expects(:status=).with 400 @response.expects(:reason_phrase=).with "mybody" @handler.set_response(@response, "mybody", 400) end end describe "and determining the request parameters" do it "should include the HTTP request parameters, with the keys as symbols" do @request.stubs(:query).returns("foo" => "baz", "bar" => "xyzzy") result = @handler.params(@request) result[:foo].should == "baz" result[:bar].should == "xyzzy" end it "should CGI-decode the HTTP parameters" do encoding = CGI.escape("foo bar") @request.expects(:query).returns('foo' => encoding) result = @handler.params(@request) result[:foo].should == "foo bar" end it "should convert the string 'true' to the boolean" do @request.expects(:query).returns('foo' => "true") result = @handler.params(@request) result[:foo].should be_true end it "should convert the string 'false' to the boolean" do @request.expects(:query).returns('foo' => "false") result = @handler.params(@request) result[:foo].should be_false end it "should YAML-load and CGI-decode values that are YAML-encoded" do escaping = CGI.escape(YAML.dump(%w{one two})) @request.expects(:query).returns('foo' => escaping) result = @handler.params(@request) result[:foo].should == %w{one two} end it "should not allow clients to set the node via the request parameters" do @request.stubs(:query).returns("node" => "foo") @handler.stubs(:resolve_node) @handler.params(@request)[:node].should be_nil end it "should not allow clients to set the IP via the request parameters" do @request.stubs(:query).returns("ip" => "foo") @handler.params(@request)[:ip].should_not == "foo" end it "should pass the client's ip address to model find" do @request.stubs(:peeraddr).returns(%w{noidea dunno hostname ipaddress}) @handler.params(@request)[:ip].should == "ipaddress" end it "should set 'authenticated' to true if a certificate is present" do cert = stub 'cert', :subject => [%w{CN host.domain.com}] @request.stubs(:client_cert).returns cert @handler.params(@request)[:authenticated].should be_true end it "should set 'authenticated' to false if no certificate is present" do @request.stubs(:client_cert).returns nil @handler.params(@request)[:authenticated].should be_false end it "should pass the client's certificate name to model method if a certificate is present" do cert = stub 'cert', :subject => [%w{CN host.domain.com}] @request.stubs(:client_cert).returns cert @handler.params(@request)[:node].should == "host.domain.com" end it "should resolve the node name with an ip address look-up if no certificate is present" do @request.stubs(:client_cert).returns nil @handler.expects(:resolve_node).returns(:resolved_node) @handler.params(@request)[:node].should == :resolved_node end end end end diff --git a/spec/unit/network/http/webrick_spec.rb b/spec/unit/network/http/webrick_spec.rb index 7b7f46c5d..be74a1052 100755 --- a/spec/unit/network/http/webrick_spec.rb +++ b/spec/unit/network/http/webrick_spec.rb @@ -1,340 +1,340 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Created by Rick Bradley on 2007-10-15. # Copyright (c) 2007. All rights reserved. require 'spec_helper' require 'puppet/network/handler' require 'puppet/network/http' require 'puppet/network/http/webrick' describe Puppet::Network::HTTP::WEBrick, "after initializing" do it "should not be listening" do Puppet::Network::HTTP::WEBrick.new.should_not be_listening end end describe Puppet::Network::HTTP::WEBrick, "when turning on listening" do before do @mock_webrick = stub('webrick', :[] => {}, :listeners => [], :status => :Running) [:mount, :start, :shutdown].each {|meth| @mock_webrick.stubs(meth)} WEBrick::HTTPServer.stubs(:new).returns(@mock_webrick) @server = Puppet::Network::HTTP::WEBrick.new [:setup_logger, :setup_ssl].each {|meth| @server.stubs(meth).returns({})} # the empty hash is required because of how we're merging @listen_params = { :address => "127.0.0.1", :port => 31337, :xmlrpc_handlers => [], :protocols => [ :rest ] } end it "should fail if already listening" do @server.listen(@listen_params) Proc.new { @server.listen(@listen_params) }.should raise_error(RuntimeError) end it "should require at least one protocol" do Proc.new { @server.listen(@listen_params.delete_if {|k,v| :protocols == k}) }.should raise_error(ArgumentError) end it "should require a listening address to be specified" do Proc.new { @server.listen(@listen_params.delete_if {|k,v| :address == k})}.should raise_error(ArgumentError) end it "should require a listening port to be specified" do Proc.new { @server.listen(@listen_params.delete_if {|k,v| :port == k})}.should raise_error(ArgumentError) end it "should order a webrick server to start in a separate thread" do @mock_webrick.expects(:start) # If you remove this you'll sometimes get race condition problems Thread.expects(:new).yields @server.listen(@listen_params) end it "should tell webrick to listen on the specified address and port" do WEBrick::HTTPServer.expects(:new).with {|args| args[:Port] == 31337 and args[:BindAddress] == "127.0.0.1" }.returns(@mock_webrick) @server.listen(@listen_params) end it "should configure a logger for webrick" do @server.expects(:setup_logger).returns(:Logger => :mylogger) WEBrick::HTTPServer.expects(:new).with {|args| args[:Logger] == :mylogger }.returns(@mock_webrick) @server.listen(@listen_params) end it "should configure SSL for webrick" do @server.expects(:setup_ssl).returns(:Ssl => :testing, :Other => :yay) WEBrick::HTTPServer.expects(:new).with {|args| args[:Ssl] == :testing and args[:Other] == :yay }.returns(@mock_webrick) @server.listen(@listen_params) end it "should be listening" do @server.listen(@listen_params) @server.should be_listening end describe "when the REST protocol is requested" do it "should register the REST handler at /" do # We don't care about the options here. @mock_webrick.expects(:mount).with { |path, klass, options| path == "/" and klass == Puppet::Network::HTTP::WEBrickREST } @server.listen(@listen_params.merge(:protocols => [:rest])) end end describe "when the XMLRPC protocol is requested" do before do @servlet = mock 'servlet' Puppet::Network::XMLRPC::WEBrickServlet.stubs(:new).returns @servlet @master_handler = mock('master_handler') @file_handler = mock('file_handler') @master = mock 'master' @file = mock 'file' @master_handler.stubs(:new).returns @master @file_handler.stubs(:new).returns @file Puppet::Network::Handler.stubs(:handler).with(:master).returns @master_handler Puppet::Network::Handler.stubs(:handler).with(:fileserver).returns @file_handler end it "should do nothing if no xmlrpc handlers have been specified" do Puppet::Network::Handler.expects(:handler).never @server.listen(@listen_params.merge(:protocols => [:xmlrpc], :xmlrpc_handlers => [])) end it "should look the handler classes up via their base class" do Puppet::Network::Handler.expects(:handler).with(:master).returns @master_handler Puppet::Network::Handler.expects(:handler).with(:fileserver).returns @file_handler @server.listen(@listen_params.merge(:protocols => [:xmlrpc], :xmlrpc_handlers => [:master, :fileserver])) end it "should create an instance for each requested xmlrpc handler" do @master_handler.expects(:new).returns @master @file_handler.expects(:new).returns @file @server.listen(@listen_params.merge(:protocols => [:xmlrpc], :xmlrpc_handlers => [:master, :fileserver])) end it "should create a webrick servlet with the xmlrpc handler instances" do Puppet::Network::XMLRPC::WEBrickServlet.expects(:new).with([@master, @file]).returns @servlet @server.listen(@listen_params.merge(:protocols => [:xmlrpc], :xmlrpc_handlers => [:master, :fileserver])) end it "should mount the webrick servlet at /RPC2" do @mock_webrick.stubs(:mount) @mock_webrick.expects(:mount).with("/RPC2", @servlet) @server.listen(@listen_params.merge(:protocols => [:xmlrpc], :xmlrpc_handlers => [:master, :fileserver])) end end end describe Puppet::Network::HTTP::WEBrick, "when looking up the class to handle a protocol" do it "should require a protocol" do lambda { Puppet::Network::HTTP::WEBrick.class_for_protocol }.should raise_error(ArgumentError) end it "should accept a protocol" do lambda { Puppet::Network::HTTP::WEBrick.class_for_protocol("bob") }.should_not raise_error(ArgumentError) end it "should use a WEBrick + REST class when a REST protocol is specified" do Puppet::Network::HTTP::WEBrick.class_for_protocol("rest").should == Puppet::Network::HTTP::WEBrickREST end it "should fail when an unknown protocol is specified" do lambda { Puppet::Network::HTTP::WEBrick.class_for_protocol("abcdefg") }.should raise_error end end describe Puppet::Network::HTTP::WEBrick, "when turning off listening" do before do @mock_webrick = stub('webrick', :[] => {}, :listeners => [], :status => :Running) [:mount, :start, :shutdown].each {|meth| @mock_webrick.stubs(meth)} WEBrick::HTTPServer.stubs(:new).returns(@mock_webrick) @server = Puppet::Network::HTTP::WEBrick.new [:setup_logger, :setup_ssl].each {|meth| @server.stubs(meth).returns({})} # the empty hash is required because of how we're merging @listen_params = { :address => "127.0.0.1", :port => 31337, :handlers => [ :node, :catalog ], :protocols => [ :rest ] } end it "should fail unless listening" do Proc.new { @server.unlisten }.should raise_error(RuntimeError) end it "should order webrick server to stop" do @mock_webrick.expects(:shutdown) @server.listen(@listen_params) @server.unlisten end it "should no longer be listening" do @server.listen(@listen_params) @server.unlisten @server.should_not be_listening end end describe Puppet::Network::HTTP::WEBrick do before do @mock_webrick = stub('webrick', :[] => {}) [:mount, :start, :shutdown].each {|meth| @mock_webrick.stubs(meth)} WEBrick::HTTPServer.stubs(:new).returns(@mock_webrick) @server = Puppet::Network::HTTP::WEBrick.new end describe "when configuring an http logger" do before do Puppet.settings.stubs(:value).returns "something" Puppet.settings.stubs(:use) @filehandle = stub 'handle', :fcntl => nil, :sync => nil File.stubs(:open).returns @filehandle end it "should use the settings for :main, :ssl, and the process name" do Puppet.settings.stubs(:value).with(:name).returns "myname" Puppet.settings.expects(:use).with(:main, :ssl, "myname") @server.setup_logger end it "should use the masterlog if the run_mode is master" do Puppet.run_mode.stubs(:master?).returns(true) Puppet.settings.expects(:value).with(:masterhttplog).returns "/master/log" File.expects(:open).with("/master/log", "a+").returns @filehandle @server.setup_logger end it "should use the httplog if the run_mode is not master" do Puppet.run_mode.stubs(:master?).returns(false) Puppet.settings.expects(:value).with(:httplog).returns "/other/log" File.expects(:open).with("/other/log", "a+").returns @filehandle @server.setup_logger end describe "and creating the logging filehandle" do it "should set fcntl to 'Fcntl::F_SETFD, Fcntl::FD_CLOEXEC'" do @filehandle.expects(:fcntl).with(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) @server.setup_logger end it "should sync the filehandle" do @filehandle.expects(:sync) @server.setup_logger end end it "should create a new WEBrick::Log instance with the open filehandle" do WEBrick::Log.expects(:new).with(@filehandle) @server.setup_logger end it "should set debugging if the current loglevel is :debug" do Puppet::Util::Log.expects(:level).returns :debug WEBrick::Log.expects(:new).with { |handle, debug| debug == WEBrick::Log::DEBUG } @server.setup_logger end it "should return the logger as the main log" do logger = mock 'logger' WEBrick::Log.expects(:new).returns logger @server.setup_logger[:Logger].should == logger end it "should return the logger as the access log using both the Common and Referer log format" do logger = mock 'logger' WEBrick::Log.expects(:new).returns logger @server.setup_logger[:AccessLog].should == [ [logger, WEBrick::AccessLog::COMMON_LOG_FORMAT], [logger, WEBrick::AccessLog::REFERER_LOG_FORMAT] ] end end describe "when configuring ssl" do before do @key = stub 'key', :content => "mykey" @cert = stub 'cert', :content => "mycert" @host = stub 'host', :key => @key, :certificate => @cert, :name => "yay", :ssl_store => "mystore" Puppet::SSL::Certificate.indirection.stubs(:find).with('ca').returns @cert Puppet::SSL::Host.stubs(:localhost).returns @host end it "should use the key from the localhost SSL::Host instance" do Puppet::SSL::Host.expects(:localhost).returns @host @host.expects(:key).returns @key @server.setup_ssl[:SSLPrivateKey].should == "mykey" end it "should configure the certificate" do @server.setup_ssl[:SSLCertificate].should == "mycert" end it "should fail if no CA certificate can be found" do Puppet::SSL::Certificate.indirection.stubs(:find).with('ca').returns nil lambda { @server.setup_ssl }.should raise_error(Puppet::Error) end it "should specify the path to the CA certificate" do Puppet.settings.stubs(:value).returns "whatever" Puppet.settings.stubs(:value).with(:hostcrl).returns 'false' Puppet.settings.stubs(:value).with(:localcacert).returns '/ca/crt' @server.setup_ssl[:SSLCACertificateFile].should == "/ca/crt" end it "should start ssl immediately" do @server.setup_ssl[:SSLStartImmediately].should be_true end it "should enable ssl" do @server.setup_ssl[:SSLEnable].should be_true end it "should configure the verification method as 'OpenSSL::SSL::VERIFY_PEER'" do @server.setup_ssl[:SSLVerifyClient].should == OpenSSL::SSL::VERIFY_PEER end it "should add an x509 store" do Puppet.settings.stubs(:value).returns "whatever" Puppet.settings.stubs(:value).with(:hostcrl).returns '/my/crl' @host.expects(:ssl_store).returns "mystore" @server.setup_ssl[:SSLCertificateStore].should == "mystore" end it "should set the certificate name to 'nil'" do @server.setup_ssl[:SSLCertName].should be_nil end end end diff --git a/spec/unit/network/http_pool_spec.rb b/spec/unit/network/http_pool_spec.rb index 83f901f09..c5d3e0470 100755 --- a/spec/unit/network/http_pool_spec.rb +++ b/spec/unit/network/http_pool_spec.rb @@ -1,206 +1,206 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Created by Luke Kanies on 2007-11-26. # Copyright (c) 2007. All rights reserved. require 'spec_helper' require 'puppet/network/http_pool' describe Puppet::Network::HttpPool do after do Puppet::Util::Cacher.expire Puppet::Network::HttpPool.clear_http_instances Puppet::Network::HttpPool.instance_variable_set("@ssl_host", nil) end it "should have keep-alive disabled" do Puppet::Network::HttpPool::HTTP_KEEP_ALIVE.should be_false end it "should use the global SSL::Host instance to get its certificate information" do host = mock 'host' Puppet::SSL::Host.expects(:localhost).with.returns host Puppet::Network::HttpPool.ssl_host.should equal(host) end describe "when managing http instances" do def stub_settings(settings) settings.each do |param, value| Puppet.settings.stubs(:value).with(param).returns(value) end end before do # All of the cert stuff is tested elsewhere Puppet::Network::HttpPool.stubs(:cert_setup) end it "should return an http instance created with the passed host and port" do http = stub 'http', :use_ssl= => nil, :read_timeout= => nil, :open_timeout= => nil, :started? => false Net::HTTP.expects(:new).with("me", 54321, nil, nil).returns(http) Puppet::Network::HttpPool.http_instance("me", 54321).should equal(http) end it "should enable ssl on the http instance" do Puppet::Network::HttpPool.http_instance("me", 54321).instance_variable_get("@use_ssl").should be_true end it "should set the read timeout" do Puppet::Network::HttpPool.http_instance("me", 54321).read_timeout.should == 120 end it "should set the open timeout" do Puppet::Network::HttpPool.http_instance("me", 54321).open_timeout.should == 120 end it "should create the http instance with the proxy host and port set if the http_proxy is not set to 'none'" do stub_settings :http_proxy_host => "myhost", :http_proxy_port => 432, :configtimeout => 120 Puppet::Network::HttpPool.http_instance("me", 54321).open_timeout.should == 120 end describe "and http keep-alive is enabled" do before do Puppet::Network::HttpPool.stubs(:keep_alive?).returns true end it "should cache http instances" do stub_settings :http_proxy_host => "myhost", :http_proxy_port => 432, :configtimeout => 120 old = Puppet::Network::HttpPool.http_instance("me", 54321) Puppet::Network::HttpPool.http_instance("me", 54321).should equal(old) end it "should have a mechanism for getting a new http instance instead of the cached instance" do stub_settings :http_proxy_host => "myhost", :http_proxy_port => 432, :configtimeout => 120 old = Puppet::Network::HttpPool.http_instance("me", 54321) Puppet::Network::HttpPool.http_instance("me", 54321, true).should_not equal(old) end it "should close existing, open connections when requesting a new connection" do stub_settings :http_proxy_host => "myhost", :http_proxy_port => 432, :configtimeout => 120 old = Puppet::Network::HttpPool.http_instance("me", 54321) old.expects(:started?).returns(true) old.expects(:finish) Puppet::Network::HttpPool.http_instance("me", 54321, true) end it "should have a mechanism for clearing the http cache" do stub_settings :http_proxy_host => "myhost", :http_proxy_port => 432, :configtimeout => 120 old = Puppet::Network::HttpPool.http_instance("me", 54321) Puppet::Network::HttpPool.http_instance("me", 54321).should equal(old) old = Puppet::Network::HttpPool.http_instance("me", 54321) Puppet::Network::HttpPool.clear_http_instances Puppet::Network::HttpPool.http_instance("me", 54321).should_not equal(old) end it "should close open http connections when clearing the cache" do stub_settings :http_proxy_host => "myhost", :http_proxy_port => 432, :configtimeout => 120 one = Puppet::Network::HttpPool.http_instance("me", 54321) one.expects(:started?).returns(true) one.expects(:finish).returns(true) Puppet::Network::HttpPool.clear_http_instances end it "should not close unopened http connections when clearing the cache" do stub_settings :http_proxy_host => "myhost", :http_proxy_port => 432, :configtimeout => 120 one = Puppet::Network::HttpPool.http_instance("me", 54321) one.expects(:started?).returns(false) one.expects(:finish).never Puppet::Network::HttpPool.clear_http_instances end end describe "and http keep-alive is disabled" do before do Puppet::Network::HttpPool.stubs(:keep_alive?).returns false end it "should not cache http instances" do stub_settings :http_proxy_host => "myhost", :http_proxy_port => 432, :configtimeout => 120 old = Puppet::Network::HttpPool.http_instance("me", 54321) Puppet::Network::HttpPool.http_instance("me", 54321).should_not equal(old) end end after do Puppet::Network::HttpPool.clear_http_instances end end describe "when adding certificate information to http instances" do before do @http = mock 'http' [:cert_store=, :verify_mode=, :ca_file=, :cert=, :key=].each { |m| @http.stubs(m) } @store = stub 'store' @cert = stub 'cert', :content => "real_cert" @key = stub 'key', :content => "real_key" @host = stub 'host', :certificate => @cert, :key => @key, :ssl_store => @store Puppet[:confdir] = "/sometthing/else" Puppet.settings.stubs(:value).returns "/some/file" Puppet.settings.stubs(:value).with(:hostcert).returns "/host/cert" Puppet.settings.stubs(:value).with(:localcacert).returns "/local/ca/cert" FileTest.stubs(:exist?).with("/host/cert").returns true FileTest.stubs(:exist?).with("/local/ca/cert").returns true Puppet::Network::HttpPool.stubs(:ssl_host).returns @host end after do Puppet.settings.clear end it "should do nothing if no host certificate is on disk" do FileTest.expects(:exist?).with("/host/cert").returns false @http.expects(:cert=).never Puppet::Network::HttpPool.cert_setup(@http) end it "should do nothing if no local certificate is on disk" do FileTest.expects(:exist?).with("/local/ca/cert").returns false @http.expects(:cert=).never Puppet::Network::HttpPool.cert_setup(@http) end it "should add a certificate store from the ssl host" do @http.expects(:cert_store=).with(@store) Puppet::Network::HttpPool.cert_setup(@http) end it "should add the client certificate" do @http.expects(:cert=).with("real_cert") Puppet::Network::HttpPool.cert_setup(@http) end it "should add the client key" do @http.expects(:key=).with("real_key") Puppet::Network::HttpPool.cert_setup(@http) end it "should set the verify mode to OpenSSL::SSL::VERIFY_PEER" do @http.expects(:verify_mode=).with(OpenSSL::SSL::VERIFY_PEER) Puppet::Network::HttpPool.cert_setup(@http) end it "should set the ca file" do Puppet.settings.stubs(:value).returns "/some/file" FileTest.stubs(:exist?).with(Puppet[:hostcert]).returns true Puppet.settings.stubs(:value).with(:localcacert).returns "/ca/cert/file" FileTest.stubs(:exist?).with("/ca/cert/file").returns true @http.expects(:ca_file=).with("/ca/cert/file") Puppet::Network::HttpPool.cert_setup(@http) end it "should set up certificate information when creating http instances" do Puppet::Network::HttpPool.expects(:cert_setup).with { |i| i.is_a?(Net::HTTP) } Puppet::Network::HttpPool.http_instance("one", "two") end end end diff --git a/spec/unit/network/http_spec.rb b/spec/unit/network/http_spec.rb index 27b652c71..550c15bf7 100755 --- a/spec/unit/network/http_spec.rb +++ b/spec/unit/network/http_spec.rb @@ -1,35 +1,35 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Created by Rick Bradley on 2007-10-03. # Copyright (c) 2007. All rights reserved. require 'spec_helper' require 'puppet/network/http' describe Puppet::Network::HTTP do it "should return the webrick HTTP server class when asked for a webrick server" do Puppet::Network::HTTP.server_class_by_type(:webrick).should be(Puppet::Network::HTTP::WEBrick) end describe "when asked for a mongrel server" do if Puppet.features.mongrel? it "should return the mongrel server class" do Puppet::Network::HTTP.server_class_by_type(:mongrel).should be(Puppet::Network::HTTP::Mongrel) end else it "should fail" do lambda { Puppet::Network::HTTP.server_class_by_type(:mongrel) }.should raise_error(ArgumentError) end end end it "should fail to return the mongrel HTTP server class if mongrel is not available " do Puppet.features.expects(:mongrel?).returns(false) Proc.new { Puppet::Network::HTTP.server_class_by_type(:mongrel) }.should raise_error(ArgumentError) end it "should return an error when asked for an unknown server" do Proc.new { Puppet::Network::HTTP.server_class_by_type :foo }.should raise_error(ArgumentError) end end diff --git a/spec/unit/network/rest_authconfig_spec.rb b/spec/unit/network/rest_authconfig_spec.rb index 736521b54..499a14b78 100755 --- a/spec/unit/network/rest_authconfig_spec.rb +++ b/spec/unit/network/rest_authconfig_spec.rb @@ -1,139 +1,138 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/network/rest_authconfig' describe Puppet::Network::RestAuthConfig do DEFAULT_ACL = [ { :acl => "~ ^\/catalog\/([^\/]+)$", :method => :find, :allow => '$1', :authenticated => true }, # this one will allow all file access, and thus delegate # to fileserver.conf { :acl => "/file" }, { :acl => "/certificate_revocation_list/ca", :method => :find, :authenticated => true }, { :acl => "/report", :method => :save, :authenticated => true }, { :acl => "/certificate/ca", :method => :find, :authenticated => false }, { :acl => "/certificate/", :method => :find, :authenticated => false }, { :acl => "/certificate_request", :method => [:find, :save], :authenticated => false }, { :acl => "/status", :method => [:find], :authenticated => true }, ] before :each do FileTest.stubs(:exists?).returns(true) File.stubs(:stat).returns(stub('stat', :ctime => :now)) Time.stubs(:now).returns Time.now @authconfig = Puppet::Network::RestAuthConfig.new("dummy", false) @authconfig.stubs(:read) @acl = stub_everything 'rights' @authconfig.rights = @acl end it "should use the puppet default rest authorization file" do Puppet.expects(:[]).with(:rest_authconfig).returns("dummy") Puppet::Network::RestAuthConfig.new(nil, false) end it "should ask for authorization to the ACL subsystem" do params = {:ip => "127.0.0.1", :node => "me", :environment => :env, :authenticated => true} @acl.expects(:is_request_forbidden_and_why?).with("path", :save, "to/resource", params).returns(nil) @authconfig.allowed?("path", :save, "to/resource", params) end describe "when defining an acl with mk_acl" do it "should create a new right for each default acl" do @acl.expects(:newright).with(:path) @authconfig.mk_acl(:acl => :path) end it "should allow everyone for each default right" do @acl.expects(:allow).with(:path, "*") @authconfig.mk_acl(:acl => :path) end it "should restrict the ACL to a method" do @acl.expects(:restrict_method).with(:path, :method) @authconfig.mk_acl(:acl => :path, :method => :method) end it "should restrict the ACL to a specific authentication state" do @acl.expects(:restrict_authenticated).with(:path, :authentication) @authconfig.mk_acl(:acl => :path, :authenticated => :authentication) end end describe "when parsing the configuration file" do it "should check for missing ACL after reading the authconfig file" do File.stubs(:open) @authconfig.expects(:insert_default_acl) @authconfig.parse end end DEFAULT_ACL.each do |acl| it "should insert #{acl[:acl]} if not present" do @authconfig.rights.stubs(:[]).returns(true) @authconfig.rights.stubs(:[]).with(acl[:acl]).returns(nil) @authconfig.expects(:mk_acl).with { |h| h[:acl] == acl[:acl] } @authconfig.insert_default_acl end it "should not insert #{acl[:acl]} if present" do @authconfig.rights.stubs(:[]).returns(true) @authconfig.rights.stubs(:[]).with(acl).returns(true) @authconfig.expects(:mk_acl).never @authconfig.insert_default_acl end end it "should create default ACL entries if no file have been read" do Puppet::Network::RestAuthConfig.any_instance.stubs(:exists?).returns(false) Puppet::Network::RestAuthConfig.any_instance.expects(:insert_default_acl) Puppet::Network::RestAuthConfig.main end describe "when adding default ACLs" do DEFAULT_ACL.each do |acl| it "should create a default right for #{acl[:acl]}" do @authconfig.stubs(:mk_acl) @authconfig.expects(:mk_acl).with(acl) @authconfig.insert_default_acl end end it "should log at info loglevel" do Puppet.expects(:info).at_least_once @authconfig.insert_default_acl end it "should create a last catch-all deny all rule" do @authconfig.stubs(:mk_acl) @acl.expects(:newright).with("/") @authconfig.insert_default_acl end it "should create a last catch-all deny all rule for any authenticated request state" do @authconfig.stubs(:mk_acl) @acl.stubs(:newright).with("/") @acl.expects(:restrict_authenticated).with("/", :any) @authconfig.insert_default_acl end end end diff --git a/spec/unit/network/rights_spec.rb b/spec/unit/network/rights_spec.rb index 70e38ba24..b709f10fa 100755 --- a/spec/unit/network/rights_spec.rb +++ b/spec/unit/network/rights_spec.rb @@ -1,539 +1,538 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/network/rights' describe Puppet::Network::Rights do before do @right = Puppet::Network::Rights.new end describe "when validating a :head request" do [:find, :save].each do |allowed_method| it "should allow the request if only #{allowed_method} is allowed" do rights = Puppet::Network::Rights.new rights.newright("/") rights.allow("/", "*") rights.restrict_method("/", allowed_method) rights.restrict_authenticated("/", :any) rights.is_request_forbidden_and_why?(:indirection_name, :head, "key", {}).should == nil end end it "should disallow the request if neither :find nor :save is allowed" do rights = Puppet::Network::Rights.new why_forbidden = rights.is_request_forbidden_and_why?(:indirection_name, :head, "key", {}) why_forbidden.should be_instance_of(Puppet::Network::AuthorizationError) why_forbidden.to_s.should == "Forbidden request: access to /indirection_name/key [find]" end end [:allow, :deny, :restrict_method, :restrict_environment, :restrict_authenticated].each do |m| it "should have a #{m} method" do @right.should respond_to(m) end describe "when using #{m}" do it "should delegate to the correct acl" do acl = stub 'acl' @right.stubs(:[]).returns(acl) acl.expects(m).with("me") @right.send(m, 'thisacl', "me") end end end it "should throw an error if type can't be determined" do lambda { @right.newright("name") }.should raise_error end describe "when creating new namespace ACLs" do it "should throw an error if the ACL already exists" do @right.newright("[name]") lambda { @right.newright("[name]") }.should raise_error end it "should create a new ACL with the correct name" do @right.newright("[name]") @right["name"].key.should == :name end it "should create an ACL of type Puppet::Network::AuthStore" do @right.newright("[name]") @right["name"].should be_a_kind_of(Puppet::Network::AuthStore) end end describe "when creating new path ACLs" do it "should not throw an error if the ACL already exists" do @right.newright("/name") lambda { @right.newright("/name")}.should_not raise_error end it "should throw an error if the acl uri path is not absolute" do lambda { @right.newright("name")}.should raise_error end it "should create a new ACL with the correct path" do @right.newright("/name") @right["/name"].should_not be_nil end it "should create an ACL of type Puppet::Network::AuthStore" do @right.newright("/name") @right["/name"].should be_a_kind_of(Puppet::Network::AuthStore) end end describe "when creating new regex ACLs" do it "should not throw an error if the ACL already exists" do @right.newright("~ .rb$") lambda { @right.newright("~ .rb$")}.should_not raise_error end it "should create a new ACL with the correct regex" do @right.newright("~ .rb$") @right.include?(".rb$").should_not be_nil end it "should be able to lookup the regex" do @right.newright("~ .rb$") @right[".rb$"].should_not be_nil end it "should be able to lookup the regex by its full name" do @right.newright("~ .rb$") @right["~ .rb$"].should_not be_nil end it "should create an ACL of type Puppet::Network::AuthStore" do @right.newright("~ .rb$").should be_a_kind_of(Puppet::Network::AuthStore) end end describe "when checking ACLs existence" do it "should return false if there are no matching rights" do @right.include?("name").should be_false end it "should return true if a namespace rights exist" do @right.newright("[name]") @right.include?("name").should be_true end it "should return false if no matching namespace rights exist" do @right.newright("[name]") @right.include?("notname").should be_false end it "should return true if a path right exists" do @right.newright("/name") @right.include?("/name").should be_true end it "should return false if no matching path rights exist" do @right.newright("/name") @right.include?("/differentname").should be_false end it "should return true if a regex right exists" do @right.newright("~ .rb$") @right.include?(".rb$").should be_true end it "should return false if no matching path rights exist" do @right.newright("~ .rb$") @right.include?(".pp$").should be_false end end describe "when checking if right is allowed" do before :each do @right.stubs(:right).returns(nil) @pathacl = stub 'pathacl', :acl_type => :regex, :"<=>" => 1, :line => 0, :file => 'dummy' Puppet::Network::Rights::Right.stubs(:new).returns(@pathacl) end it "should delegate to is_forbidden_and_why?" do @right.expects(:is_forbidden_and_why?).with("namespace", :node => "host.domain.com", :ip => "127.0.0.1").returns(nil) @right.allowed?("namespace", "host.domain.com", "127.0.0.1") end it "should return true if is_forbidden_and_why? returns nil" do @right.stubs(:is_forbidden_and_why?).returns(nil) @right.allowed?("namespace", :args).should be_true end it "should return false if is_forbidden_and_why? returns an AuthorizationError" do @right.stubs(:is_forbidden_and_why?).returns(Puppet::Network::AuthorizationError.new("forbidden")) @right.allowed?("namespace", :args1, :args2).should be_false end it "should first check namespace rights" do acl = stub 'acl', :acl_type => :name, :key => :namespace Puppet::Network::Rights::Right.stubs(:new).returns(acl) @right.newright("[namespace]") acl.expects(:match?).returns(true) acl.expects(:allowed?).with { |node,ip,h| node == "node" and ip == "ip" }.returns(true) @right.is_forbidden_and_why?("namespace", { :node => "node", :ip => "ip" } ).should == nil end it "should then check for path rights if no namespace match" do acl = stub 'nmacl', :acl_type => :name, :key => :namespace, :"<=>" => -1, :line => 0, :file => 'dummy' acl.stubs(:match?).returns(false) Puppet::Network::Rights::Right.stubs(:new).with("[namespace]").returns(acl) @right.newright("[namespace]") @right.newright("/path/to/there", 0, nil) @pathacl.stubs(:match?).returns(true) acl.expects(:allowed?).never @pathacl.expects(:allowed?).returns(true) @right.is_forbidden_and_why?("/path/to/there", {}).should == nil end it "should pass the match? return to allowed?" do @right.newright("/path/to/there") @pathacl.expects(:match?).returns(:match) @pathacl.expects(:allowed?).with { |node,ip,h| h[:match] == :match }.returns(true) @right.is_forbidden_and_why?("/path/to/there", {}).should == nil end describe "with namespace acls" do it "should return an ArgumentError if this namespace right doesn't exist" do lambda { @right.is_forbidden_and_why?("namespace") }.should raise_error(ArgumentError) end end describe "with path acls" do before :each do @long_acl = stub 'longpathacl', :name => "/path/to/there", :acl_type => :regex, :line => 0, :file => 'dummy' Puppet::Network::Rights::Right.stubs(:new).with("/path/to/there", 0, nil).returns(@long_acl) @short_acl = stub 'shortpathacl', :name => "/path/to", :acl_type => :regex, :line => 0, :file => 'dummy' Puppet::Network::Rights::Right.stubs(:new).with("/path/to", 0, nil).returns(@short_acl) @long_acl.stubs(:"<=>").with(@short_acl).returns(0) @short_acl.stubs(:"<=>").with(@long_acl).returns(0) end it "should select the first match" do @right.newright("/path/to/there", 0) @right.newright("/path/to", 0) @long_acl.stubs(:match?).returns(true) @short_acl.stubs(:match?).returns(true) @long_acl.expects(:allowed?).returns(true) @short_acl.expects(:allowed?).never @right.is_forbidden_and_why?("/path/to/there/and/there", {}).should == nil end it "should select the first match that doesn't return :dunno" do @right.newright("/path/to/there", 0, nil) @right.newright("/path/to", 0, nil) @long_acl.stubs(:match?).returns(true) @short_acl.stubs(:match?).returns(true) @long_acl.expects(:allowed?).returns(:dunno) @short_acl.expects(:allowed?).returns(true) @right.is_forbidden_and_why?("/path/to/there/and/there", {}).should == nil end it "should not select an ACL that doesn't match" do @right.newright("/path/to/there", 0) @right.newright("/path/to", 0) @long_acl.stubs(:match?).returns(false) @short_acl.stubs(:match?).returns(true) @long_acl.expects(:allowed?).never @short_acl.expects(:allowed?).returns(true) @right.is_forbidden_and_why?("/path/to/there/and/there", {}).should == nil end it "should not raise an AuthorizationError if allowed" do @right.newright("/path/to/there", 0) @long_acl.stubs(:match?).returns(true) @long_acl.stubs(:allowed?).returns(true) @right.is_forbidden_and_why?("/path/to/there/and/there", {}).should == nil end it "should raise an AuthorizationError if the match is denied" do @right.newright("/path/to/there", 0, nil) @long_acl.stubs(:match?).returns(true) @long_acl.stubs(:allowed?).returns(false) @right.is_forbidden_and_why?("/path/to/there", {}).should be_instance_of(Puppet::Network::AuthorizationError) end it "should raise an AuthorizationError if no path match" do @right.is_forbidden_and_why?("/nomatch", {}).should be_instance_of(Puppet::Network::AuthorizationError) end end describe "with regex acls" do before :each do @regex_acl1 = stub 'regex_acl1', :name => "/files/(.*)/myfile", :acl_type => :regex, :line => 0, :file => 'dummy' Puppet::Network::Rights::Right.stubs(:new).with("~ /files/(.*)/myfile", 0, nil).returns(@regex_acl1) @regex_acl2 = stub 'regex_acl2', :name => "/files/(.*)/myfile/", :acl_type => :regex, :line => 0, :file => 'dummy' Puppet::Network::Rights::Right.stubs(:new).with("~ /files/(.*)/myfile/", 0, nil).returns(@regex_acl2) @regex_acl1.stubs(:"<=>").with(@regex_acl2).returns(0) @regex_acl2.stubs(:"<=>").with(@regex_acl1).returns(0) end it "should select the first match" do @right.newright("~ /files/(.*)/myfile", 0) @right.newright("~ /files/(.*)/myfile/", 0) @regex_acl1.stubs(:match?).returns(true) @regex_acl2.stubs(:match?).returns(true) @regex_acl1.expects(:allowed?).returns(true) @regex_acl2.expects(:allowed?).never @right.is_forbidden_and_why?("/files/repository/myfile/other", {}).should == nil end it "should select the first match that doesn't return :dunno" do @right.newright("~ /files/(.*)/myfile", 0) @right.newright("~ /files/(.*)/myfile/", 0) @regex_acl1.stubs(:match?).returns(true) @regex_acl2.stubs(:match?).returns(true) @regex_acl1.expects(:allowed?).returns(:dunno) @regex_acl2.expects(:allowed?).returns(true) @right.is_forbidden_and_why?("/files/repository/myfile/other", {}).should == nil end it "should not select an ACL that doesn't match" do @right.newright("~ /files/(.*)/myfile", 0) @right.newright("~ /files/(.*)/myfile/", 0) @regex_acl1.stubs(:match?).returns(false) @regex_acl2.stubs(:match?).returns(true) @regex_acl1.expects(:allowed?).never @regex_acl2.expects(:allowed?).returns(true) @right.is_forbidden_and_why?("/files/repository/myfile/other", {}).should == nil end it "should not raise an AuthorizationError if allowed" do @right.newright("~ /files/(.*)/myfile", 0) @regex_acl1.stubs(:match?).returns(true) @regex_acl1.stubs(:allowed?).returns(true) @right.is_forbidden_and_why?("/files/repository/myfile/other", {}).should == nil end it "should raise an error if no regex acl match" do @right.is_forbidden_and_why?("/path", {}).should be_instance_of(Puppet::Network::AuthorizationError) end it "should raise an AuthorizedError on deny" do @right.is_forbidden_and_why?("/path", {}).should be_instance_of(Puppet::Network::AuthorizationError) end end end describe Puppet::Network::Rights::Right do before :each do @acl = Puppet::Network::Rights::Right.new("/path",0, nil) end describe "with path" do it "should say it's a regex ACL" do @acl.acl_type.should == :regex end it "should match up to its path length" do @acl.match?("/path/that/works").should_not be_nil end it "should match up to its path length" do @acl.match?("/paththatalsoworks").should_not be_nil end it "should return nil if no match" do @acl.match?("/notpath").should be_nil end end describe "with regex" do before :each do @acl = Puppet::Network::Rights::Right.new("~ .rb$",0, nil) end it "should say it's a regex ACL" do @acl.acl_type.should == :regex end it "should match as a regex" do @acl.match?("this should work.rb").should_not be_nil end it "should return nil if no match" do @acl.match?("do not match").should be_nil end end it "should allow all rest methods by default" do @acl.methods.should == Puppet::Network::Rights::Right::ALL end it "should allow only authenticated request by default" do @acl.authentication.should be_true end it "should allow modification of the methods filters" do @acl.restrict_method(:save) @acl.methods.should == [:save] end it "should stack methods filters" do @acl.restrict_method(:save) @acl.restrict_method(:destroy) @acl.methods.should == [:save, :destroy] end it "should raise an error if the method is already filtered" do @acl.restrict_method(:save) lambda { @acl.restrict_method(:save) }.should raise_error end it "should allow setting an environment filters" do Puppet::Node::Environment.stubs(:new).with(:environment).returns(:env) @acl.restrict_environment(:environment) @acl.environment.should == [:env] end ["on", "yes", "true", true].each do |auth| it "should allow filtering on authenticated requests with '#{auth}'" do @acl.restrict_authenticated(auth) @acl.authentication.should be_true end end ["off", "no", "false", false].each do |auth| it "should allow filtering on unauthenticated requests with '#{auth}'" do @acl.restrict_authenticated(auth) @acl.authentication.should be_false end end ["all", "any", :all, :any].each do |auth| it "should not use request authenticated state filtering with '#{auth}'" do @acl.restrict_authenticated(auth) @acl.authentication.should be_nil end end describe "when checking right authorization" do it "should return :dunno if this right is not restricted to the given method" do @acl.restrict_method(:destroy) @acl.allowed?("me","127.0.0.1", { :method => :save } ).should == :dunno end it "should return allow/deny if this right is restricted to the given method" do @acl.restrict_method(:save) @acl.allow("127.0.0.1") @acl.allowed?("me","127.0.0.1", { :method => :save }).should be_true end it "should return :dunno if this right is not restricted to the given environment" do Puppet::Node::Environment.stubs(:new).returns(:production) @acl.restrict_environment(:production) @acl.allowed?("me","127.0.0.1", { :method => :save, :environment => :development }).should == :dunno end it "should return :dunno if this right is not restricted to the given request authentication state" do @acl.restrict_authenticated(true) @acl.allowed?("me","127.0.0.1", { :method => :save, :authenticated => false }).should == :dunno end it "should return allow/deny if this right is restricted to the given request authentication state" do @acl.restrict_authenticated(false) @acl.allow("127.0.0.1") @acl.allowed?("me","127.0.0.1", { :authenticated => false }).should be_true end it "should interpolate allow/deny patterns with the given match" do @acl.expects(:interpolate).with(:match) @acl.allowed?("me","127.0.0.1", { :method => :save, :match => :match, :authenticated => true }) end it "should reset interpolation after the match" do @acl.expects(:reset_interpolation) @acl.allowed?("me","127.0.0.1", { :method => :save, :match => :match, :authenticated => true }) end # mocha doesn't allow testing super... # it "should delegate to the AuthStore for the result" do # @acl.method(:save) # # @acl.expects(:allowed?).with("me","127.0.0.1") # # @acl.allowed?("me","127.0.0.1", :save) # end end end end diff --git a/spec/unit/network/server_spec.rb b/spec/unit/network/server_spec.rb index f0f824272..912275a20 100755 --- a/spec/unit/network/server_spec.rb +++ b/spec/unit/network/server_spec.rb @@ -1,527 +1,527 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Created by Rick Bradley on 2007-10-03. # Copyright (c) 2007. All rights reserved. require 'spec_helper' require 'puppet/network/server' require 'puppet/network/handler' describe Puppet::Network::Server do before do @mock_http_server_class = mock('http server class') Puppet.settings.stubs(:use) Puppet.settings.stubs(:value).with(:name).returns("me") Puppet.settings.stubs(:value).with(:servertype).returns(:suparserver) Puppet.settings.stubs(:value).with(:bindaddress).returns("") Puppet.settings.stubs(:value).with(:masterport).returns(8140) Puppet::Network::HTTP.stubs(:server_class_by_type).returns(@mock_http_server_class) Puppet.settings.stubs(:value).with(:servertype).returns(:suparserver) @server = Puppet::Network::Server.new(:port => 31337) end describe "when initializing" do before do Puppet::Indirector::Indirection.stubs(:model).returns mock('indirection') Puppet::Network::Handler.stubs(:handler).returns mock('xmlrpc_handler') Puppet.settings.stubs(:value).with(:bindaddress).returns("") Puppet.settings.stubs(:value).with(:masterport).returns('') end it 'should fail if an unknown option is provided' do lambda { Puppet::Network::Server.new(:foo => 31337) }.should raise_error(ArgumentError) end it "should allow specifying a listening port" do Puppet.settings.stubs(:value).with(:bindaddress).returns('') @server = Puppet::Network::Server.new(:port => 31337) @server.port.should == 31337 end it "should use the :bindaddress setting to determine the default listening address" do Puppet.settings.stubs(:value).with(:masterport).returns('') Puppet.settings.expects(:value).with(:bindaddress).returns("10.0.0.1") @server = Puppet::Network::Server.new @server.address.should == "10.0.0.1" end it "should set the bind address to '127.0.0.1' if the default address is an empty string and the server type is mongrel" do Puppet.settings.stubs(:value).with(:servertype).returns("mongrel") Puppet.settings.expects(:value).with(:bindaddress).returns("") @server = Puppet::Network::Server.new @server.address.should == '127.0.0.1' end it "should set the bind address to '0.0.0.0' if the default address is an empty string and the server type is webrick" do Puppet.settings.stubs(:value).with(:servertype).returns("webrick") Puppet.settings.expects(:value).with(:bindaddress).returns("") @server = Puppet::Network::Server.new @server.address.should == '0.0.0.0' end it "should use the Puppet configurator to find a default listening port" do Puppet.settings.stubs(:value).with(:bindaddress).returns('') Puppet.settings.expects(:value).with(:masterport).returns(6667) @server = Puppet::Network::Server.new @server.port.should == 6667 end it "should fail to initialize if no listening port can be found" do Puppet.settings.stubs(:value).with(:bindaddress).returns("127.0.0.1") Puppet.settings.stubs(:value).with(:masterport).returns(nil) lambda { Puppet::Network::Server.new }.should raise_error(ArgumentError) end it "should use the Puppet configurator to determine which HTTP server will be used to provide access to clients" do Puppet.settings.expects(:value).with(:servertype).returns(:suparserver) @server = Puppet::Network::Server.new(:port => 31337) @server.server_type.should == :suparserver end it "should fail to initialize if there is no HTTP server known to the Puppet configurator" do Puppet.settings.expects(:value).with(:servertype).returns(nil) lambda { Puppet::Network::Server.new(:port => 31337) }.should raise_error end it "should ask the Puppet::Network::HTTP class to fetch the proper HTTP server class" do Puppet::Network::HTTP.expects(:server_class_by_type).with(:suparserver).returns(@mock_http_server_class) @server = Puppet::Network::Server.new(:port => 31337) end it "should fail if the HTTP server class is unknown" do Puppet::Network::HTTP.stubs(:server_class_by_type).returns(nil) lambda { Puppet::Network::Server.new(:port => 31337) }.should raise_error(ArgumentError) end it "should allow registering REST handlers" do @server = Puppet::Network::Server.new(:port => 31337, :handlers => [ :foo, :bar, :baz]) lambda { @server.unregister(:foo, :bar, :baz) }.should_not raise_error end it "should allow registering XMLRPC handlers" do @server = Puppet::Network::Server.new(:port => 31337, :xmlrpc_handlers => [ :foo, :bar, :baz]) lambda { @server.unregister_xmlrpc(:foo, :bar, :baz) }.should_not raise_error end it "should not be listening after initialization" do Puppet::Network::Server.new(:port => 31337).should_not be_listening end it "should use the :main setting section" do Puppet.settings.expects(:use).with { |*args| args.include?(:main) } @server = Puppet::Network::Server.new(:port => 31337, :xmlrpc_handlers => [ :foo, :bar, :baz]) end it "should use the Puppet[:name] setting section" do Puppet.settings.expects(:value).with(:name).returns "me" Puppet.settings.expects(:use).with { |*args| args.include?("me") } @server = Puppet::Network::Server.new(:port => 31337, :xmlrpc_handlers => [ :foo, :bar, :baz]) end end # We don't test the method, because it's too much of a Unix-y pain. it "should be able to daemonize" do @server.should respond_to(:daemonize) end describe "when being started" do before do @server.stubs(:listen) @server.stubs(:create_pidfile) end it "should listen" do @server.expects(:listen) @server.start end it "should create its PID file" do @server.expects(:create_pidfile) @server.start end end describe "when being stopped" do before do @server.stubs(:unlisten) @server.stubs(:remove_pidfile) end it "should unlisten" do @server.expects(:unlisten) @server.stop end it "should remove its PID file" do @server.expects(:remove_pidfile) @server.stop end end describe "when creating its pidfile" do it "should use an exclusive mutex" do Puppet.settings.expects(:value).with(:name).returns "me" Puppet::Util.expects(:synchronize_on).with("me",Sync::EX) @server.create_pidfile end it "should lock the pidfile using the Pidlock class" do pidfile = mock 'pidfile' Puppet.settings.stubs(:value).with(:name).returns "eh" Puppet.settings.expects(:value).with(:pidfile).returns "/my/file" Puppet::Util::Pidlock.expects(:new).with("/my/file").returns pidfile pidfile.expects(:lock).returns true @server.create_pidfile end it "should fail if it cannot lock" do pidfile = mock 'pidfile' Puppet.settings.stubs(:value).with(:name).returns "eh" Puppet.settings.stubs(:value).with(:pidfile).returns "/my/file" Puppet::Util::Pidlock.expects(:new).with("/my/file").returns pidfile pidfile.expects(:lock).returns false lambda { @server.create_pidfile }.should raise_error end end describe "when removing its pidfile" do it "should use an exclusive mutex" do Puppet.settings.expects(:value).with(:name).returns "me" Puppet::Util.expects(:synchronize_on).with("me",Sync::EX) @server.remove_pidfile end it "should do nothing if the pidfile is not present" do pidfile = mock 'pidfile', :locked? => false Puppet::Util::Pidlock.expects(:new).with("/my/file").returns pidfile Puppet.settings.stubs(:value).with(:name).returns "eh" Puppet.settings.stubs(:value).with(:pidfile).returns "/my/file" pidfile.expects(:unlock).never @server.remove_pidfile end it "should unlock the pidfile using the Pidlock class" do pidfile = mock 'pidfile', :locked? => true Puppet::Util::Pidlock.expects(:new).with("/my/file").returns pidfile pidfile.expects(:unlock).returns true Puppet.settings.stubs(:value).with(:name).returns "eh" Puppet.settings.stubs(:value).with(:pidfile).returns "/my/file" @server.remove_pidfile end it "should warn if it cannot remove the pidfile" do pidfile = mock 'pidfile', :locked? => true Puppet::Util::Pidlock.expects(:new).with("/my/file").returns pidfile pidfile.expects(:unlock).returns false Puppet.settings.stubs(:value).with(:name).returns "eh" Puppet.settings.stubs(:value).with(:pidfile).returns "/my/file" Puppet.expects :err @server.remove_pidfile end end describe "when managing indirection registrations" do before do Puppet::Indirector::Indirection.stubs(:model).returns mock('indirection') end it "should allow registering an indirection for client access by specifying its indirection name" do lambda { @server.register(:foo) }.should_not raise_error end it "should require that the indirection be valid" do Puppet::Indirector::Indirection.expects(:model).with(:foo).returns nil lambda { @server.register(:foo) }.should raise_error(ArgumentError) end it "should require at least one indirection name when registering indirections for client access" do lambda { @server.register }.should raise_error(ArgumentError) end it "should allow for numerous indirections to be registered at once for client access" do lambda { @server.register(:foo, :bar, :baz) }.should_not raise_error end it "should allow the use of indirection names to specify which indirections are to be no longer accessible to clients" do @server.register(:foo) lambda { @server.unregister(:foo) }.should_not raise_error end it "should leave other indirections accessible to clients when turning off indirections" do @server.register(:foo, :bar) @server.unregister(:foo) lambda { @server.unregister(:bar)}.should_not raise_error end it "should allow specifying numerous indirections which are to be no longer accessible to clients" do @server.register(:foo, :bar) lambda { @server.unregister(:foo, :bar) }.should_not raise_error end it "should not turn off any indirections if given unknown indirection names to turn off" do @server.register(:foo, :bar) lambda { @server.unregister(:foo, :bar, :baz) }.should raise_error(ArgumentError) lambda { @server.unregister(:foo, :bar) }.should_not raise_error end it "should not allow turning off unknown indirection names" do @server.register(:foo, :bar) lambda { @server.unregister(:baz) }.should raise_error(ArgumentError) end it "should disable client access immediately when turning off indirections" do @server.register(:foo, :bar) @server.unregister(:foo) lambda { @server.unregister(:foo) }.should raise_error(ArgumentError) end it "should allow turning off all indirections at once" do @server.register(:foo, :bar) @server.unregister [ :foo, :bar, :baz].each do |indirection| lambda { @server.unregister(indirection) }.should raise_error(ArgumentError) end end end it "should provide a means of determining whether it is listening" do @server.should respond_to(:listening?) end it "should provide a means of determining which HTTP server will be used to provide access to clients" do @server.server_type.should == :suparserver end it "should provide a means of determining which protocols are in use" do @server.should respond_to(:protocols) end it "should set the protocols to :rest and :xmlrpc" do @server.protocols.should == [ :rest, :xmlrpc ] end it "should provide a means of determining the listening address" do @server.address.should == "127.0.0.1" end it "should provide a means of determining the listening port" do @server.port.should == 31337 end it "should allow for multiple configurations, each handling different indirections" do Puppet::Indirector::Indirection.stubs(:model).returns mock('indirection') @server2 = Puppet::Network::Server.new(:port => 31337) @server.register(:foo, :bar) @server2.register(:foo, :xyzzy) @server.unregister(:foo, :bar) @server2.unregister(:foo, :xyzzy) lambda { @server.unregister(:xyzzy) }.should raise_error(ArgumentError) lambda { @server2.unregister(:bar) }.should raise_error(ArgumentError) end describe "when managing xmlrpc registrations" do before do Puppet::Network::Handler.stubs(:handler).returns mock('xmlrpc_handler') end it "should allow registering an xmlrpc handler by specifying its namespace" do lambda { @server.register_xmlrpc(:foo) }.should_not raise_error end it "should require that the xmlrpc namespace be valid" do Puppet::Network::Handler.stubs(:handler).returns nil lambda { @server.register_xmlrpc(:foo) }.should raise_error(ArgumentError) end it "should require at least one namespace" do lambda { @server.register_xmlrpc }.should raise_error(ArgumentError) end it "should allow multiple namespaces to be registered at once" do lambda { @server.register_xmlrpc(:foo, :bar) }.should_not raise_error end it "should allow the use of namespaces to specify which are no longer accessible to clients" do @server.register_xmlrpc(:foo, :bar) end it "should leave other namespaces accessible to clients when turning off xmlrpc namespaces" do @server.register_xmlrpc(:foo, :bar) @server.unregister_xmlrpc(:foo) lambda { @server.unregister_xmlrpc(:bar)}.should_not raise_error end it "should allow specifying numerous namespaces which are to be no longer accessible to clients" do @server.register_xmlrpc(:foo, :bar) lambda { @server.unregister_xmlrpc(:foo, :bar) }.should_not raise_error end it "should not turn off any indirections if given unknown namespaces to turn off" do @server.register_xmlrpc(:foo, :bar) lambda { @server.unregister_xmlrpc(:foo, :bar, :baz) }.should raise_error(ArgumentError) lambda { @server.unregister_xmlrpc(:foo, :bar) }.should_not raise_error end it "should not allow turning off unknown namespaces" do @server.register_xmlrpc(:foo, :bar) lambda { @server.unregister_xmlrpc(:baz) }.should raise_error(ArgumentError) end it "should disable client access immediately when turning off namespaces" do @server.register_xmlrpc(:foo, :bar) @server.unregister_xmlrpc(:foo) lambda { @server.unregister_xmlrpc(:foo) }.should raise_error(ArgumentError) end it "should allow turning off all namespaces at once" do @server.register_xmlrpc(:foo, :bar) @server.unregister_xmlrpc [ :foo, :bar, :baz].each do |indirection| lambda { @server.unregister_xmlrpc(indirection) }.should raise_error(ArgumentError) end end end describe "when listening is off" do before do @mock_http_server = mock('http server') @mock_http_server.stubs(:listen) @server.stubs(:http_server).returns(@mock_http_server) end it "should indicate that it is not listening" do @server.should_not be_listening end it "should not allow listening to be turned off" do lambda { @server.unlisten }.should raise_error(RuntimeError) end it "should allow listening to be turned on" do lambda { @server.listen }.should_not raise_error end end describe "when listening is on" do before do @mock_http_server = mock('http server') @mock_http_server.stubs(:listen) @mock_http_server.stubs(:unlisten) @server.stubs(:http_server).returns(@mock_http_server) @server.listen end it "should indicate that it is listening" do @server.should be_listening end it "should not allow listening to be turned on" do lambda { @server.listen }.should raise_error(RuntimeError) end it "should allow listening to be turned off" do lambda { @server.unlisten }.should_not raise_error end end describe "when listening is being turned on" do before do Puppet::Indirector::Indirection.stubs(:model).returns mock('indirection') Puppet::Network::Handler.stubs(:handler).returns mock('xmlrpc_handler') @server = Puppet::Network::Server.new(:port => 31337, :handlers => [:node], :xmlrpc_handlers => [:master]) @mock_http_server = mock('http server') @mock_http_server.stubs(:listen) end it "should fetch an instance of an HTTP server" do @server.stubs(:http_server_class).returns(@mock_http_server_class) @mock_http_server_class.expects(:new).returns(@mock_http_server) @server.listen end it "should cause the HTTP server to listen" do @server.stubs(:http_server).returns(@mock_http_server) @mock_http_server.expects(:listen) @server.listen end it "should pass the listening address to the HTTP server" do @server.stubs(:http_server).returns(@mock_http_server) @mock_http_server.expects(:listen).with do |args| args[:address] == '127.0.0.1' end @server.listen end it "should pass the listening port to the HTTP server" do @server.stubs(:http_server).returns(@mock_http_server) @mock_http_server.expects(:listen).with do |args| args[:port] == 31337 end @server.listen end it "should pass a list of REST handlers to the HTTP server" do @server.stubs(:http_server).returns(@mock_http_server) @mock_http_server.expects(:listen).with do |args| args[:handlers] == [ :node ] end @server.listen end it "should pass a list of XMLRPC handlers to the HTTP server" do @server.stubs(:http_server).returns(@mock_http_server) @mock_http_server.expects(:listen).with do |args| args[:xmlrpc_handlers] == [ :master ] end @server.listen end it "should pass a list of protocols to the HTTP server" do @server.stubs(:http_server).returns(@mock_http_server) @mock_http_server.expects(:listen).with do |args| args[:protocols] == [ :rest, :xmlrpc ] end @server.listen end end describe "when listening is being turned off" do before do @mock_http_server = mock('http server') @mock_http_server.stubs(:listen) @server.stubs(:http_server).returns(@mock_http_server) @server.listen end it "should cause the HTTP server to stop listening" do @mock_http_server.expects(:unlisten) @server.unlisten end it "should not allow for indirections to be turned off" do Puppet::Indirector::Indirection.stubs(:model).returns mock('indirection') @server.register(:foo) lambda { @server.unregister(:foo) }.should raise_error(RuntimeError) end end end diff --git a/spec/unit/network/xmlrpc/client_spec.rb b/spec/unit/network/xmlrpc/client_spec.rb index 012907a00..b9be0a906 100755 --- a/spec/unit/network/xmlrpc/client_spec.rb +++ b/spec/unit/network/xmlrpc/client_spec.rb @@ -1,172 +1,172 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec require 'puppet/network/client' require 'spec_helper' describe Puppet::Network::XMLRPCClient do describe "when performing the rpc call" do before do Puppet::SSL::Host.any_instance.stubs(:certificate_matches_key?).returns true @client = Puppet::Network::Client.report.xmlrpc_client.new @client.stubs(:call).returns "foo" end it "should call the specified namespace and method, with the specified arguments" do @client.expects(:call).with("puppetreports.report", "eh").returns "foo" @client.report("eh") end it "should return the results from the call" do @client.expects(:call).returns "foo" @client.report("eh").should == "foo" end it "should always close the http connection if it is still open after the call" do http = mock 'http' @client.stubs(:http).returns http http.expects(:started?).returns true http.expects(:finish) @client.report("eh").should == "foo" end it "should always close the http connection if it is still open after a call that raises an exception" do http = mock 'http' @client.stubs(:http).returns http @client.expects(:call).raises RuntimeError http.expects(:started?).returns true http.expects(:finish) lambda { @client.report("eh") }.should raise_error end describe "when returning the http instance" do it "should use the http pool to create the instance" do @client.instance_variable_set("@http", nil) @client.expects(:host).returns "myhost" @client.expects(:port).returns "myport" Puppet::Network::HttpPool.expects(:http_instance).with("myhost", "myport", true).returns "http" @client.http.should == "http" end it "should reuse existing instances" do @client.http.should equal(@client.http) end end describe "when recycling the connection" do it "should close the existing instance if it's open" do http = mock 'http' @client.stubs(:http).returns http http.expects(:started?).returns true http.expects(:finish) @client.recycle_connection end it "should force creation of a new instance" do Puppet::Network::HttpPool.expects(:http_instance).returns "second_http" @client.recycle_connection @client.http.should == "second_http" end end describe "and an exception is raised" do it "should raise XMLRPCClientError if XMLRPC::FaultException is raised" do error = XMLRPC::FaultException.new("foo", "bar") @client.expects(:call).raises(error) lambda { @client.report("eh") }.should raise_error(Puppet::Network::XMLRPCClientError) end it "should raise XMLRPCClientError if Errno::ECONNREFUSED is raised" do @client.expects(:call).raises(Errno::ECONNREFUSED) lambda { @client.report("eh") }.should raise_error(Puppet::Network::XMLRPCClientError) end it "should log and raise XMLRPCClientError if Timeout::Error is raised" do Puppet.expects(:err) @client.expects(:call).raises(Timeout::Error) lambda { @client.report("eh") }.should raise_error(Puppet::Network::XMLRPCClientError) end it "should log and raise XMLRPCClientError if SocketError is raised" do Puppet.expects(:err) @client.expects(:call).raises(SocketError) lambda { @client.report("eh") }.should raise_error(Puppet::Network::XMLRPCClientError) end it "should log, recycle the connection, and retry if Errno::EPIPE is raised" do @client.expects(:call).times(2).raises(Errno::EPIPE).then.returns "eh" Puppet.expects(:info) @client.expects(:recycle_connection) @client.report("eh") end it "should log, recycle the connection, and retry if EOFError is raised" do @client.expects(:call).times(2).raises(EOFError).then.returns "eh" Puppet.expects(:info) @client.expects(:recycle_connection) @client.report("eh") end it "should log and retry if an exception containing 'Wrong size' is raised" do error = RuntimeError.new("Wrong size. Was 15, should be 30") @client.expects(:call).times(2).raises(error).then.returns "eh" Puppet.expects(:warning) @client.report("eh") end it "should raise XMLRPCClientError if OpenSSL::SSL::SSLError is raised" do @client.expects(:call).raises(OpenSSL::SSL::SSLError) lambda { @client.report("eh") }.should raise_error(Puppet::Network::XMLRPCClientError) end it "should log and raise XMLRPCClientError if OpenSSL::SSL::SSLError is raised with certificate issues" do error = OpenSSL::SSL::SSLError.new("hostname was not match") @client.expects(:call).raises(error) Puppet.expects(:warning) lambda { @client.report("eh") }.should raise_error(Puppet::Network::XMLRPCClientError) end it "should log, recycle the connection, and retry if OpenSSL::SSL::SSLError is raised containing 'bad write retry'" do error = OpenSSL::SSL::SSLError.new("bad write retry") @client.expects(:call).times(2).raises(error).then.returns "eh" @client.expects(:recycle_connection) Puppet.expects(:warning) @client.report("eh") end it "should log and raise XMLRPCClientError if any other exception is raised" do @client.expects(:call).raises(RuntimeError) Puppet.expects(:err) lambda { @client.report("eh") }.should raise_error(Puppet::Network::XMLRPCClientError) end end end end diff --git a/spec/unit/node/environment_spec.rb b/spec/unit/node/environment_spec.rb index b8e7f6890..d1badfa3a 100755 --- a/spec/unit/node/environment_spec.rb +++ b/spec/unit/node/environment_spec.rb @@ -1,335 +1,334 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/node/environment' require 'puppet/util/execution' describe Puppet::Node::Environment do include PuppetSpec::Files after do Puppet::Node::Environment.clear end it "should include the Cacher module" do Puppet::Node::Environment.ancestors.should be_include(Puppet::Util::Cacher) end it "should use the filetimeout for the ttl for the modulepath" do Puppet::Node::Environment.attr_ttl(:modulepath).should == Integer(Puppet[:filetimeout]) end it "should use the filetimeout for the ttl for the module list" do Puppet::Node::Environment.attr_ttl(:modules).should == Integer(Puppet[:filetimeout]) end it "should use the filetimeout for the ttl for the manifestdir" do Puppet::Node::Environment.attr_ttl(:manifestdir).should == Integer(Puppet[:filetimeout]) end it "should use the default environment if no name is provided while initializing an environment" do Puppet.settings.expects(:value).with(:environment).returns("one") Puppet::Node::Environment.new.name.should == :one end it "should treat environment instances as singletons" do Puppet::Node::Environment.new("one").should equal(Puppet::Node::Environment.new("one")) end it "should treat an environment specified as names or strings as equivalent" do Puppet::Node::Environment.new(:one).should equal(Puppet::Node::Environment.new("one")) end it "should return its name when converted to a string" do Puppet::Node::Environment.new(:one).to_s.should == "one" end it "should just return any provided environment if an environment is provided as the name" do one = Puppet::Node::Environment.new(:one) Puppet::Node::Environment.new(one).should equal(one) end describe "when managing known resource types" do before do @env = Puppet::Node::Environment.new("dev") @collection = Puppet::Resource::TypeCollection.new(@env) @env.stubs(:perform_initial_import).returns(Puppet::Parser::AST::Hostclass.new('')) Thread.current[:known_resource_types] = nil end it "should create a resource type collection if none exists" do Puppet::Resource::TypeCollection.expects(:new).with(@env).returns @collection @env.known_resource_types.should equal(@collection) end it "should reuse any existing resource type collection" do @env.known_resource_types.should equal(@env.known_resource_types) end it "should perform the initial import when creating a new collection" do @env = Puppet::Node::Environment.new("dev") @env.expects(:perform_initial_import).returns(Puppet::Parser::AST::Hostclass.new('')) @env.known_resource_types end it "should return the same collection even if stale if it's the same thread" do Puppet::Resource::TypeCollection.stubs(:new).returns @collection @env.known_resource_types.stubs(:stale?).returns true @env.known_resource_types.should equal(@collection) end it "should return the current thread associated collection if there is one" do Thread.current[:known_resource_types] = @collection @env.known_resource_types.should equal(@collection) end it "should give to all threads using the same environment the same collection if the collection isn't stale" do original_thread_type_collection = Puppet::Resource::TypeCollection.new(@env) Puppet::Resource::TypeCollection.expects(:new).with(@env).returns original_thread_type_collection @env.known_resource_types.should equal(original_thread_type_collection) original_thread_type_collection.expects(:require_reparse?).returns(false) Puppet::Resource::TypeCollection.stubs(:new).with(@env).returns @collection t = Thread.new { @env.known_resource_types.should equal(original_thread_type_collection) } t.join end it "should generate a new TypeCollection if the current one requires reparsing" do old_type_collection = @env.known_resource_types old_type_collection.stubs(:require_reparse?).returns true Thread.current[:known_resource_types] = nil new_type_collection = @env.known_resource_types new_type_collection.should be_a Puppet::Resource::TypeCollection new_type_collection.should_not equal(old_type_collection) end end [:modulepath, :manifestdir].each do |setting| it "should validate the #{setting} directories" do path = %w{/one /two}.join(File::PATH_SEPARATOR) env = Puppet::Node::Environment.new("testing") env.stubs(:[]).with(setting).returns path env.expects(:validate_dirs).with(%w{/one /two}) env.send(setting) end it "should return the validated dirs for #{setting}" do path = %w{/one /two}.join(File::PATH_SEPARATOR) env = Puppet::Node::Environment.new("testing") env.stubs(:[]).with(setting).returns path env.stubs(:validate_dirs).returns %w{/one /two} env.send(setting).should == %w{/one /two} end end it "should prefix the value of the 'PUPPETLIB' environment variable to the module path if present" do Puppet::Util::Execution.withenv("PUPPETLIB" => %w{/l1 /l2}.join(File::PATH_SEPARATOR)) do env = Puppet::Node::Environment.new("testing") module_path = %w{/one /two}.join(File::PATH_SEPARATOR) env.expects(:validate_dirs).with(%w{/l1 /l2 /one /two}).returns %w{/l1 /l2 /one /two} env.expects(:[]).with(:modulepath).returns module_path env.modulepath.should == %w{/l1 /l2 /one /two} end end describe "when validating modulepath or manifestdir directories" do it "should not return non-directories" do env = Puppet::Node::Environment.new("testing") FileTest.expects(:directory?).with("/one").returns true FileTest.expects(:directory?).with("/two").returns false env.validate_dirs(%w{/one /two}).should == %w{/one} end it "should use the current working directory to fully-qualify unqualified paths" do FileTest.stubs(:directory?).returns true env = Puppet::Node::Environment.new("testing") two = File.join(Dir.getwd, "two") env.validate_dirs(%w{/one two}).should == ["/one", two] end end describe "when modeling a specific environment" do it "should have a method for returning the environment name" do Puppet::Node::Environment.new("testing").name.should == :testing end it "should provide an array-like accessor method for returning any environment-specific setting" do env = Puppet::Node::Environment.new("testing") env.should respond_to(:[]) end it "should ask the Puppet settings instance for the setting qualified with the environment name" do Puppet.settings.expects(:value).with("myvar", :testing).returns("myval") env = Puppet::Node::Environment.new("testing") env["myvar"].should == "myval" end it "should be able to return an individual module that exists in its module path" do env = Puppet::Node::Environment.new("testing") mod = mock 'module' Puppet::Module.expects(:new).with("one", env).returns mod mod.expects(:exist?).returns true env.module("one").should equal(mod) end it "should return nil if asked for a module that does not exist in its path" do env = Puppet::Node::Environment.new("testing") mod = mock 'module' Puppet::Module.expects(:new).with("one", env).returns mod mod.expects(:exist?).returns false env.module("one").should be_nil end it "should be able to return its modules" do Puppet::Node::Environment.new("testing").should respond_to(:modules) end describe ".modules" do it "should return a module named for every directory in each module path" do env = Puppet::Node::Environment.new("testing") env.expects(:modulepath).at_least_once.returns %w{/a /b} Dir.expects(:entries).with("/a").returns %w{foo bar} Dir.expects(:entries).with("/b").returns %w{bee baz} env.modules.collect{|mod| mod.name}.sort.should == %w{foo bar bee baz}.sort end it "should remove duplicates" do env = Puppet::Node::Environment.new("testing") env.expects(:modulepath).returns( %w{/a /b} ).at_least_once Dir.expects(:entries).with("/a").returns %w{foo} Dir.expects(:entries).with("/b").returns %w{foo} env.modules.collect{|mod| mod.name}.sort.should == %w{foo} end it "should ignore invalid modules" do env = Puppet::Node::Environment.new("testing") env.stubs(:modulepath).returns %w{/a} Dir.expects(:entries).with("/a").returns %w{foo bar} Puppet::Module.expects(:new).with { |name, env| name == "foo" }.returns mock("foomod", :name => "foo") Puppet::Module.expects(:new).with { |name, env| name == "bar" }.raises( Puppet::Module::InvalidName, "name is invalid" ) env.modules.collect{|mod| mod.name}.sort.should == %w{foo} end it "should create modules with the correct environment" do env = Puppet::Node::Environment.new("testing") env.expects(:modulepath).at_least_once.returns %w{/a} Dir.expects(:entries).with("/a").returns %w{foo} env.modules.each {|mod| mod.environment.should == env } end it "should cache the module list" do env = Puppet::Node::Environment.new("testing") env.expects(:modulepath).at_least_once.returns %w{/a} Dir.expects(:entries).once.with("/a").returns %w{foo} env.modules env.modules end end end describe Puppet::Node::Environment::Helper do before do @helper = Object.new @helper.extend(Puppet::Node::Environment::Helper) end it "should be able to set and retrieve the environment" do @helper.environment = :foo @helper.environment.name.should == :foo end it "should accept an environment directly" do env = Puppet::Node::Environment.new :foo @helper.environment = env @helper.environment.name.should == :foo end it "should accept an environment as a string" do env = Puppet::Node::Environment.new "foo" @helper.environment = env @helper.environment.name.should == :foo end end describe "when performing initial import" do before do @parser = Puppet::Parser::Parser.new("test") Puppet::Parser::Parser.stubs(:new).returns @parser @env = Puppet::Node::Environment.new("env") end it "should set the parser's string to the 'code' setting and parse if code is available" do Puppet.settings[:code] = "my code" @parser.expects(:string=).with "my code" @parser.expects(:parse) @env.instance_eval { perform_initial_import } end it "should set the parser's file to the 'manifest' setting and parse if no code is available and the manifest is available" do filename = tmpfile('myfile') File.open(filename, 'w'){|f| } Puppet.settings[:manifest] = filename @parser.expects(:file=).with filename @parser.expects(:parse) @env.instance_eval { perform_initial_import } end it "should pass the manifest file to the parser even if it does not exist on disk" do filename = tmpfile('myfile') Puppet.settings[:code] = "" Puppet.settings[:manifest] = filename @parser.expects(:file=).with(filename).once @parser.expects(:parse).once @env.instance_eval { perform_initial_import } end it "should fail helpfully if there is an error importing" do File.stubs(:exist?).returns true @env.stubs(:known_resource_types).returns Puppet::Resource::TypeCollection.new(@env) @parser.expects(:file=).once @parser.expects(:parse).raises ArgumentError lambda { @env.instance_eval { perform_initial_import } }.should raise_error(Puppet::Error) end it "should not do anything if the ignore_import settings is set" do Puppet.settings[:ignoreimport] = true @parser.expects(:string=).never @parser.expects(:file=).never @parser.expects(:parse).never @env.instance_eval { perform_initial_import } end it "should mark the type collection as needing a reparse when there is an error parsing" do @parser.expects(:parse).raises Puppet::ParseError.new("Syntax error at ...") @env.stubs(:known_resource_types).returns Puppet::Resource::TypeCollection.new(@env) lambda { @env.instance_eval { perform_initial_import } }.should raise_error(Puppet::Error, /Syntax error at .../) @env.known_resource_types.require_reparse?.should be_true end end end diff --git a/spec/unit/node/facts_spec.rb b/spec/unit/node/facts_spec.rb index b548e4d99..a130ae3f8 100755 --- a/spec/unit/node/facts_spec.rb +++ b/spec/unit/node/facts_spec.rb @@ -1,131 +1,130 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/node/facts' describe Puppet::Node::Facts, "when indirecting" do before do @facts = Puppet::Node::Facts.new("me") end it "should be able to convert all fact values to strings" do @facts.values["one"] = 1 @facts.stringify @facts.values["one"].should == "1" end it "should add the node's certificate name as the 'clientcert' fact when adding local facts" do @facts.add_local_facts @facts.values["clientcert"].should == Puppet.settings[:certname] end it "should add the Puppet version as a 'clientversion' fact when adding local facts" do @facts.add_local_facts @facts.values["clientversion"].should == Puppet.version.to_s end it "should add the current environment as a fact if one is not set when adding local facts" do @facts.add_local_facts @facts.values["environment"].should == Puppet[:environment] end it "should not replace any existing environment fact when adding local facts" do @facts.values["environment"] = "foo" @facts.add_local_facts @facts.values["environment"].should == "foo" end it "should be able to downcase fact values" do Puppet.settings.stubs(:value).returns "eh" Puppet.settings.expects(:value).with(:downcasefacts).returns true @facts.values["one"] = "Two" @facts.downcase_if_necessary @facts.values["one"].should == "two" end it "should only try to downcase strings" do Puppet.settings.stubs(:value).returns "eh" Puppet.settings.expects(:value).with(:downcasefacts).returns true @facts.values["now"] = Time.now @facts.downcase_if_necessary @facts.values["now"].should be_instance_of(Time) end it "should not downcase facts if not configured to do so" do Puppet.settings.stubs(:value).returns "eh" Puppet.settings.expects(:value).with(:downcasefacts).returns false @facts.values["one"] = "Two" @facts.downcase_if_necessary @facts.values["one"].should == "Two" end describe "when indirecting" do before do @indirection = stub 'indirection', :request => mock('request'), :name => :facts # We have to clear the cache so that the facts ask for our indirection stub, # instead of anything that might be cached. Puppet::Util::Cacher.expire @facts = Puppet::Node::Facts.new("me", "one" => "two") end it "should redirect to the specified fact store for storage" do Puppet::Node::Facts.stubs(:indirection).returns(@indirection) @indirection.expects(:save) Puppet::Node::Facts.indirection.save(@facts) end describe "when the Puppet application is 'master'" do it "should default to the 'yaml' terminus" do pending "Cannot test the behavior of defaults in defaults.rb" # Puppet::Node::Facts.indirection.terminus_class.should == :yaml end end describe "when the Puppet application is not 'master'" do it "should default to the 'facter' terminus" do pending "Cannot test the behavior of defaults in defaults.rb" # Puppet::Node::Facts.indirection.terminus_class.should == :facter end end end describe "when storing and retrieving" do it "should add metadata to the facts" do facts = Puppet::Node::Facts.new("me", "one" => "two", "three" => "four") facts.values[:_timestamp].should be_instance_of(Time) end describe "using pson" do before :each do @timestamp = Time.parse("Thu Oct 28 11:16:31 -0700 2010") @expiration = Time.parse("Thu Oct 28 11:21:31 -0700 2010") end it "should accept properly formatted pson" do pson = %Q({"name": "foo", "expiration": "#{@expiration}", "timestamp": "#{@timestamp}", "values": {"a": "1", "b": "2", "c": "3"}}) format = Puppet::Network::FormatHandler.format('pson') facts = format.intern(Puppet::Node::Facts,pson) facts.name.should == 'foo' facts.expiration.should == @expiration facts.values.should == {'a' => '1', 'b' => '2', 'c' => '3', :_timestamp => @timestamp} end it "should generate properly formatted pson" do Time.stubs(:now).returns(@timestamp) facts = Puppet::Node::Facts.new("foo", {'a' => 1, 'b' => 2, 'c' => 3}) facts.expiration = @expiration pson = PSON.parse(facts.to_pson) pson.should == {"name"=>"foo", "timestamp"=>@timestamp.to_s, "expiration"=>@expiration.to_s, "values"=>{"a"=>1, "b"=>2, "c"=>3}} end end end end diff --git a/spec/unit/node_spec.rb b/spec/unit/node_spec.rb index cd5fadada..7d813ba30 100755 --- a/spec/unit/node_spec.rb +++ b/spec/unit/node_spec.rb @@ -1,203 +1,202 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe Puppet::Node do describe "when managing its environment" do it "should use any set environment" do Puppet::Node.new("foo", :environment => "bar").environment.name.should == :bar end it "should support providing an actual environment instance" do Puppet::Node.new("foo", :environment => Puppet::Node::Environment.new(:bar)).environment.name.should == :bar end it "should determine its environment from its parameters if no environment is set" do Puppet::Node.new("foo", :parameters => {"environment" => :bar}).environment.name.should == :bar end it "should use the default environment if no environment is provided" do Puppet::Node.new("foo").environment.name.should == Puppet::Node::Environment.new.name end it "should always return an environment instance rather than a string" do Puppet::Node.new("foo").environment.should be_instance_of(Puppet::Node::Environment) end it "should allow the environment to be set after initialization" do node = Puppet::Node.new("foo") node.environment = :bar node.environment.name.should == :bar end it "should allow its environment to be set by parameters after initialization" do node = Puppet::Node.new("foo") node.parameters["environment"] = :bar node.environment.name.should == :bar end end end describe Puppet::Node, "when initializing" do before do @node = Puppet::Node.new("testnode") end it "should set the node name" do @node.name.should == "testnode" end it "should not allow nil node names" do proc { Puppet::Node.new(nil) }.should raise_error(ArgumentError) end it "should default to an empty parameter hash" do @node.parameters.should == {} end it "should default to an empty class array" do @node.classes.should == [] end it "should note its creation time" do @node.time.should be_instance_of(Time) end it "should accept parameters passed in during initialization" do params = {"a" => "b"} @node = Puppet::Node.new("testing", :parameters => params) @node.parameters.should == params end it "should accept classes passed in during initialization" do classes = %w{one two} @node = Puppet::Node.new("testing", :classes => classes) @node.classes.should == classes end it "should always return classes as an array" do @node = Puppet::Node.new("testing", :classes => "myclass") @node.classes.should == ["myclass"] end end describe Puppet::Node, "when merging facts" do before do @node = Puppet::Node.new("testnode") Puppet::Node::Facts.indirection.stubs(:find).with(@node.name).returns(Puppet::Node::Facts.new(@node.name, "one" => "c", "two" => "b")) end it "should fail intelligently if it cannot find facts" do Puppet::Node::Facts.indirection.expects(:find).with(@node.name).raises "foo" lambda { @node.fact_merge }.should raise_error(Puppet::Error) end it "should prefer parameters already set on the node over facts from the node" do @node = Puppet::Node.new("testnode", :parameters => {"one" => "a"}) @node.fact_merge @node.parameters["one"].should == "a" end it "should add passed parameters to the parameter list" do @node = Puppet::Node.new("testnode", :parameters => {"one" => "a"}) @node.fact_merge @node.parameters["two"].should == "b" end it "should accept arbitrary parameters to merge into its parameters" do @node = Puppet::Node.new("testnode", :parameters => {"one" => "a"}) @node.merge "two" => "three" @node.parameters["two"].should == "three" end it "should add the environment to the list of parameters" do Puppet.settings.stubs(:value).with(:environments).returns("one,two") Puppet.settings.stubs(:value).with(:environment).returns("one") @node = Puppet::Node.new("testnode", :environment => "one") @node.merge "two" => "three" @node.parameters["environment"].should == "one" end it "should not set the environment if it is already set in the parameters" do Puppet.settings.stubs(:value).with(:environments).returns("one,two") Puppet.settings.stubs(:value).with(:environment).returns("one") @node = Puppet::Node.new("testnode", :environment => "one") @node.merge "environment" => "two" @node.parameters["environment"].should == "two" end end describe Puppet::Node, "when indirecting" do it "should default to the 'plain' node terminus" do Puppet::Node.indirection.terminus_class.should == :plain end it "should not have a cache class defined" do Puppet::Node.indirection.cache_class.should be_nil end after do Puppet::Util::Cacher.expire end end describe Puppet::Node, "when generating the list of names to search through" do before do @node = Puppet::Node.new("foo.domain.com", :parameters => {"hostname" => "yay", "domain" => "domain.com"}) end it "should return an array of names" do @node.names.should be_instance_of(Array) end describe "and the node name is fully qualified" do it "should contain an entry for each part of the node name" do @node.names.should be_include("foo.domain.com") @node.names.should be_include("foo.domain") @node.names.should be_include("foo") end end it "should include the node's fqdn" do @node.names.should be_include("yay.domain.com") end it "should combine and include the node's hostname and domain if no fqdn is available" do @node.names.should be_include("yay.domain.com") end it "should contain an entry for each name available by stripping a segment of the fqdn" do @node.parameters["fqdn"] = "foo.deep.sub.domain.com" @node.names.should be_include("foo.deep.sub.domain") @node.names.should be_include("foo.deep.sub") end describe "and :node_name is set to 'cert'" do before do Puppet.settings.stubs(:value).with(:strict_hostname_checking).returns false Puppet.settings.stubs(:value).with(:node_name).returns "cert" end it "should use the passed-in key as the first value" do @node.names[0].should == "foo.domain.com" end describe "and strict hostname checking is enabled" do it "should only use the passed-in key" do Puppet.settings.expects(:value).with(:strict_hostname_checking).returns true @node.names.should == ["foo.domain.com"] end end end describe "and :node_name is set to 'facter'" do before do Puppet.settings.stubs(:value).with(:strict_hostname_checking).returns false Puppet.settings.stubs(:value).with(:node_name).returns "facter" end it "should use the node's 'hostname' fact as the first value" do @node.names[0].should == "yay" end end end diff --git a/spec/unit/other/selinux_spec.rb b/spec/unit/other/selinux_spec.rb index a936fdf9d..216feaf1f 100755 --- a/spec/unit/other/selinux_spec.rb +++ b/spec/unit/other/selinux_spec.rb @@ -1,94 +1,93 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/type/selboolean' require 'puppet/type/selmodule' describe Puppet::Type.type(:file), " when manipulating file contexts" do before :each do @file = Puppet::Type::File.new( :name => "/tmp/foo", :ensure => "file", :seluser => "user_u", :selrole => "role_r", :seltype => "type_t" ) end it "should use :seluser to get/set an SELinux user file context attribute" do @file.property(:seluser).should == "user_u" end it "should use :selrole to get/set an SELinux role file context attribute" do @file.property(:selrole).should == "role_r" end it "should use :seltype to get/set an SELinux user file context attribute" do @file.property(:seltype).should == "type_t" end end describe Puppet::Type.type(:selboolean), " when manipulating booleans" do before :each do provider_class = Puppet::Type::Selboolean.provider(Puppet::Type::Selboolean.providers[0]) Puppet::Type::Selboolean.stubs(:defaultprovider).returns provider_class @bool = Puppet::Type::Selboolean.new( :name => "foo", :value => "on", :persistent => true ) end it "should be able to access :name" do @bool[:name].should == "foo" end it "should be able to access :value" do @bool.property(:value).should == :on end it "should set :value to off" do @bool[:value] = :off @bool.property(:value).should == :off end it "should be able to access :persistent" do @bool[:persistent].should == :true end it "should set :persistent to false" do @bool[:persistent] = false @bool[:persistent].should == :false end end describe Puppet::Type.type(:selmodule), " when checking policy modules" do before :each do provider_class = Puppet::Type::Selmodule.provider(Puppet::Type::Selmodule.providers[0]) Puppet::Type::Selmodule.stubs(:defaultprovider).returns provider_class @module = Puppet::Type::Selmodule.new( :name => "foo", :selmoduledir => "/some/path", :selmodulepath => "/some/path/foo.pp", :syncversion => true) end it "should be able to access :name" do @module[:name].should == "foo" end it "should be able to access :selmoduledir" do @module[:selmoduledir].should == "/some/path" end it "should be able to access :selmodulepath" do @module[:selmodulepath].should == "/some/path/foo.pp" end it "should be able to access :syncversion" do @module.property(:syncversion).should == :true end it "should set the syncversion value to false" do @module[:syncversion] = :false @module.property(:syncversion).should == :false end end diff --git a/spec/unit/other/transbucket_spec.rb b/spec/unit/other/transbucket_spec.rb index 8b8cdeb0f..b95a4abca 100755 --- a/spec/unit/other/transbucket_spec.rb +++ b/spec/unit/other/transbucket_spec.rb @@ -1,188 +1,187 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe Puppet::TransBucket do before do @bucket = Puppet::TransBucket.new end it "should be able to produce a RAL component" do @bucket.name = "luke" @bucket.type = "foo" resource = nil proc { resource = @bucket.to_ral }.should_not raise_error resource.should be_instance_of(Puppet::Type::Component) resource.title.should == "Foo[luke]" end it "should accept TransObjects into its children list" do object = Puppet::TransObject.new("luke", "user") proc { @bucket.push(object) }.should_not raise_error @bucket.each do |o| o.should equal(object) end end it "should accept TransBuckets into its children list" do object = Puppet::TransBucket.new proc { @bucket.push(object) }.should_not raise_error @bucket.each do |o| o.should equal(object) end end it "should refuse to accept any children that are not TransObjects or TransBuckets" do proc { @bucket.push "a test" }.should raise_error end it "should return use 'node' as the type and the provided name as the title if only a type is provided" do @bucket.type = "mystuff" @bucket.to_ref.should == "Node[mystuff]" end it "should return use 'component' as the type and the provided type as the title if only a name is provided" do @bucket.name = "mystuff" @bucket.to_ref.should == "Class[Mystuff]" end it "should return nil as its reference when type and name are missing" do @bucket.to_ref.should be_nil end it "should return the title as its reference" do @bucket.name = "luke" @bucket.type = "user" @bucket.to_ref.should == "User[luke]" end it "should canonize resource references when the type is 'component'" do @bucket.name = 'something' @bucket.type = 'foo::bar' @bucket.to_ref.should == "Foo::Bar[something]" end end describe Puppet::TransBucket, " when generating a catalog" do before do @bottom = Puppet::TransBucket.new @bottom.type = "fake" @bottom.name = "bottom" @bottomobj = Puppet::TransObject.new("bottom", "notify") @bottom.push @bottomobj @middle = Puppet::TransBucket.new @middle.type = "fake" @middle.name = "middle" @middleobj = Puppet::TransObject.new("middle", "notify") @middle.push(@middleobj) @middle.push(@bottom) @top = Puppet::TransBucket.new @top.type = "fake" @top.name = "top" @topobj = Puppet::TransObject.new("top", "notify") @top.push(@topobj) @top.push(@middle) @users = %w{top middle bottom} @fakes = %w{Fake[bottom] Fake[middle] Fake[top]} end it "should convert all transportable objects to RAL resources" do @catalog = @top.to_catalog @users.each do |name| @catalog.vertices.find { |r| r.class.name == :notify and r.title == name }.should be_instance_of(Puppet::Type.type(:notify)) end end it "should fail if any transportable resources fail to convert to RAL resources" do @bottomobj.expects(:to_ral).raises ArgumentError lambda { @bottom.to_catalog }.should raise_error(ArgumentError) end it "should convert all transportable buckets to RAL components" do @catalog = @top.to_catalog @fakes.each do |name| @catalog.vertices.find { |r| r.class.name == :component and r.title == name }.should be_instance_of(Puppet::Type.type(:component)) end end it "should add all resources to the graph's resource table" do @catalog = @top.to_catalog @catalog.resource("fake[top]").should equal(@top) end it "should finalize all resources" do @catalog = @top.to_catalog @catalog.vertices.each do |vertex| vertex.should be_finalized end end it "should only call to_ral on each resource once" do # We just raise exceptions here because we're not interested in # what happens with the result, only that the method only # gets called once. resource = @topobj.to_ral @topobj.expects(:to_ral).once.returns resource @top.to_catalog end it "should set each TransObject's catalog before converting to a RAL resource" do @middleobj.expects(:catalog=).with { |c| c.is_a?(Puppet::Resource::Catalog) } @top.to_catalog end it "should set each TransBucket's catalog before converting to a RAL resource" do # each bucket is seen twice in the loop, so we have to handle the case where the config # is set twice @bottom.expects(:catalog=).with { |c| c.is_a?(Puppet::Resource::Catalog) }.at_least_once @top.to_catalog end end describe Puppet::TransBucket, " when serializing" do before do @bucket = Puppet::TransBucket.new(%w{one two}) @bucket.name = "one" @bucket.type = "two" end it "should be able to be dumped to yaml" do proc { YAML.dump(@bucket) }.should_not raise_error end it "should dump YAML that produces an equivalent object" do result = YAML.dump(@bucket) newobj = YAML.load(result) newobj.name.should == "one" newobj.type.should == "two" children = [] newobj.each do |o| children << o end children.should == %w{one two} end end describe Puppet::TransBucket, " when converting to a Puppet::Resource" do before do @trans = Puppet::TransBucket.new @trans.name = "foo" @trans.type = "bar" @trans.param(:noop, true) end it "should create a resource with the correct type and title" do result = @trans.to_resource result.type.should == "Bar" result.title.should == "foo" end it "should add all of its parameters to the created resource" do @trans.param(:noop, true) @trans.to_resource[:noop].should be_true end end diff --git a/spec/unit/other/transobject_spec.rb b/spec/unit/other/transobject_spec.rb index a56ecef9d..4715e2fa1 100755 --- a/spec/unit/other/transobject_spec.rb +++ b/spec/unit/other/transobject_spec.rb @@ -1,112 +1,111 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/transportable' describe Puppet::TransObject do it "should canonize resource references" do resource = Puppet::TransObject.new("me", "foo::bar") resource.ref.should == 'Foo::Bar[me]' end it "should lower-case resource types for backward compatibility with 0.23.2" do resource = Puppet::TransObject.new("me", "Foo") resource.type.should == 'foo' end end describe Puppet::TransObject, " when serializing" do before do @resource = Puppet::TransObject.new("/my/file", "file") @resource["one"] = "test" @resource["two"] = "other" end it "should be able to be dumped to yaml" do proc { YAML.dump(@resource) }.should_not raise_error end it "should produce an equivalent yaml object" do text = YAML.dump(@resource) newresource = YAML.load(text) newresource.name.should == "/my/file" newresource.type.should == "file" %w{one two}.each do |param| newresource[param].should == @resource[param] end end end describe Puppet::TransObject, " when converting to a Puppet::Resource" do before do @trans = Puppet::TransObject.new("/my/file", "file") @trans["one"] = "test" @trans["two"] = "other" end it "should create a resource with the correct type and title" do result = @trans.to_resource result.type.should == "File" result.title.should == "/my/file" end it "should add all of its parameters to the created resource" do @trans[:noop] = true @trans.to_resource[:noop].should be_true end it "should copy over the tags" do @trans.tags = %w{foo bar} result = @trans.to_resource result.should be_tagged("foo") result.should be_tagged("bar") end end describe Puppet::TransObject, " when converting to a RAL resource" do before do @resource = Puppet::TransObject.new("/my/file", "file") @resource["one"] = "test" @resource["two"] = "other" end it "should use a Puppet::Resource to create the resource" do resource = mock 'resource' @resource.expects(:to_resource).returns resource resource.expects(:to_ral).returns "myral" @resource.to_ral.should == "myral" end end describe Puppet::TransObject, " when converting to a RAL component instance" do before do @resource = Puppet::TransObject.new("/my/file", "one::two") @resource["one"] = "test" @resource["noop"] = "other" end it "should use a new TransObject whose name is a resource reference of the type and title of the original TransObject" do Puppet::Type::Component.expects(:new).with { |resource| resource.type == "component" and resource.name == "One::Two[/my/file]" }.returns(:yay) @resource.to_component.should == :yay end it "should pass the resource parameters on to the newly created TransObject" do Puppet::Type::Component.expects(:new).with { |resource| resource["noop"] == "other" }.returns(:yay) @resource.to_component.should == :yay end it "should copy over the catalog" do @resource.catalog = "mycat" Puppet::Type::Component.expects(:new).with { |resource| resource.catalog == "mycat" }.returns(:yay) @resource.to_component end # LAK:FIXME This really isn't the design we want going forward, but it's # good enough for now. it "should not pass resource parameters that are not metaparams" do Puppet::Type::Component.expects(:new).with { |resource| resource["one"].nil? }.returns(:yay) @resource.to_component.should == :yay end end diff --git a/spec/unit/parameter/path_spec.rb b/spec/unit/parameter/path_spec.rb index 0826265c3..d113a1581 100755 --- a/spec/unit/parameter/path_spec.rb +++ b/spec/unit/parameter/path_spec.rb @@ -1,24 +1,24 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/parameter/path' [false, true].each do |arrays| describe "Puppet::Parameter::Path with arrays #{arrays}" do it_should_behave_like "all path parameters", :path, :array => arrays do # The new type allows us a test that is guaranteed to go direct to our # validation code, without passing through any "real type" overrides or # whatever on the way. Puppet::newtype(:test_puppet_parameter_path) do newparam(:path, :parent => Puppet::Parameter::Path, :arrays => arrays) do isnamevar accept_arrays arrays end end def instance(path) Puppet::Type.type(:test_puppet_parameter_path).new(:path => path) end end end end diff --git a/spec/unit/parameter/value_collection_spec.rb b/spec/unit/parameter/value_collection_spec.rb index 7e85574a8..af70160c1 100755 --- a/spec/unit/parameter/value_collection_spec.rb +++ b/spec/unit/parameter/value_collection_spec.rb @@ -1,167 +1,166 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/parameter' describe Puppet::Parameter::ValueCollection do before do @collection = Puppet::Parameter::ValueCollection.new end it "should have a method for defining new values" do @collection.should respond_to(:newvalues) end it "should have a method for adding individual values" do @collection.should respond_to(:newvalue) end it "should be able to retrieve individual values" do value = @collection.newvalue(:foo) @collection.value(:foo).should equal(value) end it "should be able to add an individual value with a block" do @collection.newvalue(:foo) { raise "testing" } @collection.value(:foo).block.should be_instance_of(Proc) end it "should be able to add values that are empty strings" do lambda { @collection.newvalue('') }.should_not raise_error end it "should be able to add values that are empty strings" do value = @collection.newvalue('') @collection.match?('').should equal(value) end it "should set :call to :none when adding a value with no block" do value = @collection.newvalue(:foo) value.call.should == :none end describe "when adding a value with a block" do it "should set the method name to 'set_' plus the value name" do value = @collection.newvalue(:myval) { raise "testing" } value.method.should == "set_myval" end end it "should be able to add an individual value with options" do value = @collection.newvalue(:foo, :call => :bar) value.call.should == :bar end it "should have a method for validating a value" do @collection.should respond_to(:validate) end it "should have a method for munging a value" do @collection.should respond_to(:munge) end it "should be able to generate documentation when it has both values and regexes" do @collection.newvalues :foo, "bar", %r{test} @collection.doc.should be_instance_of(String) end it "should correctly generate documentation for values" do @collection.newvalues :foo @collection.doc.should be_include("Valid values are `foo`") end it "should correctly generate documentation for regexes" do @collection.newvalues %r{\w+} @collection.doc.should be_include("Values can match `/\\w+/`") end it "should be able to find the first matching value" do @collection.newvalues :foo, :bar @collection.match?("foo").should be_instance_of(Puppet::Parameter::Value) end it "should be able to match symbols" do @collection.newvalues :foo, :bar @collection.match?(:foo).should be_instance_of(Puppet::Parameter::Value) end it "should be able to match symbols when a regex is provided" do @collection.newvalues %r{.} @collection.match?(:foo).should be_instance_of(Puppet::Parameter::Value) end it "should be able to match values using regexes" do @collection.newvalues %r{.} @collection.match?("foo").should_not be_nil end it "should prefer value matches to regex matches" do @collection.newvalues %r{.}, :foo @collection.match?("foo").name.should == :foo end describe "when validating values" do it "should do nothing if no values or regexes have been defined" do @collection.validate("foo") end it "should fail if the value is not a defined value or alias and does not match a regex" do @collection.newvalues :foo lambda { @collection.validate("bar") }.should raise_error(ArgumentError) end it "should succeed if the value is one of the defined values" do @collection.newvalues :foo lambda { @collection.validate(:foo) }.should_not raise_error(ArgumentError) end it "should succeed if the value is one of the defined values even if the definition uses a symbol and the validation uses a string" do @collection.newvalues :foo lambda { @collection.validate("foo") }.should_not raise_error(ArgumentError) end it "should succeed if the value is one of the defined values even if the definition uses a string and the validation uses a symbol" do @collection.newvalues "foo" lambda { @collection.validate(:foo) }.should_not raise_error(ArgumentError) end it "should succeed if the value is one of the defined aliases" do @collection.newvalues :foo @collection.aliasvalue :bar, :foo lambda { @collection.validate("bar") }.should_not raise_error(ArgumentError) end it "should succeed if the value matches one of the regexes" do @collection.newvalues %r{\d} lambda { @collection.validate("10") }.should_not raise_error(ArgumentError) end end describe "when munging values" do it "should do nothing if no values or regexes have been defined" do @collection.munge("foo").should == "foo" end it "should return return any matching defined values" do @collection.newvalues :foo, :bar @collection.munge("foo").should == :foo end it "should return any matching aliases" do @collection.newvalues :foo @collection.aliasvalue :bar, :foo @collection.munge("bar").should == :foo end it "should return the value if it matches a regex" do @collection.newvalues %r{\w} @collection.munge("bar").should == "bar" end it "should return the value if no other option is matched" do @collection.newvalues :foo @collection.munge("bar").should == "bar" end end end diff --git a/spec/unit/parameter/value_spec.rb b/spec/unit/parameter/value_spec.rb index f874d7736..f3414e4e0 100755 --- a/spec/unit/parameter/value_spec.rb +++ b/spec/unit/parameter/value_spec.rb @@ -1,88 +1,87 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/parameter' describe Puppet::Parameter::Value do it "should require a name" do lambda { Puppet::Parameter::Value.new }.should raise_error(ArgumentError) end it "should set its name" do Puppet::Parameter::Value.new(:foo).name.should == :foo end it "should support regexes as names" do lambda { Puppet::Parameter::Value.new(%r{foo}) }.should_not raise_error end it "should mark itself as a regex if its name is a regex" do Puppet::Parameter::Value.new(%r{foo}).should be_regex end it "should always convert its name to a symbol if it is not a regex" do Puppet::Parameter::Value.new("foo").name.should == :foo Puppet::Parameter::Value.new(true).name.should == :true end it "should support adding aliases" do Puppet::Parameter::Value.new("foo").should respond_to(:alias) end it "should be able to return its aliases" do value = Puppet::Parameter::Value.new("foo") value.alias("bar") value.alias("baz") value.aliases.should == [:bar, :baz] end [:block, :call, :method, :event, :required_features].each do |attr| it "should support a #{attr} attribute" do value = Puppet::Parameter::Value.new("foo") value.should respond_to(attr.to_s + "=") value.should respond_to(attr) end end it "should default to :instead for :call if a block is provided" do Puppet::Parameter::Value.new("foo").call.should == :instead end it "should always return events as symbols" do value = Puppet::Parameter::Value.new("foo") value.event = "foo_test" value.event.should == :foo_test end describe "when matching" do describe "a regex" do it "should return true if the regex matches the value" do Puppet::Parameter::Value.new(/\w/).should be_match("foo") end it "should return false if the regex does not match the value" do Puppet::Parameter::Value.new(/\d/).should_not be_match("foo") end end describe "a non-regex" do it "should return true if the value, converted to a symbol, matches the name" do Puppet::Parameter::Value.new("foo").should be_match("foo") Puppet::Parameter::Value.new(:foo).should be_match(:foo) Puppet::Parameter::Value.new(:foo).should be_match("foo") Puppet::Parameter::Value.new("foo").should be_match(:foo) end it "should return false if the value, converted to a symbol, does not match the name" do Puppet::Parameter::Value.new(:foo).should_not be_match(:bar) end it "should return true if any of its aliases match" do value = Puppet::Parameter::Value.new("foo") value.alias("bar") value.should be_match("bar") end end end end diff --git a/spec/unit/parameter_spec.rb b/spec/unit/parameter_spec.rb index 714c391a8..04556c013 100755 --- a/spec/unit/parameter_spec.rb +++ b/spec/unit/parameter_spec.rb @@ -1,171 +1,170 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/parameter' describe Puppet::Parameter do before do @class = Class.new(Puppet::Parameter) do @name = :foo end @class.initvars @resource = mock 'resource' @resource.stub_everything @parameter = @class.new :resource => @resource end it "should create a value collection" do @class = Class.new(Puppet::Parameter) @class.value_collection.should be_nil @class.initvars @class.value_collection.should be_instance_of(Puppet::Parameter::ValueCollection) end it "should return its name as a string when converted to a string" do @parameter.to_s.should == @parameter.name.to_s end it "should be able to use cached attributes" do Puppet::Parameter.ancestors.should be_include(Puppet::Util::Cacher) end it "should use the resource catalog for expiration" do catalog = mock 'catalog' @resource.stubs(:catalog).returns catalog @parameter.expirer.should equal(catalog) end [:line, :file, :version].each do |data| it "should return its resource's #{data} as its #{data}" do @resource.expects(data).returns "foo" @parameter.send(data).should == "foo" end end it "should return the resource's tags plus its name as its tags" do @resource.expects(:tags).returns %w{one two} @parameter.tags.should == %w{one two foo} end it "should provide source_descriptors" do @resource.expects(:line).returns 10 @resource.expects(:file).returns "file" @resource.expects(:tags).returns %w{one two} @parameter.source_descriptors.should == {:tags=>["one", "two", "foo"], :path=>"//foo", :file => "file", :line => 10} end describe "when returning the value" do it "should return nil if no value is set" do @parameter.value.should be_nil end it "should validate the value" do @parameter.expects(:validate).with("foo") @parameter.value = "foo" end it "should munge the value and use any result as the actual value" do @parameter.expects(:munge).with("foo").returns "bar" @parameter.value = "foo" @parameter.value.should == "bar" end it "should unmunge the value when accessing the actual value" do @parameter.class.unmunge do |value| value.to_sym end @parameter.value = "foo" @parameter.value.should == :foo end it "should return the actual value by default when unmunging" do @parameter.unmunge("bar").should == "bar" end it "should return any set value" do @parameter.value = "foo" @parameter.value.should == "foo" end end describe "when validating values" do it "should do nothing if no values or regexes have been defined" do @parameter.validate("foo") end it "should catch abnormal failures thrown during validation" do @class.validate { |v| raise "This is broken" } lambda { @parameter.validate("eh") }.should raise_error(Puppet::DevError) end it "should fail if the value is not a defined value or alias and does not match a regex" do @class.newvalues :foo lambda { @parameter.validate("bar") }.should raise_error(Puppet::Error) end it "should succeed if the value is one of the defined values" do @class.newvalues :foo lambda { @parameter.validate(:foo) }.should_not raise_error(ArgumentError) end it "should succeed if the value is one of the defined values even if the definition uses a symbol and the validation uses a string" do @class.newvalues :foo lambda { @parameter.validate("foo") }.should_not raise_error(ArgumentError) end it "should succeed if the value is one of the defined values even if the definition uses a string and the validation uses a symbol" do @class.newvalues "foo" lambda { @parameter.validate(:foo) }.should_not raise_error(ArgumentError) end it "should succeed if the value is one of the defined aliases" do @class.newvalues :foo @class.aliasvalue :bar, :foo lambda { @parameter.validate("bar") }.should_not raise_error(ArgumentError) end it "should succeed if the value matches one of the regexes" do @class.newvalues %r{\d} lambda { @parameter.validate("10") }.should_not raise_error(ArgumentError) end end describe "when munging values" do it "should do nothing if no values or regexes have been defined" do @parameter.munge("foo").should == "foo" end it "should catch abnormal failures thrown during munging" do @class.munge { |v| raise "This is broken" } lambda { @parameter.munge("eh") }.should raise_error(Puppet::DevError) end it "should return return any matching defined values" do @class.newvalues :foo, :bar @parameter.munge("foo").should == :foo end it "should return any matching aliases" do @class.newvalues :foo @class.aliasvalue :bar, :foo @parameter.munge("bar").should == :foo end it "should return the value if it matches a regex" do @class.newvalues %r{\w} @parameter.munge("bar").should == "bar" end it "should return the value if no other option is matched" do @class.newvalues :foo @parameter.munge("bar").should == "bar" end end describe "when logging" do it "should use its resource's log level and the provided message" do @resource.expects(:[]).with(:loglevel).returns :notice @parameter.expects(:send_log).with(:notice, "mymessage") @parameter.log "mymessage" end end end diff --git a/spec/unit/parser/ast/arithmetic_operator_spec.rb b/spec/unit/parser/ast/arithmetic_operator_spec.rb index 9b54f09d8..144ebd78c 100755 --- a/spec/unit/parser/ast/arithmetic_operator_spec.rb +++ b/spec/unit/parser/ast/arithmetic_operator_spec.rb @@ -1,63 +1,62 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe Puppet::Parser::AST::ArithmeticOperator do ast = Puppet::Parser::AST before :each do @scope = Puppet::Parser::Scope.new @one = stub 'lval', :safeevaluate => 1 @two = stub 'rval', :safeevaluate => 2 end it "should evaluate both branches" do lval = stub "lval" lval.expects(:safeevaluate).with(@scope).returns(1) rval = stub "rval" rval.expects(:safeevaluate).with(@scope).returns(2) operator = ast::ArithmeticOperator.new :rval => rval, :operator => "+", :lval => lval operator.evaluate(@scope) end it "should fail for an unknown operator" do lambda { operator = ast::ArithmeticOperator.new :lval => @one, :operator => "%", :rval => @two }.should raise_error end it "should call Puppet::Parser::Scope.number?" do Puppet::Parser::Scope.expects(:number?).with(1).returns(1) Puppet::Parser::Scope.expects(:number?).with(2).returns(2) ast::ArithmeticOperator.new(:lval => @one, :operator => "+", :rval => @two).evaluate(@scope) end %w{ + - * / << >>}.each do |op| it "should call ruby Numeric '#{op}'" do one = stub 'one' two = stub 'two' operator = ast::ArithmeticOperator.new :lval => @one, :operator => op, :rval => @two Puppet::Parser::Scope.stubs(:number?).with(1).returns(one) Puppet::Parser::Scope.stubs(:number?).with(2).returns(two) one.expects(:send).with(op,two) operator.evaluate(@scope) end end it "should work even with numbers embedded in strings" do two = stub 'two', :safeevaluate => "2" one = stub 'one', :safeevaluate => "1" operator = ast::ArithmeticOperator.new :lval => two, :operator => "+", :rval => one operator.evaluate(@scope).should == 3 end it "should work even with floats" do two = stub 'two', :safeevaluate => 2.53 one = stub 'one', :safeevaluate => 1.80 operator = ast::ArithmeticOperator.new :lval => two, :operator => "+", :rval => one operator.evaluate(@scope).should == 4.33 end end diff --git a/spec/unit/parser/ast/astarray_spec.rb b/spec/unit/parser/ast/astarray_spec.rb index 4429ab1fe..a3f56052a 100755 --- a/spec/unit/parser/ast/astarray_spec.rb +++ b/spec/unit/parser/ast/astarray_spec.rb @@ -1,55 +1,54 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe Puppet::Parser::AST::ASTArray do before :each do @scope = Puppet::Parser::Scope.new end it "should have a [] accessor" do array = Puppet::Parser::AST::ASTArray.new :children => [] array.should respond_to(:[]) end it "should evaluate all its children" do item1 = stub "item1", :is_a? => true item2 = stub "item2", :is_a? => true item1.expects(:safeevaluate).with(@scope).returns(123) item2.expects(:safeevaluate).with(@scope).returns(246) operator = Puppet::Parser::AST::ASTArray.new :children => [item1,item2] operator.evaluate(@scope) end it "should not flatten children coming from children ASTArray" do item = Puppet::Parser::AST::String.new :value => 'foo' inner_array = Puppet::Parser::AST::ASTArray.new :children => [item, item] operator = Puppet::Parser::AST::ASTArray.new :children => [inner_array, inner_array] operator.evaluate(@scope).should == [['foo', 'foo'], ['foo', 'foo']] end it "should not flatten the results of children evaluation" do item = Puppet::Parser::AST::String.new :value => 'foo' item.stubs(:evaluate).returns(['foo']) operator = Puppet::Parser::AST::ASTArray.new :children => [item, item] operator.evaluate(@scope).should == [['foo'], ['foo']] end it "should discard nil results from children evaluation" do item1 = Puppet::Parser::AST::String.new :value => 'foo' item2 = Puppet::Parser::AST::String.new :value => 'foo' item2.stubs(:evaluate).returns(nil) operator = Puppet::Parser::AST::ASTArray.new :children => [item1, item2] operator.evaluate(@scope).should == ['foo'] end it "should return a valid string with to_s" do a = stub 'a', :is_a? => true, :to_s => "a" b = stub 'b', :is_a? => true, :to_s => "b" array = Puppet::Parser::AST::ASTArray.new :children => [a,b] array.to_s.should == "[a, b]" end end diff --git a/spec/unit/parser/ast/asthash_spec.rb b/spec/unit/parser/ast/asthash_spec.rb index 09033284e..d7fbbfae9 100755 --- a/spec/unit/parser/ast/asthash_spec.rb +++ b/spec/unit/parser/ast/asthash_spec.rb @@ -1,98 +1,97 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe Puppet::Parser::AST::ASTHash do before :each do @scope = Puppet::Parser::Scope.new end it "should have a merge functionality" do hash = Puppet::Parser::AST::ASTHash.new(:value => {}) hash.should respond_to(:merge) end it "should be able to merge 2 AST hashes" do hash = Puppet::Parser::AST::ASTHash.new(:value => { "a" => "b" }) hash.merge(Puppet::Parser::AST::ASTHash.new(:value => {"c" => "d"})) hash.value.should == { "a" => "b", "c" => "d" } end it "should be able to merge with a ruby Hash" do hash = Puppet::Parser::AST::ASTHash.new(:value => { "a" => "b" }) hash.merge({"c" => "d"}) hash.value.should == { "a" => "b", "c" => "d" } end it "should evaluate each hash value" do key1 = stub "key1" value1 = stub "value1" key2 = stub "key2" value2 = stub "value2" value1.expects(:safeevaluate).with(@scope).returns("b") value2.expects(:safeevaluate).with(@scope).returns("d") operator = Puppet::Parser::AST::ASTHash.new(:value => { key1 => value1, key2 => value2}) operator.evaluate(@scope) end it "should evaluate the hash keys if they are AST instances" do key1 = stub "key1" value1 = stub "value1", :safeevaluate => "one" key2 = stub "key2" value2 = stub "value2", :safeevaluate => "two" key1.expects(:safeevaluate).with(@scope).returns("1") key2.expects(:safeevaluate).with(@scope).returns("2") operator = Puppet::Parser::AST::ASTHash.new(:value => { key1 => value1, key2 => value2}) hash = operator.evaluate(@scope) hash["1"].should == "one" hash["2"].should == "two" end it "should evaluate the hash keys if they are not AST instances" do key1 = "1" value1 = stub "value1", :safeevaluate => "one" key2 = "2" value2 = stub "value2", :safeevaluate => "two" operator = Puppet::Parser::AST::ASTHash.new(:value => { key1 => value1, key2 => value2}) hash = operator.evaluate(@scope) hash["1"].should == "one" hash["2"].should == "two" end it "should return an evaluated hash" do key1 = stub "key1" value1 = stub "value1", :safeevaluate => "b" key2 = stub "key2" value2 = stub "value2", :safeevaluate => "d" operator = Puppet::Parser::AST::ASTHash.new(:value => { key1 => value1, key2 => value2}) operator.evaluate(@scope).should == { key1 => "b", key2 => "d" } end describe "when being initialized without arguments" do it "should evaluate to an empty hash" do hash = Puppet::Parser::AST::ASTHash.new({}) hash.evaluate(@scope).should == {} end it "should support merging" do hash = Puppet::Parser::AST::ASTHash.new({}) hash.merge({"a" => "b"}).should == {"a" => "b"} end end it "should return a valid string with to_s" do hash = Puppet::Parser::AST::ASTHash.new(:value => { "a" => "b", "c" => "d" }) hash.to_s.should == '{a => b, c => d}' end end diff --git a/spec/unit/parser/ast/boolean_operator_spec.rb b/spec/unit/parser/ast/boolean_operator_spec.rb index 2251d0827..287f466a7 100755 --- a/spec/unit/parser/ast/boolean_operator_spec.rb +++ b/spec/unit/parser/ast/boolean_operator_spec.rb @@ -1,53 +1,52 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe Puppet::Parser::AST::BooleanOperator do ast = Puppet::Parser::AST before :each do @scope = Puppet::Parser::Scope.new @true_ast = ast::Boolean.new( :value => true) @false_ast = ast::Boolean.new( :value => false) end it "should evaluate left operand inconditionally" do lval = stub "lval" lval.expects(:safeevaluate).with(@scope).returns("true") rval = stub "rval", :safeevaluate => false rval.expects(:safeevaluate).never operator = ast::BooleanOperator.new :rval => rval, :operator => "or", :lval => lval operator.evaluate(@scope) end it "should evaluate right 'and' operand only if left operand is true" do lval = stub "lval", :safeevaluate => true rval = stub "rval", :safeevaluate => false rval.expects(:safeevaluate).with(@scope).returns(false) operator = ast::BooleanOperator.new :rval => rval, :operator => "and", :lval => lval operator.evaluate(@scope) end it "should evaluate right 'or' operand only if left operand is false" do lval = stub "lval", :safeevaluate => false rval = stub "rval", :safeevaluate => false rval.expects(:safeevaluate).with(@scope).returns(false) operator = ast::BooleanOperator.new :rval => rval, :operator => "or", :lval => lval operator.evaluate(@scope) end it "should return true for false OR true" do ast::BooleanOperator.new(:rval => @true_ast, :operator => "or", :lval => @false_ast).evaluate(@scope).should be_true end it "should return false for true AND false" do ast::BooleanOperator.new(:rval => @true_ast, :operator => "and", :lval => @false_ast ).evaluate(@scope).should be_false end it "should return true for true AND true" do ast::BooleanOperator.new(:rval => @true_ast, :operator => "and", :lval => @true_ast ).evaluate(@scope).should be_true end end diff --git a/spec/unit/parser/ast/casestatement_spec.rb b/spec/unit/parser/ast/casestatement_spec.rb index d507beb58..e21190706 100755 --- a/spec/unit/parser/ast/casestatement_spec.rb +++ b/spec/unit/parser/ast/casestatement_spec.rb @@ -1,165 +1,164 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe Puppet::Parser::AST::CaseStatement do before :each do @scope = Puppet::Parser::Scope.new end describe "when evaluating" do before :each do @test = stub 'test' @test.stubs(:safeevaluate).with(@scope).returns("value") @option1 = Puppet::Parser::AST::CaseOpt.new({}) @option1.stubs(:eachopt) @option1.stubs(:default?).returns false @option2 = Puppet::Parser::AST::CaseOpt.new({}) @option2.stubs(:eachopt) @option2.stubs(:default?).returns false @options = Puppet::Parser::AST::ASTArray.new(:children => [@option1, @option2]) @casestmt = Puppet::Parser::AST::CaseStatement.new :test => @test, :options => @options end it "should evaluate test" do @test.expects(:safeevaluate).with(@scope) @casestmt.evaluate(@scope) end it "should scan each option" do @casestmt.evaluate(@scope) end describe "when scanning options" do before :each do @opval1 = stub_everything 'opval1' @option1.stubs(:eachopt).yields(@opval1) @opval2 = stub_everything 'opval2' @option2.stubs(:eachopt).yields(@opval2) end it "should evaluate each sub-option" do @option1.expects(:eachopt) @option2.expects(:eachopt) @casestmt.evaluate(@scope) end it "should evaluate first matching option" do @opval2.stubs(:evaluate_match).with { |*arg| arg[0] == "value" }.returns(true) @option2.expects(:safeevaluate).with(@scope) @casestmt.evaluate(@scope) end it "should return the first matching evaluated option" do @opval2.stubs(:evaluate_match).with { |*arg| arg[0] == "value" }.returns(true) @option2.stubs(:safeevaluate).with(@scope).returns(:result) @casestmt.evaluate(@scope).should == :result end it "should evaluate the default option if none matched" do @option1.stubs(:default?).returns(true) @option1.expects(:safeevaluate).with(@scope) @casestmt.evaluate(@scope) end it "should return the default evaluated option if none matched" do @option1.stubs(:default?).returns(true) @option1.stubs(:safeevaluate).with(@scope).returns(:result) @casestmt.evaluate(@scope).should == :result end it "should return nil if nothing matched" do @casestmt.evaluate(@scope).should be_nil end it "should match and set scope ephemeral variables" do @opval1.expects(:evaluate_match).with { |*arg| arg[0] == "value" and arg[1] == @scope } @casestmt.evaluate(@scope) end it "should evaluate this regex option if it matches" do @opval1.stubs(:evaluate_match).with { |*arg| arg[0] == "value" and arg[1] == @scope }.returns(true) @option1.expects(:safeevaluate).with(@scope) @casestmt.evaluate(@scope) end it "should return this evaluated regex option if it matches" do @opval1.stubs(:evaluate_match).with { |*arg| arg[0] == "value" and arg[1] == @scope }.returns(true) @option1.stubs(:safeevaluate).with(@scope).returns(:result) @casestmt.evaluate(@scope).should == :result end it "should unset scope ephemeral variables after option evaluation" do @scope.stubs(:ephemeral_level).returns(:level) @opval1.stubs(:evaluate_match).with { |*arg| arg[0] == "value" and arg[1] == @scope }.returns(true) @option1.stubs(:safeevaluate).with(@scope).returns(:result) @scope.expects(:unset_ephemeral_var).with(:level) @casestmt.evaluate(@scope) end it "should not leak ephemeral variables even if evaluation fails" do @scope.stubs(:ephemeral_level).returns(:level) @opval1.stubs(:evaluate_match).with { |*arg| arg[0] == "value" and arg[1] == @scope }.returns(true) @option1.stubs(:safeevaluate).with(@scope).raises @scope.expects(:unset_ephemeral_var).with(:level) lambda { @casestmt.evaluate(@scope) }.should raise_error end end end it "should match if any of the provided options evaluate as true" do ast = nil AST = Puppet::Parser::AST tests = { "one" => %w{a b c}, "two" => %w{e f g} } options = tests.collect do |result, values| values = values.collect { |v| AST::Leaf.new :value => v } AST::CaseOpt.new( :value => AST::ASTArray.new(:children => values), :statements => AST::Leaf.new(:value => result) ) end options << AST::CaseOpt.new( :value => AST::Default.new(:value => "default"), :statements => AST::Leaf.new(:value => "default") ) ast = nil param = AST::Variable.new(:value => "testparam") ast = AST::CaseStatement.new(:test => param, :options => options) tests.each do |should, values| values.each do |value| @scope = Puppet::Parser::Scope.new @scope.setvar("testparam", value) result = ast.evaluate(@scope) result.should == should end end end end diff --git a/spec/unit/parser/ast/collection_spec.rb b/spec/unit/parser/ast/collection_spec.rb index fd7bf75c1..78094e68d 100755 --- a/spec/unit/parser/ast/collection_spec.rb +++ b/spec/unit/parser/ast/collection_spec.rb @@ -1,71 +1,70 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe Puppet::Parser::AST::Collection do before :each do @mytype = Puppet::Resource::Type.new(:definition, "mytype") @environment = Puppet::Node::Environment.new @environment.known_resource_types.add @mytype @compiler = Puppet::Parser::Compiler.new(Puppet::Node.new("foonode", :environment => @environment)) @scope = Puppet::Parser::Scope.new(:compiler => @compiler) @overrides = stub_everything 'overrides' @overrides.stubs(:is_a?).with(Puppet::Parser::AST).returns(true) end it "should evaluate its query" do query = mock 'query' collection = Puppet::Parser::AST::Collection.new :query => query, :form => :virtual collection.type = 'mytype' query.expects(:safeevaluate).with(@scope) collection.evaluate(@scope) end it "should instantiate a Collector for this type" do collection = Puppet::Parser::AST::Collection.new :form => :virtual, :type => "test" @test_type = Puppet::Resource::Type.new(:definition, "test") @environment.known_resource_types.add @test_type Puppet::Parser::Collector.expects(:new).with(@scope, "test", nil, nil, :virtual) collection.evaluate(@scope) end it "should tell the compiler about this collector" do collection = Puppet::Parser::AST::Collection.new :form => :virtual, :type => "mytype" Puppet::Parser::Collector.stubs(:new).returns("whatever") @compiler.expects(:add_collection).with("whatever") collection.evaluate(@scope) end it "should evaluate overriden paramaters" do collector = stub_everything 'collector' collection = Puppet::Parser::AST::Collection.new :form => :virtual, :type => "mytype", :override => @overrides Puppet::Parser::Collector.stubs(:new).returns(collector) @overrides.expects(:safeevaluate).with(@scope) collection.evaluate(@scope) end it "should tell the collector about overrides" do collector = mock 'collector' collection = Puppet::Parser::AST::Collection.new :form => :virtual, :type => "mytype", :override => @overrides Puppet::Parser::Collector.stubs(:new).returns(collector) collector.expects(:add_override) collection.evaluate(@scope) end it "should fail when evaluating undefined resource types" do collection = Puppet::Parser::AST::Collection.new :form => :virtual, :type => "bogus" lambda { collection.evaluate(@scope) }.should raise_error "Resource type bogus doesn't exist" end end diff --git a/spec/unit/parser/ast/collexpr_spec.rb b/spec/unit/parser/ast/collexpr_spec.rb index f5e340ce8..454e7481b 100755 --- a/spec/unit/parser/ast/collexpr_spec.rb +++ b/spec/unit/parser/ast/collexpr_spec.rb @@ -1,115 +1,114 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe Puppet::Parser::AST::CollExpr do ast = Puppet::Parser::AST before :each do @scope = Puppet::Parser::Scope.new end describe "when evaluating with two operands" do before :each do @test1 = mock 'test1' @test1.expects(:safeevaluate).with(@scope).returns("test1") @test2 = mock 'test2' @test2.expects(:safeevaluate).with(@scope).returns("test2") end it "should evaluate both" do collexpr = ast::CollExpr.new(:test1 => @test1, :test2 => @test2, :oper=>"==") collexpr.evaluate(@scope) end it "should produce a textual representation and code of the expression" do collexpr = ast::CollExpr.new(:test1 => @test1, :test2 => @test2, :oper=>"==") result = collexpr.evaluate(@scope) result[0].should == "param_values.value = 'test2' and param_names.name = 'test1'" result[1].should be_an_instance_of(Proc) end it "should propagate expression type and form to child if expression themselves" do [@test1, @test2].each do |t| t.expects(:is_a?).returns(true) t.expects(:form).returns(false) t.expects(:type).returns(false) t.expects(:type=) t.expects(:form=) end collexpr = ast::CollExpr.new(:test1 => @test1, :test2 => @test2, :oper=>"==", :form => true, :type => true) result = collexpr.evaluate(@scope) end describe "and when evaluating the produced code" do before :each do @resource = mock 'resource' @resource.expects(:[]).with("test1").at_least(1).returns("test2") end it "should evaluate like the original expression for ==" do collexpr = ast::CollExpr.new(:test1 => @test1, :test2 => @test2, :oper => "==") collexpr.evaluate(@scope)[1].call(@resource).should === (@resource["test1"] == "test2") end it "should evaluate like the original expression for !=" do collexpr = ast::CollExpr.new(:test1 => @test1, :test2 => @test2, :oper => "!=") collexpr.evaluate(@scope)[1].call(@resource).should === (@resource["test1"] != "test2") end end it "should warn if this is an exported collection containing parenthesis (unsupported)" do collexpr = ast::CollExpr.new(:test1 => @test1, :test2 => @test2, :oper=>"==", :parens => true, :form => :exported) Puppet.expects(:warning) collexpr.evaluate(@scope) end %w{and or}.each do |op| it "should raise an error if this is an exported collection with #{op} operator (unsupported)" do collexpr = ast::CollExpr.new(:test1 => @test1, :test2 => @test2, :oper=> op, :form => :exported) lambda { collexpr.evaluate(@scope) }.should raise_error(Puppet::ParseError) end end end describe "when evaluating with tags" do before :each do @tag = stub 'tag', :safeevaluate => 'tag' @value = stub 'value', :safeevaluate => 'value' @resource = stub 'resource' @resource.stubs(:tagged?).with("value").returns(true) end it "should produce a textual representation of the expression" do collexpr = ast::CollExpr.new(:test1 => @tag, :test2 => @value, :oper=>"==") result = collexpr.evaluate(@scope) result[0].should == "puppet_tags.name = 'value'" end it "should inspect resource tags if the query term is on tags" do collexpr = ast::CollExpr.new(:test1 => @tag, :test2 => @value, :oper => "==") collexpr.evaluate(@scope)[1].call(@resource).should be_true end end [:exported,:virtual].each do |mode| it "should check for array member equality if resource parameter is an array for == in mode #{mode}" do array = mock 'array', :safeevaluate => "array" test1 = mock 'test1' test1.expects(:safeevaluate).with(@scope).returns("test1") resource = mock 'resource' resource.expects(:[]).with("array").at_least(1).returns(["test1","test2","test3"]) collexpr = ast::CollExpr.new(:test1 => array, :test2 => test1, :oper => "==", :form => mode) collexpr.evaluate(@scope)[1].call(resource).should be_true end end it "should raise an error for invalid operator" do lambda { collexpr = ast::CollExpr.new(:oper=>">") }.should raise_error end end diff --git a/spec/unit/parser/ast/comparison_operator_spec.rb b/spec/unit/parser/ast/comparison_operator_spec.rb index 060827390..96f4562e9 100755 --- a/spec/unit/parser/ast/comparison_operator_spec.rb +++ b/spec/unit/parser/ast/comparison_operator_spec.rb @@ -1,116 +1,115 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe Puppet::Parser::AST::ComparisonOperator do before :each do @scope = Puppet::Parser::Scope.new @one = Puppet::Parser::AST::Leaf.new(:value => "1") @two = Puppet::Parser::AST::Leaf.new(:value => "2") @lval = Puppet::Parser::AST::Leaf.new(:value => "one") @rval = Puppet::Parser::AST::Leaf.new(:value => "two") end it "should evaluate both values" do @lval.expects(:safeevaluate).with(@scope) @rval.expects(:safeevaluate).with(@scope) operator = Puppet::Parser::AST::ComparisonOperator.new :lval => @lval, :operator => "==", :rval => @rval operator.evaluate(@scope) end it "should convert the arguments to numbers if they are numbers in string" do Puppet::Parser::Scope.expects(:number?).with("1").returns(1) Puppet::Parser::Scope.expects(:number?).with("2").returns(2) operator = Puppet::Parser::AST::ComparisonOperator.new :lval => @one, :operator => "==", :rval => @two operator.evaluate(@scope) end %w{< > <= >=}.each do |oper| it "should use string comparison #{oper} if operands are strings" do operator = Puppet::Parser::AST::ComparisonOperator.new :lval => @lval, :operator => oper, :rval => @rval operator.evaluate(@scope).should == "one".send(oper,"two") end end describe "with string comparison" do it "should use matching" do @rval.expects(:evaluate_match).with("one", @scope) operator = Puppet::Parser::AST::ComparisonOperator.new :lval => @lval, :operator => "==", :rval => @rval operator.evaluate(@scope) end it "should return true for :undef to '' equality" do astundef = Puppet::Parser::AST::Leaf.new(:value => :undef) empty = Puppet::Parser::AST::Leaf.new(:value => '') operator = Puppet::Parser::AST::ComparisonOperator.new :lval => astundef, :operator => "==", :rval => empty operator.evaluate(@scope).should be_true end [true, false].each do |result| it "should return #{(result).inspect} with '==' when matching return #{result.inspect}" do @rval.expects(:evaluate_match).with("one", @scope).returns result operator = Puppet::Parser::AST::ComparisonOperator.new :lval => @lval, :operator => "==", :rval => @rval operator.evaluate(@scope).should == result end it "should return #{(!result).inspect} with '!=' when matching return #{result.inspect}" do @rval.expects(:evaluate_match).with("one", @scope).returns result operator = Puppet::Parser::AST::ComparisonOperator.new :lval => @lval, :operator => "!=", :rval => @rval operator.evaluate(@scope).should == !result end end end it "should fail with arguments of different types" do operator = Puppet::Parser::AST::ComparisonOperator.new :lval => @one, :operator => ">", :rval => @rval lambda { operator.evaluate(@scope) }.should raise_error(ArgumentError) end it "should fail for an unknown operator" do lambda { operator = Puppet::Parser::AST::ComparisonOperator.new :lval => @one, :operator => "or", :rval => @two }.should raise_error end %w{< > <= >= ==}.each do |oper| it "should return the result of using '#{oper}' to compare the left and right sides" do operator = Puppet::Parser::AST::ComparisonOperator.new :lval => @one, :operator => oper, :rval => @two operator.evaluate(@scope).should == 1.send(oper,2) end end it "should return the result of using '!=' to compare the left and right sides" do operator = Puppet::Parser::AST::ComparisonOperator.new :lval => @one, :operator => '!=', :rval => @two operator.evaluate(@scope).should == true end it "should work for variables too" do one = Puppet::Parser::AST::Variable.new( :value => "one" ) two = Puppet::Parser::AST::Variable.new( :value => "two" ) one.expects(:safeevaluate).with(@scope).returns(1) two.expects(:safeevaluate).with(@scope).returns(2) operator = Puppet::Parser::AST::ComparisonOperator.new :lval => one, :operator => "<", :rval => two operator.evaluate(@scope).should == true end # see ticket #1759 %w{< > <= >=}.each do |oper| it "should return the correct result of using '#{oper}' to compare 10 and 9" do ten = Puppet::Parser::AST::Leaf.new(:value => "10") nine = Puppet::Parser::AST::Leaf.new(:value => "9") operator = Puppet::Parser::AST::ComparisonOperator.new :lval => ten, :operator => oper, :rval => nine operator.evaluate(@scope).should == 10.send(oper,9) end end end diff --git a/spec/unit/parser/ast/definition_spec.rb b/spec/unit/parser/ast/definition_spec.rb index f2a211ad2..8b2f7f26f 100755 --- a/spec/unit/parser/ast/definition_spec.rb +++ b/spec/unit/parser/ast/definition_spec.rb @@ -1,22 +1,21 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe Puppet::Parser::AST::Definition do it "should make its context available through an accessor" do definition = Puppet::Parser::AST::Definition.new('foo', :line => 5) definition.context.should == {:line => 5} end describe "when instantiated" do it "should create a definition with the proper type, name, context, and module name" do definition = Puppet::Parser::AST::Definition.new('foo', :line => 5) instantiated_definitions = definition.instantiate('modname') instantiated_definitions.length.should == 1 instantiated_definitions[0].type.should == :definition instantiated_definitions[0].name.should == 'foo' instantiated_definitions[0].line.should == 5 instantiated_definitions[0].module_name.should == 'modname' end end end diff --git a/spec/unit/parser/ast/function_spec.rb b/spec/unit/parser/ast/function_spec.rb index 6f9f33b8e..c52e806e9 100755 --- a/spec/unit/parser/ast/function_spec.rb +++ b/spec/unit/parser/ast/function_spec.rb @@ -1,93 +1,92 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe Puppet::Parser::AST::Function do before :each do @scope = mock 'scope' end describe "when initializing" do it "should not fail if the function doesn't exist" do Puppet::Parser::Functions.stubs(:function).returns(false) lambda{ Puppet::Parser::AST::Function.new :name => "dontexist" }.should_not raise_error(Puppet::ParseError) end end it "should return its representation with to_s" do args = stub 'args', :is_a? => true, :to_s => "[a, b]" Puppet::Parser::AST::Function.new(:name => "func", :arguments => args).to_s.should == "func(a, b)" end describe "when evaluating" do it "should fail if the function doesn't exist" do Puppet::Parser::Functions.stubs(:function).returns(false) func = Puppet::Parser::AST::Function.new :name => "dontexist" lambda{ func.evaluate(@scope) }.should raise_error(Puppet::ParseError) end it "should fail if the function is a statement used as rvalue" do Puppet::Parser::Functions.stubs(:function).with("exist").returns(true) Puppet::Parser::Functions.stubs(:rvalue?).with("exist").returns(false) func = Puppet::Parser::AST::Function.new :name => "exist", :ftype => :rvalue lambda{ func.evaluate(@scope) }.should raise_error(Puppet::ParseError, "Function 'exist' does not return a value") end it "should fail if the function is an rvalue used as statement" do Puppet::Parser::Functions.stubs(:function).with("exist").returns(true) Puppet::Parser::Functions.stubs(:rvalue?).with("exist").returns(true) func = Puppet::Parser::AST::Function.new :name => "exist", :ftype => :statement lambda{ func.evaluate(@scope) }.should raise_error(Puppet::ParseError,"Function 'exist' must be the value of a statement") end it "should evaluate its arguments" do argument = stub 'arg' Puppet::Parser::Functions.stubs(:function).with("exist").returns(true) func = Puppet::Parser::AST::Function.new :name => "exist", :ftype => :statement, :arguments => argument @scope.stubs(:function_exist) argument.expects(:safeevaluate).with(@scope).returns("argument") func.evaluate(@scope) end it "should call the underlying ruby function" do argument = stub 'arg', :safeevaluate => ["nothing"] Puppet::Parser::Functions.stubs(:function).with("exist").returns(true) func = Puppet::Parser::AST::Function.new :name => "exist", :ftype => :statement, :arguments => argument @scope.expects(:function_exist).with(["nothing"]) func.evaluate(@scope) end it "should convert :undef to '' in arguments" do argument = stub 'arg', :safeevaluate => ["foo", :undef, "bar"] Puppet::Parser::Functions.stubs(:function).with("exist").returns(true) func = Puppet::Parser::AST::Function.new :name => "exist", :ftype => :statement, :arguments => argument @scope.expects(:function_exist).with(["foo", "", "bar"]) func.evaluate(@scope) end it "should return the ruby function return for rvalue functions" do argument = stub 'arg', :safeevaluate => ["nothing"] Puppet::Parser::Functions.stubs(:function).with("exist").returns(true) func = Puppet::Parser::AST::Function.new :name => "exist", :ftype => :statement, :arguments => argument @scope.stubs(:function_exist).with(["nothing"]).returns("returning") func.evaluate(@scope).should == "returning" end end end diff --git a/spec/unit/parser/ast/hostclass_spec.rb b/spec/unit/parser/ast/hostclass_spec.rb index 9c320d1be..ee154fac8 100755 --- a/spec/unit/parser/ast/hostclass_spec.rb +++ b/spec/unit/parser/ast/hostclass_spec.rb @@ -1,73 +1,72 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe Puppet::Parser::AST::Hostclass do def ast Puppet::Parser::AST end def newarray(*elems) ast::ASTArray.new({}).push(*elems) end it "should make its name and context available through accessors" do hostclass = ast::Hostclass.new('foo', :line => 5) hostclass.name.should == 'foo' hostclass.context.should == {:line => 5} end it "should make its code available through an accessor" do code = newarray hostclass = ast::Hostclass.new('foo', :code => code) hostclass.code.should be_equal(code) end describe "when instantiated" do it "should create a class with the proper type, code, name, context, and module name" do code = newarray hostclass = ast::Hostclass.new('foo', :code => code, :line => 5) instantiated_class = hostclass.instantiate('modname')[0] instantiated_class.type.should == :hostclass instantiated_class.name.should == 'foo' instantiated_class.code.should be_equal(code) instantiated_class.line.should == 5 instantiated_class.module_name.should == 'modname' end it "should instantiate all nested classes, defines, and nodes with the same module name." do nested_objects = newarray(ast::Hostclass.new('foo::child1'), ast::Definition.new('foo::child2'), ast::Definition.new('child3')) hostclass = ast::Hostclass.new('foo', :code => nested_objects) instantiated_classes = hostclass.instantiate('modname') instantiated_classes.length.should == 4 instantiated_classes[0].name.should == 'foo' instantiated_classes[1].name.should == 'foo::child1' instantiated_classes[2].name.should == 'foo::child2' instantiated_classes[3].name.should == 'child3' instantiated_classes.each { |cls| cls.module_name.should == 'modname' } end it "should handle a nested class that contains its own nested classes." do foo_bar_baz = ast::Hostclass.new('foo::bar::baz') foo_bar = ast::Hostclass.new('foo::bar', :code => newarray(foo_bar_baz)) foo = ast::Hostclass.new('foo', :code => newarray(foo_bar)) instantiated_classes = foo.instantiate('') instantiated_classes.length.should == 3 instantiated_classes[0].name.should == 'foo' instantiated_classes[1].name.should == 'foo::bar' instantiated_classes[2].name.should == 'foo::bar::baz' end it "should skip nested elements that are not classes, definitions, or nodes." do func = ast::Function.new(:name => 'biz', :arguments => newarray(ast::Name.new(:value => 'baz'))) foo = ast::Hostclass.new('foo', :code => newarray(func)) instantiated_classes = foo.instantiate('') instantiated_classes.length.should == 1 instantiated_classes[0].should be_a(Puppet::Resource::Type) instantiated_classes[0].name.should == 'foo' end end end diff --git a/spec/unit/parser/ast/ifstatement_spec.rb b/spec/unit/parser/ast/ifstatement_spec.rb index 24e07f5fe..4b6e0b8e5 100755 --- a/spec/unit/parser/ast/ifstatement_spec.rb +++ b/spec/unit/parser/ast/ifstatement_spec.rb @@ -1,76 +1,75 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe Puppet::Parser::AST::IfStatement do before :each do @scope = Puppet::Parser::Scope.new end describe "when evaluating" do before :each do @test = stub 'test' @test.stubs(:safeevaluate).with(@scope) @stmt = stub 'stmt' @stmt.stubs(:safeevaluate).with(@scope) @else = stub 'else' @else.stubs(:safeevaluate).with(@scope) @ifstmt = Puppet::Parser::AST::IfStatement.new :test => @test, :statements => @stmt @ifelsestmt = Puppet::Parser::AST::IfStatement.new :test => @test, :statements => @stmt, :else => @else end it "should evaluate test" do Puppet::Parser::Scope.stubs(:true?).returns(false) @test.expects(:safeevaluate).with(@scope) @ifstmt.evaluate(@scope) end it "should evaluate if statements if test is true" do Puppet::Parser::Scope.stubs(:true?).returns(true) @stmt.expects(:safeevaluate).with(@scope) @ifstmt.evaluate(@scope) end it "should not evaluate if statements if test is false" do Puppet::Parser::Scope.stubs(:true?).returns(false) @stmt.expects(:safeevaluate).with(@scope).never @ifstmt.evaluate(@scope) end it "should evaluate the else branch if test is false" do Puppet::Parser::Scope.stubs(:true?).returns(false) @else.expects(:safeevaluate).with(@scope) @ifelsestmt.evaluate(@scope) end it "should not evaluate the else branch if test is true" do Puppet::Parser::Scope.stubs(:true?).returns(true) @else.expects(:safeevaluate).with(@scope).never @ifelsestmt.evaluate(@scope) end it "should reset ephemeral statements after evaluation" do @scope.expects(:ephemeral_level).returns(:level) Puppet::Parser::Scope.stubs(:true?).returns(true) @stmt.expects(:safeevaluate).with(@scope) @scope.expects(:unset_ephemeral_var).with(:level) @ifstmt.evaluate(@scope) end end end diff --git a/spec/unit/parser/ast/in_operator_spec.rb b/spec/unit/parser/ast/in_operator_spec.rb index 95349d45d..b6b6fbb89 100755 --- a/spec/unit/parser/ast/in_operator_spec.rb +++ b/spec/unit/parser/ast/in_operator_spec.rb @@ -1,60 +1,59 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/parser/ast/in_operator' describe Puppet::Parser::AST::InOperator do before :each do @scope = Puppet::Parser::Scope.new @lval = stub 'lval' @lval.stubs(:safeevaluate).with(@scope).returns("left") @rval = stub 'rval' @rval.stubs(:safeevaluate).with(@scope).returns("right") @operator = Puppet::Parser::AST::InOperator.new :lval => @lval, :rval => @rval end it "should evaluate the left operand" do @lval.expects(:safeevaluate).with(@scope).returns("string") @operator.evaluate(@scope) end it "should evaluate the right operand" do @rval.expects(:safeevaluate).with(@scope).returns("string") @operator.evaluate(@scope) end it "should raise an argument error if lval is not a string" do @lval.expects(:safeevaluate).with(@scope).returns([12,13]) lambda { @operator.evaluate(@scope) }.should raise_error end it "should raise an argument error if rval doesn't support the include? method" do @rval.expects(:safeevaluate).with(@scope).returns(stub('value')) lambda { @operator.evaluate(@scope) }.should raise_error end it "should not raise an argument error if rval supports the include? method" do @rval.expects(:safeevaluate).with(@scope).returns(stub('value', :include? => true)) lambda { @operator.evaluate(@scope) }.should_not raise_error end it "should return rval.include?(lval)" do lval = stub 'lvalue', :is_a? => true @lval.stubs(:safeevaluate).with(@scope).returns(lval) rval = stub 'rvalue' @rval.stubs(:safeevaluate).with(@scope).returns(rval) rval.expects(:include?).with(lval).returns(:result) @operator.evaluate(@scope).should == :result end end diff --git a/spec/unit/parser/ast/leaf_spec.rb b/spec/unit/parser/ast/leaf_spec.rb index cd09eaf94..ff3fed5e9 100755 --- a/spec/unit/parser/ast/leaf_spec.rb +++ b/spec/unit/parser/ast/leaf_spec.rb @@ -1,413 +1,412 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe Puppet::Parser::AST::Leaf do before :each do @scope = stub 'scope' @value = stub 'value' @leaf = Puppet::Parser::AST::Leaf.new(:value => @value) end it "should have a evaluate_match method" do Puppet::Parser::AST::Leaf.new(:value => "value").should respond_to(:evaluate_match) end describe "when converting to string" do it "should transform its value to string" do value = stub 'value', :is_a? => true value.expects(:to_s) Puppet::Parser::AST::Leaf.new( :value => value ).to_s end end it "should have a match method" do @leaf.should respond_to(:match) end it "should delegate match to ==" do @value.expects(:==).with("value") @leaf.match("value") end end describe Puppet::Parser::AST::FlatString do describe "when converting to string" do it "should transform its value to a quoted string" do value = stub 'value', :is_a? => true, :to_s => "ab" Puppet::Parser::AST::FlatString.new( :value => value ).to_s.should == "\"ab\"" end end end describe Puppet::Parser::AST::String do describe "when converting to string" do it "should transform its value to a quoted string" do value = stub 'value', :is_a? => true, :to_s => "ab" Puppet::Parser::AST::String.new( :value => value ).to_s.should == "\"ab\"" end it "should return a dup of its value" do value = "" Puppet::Parser::AST::String.new( :value => value ).evaluate(stub('scope')).should_not be_equal(value) end end end describe Puppet::Parser::AST::Concat do describe "when evaluating" do before :each do @scope = stub_everything 'scope' end it "should interpolate variables and concatenate their values" do one = Puppet::Parser::AST::String.new(:value => "one") one.stubs(:evaluate).returns("one ") two = Puppet::Parser::AST::String.new(:value => "two") two.stubs(:evaluate).returns(" two ") three = Puppet::Parser::AST::String.new(:value => "three") three.stubs(:evaluate).returns(" three") var = Puppet::Parser::AST::Variable.new(:value => "myvar") var.stubs(:evaluate).returns("foo") array = Puppet::Parser::AST::Variable.new(:value => "array") array.stubs(:evaluate).returns(["bar","baz"]) concat = Puppet::Parser::AST::Concat.new(:value => [one,var,two,array,three]) concat.evaluate(@scope).should == 'one foo two barbaz three' end it "should transform undef variables to empty string" do var = Puppet::Parser::AST::Variable.new(:value => "myvar") var.stubs(:evaluate).returns(:undef) concat = Puppet::Parser::AST::Concat.new(:value => [var]) concat.evaluate(@scope).should == '' end end end describe Puppet::Parser::AST::Undef do before :each do @scope = stub 'scope' @undef = Puppet::Parser::AST::Undef.new(:value => :undef) end it "should match undef with undef" do @undef.evaluate_match(:undef, @scope).should be_true end it "should not match undef with an empty string" do @undef.evaluate_match("", @scope).should be_false end end describe Puppet::Parser::AST::HashOrArrayAccess do before :each do @scope = stub 'scope' end describe "when evaluating" do it "should evaluate the variable part if necessary" do @scope.stubs(:lookupvar).with { |name,options| name == 'a'}.returns(["b"]) variable = stub 'variable', :evaluate => "a" access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => variable, :key => 0 ) variable.expects(:safeevaluate).with(@scope).returns("a") access.evaluate(@scope).should == "b" end it "should evaluate the access key part if necessary" do @scope.stubs(:lookupvar).with { |name,options| name == 'a'}.returns(["b"]) index = stub 'index', :evaluate => 0 access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => index ) index.expects(:safeevaluate).with(@scope).returns(0) access.evaluate(@scope).should == "b" end it "should be able to return an array member" do @scope.stubs(:lookupvar).with { |name,options| name == 'a'}.returns(["val1", "val2", "val3"]) access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => 1 ) access.evaluate(@scope).should == "val2" end it "should be able to return an array member when index is a stringified number" do @scope.stubs(:lookupvar).with { |name,options| name == "a" }.returns(["val1", "val2", "val3"]) access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "1" ) access.evaluate(@scope).should == "val2" end it "should raise an error when accessing an array with a key" do @scope.stubs(:lookupvar).with { |name,options| name == "a"}.returns(["val1", "val2", "val3"]) access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "get_me_the_second_element_please" ) lambda { access.evaluate(@scope) }.should raise_error end it "should be able to return an hash value" do @scope.stubs(:lookupvar).with { |name,options| name == 'a'}.returns({ "key1" => "val1", "key2" => "val2", "key3" => "val3" }) access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "key2" ) access.evaluate(@scope).should == "val2" end it "should be able to return an hash value with a numerical key" do @scope.stubs(:lookupvar).with { |name,options| name == "a"}.returns({ "key1" => "val1", "key2" => "val2", "45" => "45", "key3" => "val3" }) access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "45" ) access.evaluate(@scope).should == "45" end it "should raise an error if the variable lookup didn't return an hash or an array" do @scope.stubs(:lookupvar).with { |name,options| name == "a"}.returns("I'm a string") access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "key2" ) lambda { access.evaluate(@scope) }.should raise_error end it "should raise an error if the variable wasn't in the scope" do @scope.stubs(:lookupvar).with { |name,options| name == 'a'}.returns(nil) access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "key2" ) lambda { access.evaluate(@scope) }.should raise_error end it "should return a correct string representation" do access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "key2" ) access.to_s.should == '$a[key2]' end it "should work with recursive hash access" do @scope.stubs(:lookupvar).with { |name,options| name == 'a'}.returns({ "key" => { "subkey" => "b" }}) access1 = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "key") access2 = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => access1, :key => "subkey") access2.evaluate(@scope).should == 'b' end it "should work with interleaved array and hash access" do @scope.stubs(:lookupvar).with { |name,options| name == 'a'}.returns({ "key" => [ "a" , "b" ]}) access1 = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "key") access2 = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => access1, :key => 1) access2.evaluate(@scope).should == 'b' end end describe "when assigning" do it "should add a new key and value" do scope = Puppet::Parser::Scope.new scope.setvar("a", { 'a' => 'b' }) access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "b") access.assign(scope, "c" ) scope.lookupvar("a").should be_include("b") end it "should raise an error when assigning an array element with a key" do @scope.stubs(:lookupvar).with { |name,options| name == "a"}.returns([]) access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "get_me_the_second_element_please" ) lambda { access.assign(@scope, "test") }.should raise_error end it "should be able to return an array member when index is a stringified number" do scope = Puppet::Parser::Scope.new scope.setvar("a", []) access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "0" ) access.assign(scope, "val2") scope.lookupvar("a").should == ["val2"] end it "should raise an error when trying to overwrite an hash value" do @scope.stubs(:lookupvar).with { |name,options| name == "a" }.returns({ "key" => [ "a" , "b" ]}) access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "key") lambda { access.assign(@scope, "test") }.should raise_error end end end describe Puppet::Parser::AST::Regex do before :each do @scope = stub 'scope' end describe "when initializing" do it "should create a Regexp with its content when value is not a Regexp" do Regexp.expects(:new).with("/ab/") Puppet::Parser::AST::Regex.new :value => "/ab/" end it "should not create a Regexp with its content when value is a Regexp" do value = Regexp.new("/ab/") Regexp.expects(:new).with("/ab/").never Puppet::Parser::AST::Regex.new :value => value end end describe "when evaluating" do it "should return self" do val = Puppet::Parser::AST::Regex.new :value => "/ab/" val.evaluate(@scope).should === val end end describe "when evaluate_match" do before :each do @value = stub 'regex' @value.stubs(:match).with("value").returns(true) Regexp.stubs(:new).returns(@value) @regex = Puppet::Parser::AST::Regex.new :value => "/ab/" end it "should issue the regexp match" do @value.expects(:match).with("value") @regex.evaluate_match("value", @scope) end it "should not downcase the paramater value" do @value.expects(:match).with("VaLuE") @regex.evaluate_match("VaLuE", @scope) end it "should set ephemeral scope vars if there is a match" do @scope.expects(:ephemeral_from).with(true, nil, nil) @regex.evaluate_match("value", @scope) end it "should return the match to the caller" do @value.stubs(:match).with("value").returns(:match) @scope.stubs(:ephemeral_from) @regex.evaluate_match("value", @scope) end end it "should return the regex source with to_s" do regex = stub 'regex' Regexp.stubs(:new).returns(regex) val = Puppet::Parser::AST::Regex.new :value => "/ab/" regex.expects(:source) val.to_s end it "should delegate match to the underlying regexp match method" do regex = Regexp.new("/ab/") val = Puppet::Parser::AST::Regex.new :value => regex regex.expects(:match).with("value") val.match("value") end end describe Puppet::Parser::AST::Variable do before :each do @scope = stub 'scope' @var = Puppet::Parser::AST::Variable.new(:value => "myvar", :file => 'my.pp', :line => 222) end it "should lookup the variable in scope" do @scope.expects(:lookupvar).with { |name,options| name == "myvar" }.returns(:myvalue) @var.safeevaluate(@scope).should == :myvalue end it "should pass the source location to lookupvar" do @scope.expects(:lookupvar).with { |name,options| name == "myvar" and options[:file] == 'my.pp' and options[:line] == 222 }.returns(:myvalue) @var.safeevaluate(@scope).should == :myvalue end it "should return undef if the variable wasn't set" do @scope.expects(:lookupvar).with { |name,options| name == "myvar" }.returns(:undefined) @var.safeevaluate(@scope).should == :undef end describe "when converting to string" do it "should transform its value to a variable" do value = stub 'value', :is_a? => true, :to_s => "myvar" Puppet::Parser::AST::Variable.new( :value => value ).to_s.should == "\$myvar" end end end describe Puppet::Parser::AST::HostName do before :each do @scope = stub 'scope' @value = stub 'value', :=~ => false @value.stubs(:to_s).returns(@value) @value.stubs(:downcase).returns(@value) @host = Puppet::Parser::AST::HostName.new( :value => @value) end it "should raise an error if hostname is not valid" do lambda { Puppet::Parser::AST::HostName.new( :value => "not an hostname!" ) }.should raise_error end it "should not raise an error if hostname is a regex" do lambda { Puppet::Parser::AST::HostName.new( :value => Puppet::Parser::AST::Regex.new(:value => "/test/") ) }.should_not raise_error end it "should stringify the value" do value = stub 'value', :=~ => false value.expects(:to_s).returns("test") Puppet::Parser::AST::HostName.new(:value => value) end it "should downcase the value" do value = stub 'value', :=~ => false value.stubs(:to_s).returns("UPCASED") host = Puppet::Parser::AST::HostName.new(:value => value) host.value == "upcased" end it "should evaluate to its value" do @host.evaluate(@scope).should == @value end it "should delegate eql? to the underlying value if it is an HostName" do @value.expects(:eql?).with("value") @host.eql?("value") end it "should delegate eql? to the underlying value if it is not an HostName" do value = stub 'compared', :is_a? => true, :value => "value" @value.expects(:eql?).with("value") @host.eql?(value) end it "should delegate hash to the underlying value" do @value.expects(:hash) @host.hash end end diff --git a/spec/unit/parser/ast/match_operator_spec.rb b/spec/unit/parser/ast/match_operator_spec.rb index 188b837b3..0f9235aeb 100755 --- a/spec/unit/parser/ast/match_operator_spec.rb +++ b/spec/unit/parser/ast/match_operator_spec.rb @@ -1,50 +1,49 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe Puppet::Parser::AST::MatchOperator do before :each do @scope = Puppet::Parser::Scope.new @lval = stub 'lval' @lval.stubs(:safeevaluate).with(@scope).returns("this is a string") @rval = stub 'rval' @rval.stubs(:evaluate_match) @operator = Puppet::Parser::AST::MatchOperator.new :lval => @lval, :rval => @rval, :operator => "=~" end it "should evaluate the left operand" do @lval.expects(:safeevaluate).with(@scope) @operator.evaluate(@scope) end it "should fail for an unknown operator" do lambda { operator = Puppet::Parser::AST::MatchOperator.new :lval => @lval, :operator => "unknown", :rval => @rval }.should raise_error end it "should evaluate_match the left operand" do @rval.expects(:evaluate_match).with("this is a string", @scope).returns(:match) @operator.evaluate(@scope) end { "=~" => true, "!~" => false }.each do |op, res| it "should return #{res} if the regexp matches with #{op}" do match = stub 'match' @rval.stubs(:evaluate_match).with("this is a string", @scope).returns(match) operator = Puppet::Parser::AST::MatchOperator.new :lval => @lval, :rval => @rval, :operator => op operator.evaluate(@scope).should == res end it "should return #{!res} if the regexp doesn't match" do @rval.stubs(:evaluate_match).with("this is a string", @scope).returns(nil) operator = Puppet::Parser::AST::MatchOperator.new :lval => @lval, :rval => @rval, :operator => op operator.evaluate(@scope).should == !res end end end diff --git a/spec/unit/parser/ast/minus_spec.rb b/spec/unit/parser/ast/minus_spec.rb index c8e5339a7..8ebd14e80 100755 --- a/spec/unit/parser/ast/minus_spec.rb +++ b/spec/unit/parser/ast/minus_spec.rb @@ -1,36 +1,35 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe Puppet::Parser::AST::Minus do before :each do @scope = Puppet::Parser::Scope.new end it "should evaluate its argument" do value = stub "value" value.expects(:safeevaluate).with(@scope).returns(123) operator = Puppet::Parser::AST::Minus.new :value => value operator.evaluate(@scope) end it "should fail if argument is not a string or integer" do array_ast = stub 'array_ast', :safeevaluate => [2] operator = Puppet::Parser::AST::Minus.new :value => array_ast lambda { operator.evaluate(@scope) }.should raise_error end it "should work with integer as string" do string = stub 'string', :safeevaluate => "123" operator = Puppet::Parser::AST::Minus.new :value => string operator.evaluate(@scope).should == -123 end it "should work with integers" do int = stub 'int', :safeevaluate => 123 operator = Puppet::Parser::AST::Minus.new :value => int operator.evaluate(@scope).should == -123 end end diff --git a/spec/unit/parser/ast/node_spec.rb b/spec/unit/parser/ast/node_spec.rb index 434cb95bf..c2e187184 100755 --- a/spec/unit/parser/ast/node_spec.rb +++ b/spec/unit/parser/ast/node_spec.rb @@ -1,31 +1,30 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe Puppet::Parser::AST::Node do describe "when instantiated" do it "should make its names and context available through accessors" do node = Puppet::Parser::AST::Node.new(['foo', 'bar'], :line => 5) node.names.should == ['foo', 'bar'] node.context.should == {:line => 5} end it "should create a node with the proper type, name, context, and module name" do node = Puppet::Parser::AST::Node.new(['foo'], :line => 5) instantiated_nodes = node.instantiate('modname') instantiated_nodes.length.should == 1 instantiated_nodes[0].type.should == :node instantiated_nodes[0].name.should == 'foo' instantiated_nodes[0].line.should == 5 instantiated_nodes[0].module_name.should == 'modname' end it "should handle multiple names" do node = Puppet::Parser::AST::Node.new(['foo', 'bar']) instantiated_nodes = node.instantiate('modname') instantiated_nodes.length.should == 2 instantiated_nodes[0].name.should == 'foo' instantiated_nodes[1].name.should == 'bar' end end end diff --git a/spec/unit/parser/ast/nop_spec.rb b/spec/unit/parser/ast/nop_spec.rb index d2307c84a..81302fa55 100755 --- a/spec/unit/parser/ast/nop_spec.rb +++ b/spec/unit/parser/ast/nop_spec.rb @@ -1,20 +1,19 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe Puppet::Parser::AST::Nop do before do @scope = mock 'scope' end it "should do nothing on evaluation" do Puppet::Parser::AST.expects(:safeevaluate).never Puppet::Parser::AST::Nop.new({}).evaluate(@scope) end it "should not return anything" do Puppet::Parser::AST::Nop.new({}).evaluate(@scope).should be_nil end end diff --git a/spec/unit/parser/ast/not_spec.rb b/spec/unit/parser/ast/not_spec.rb index 60fc11c5c..6569af699 100755 --- a/spec/unit/parser/ast/not_spec.rb +++ b/spec/unit/parser/ast/not_spec.rb @@ -1,30 +1,29 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe Puppet::Parser::AST::Not do before :each do @scope = Puppet::Parser::Scope.new @true_ast = Puppet::Parser::AST::Boolean.new( :value => true) @false_ast = Puppet::Parser::AST::Boolean.new( :value => false) end it "should evaluate its child expression" do val = stub "val" val.expects(:safeevaluate).with(@scope) operator = Puppet::Parser::AST::Not.new :value => val operator.evaluate(@scope) end it "should return true for ! false" do operator = Puppet::Parser::AST::Not.new :value => @false_ast operator.evaluate(@scope).should == true end it "should return false for ! true" do operator = Puppet::Parser::AST::Not.new :value => @true_ast operator.evaluate(@scope).should == false end end diff --git a/spec/unit/parser/ast/relationship_spec.rb b/spec/unit/parser/ast/relationship_spec.rb index 871b05c30..441ac45b1 100755 --- a/spec/unit/parser/ast/relationship_spec.rb +++ b/spec/unit/parser/ast/relationship_spec.rb @@ -1,88 +1,87 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe Puppet::Parser::AST::Relationship do before do @class = Puppet::Parser::AST::Relationship end it "should set its 'left' and 'right' arguments accordingly" do dep = @class.new(:left, :right, '->') dep.left.should == :left dep.right.should == :right end it "should set its arrow to whatever arrow is passed" do @class.new(:left, :right, '->').arrow.should == '->' end it "should set its type to :relationship if the relationship type is '<-'" do @class.new(:left, :right, '<-').type.should == :relationship end it "should set its type to :relationship if the relationship type is '->'" do @class.new(:left, :right, '->').type.should == :relationship end it "should set its type to :subscription if the relationship type is '~>'" do @class.new(:left, :right, '~>').type.should == :subscription end it "should set its type to :subscription if the relationship type is '<~'" do @class.new(:left, :right, '<~').type.should == :subscription end it "should set its line and file if provided" do dep = @class.new(:left, :right, '->', :line => 50, :file => "/foo") dep.line.should == 50 dep.file.should == "/foo" end describe "when evaluating" do before do @compiler = Puppet::Parser::Compiler.new(Puppet::Node.new("foo")) @scope = Puppet::Parser::Scope.new(:compiler => @compiler) end it "should create a relationship with the evaluated source and target and add it to the scope" do source = stub 'source', :safeevaluate => :left target = stub 'target', :safeevaluate => :right @class.new(source, target, '->').evaluate(@scope) @compiler.relationships[0].source.should == :left @compiler.relationships[0].target.should == :right end describe "a chained relationship" do before do @left = stub 'left', :safeevaluate => :left @middle = stub 'middle', :safeevaluate => :middle @right = stub 'right', :safeevaluate => :right @first = @class.new(@left, @middle, '->') @second = @class.new(@first, @right, '->') end it "should evaluate the relationship to the left" do @first.expects(:evaluate).with(@scope).returns Puppet::Parser::Relationship.new(:left, :right, :relationship) @second.evaluate(@scope) end it "should use the right side of the left relationship as its source" do @second.evaluate(@scope) @compiler.relationships[0].source.should == :left @compiler.relationships[0].target.should == :middle @compiler.relationships[1].source.should == :middle @compiler.relationships[1].target.should == :right end it "should only evaluate a given AST node once" do @left.expects(:safeevaluate).once.returns :left @middle.expects(:safeevaluate).once.returns :middle @right.expects(:safeevaluate).once.returns :right @second.evaluate(@scope) end end end end diff --git a/spec/unit/parser/ast/resource_defaults_spec.rb b/spec/unit/parser/ast/resource_defaults_spec.rb index 7402be8ea..8164828e1 100755 --- a/spec/unit/parser/ast/resource_defaults_spec.rb +++ b/spec/unit/parser/ast/resource_defaults_spec.rb @@ -1,22 +1,21 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe Puppet::Parser::AST::ResourceDefaults do ast = Puppet::Parser::AST before :each do @compiler = Puppet::Parser::Compiler.new(Puppet::Node.new("mynode")) @scope = Puppet::Parser::Scope.new(:compiler => @compiler) @params = Puppet::Parser::AST::ASTArray.new({}) @compiler.stubs(:add_override) end it "should add defaults when evaluated" do default = Puppet::Parser::AST::ResourceDefaults.new :type => "file", :parameters => Puppet::Parser::AST::ASTArray.new(:children => []) default.evaluate @scope @scope.lookupdefaults("file").should_not be_nil end end diff --git a/spec/unit/parser/ast/resource_override_spec.rb b/spec/unit/parser/ast/resource_override_spec.rb index cb126ce62..458d9a4bf 100755 --- a/spec/unit/parser/ast/resource_override_spec.rb +++ b/spec/unit/parser/ast/resource_override_spec.rb @@ -1,51 +1,50 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe Puppet::Parser::AST::ResourceOverride do ast = Puppet::Parser::AST before :each do @compiler = Puppet::Parser::Compiler.new(Puppet::Node.new("mynode")) @scope = Puppet::Parser::Scope.new(:compiler => @compiler) @params = ast::ASTArray.new({}) @compiler.stubs(:add_override) end it "should evaluate the overriden object" do klass = stub 'klass', :title => "title", :type => "type" object = mock 'object' object.expects(:safeevaluate).with(@scope).returns(klass) ast::ResourceOverride.new(:object => object, :parameters => @params ).evaluate(@scope) end it "should tell the compiler to override the resource with our own" do @compiler.expects(:add_override) klass = stub 'klass', :title => "title", :type => "one" object = mock 'object', :safeevaluate => klass ast::ResourceOverride.new(:object => object , :parameters => @params).evaluate(@scope) end it "should return the overriden resource directly when called with one item" do klass = stub 'klass', :title => "title", :type => "one" object = mock 'object', :safeevaluate => klass override = ast::ResourceOverride.new(:object => object , :parameters => @params).evaluate(@scope) override.should be_an_instance_of(Puppet::Parser::Resource) override.title.should == "title" override.type.should == "One" end it "should return an array of overriden resources when called with an array of titles" do klass1 = stub 'klass1', :title => "title1", :type => "one" klass2 = stub 'klass2', :title => "title2", :type => "one" object = mock 'object', :safeevaluate => [klass1,klass2] override = ast::ResourceOverride.new(:object => object , :parameters => @params).evaluate(@scope) override.should have(2).elements override.each {|o| o.should be_an_instance_of(Puppet::Parser::Resource) } end end diff --git a/spec/unit/parser/ast/resource_reference_spec.rb b/spec/unit/parser/ast/resource_reference_spec.rb index b581e9305..627754dd1 100755 --- a/spec/unit/parser/ast/resource_reference_spec.rb +++ b/spec/unit/parser/ast/resource_reference_spec.rb @@ -1,41 +1,40 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe Puppet::Parser::AST::ResourceReference do ast = Puppet::Parser::AST before :each do @scope = Puppet::Parser::Scope.new end def newref(type, title) title = stub 'title', :safeevaluate => title ref = Puppet::Parser::AST::ResourceReference.new(:type => type, :title => title) end it "should correctly produce reference strings" do newref("File", "/tmp/yay").evaluate(@scope).to_s.should == "File[/tmp/yay]" end it "should produce a single resource when the title evaluates to a string" do newref("File", "/tmp/yay").evaluate(@scope).should == Puppet::Resource.new("file", "/tmp/yay") end it "should return an array of resources if given an array of titles" do titles = mock 'titles', :safeevaluate => ["title1","title2"] ref = ast::ResourceReference.new( :title => titles, :type => "File" ) ref.evaluate(@scope).should == [ Puppet::Resource.new("file", "title1"), Puppet::Resource.new("file", "title2") ] end it "should return a correct representation when converting to string" do type = stub 'type', :is_a? => true, :to_s => "file" title = stub 'title', :is_a? => true, :to_s => "[/tmp/a, /tmp/b]" ast::ResourceReference.new( :type => type, :title => title ).to_s.should == "File[/tmp/a, /tmp/b]" end end diff --git a/spec/unit/parser/ast/resource_spec.rb b/spec/unit/parser/ast/resource_spec.rb index 883b71866..68ad9c229 100755 --- a/spec/unit/parser/ast/resource_spec.rb +++ b/spec/unit/parser/ast/resource_spec.rb @@ -1,184 +1,183 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe Puppet::Parser::AST::Resource do ast = Puppet::Parser::AST describe "for builtin types" do before :each do @title = Puppet::Parser::AST::String.new(:value => "mytitle") @compiler = Puppet::Parser::Compiler.new(Puppet::Node.new("mynode")) @scope = Puppet::Parser::Scope.new(:compiler => @compiler) @scope.stubs(:resource).returns(stub_everything) @instance = ast::ResourceInstance.new(:title => @title, :parameters => ast::ASTArray.new(:children => [])) @resource = ast::Resource.new(:type => "file", :instances => ast::ASTArray.new(:children => [@instance])) @resource.stubs(:qualified_type).returns("Resource") end it "should evaluate all its parameters" do param = stub 'param' param.expects(:safeevaluate).with(@scope).returns Puppet::Parser::Resource::Param.new(:name => "myparam", :value => "myvalue", :source => stub("source")) @instance.stubs(:parameters).returns [param] @resource.evaluate(@scope) end it "should evaluate its title" do @resource.evaluate(@scope)[0].title.should == "mytitle" end it "should flatten the titles array" do titles = [] %w{one two}.each do |title| titles << Puppet::Parser::AST::String.new(:value => title) end array = Puppet::Parser::AST::ASTArray.new(:children => titles) @instance.title = array result = @resource.evaluate(@scope).collect { |r| r.title } result.should be_include("one") result.should be_include("two") end it "should create and return one resource objects per title" do titles = [] %w{one two}.each do |title| titles << Puppet::Parser::AST::String.new(:value => title) end array = Puppet::Parser::AST::ASTArray.new(:children => titles) @instance.title = array result = @resource.evaluate(@scope).collect { |r| r.title } result.should be_include("one") result.should be_include("two") end it "should implicitly iterate over instances" do new_title = Puppet::Parser::AST::String.new(:value => "other_title") new_instance = ast::ResourceInstance.new(:title => new_title, :parameters => ast::ASTArray.new(:children => [])) @resource.instances.push(new_instance) @resource.evaluate(@scope).collect { |r| r.title }.should == ["mytitle", "other_title"] end it "should handover resources to the compiler" do titles = [] %w{one two}.each do |title| titles << Puppet::Parser::AST::String.new(:value => title) end array = Puppet::Parser::AST::ASTArray.new(:children => titles) @instance.title = array result = @resource.evaluate(@scope) result.each do |res| @compiler.catalog.resource(res.ref).should be_instance_of(Puppet::Parser::Resource) end end it "should generate virtual resources if it is virtual" do @resource.virtual = true result = @resource.evaluate(@scope) result[0].should be_virtual end it "should generate virtual and exported resources if it is exported" do @resource.exported = true result = @resource.evaluate(@scope) result[0].should be_virtual result[0].should be_exported end # Related to #806, make sure resources always look up the full path to the resource. describe "when generating qualified resources" do before do @scope = Puppet::Parser::Scope.new :compiler => Puppet::Parser::Compiler.new(Puppet::Node.new("mynode")) @parser = Puppet::Parser::Parser.new(Puppet::Node::Environment.new) ["one", "one::two", "three"].each do |name| @parser.environment.known_resource_types.add(Puppet::Resource::Type.new(:definition, name, {})) end @twoscope = @scope.newscope(:namespace => "one") @twoscope.resource = @scope.resource end def resource(type, params = nil) params ||= Puppet::Parser::AST::ASTArray.new(:children => []) instance = Puppet::Parser::AST::ResourceInstance.new( :title => Puppet::Parser::AST::String.new(:value => "myresource"), :parameters => params) Puppet::Parser::AST::Resource.new(:type => type, :instances => Puppet::Parser::AST::ASTArray.new(:children => [instance])) end it "should be able to generate resources with fully qualified type information" do resource("two").evaluate(@twoscope)[0].type.should == "One::Two" end it "should be able to generate resources with unqualified type information" do resource("one").evaluate(@twoscope)[0].type.should == "One" end it "should correctly generate resources that can look up builtin types" do resource("file").evaluate(@twoscope)[0].type.should == "File" end it "should correctly generate resources that can look up defined classes by title" do @scope.known_resource_types.add_hostclass Puppet::Resource::Type.new(:hostclass, "Myresource", {}) @scope.compiler.stubs(:evaluate_classes) res = resource("class").evaluate(@twoscope)[0] res.type.should == "Class" res.title.should == "Myresource" end it "should evaluate parameterized classes when they are instantiated" do @scope.known_resource_types.add_hostclass Puppet::Resource::Type.new(:hostclass, "Myresource", {}) @scope.compiler.expects(:evaluate_classes).with(['myresource'],@twoscope,false) resource("class").evaluate(@twoscope)[0] end it "should fail for resource types that do not exist" do lambda { resource("nosuchtype").evaluate(@twoscope) }.should raise_error(Puppet::ParseError) end end end describe "for class resources" do before do @title = Puppet::Parser::AST::String.new(:value => "classname") @compiler = Puppet::Parser::Compiler.new(Puppet::Node.new("mynode")) @scope = Puppet::Parser::Scope.new(:compiler => @compiler) @scope.stubs(:resource).returns(stub_everything) @instance = ast::ResourceInstance.new(:title => @title, :parameters => ast::ASTArray.new(:children => [])) @resource = ast::Resource.new(:type => "Class", :instances => ast::ASTArray.new(:children => [@instance])) @resource.stubs(:qualified_type).returns("Resource") @type = Puppet::Resource::Type.new(:hostclass, "classname") @compiler.known_resource_types.add(@type) end it "should instantiate the class" do @compiler.stubs(:evaluate_classes) result = @resource.evaluate(@scope) result.length.should == 1 result.first.ref.should == "Class[Classname]" @compiler.catalog.resource("Class[Classname]").should equal(result.first) end it "should cause its parent to be evaluated" do parent_type = Puppet::Resource::Type.new(:hostclass, "parentname") @compiler.stubs(:evaluate_classes) @compiler.known_resource_types.add(parent_type) @type.parent = "parentname" result = @resource.evaluate(@scope) result.length.should == 1 result.first.ref.should == "Class[Classname]" @compiler.catalog.resource("Class[Classname]").should equal(result.first) @compiler.catalog.resource("Class[Parentname]").should be_instance_of(Puppet::Parser::Resource) end end end diff --git a/spec/unit/parser/ast/selector_spec.rb b/spec/unit/parser/ast/selector_spec.rb index 787a3360f..1bf5f6757 100755 --- a/spec/unit/parser/ast/selector_spec.rb +++ b/spec/unit/parser/ast/selector_spec.rb @@ -1,139 +1,138 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe Puppet::Parser::AST::Selector do before :each do @scope = Puppet::Parser::Scope.new end describe "when evaluating" do before :each do @param = stub 'param' @param.stubs(:safeevaluate).with(@scope).returns("value") @value1 = stub 'value1' @param1 = stub_everything 'param1' @param1.stubs(:safeevaluate).with(@scope).returns(@param1) @param1.stubs(:respond_to?).with(:downcase).returns(false) @value1.stubs(:param).returns(@param1) @value1.stubs(:value).returns(@value1) @value2 = stub 'value2' @param2 = stub_everything 'param2' @param2.stubs(:safeevaluate).with(@scope).returns(@param2) @param2.stubs(:respond_to?).with(:downcase).returns(false) @value2.stubs(:param).returns(@param2) @value2.stubs(:value).returns(@value2) @values = stub 'values', :instance_of? => true @values.stubs(:each).multiple_yields(@value1, @value2) @selector = Puppet::Parser::AST::Selector.new :param => @param, :values => @values @selector.stubs(:fail) end it "should evaluate param" do @param.expects(:safeevaluate).with(@scope) @selector.evaluate(@scope) end it "should scan each option" do @values.expects(:each).multiple_yields(@value1, @value2) @selector.evaluate(@scope) end describe "when scanning values" do it "should evaluate first matching option" do @param2.stubs(:evaluate_match).with { |*arg| arg[0] == "value" }.returns(true) @value2.expects(:safeevaluate).with(@scope) @selector.evaluate(@scope) end it "should return the first matching evaluated option" do @param2.stubs(:evaluate_match).with { |*arg| arg[0] == "value" }.returns(true) @value2.stubs(:safeevaluate).with(@scope).returns(:result) @selector.evaluate(@scope).should == :result end it "should evaluate the default option if none matched" do @param1.stubs(:is_a?).with(Puppet::Parser::AST::Default).returns(true) @value1.expects(:safeevaluate).with(@scope).returns(@param1) @selector.evaluate(@scope) end it "should return the default evaluated option if none matched" do result = stub 'result' @param1.stubs(:is_a?).with(Puppet::Parser::AST::Default).returns(true) @value1.stubs(:safeevaluate).returns(result) @selector.evaluate(@scope).should == result end it "should return nil if nothing matched" do @selector.evaluate(@scope).should be_nil end it "should delegate matching to evaluate_match" do @param1.expects(:evaluate_match).with { |*arg| arg[0] == "value" and arg[1] == @scope } @selector.evaluate(@scope) end it "should evaluate the matching param" do @param1.stubs(:evaluate_match).with { |*arg| arg[0] == "value" and arg[1] == @scope }.returns(true) @value1.expects(:safeevaluate).with(@scope) @selector.evaluate(@scope) end it "should return this evaluated option if it matches" do @param1.stubs(:evaluate_match).with { |*arg| arg[0] == "value" and arg[1] == @scope }.returns(true) @value1.stubs(:safeevaluate).with(@scope).returns(:result) @selector.evaluate(@scope).should == :result end it "should unset scope ephemeral variables after option evaluation" do @scope.stubs(:ephemeral_level).returns(:level) @param1.stubs(:evaluate_match).with { |*arg| arg[0] == "value" and arg[1] == @scope }.returns(true) @value1.stubs(:safeevaluate).with(@scope).returns(:result) @scope.expects(:unset_ephemeral_var).with(:level) @selector.evaluate(@scope) end it "should not leak ephemeral variables even if evaluation fails" do @scope.stubs(:ephemeral_level).returns(:level) @param1.stubs(:evaluate_match).with { |*arg| arg[0] == "value" and arg[1] == @scope }.returns(true) @value1.stubs(:safeevaluate).with(@scope).raises @scope.expects(:unset_ephemeral_var).with(:level) lambda { @selector.evaluate(@scope) }.should raise_error end it "should fail if there is no default" do @selector.expects(:fail) @selector.evaluate(@scope) end end end describe "when converting to string" do it "should produce a string version of this selector" do values = Puppet::Parser::AST::ASTArray.new :children => [ Puppet::Parser::AST::ResourceParam.new(:param => "type", :value => "value", :add => false) ] param = Puppet::Parser::AST::Variable.new :value => "myvar" selector = Puppet::Parser::AST::Selector.new :param => param, :values => values selector.to_s.should == "$myvar ? { type => value }" end end end diff --git a/spec/unit/parser/ast/vardef_spec.rb b/spec/unit/parser/ast/vardef_spec.rb index 5a851bb13..7dd2b31e7 100755 --- a/spec/unit/parser/ast/vardef_spec.rb +++ b/spec/unit/parser/ast/vardef_spec.rb @@ -1,67 +1,66 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe Puppet::Parser::AST::VarDef do before :each do @scope = Puppet::Parser::Scope.new end describe "when evaluating" do it "should evaluate arguments" do name = mock 'name' value = mock 'value' name.expects(:safeevaluate).with(@scope) value.expects(:safeevaluate).with(@scope) vardef = Puppet::Parser::AST::VarDef.new :name => name, :value => value, :file => nil, :line => nil vardef.evaluate(@scope) end it "should be in append=false mode if called without append" do name = stub 'name', :safeevaluate => "var" value = stub 'value', :safeevaluate => "1" @scope.expects(:setvar).with { |name,value,options| options[:append] == nil } vardef = Puppet::Parser::AST::VarDef.new :name => name, :value => value, :file => nil, :line => nil vardef.evaluate(@scope) end it "should call scope in append mode if append is true" do name = stub 'name', :safeevaluate => "var" value = stub 'value', :safeevaluate => "1" @scope.expects(:setvar).with { |name,value,options| options[:append] == true } vardef = Puppet::Parser::AST::VarDef.new :name => name, :value => value, :file => nil, :line => nil, :append => true vardef.evaluate(@scope) end it "should call pass the source location to setvar" do name = stub 'name', :safeevaluate => "var" value = stub 'value', :safeevaluate => "1" @scope.expects(:setvar).with { |name,value,options| options[:file] == 'setvar.pp' and options[:line] == 917 } vardef = Puppet::Parser::AST::VarDef.new :name => name, :value => value, :file => 'setvar.pp', :line => 917 vardef.evaluate(@scope) end describe "when dealing with hash" do it "should delegate to the HashOrArrayAccess assign" do access = stub 'name' access.stubs(:is_a?).with(Puppet::Parser::AST::HashOrArrayAccess).returns(true) value = stub 'value', :safeevaluate => "1" vardef = Puppet::Parser::AST::VarDef.new :name => access, :value => value, :file => nil, :line => nil access.expects(:assign).with(@scope, '1') vardef.evaluate(@scope) end end end end diff --git a/spec/unit/parser/ast_spec.rb b/spec/unit/parser/ast_spec.rb index ba8724242..4d4871219 100755 --- a/spec/unit/parser/ast_spec.rb +++ b/spec/unit/parser/ast_spec.rb @@ -1,111 +1,110 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/parser/ast' describe Puppet::Parser::AST do it "should use the file lookup module" do Puppet::Parser::AST.ancestors.should be_include(Puppet::FileCollection::Lookup) end it "should have a doc accessor" do ast = Puppet::Parser::AST.new({}) ast.should respond_to(:doc) end it "should have a use_docs accessor to indicate it wants documentation" do ast = Puppet::Parser::AST.new({}) ast.should respond_to(:use_docs) end [ Puppet::Parser::AST::Collection, Puppet::Parser::AST::Else, Puppet::Parser::AST::Function, Puppet::Parser::AST::IfStatement, Puppet::Parser::AST::Resource, Puppet::Parser::AST::ResourceDefaults, Puppet::Parser::AST::ResourceOverride, Puppet::Parser::AST::VarDef ].each do |k| it "#{k}.use_docs should return true" do ast = k.new({}) ast.use_docs.should be_true end end describe "when initializing" do it "should store the doc argument if passed" do ast = Puppet::Parser::AST.new(:doc => "documentation") ast.doc.should == "documentation" end end end describe 'AST Generic Child' do before :each do @value = stub 'value' class Evaluateable < Puppet::Parser::AST attr_accessor :value def safeevaluate(*options) return value end end @evaluateable = Evaluateable.new(:value => @value) @scope = stubs 'scope' end describe "when evaluate_match is called" do it "should evaluate itself" do @evaluateable.expects(:safeevaluate).with(@scope) @evaluateable.evaluate_match("value", @scope) end it "should match values by equality" do @value.expects(:==).with("value").returns(true) @evaluateable.evaluate_match("value", @scope) end it "should downcase the evaluated value if wanted" do @value.expects(:downcase).returns("value") @evaluateable.evaluate_match("value", @scope) end it "should convert values to number" do Puppet::Parser::Scope.expects(:number?).with(@value).returns(2) Puppet::Parser::Scope.expects(:number?).with("23").returns(23) @evaluateable.evaluate_match("23", @scope) end it "should compare 'numberized' values" do two = stub_everything 'two' one = stub_everything 'one' Puppet::Parser::Scope.stubs(:number?).with(@value).returns(one) Puppet::Parser::Scope.stubs(:number?).with("2").returns(two) one.expects(:==).with(two) @evaluateable.evaluate_match("2", @scope) end it "should match undef if value is an empty string" do @evaluateable.value = '' @evaluateable.evaluate_match(:undef, @scope).should be_true end it "should downcase the parameter value if wanted" do parameter = stub 'parameter' parameter.expects(:downcase).returns("value") @evaluateable.evaluate_match(parameter, @scope) end it "should not match '' if value is undef" do @evaluateable.value = :undef @evaluateable.evaluate_match('', @scope).should be_false end end end diff --git a/spec/unit/parser/collector_spec.rb b/spec/unit/parser/collector_spec.rb index 75c113eae..01918d2a0 100755 --- a/spec/unit/parser/collector_spec.rb +++ b/spec/unit/parser/collector_spec.rb @@ -1,556 +1,555 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/rails' require 'puppet/parser/collector' describe Puppet::Parser::Collector, "when initializing" do before do @scope = mock 'scope' @resource_type = 'resource_type' @form = :exported @vquery = mock 'vquery' @equery = mock 'equery' @collector = Puppet::Parser::Collector.new(@scope, @resource_type, @equery, @vquery, @form) end it "should require a scope" do @collector.scope.should equal(@scope) end it "should require a resource type" do @collector.type.should == 'Resource_type' end it "should only accept :virtual or :exported as the collector form" do proc { @collector = Puppet::Parser::Collector.new(@scope, @resource_type, @vquery, @equery, :other) }.should raise_error(ArgumentError) end it "should accept an optional virtual query" do @collector.vquery.should equal(@vquery) end it "should accept an optional exported query" do @collector.equery.should equal(@equery) end it "should canonize the type name" do @collector = Puppet::Parser::Collector.new(@scope, "resource::type", @equery, @vquery, @form) @collector.type.should == "Resource::Type" end it "should accept an optional resource override" do @collector = Puppet::Parser::Collector.new(@scope, "resource::type", @equery, @vquery, @form) override = { :parameters => "whatever" } @collector.add_override(override) @collector.overrides.should equal(override) end end describe Puppet::Parser::Collector, "when collecting specific virtual resources" do before do @scope = mock 'scope' @vquery = mock 'vquery' @equery = mock 'equery' @collector = Puppet::Parser::Collector.new(@scope, "resource_type", @equery, @vquery, :virtual) end it "should not fail when it does not find any resources to collect" do @collector.resources = ["File[virtual1]", "File[virtual2]"] @scope.stubs(:findresource).returns(false) proc { @collector.evaluate }.should_not raise_error end it "should mark matched resources as non-virtual" do @collector.resources = ["File[virtual1]", "File[virtual2]"] one = stub_everything 'one' one.expects(:virtual=).with(false) @scope.stubs(:findresource).with("File[virtual1]").returns(one) @scope.stubs(:findresource).with("File[virtual2]").returns(nil) @collector.evaluate end it "should return matched resources" do @collector.resources = ["File[virtual1]", "File[virtual2]"] one = stub_everything 'one' @scope.stubs(:findresource).with("File[virtual1]").returns(one) @scope.stubs(:findresource).with("File[virtual2]").returns(nil) @collector.evaluate.should == [one] end it "should delete itself from the compile's collection list if it has found all of its resources" do @collector.resources = ["File[virtual1]"] one = stub_everything 'one' @compiler.expects(:delete_collection).with(@collector) @scope.expects(:compiler).returns(@compiler) @scope.stubs(:findresource).with("File[virtual1]").returns(one) @collector.evaluate end it "should not delete itself from the compile's collection list if it has unfound resources" do @collector.resources = ["File[virtual1]"] one = stub_everything 'one' @compiler.expects(:delete_collection).never @scope.stubs(:findresource).with("File[virtual1]").returns(nil) @collector.evaluate end end describe Puppet::Parser::Collector, "when collecting virtual and catalog resources" do before do @scope = mock 'scope' @compiler = mock 'compile' @scope.stubs(:compiler).returns(@compiler) @resource_type = "Mytype" @vquery = proc { |res| true } @collector = Puppet::Parser::Collector.new(@scope, @resource_type, nil, @vquery, :virtual) end it "should find all virtual resources matching the vquery" do one = stub_everything 'one', :type => "Mytype", :virtual? => true two = stub_everything 'two', :type => "Mytype", :virtual? => true @compiler.expects(:resources).returns([one, two]) @collector.evaluate.should == [one, two] end it "should find all non-virtual resources matching the vquery" do one = stub_everything 'one', :type => "Mytype", :virtual? => false two = stub_everything 'two', :type => "Mytype", :virtual? => false @compiler.expects(:resources).returns([one, two]) @collector.evaluate.should == [one, two] end it "should mark all matched resources as non-virtual" do one = stub_everything 'one', :type => "Mytype", :virtual? => true one.expects(:virtual=).with(false) @compiler.expects(:resources).returns([one]) @collector.evaluate end it "should return matched resources" do one = stub_everything 'one', :type => "Mytype", :virtual? => true two = stub_everything 'two', :type => "Mytype", :virtual? => true @compiler.expects(:resources).returns([one, two]) @collector.evaluate.should == [one, two] end it "should return all resources of the correct type if there is no virtual query" do one = stub_everything 'one', :type => "Mytype", :virtual? => true two = stub_everything 'two', :type => "Mytype", :virtual? => true one.expects(:virtual=).with(false) two.expects(:virtual=).with(false) @compiler.expects(:resources).returns([one, two]) @collector = Puppet::Parser::Collector.new(@scope, @resource_type, nil, nil, :virtual) @collector.evaluate.should == [one, two] end it "should not return or mark resources of a different type" do one = stub_everything 'one', :type => "Mytype", :virtual? => true two = stub_everything 'two', :type => :other, :virtual? => true one.expects(:virtual=).with(false) two.expects(:virtual=).never @compiler.expects(:resources).returns([one, two]) @collector.evaluate.should == [one] end it "should create a resource with overridden parameters" do one = stub_everything 'one', :type => "Mytype", :virtual? => true, :title => "test" param = stub 'param' @compiler.stubs(:add_override) @compiler.expects(:resources).returns([one]) @collector.add_override(:parameters => param ) Puppet::Parser::Resource.expects(:new).with { |type, title, h| h[:parameters] == param } @collector.evaluate end it "should define a new allow all child_of? on overriden resource" do one = stub_everything 'one', :type => "Mytype", :virtual? => true, :title => "test" param = stub 'param' source = stub 'source' @compiler.stubs(:add_override) @compiler.expects(:resources).returns([one]) @collector.add_override(:parameters => param, :source => source ) Puppet::Parser::Resource.stubs(:new) source.expects(:meta_def).with { |name,block| name == :child_of? } @collector.evaluate end it "should not override already overriden resources for this same collection in a previous run" do one = stub_everything 'one', :type => "Mytype", :virtual? => true, :title => "test" param = stub 'param' @compiler.stubs(:add_override) @compiler.expects(:resources).at_least(2).returns([one]) @collector.add_override(:parameters => param ) Puppet::Parser::Resource.expects(:new).once.with { |type, title, h| h[:parameters] == param } @collector.evaluate @collector.evaluate end it "should not return resources that were collected in a previous run of this collector" do one = stub_everything 'one', :type => "Mytype", :virtual? => true, :title => "test" @compiler.stubs(:resources).returns([one]) @collector.evaluate @collector.evaluate.should be_false end it "should tell the compiler about the overriden resources" do one = stub_everything 'one', :type => "Mytype", :virtual? => true, :title => "test" param = stub 'param' one.expects(:virtual=).with(false) @compiler.expects(:resources).returns([one]) @collector.add_override(:parameters => param ) Puppet::Parser::Resource.stubs(:new).returns("whatever") @compiler.expects(:add_override).with("whatever") @collector.evaluate end it "should not return or mark non-matching resources" do @collector.vquery = proc { |res| res.name == :one } one = stub_everything 'one', :name => :one, :type => "Mytype", :virtual? => true two = stub_everything 'two', :name => :two, :type => "Mytype", :virtual? => true one.expects(:virtual=).with(false) two.expects(:virtual=).never @compiler.expects(:resources).returns([one, two]) @collector.evaluate.should == [one] end end describe Puppet::Parser::Collector, "when collecting exported resources", :if => Puppet.features.rails? do before do @compiler = Puppet::Parser::Compiler.new(Puppet::Node.new("mynode")) @scope = Puppet::Parser::Scope.new :compiler => @compiler @resource_type = "Mytype" @equery = "test = true" @vquery = proc { |r| true } res = stub("resource 1") res.stubs(:type).returns @resource_type Puppet::Resource.stubs(:new).returns res Puppet.settings.stubs(:value).with(:storeconfigs).returns true Puppet.settings.stubs(:value).with(:environment).returns "production" @collector = Puppet::Parser::Collector.new(@scope, @resource_type, @equery, @vquery, :exported) end # Stub most of our interface to Rails. def stub_rails(everything = false) ActiveRecord::Base.stubs(:connected?).returns(false) Puppet::Rails.stubs(:init) if everything Puppet::Rails::Host.stubs(:find_by_name).returns(nil) Puppet::Rails::Resource.stubs(:find).returns([]) end end it "should just return false if :storeconfigs is not enabled" do Puppet.settings.expects(:value).with(:storeconfigs).returns false @collector.evaluate.should be_false end it "should use initialize the Rails support if ActiveRecord is not connected" do @compiler.stubs(:resources).returns([]) ActiveRecord::Base.expects(:connected?).returns(false) Puppet::Rails.expects(:init) Puppet::Rails::Host.stubs(:find_by_name).returns(nil) Puppet::Rails::Resource.stubs(:find).returns([]) @collector.evaluate end it "should return all matching resources from the current compile and mark them non-virtual and non-exported" do stub_rails(true) one = stub 'one', :type => "Mytype", :virtual? => true, :exported? => true, :ref => "one" two = stub 'two', :type => "Mytype", :virtual? => true, :exported? => true, :ref => "two" one.stubs(:exported=) one.stubs(:virtual=) two.stubs(:exported=) two.stubs(:virtual=) @compiler.expects(:resources).returns([one, two]) @collector.evaluate.should == [one, two] end it "should mark all returned resources as not virtual" do stub_rails(true) one = stub 'one', :type => "Mytype", :virtual? => true, :exported? => true, :ref => "one" one.stubs(:exported=) one.expects(:virtual=).with(false) @compiler.expects(:resources).returns([one]) @collector.evaluate.should == [one] end it "should convert all found resources into parser resources" do stub_rails Puppet::Rails::Host.stubs(:find_by_name).returns(nil) one = stub 'one', :restype => "Mytype", :title => "one", :virtual? => true, :exported? => true, :ref => "one" Puppet::Rails::Resource.stubs(:find).returns([one]) resource = mock 'resource' one.expects(:to_resource).with(@scope).returns(resource) resource.stubs(:exported=) resource.stubs(:virtual=) resource.stubs(:ref) @compiler.stubs(:resources).returns([]) @scope.stubs(:findresource).returns(nil) @compiler.stubs(:add_resource) @collector.evaluate.should == [resource] end it "should override all exported collected resources if collector has an override" do stub_rails Puppet::Rails::Host.stubs(:find_by_name).returns(nil) one = stub 'one', :restype => "Mytype", :title => "one", :virtual? => true, :exported? => true, :ref => "one" Puppet::Rails::Resource.stubs(:find).returns([one]) resource = mock 'resource', :type => "Mytype" one.expects(:to_resource).with(@scope).returns(resource) resource.stubs(:exported=) resource.stubs(:virtual=) resource.stubs(:ref) resource.stubs(:title) @compiler.stubs(:resources).returns([]) @scope.stubs(:findresource).returns(nil) param = stub 'param' @compiler.stubs(:add_override) @compiler.stubs(:add_resource) @collector.add_override(:parameters => param ) Puppet::Parser::Resource.expects(:new).once.with { |type, title, h| h[:parameters] == param } @collector.evaluate end it "should store converted resources in the compile's resource list" do stub_rails Puppet::Rails::Host.stubs(:find_by_name).returns(nil) one = stub 'one', :restype => "Mytype", :title => "one", :virtual? => true, :exported? => true, :ref => "one" Puppet::Rails::Resource.stubs(:find).returns([one]) resource = mock 'resource' one.expects(:to_resource).with(@scope).returns(resource) resource.stubs(:exported=) resource.stubs(:virtual=) resource.stubs(:ref) @compiler.stubs(:resources).returns([]) @scope.stubs(:findresource).returns(nil) @compiler.expects(:add_resource).with(@scope, resource) @collector.evaluate.should == [resource] end # This way one host doesn't store another host's resources as exported. it "should mark resources collected from the database as not exported" do stub_rails Puppet::Rails::Host.stubs(:find_by_name).returns(nil) one = stub 'one', :restype => "Mytype", :title => "one", :virtual? => true, :exported? => true, :ref => "one" Puppet::Rails::Resource.stubs(:find).returns([one]) resource = mock 'resource' one.expects(:to_resource).with(@scope).returns(resource) resource.expects(:exported=).with(false) resource.stubs(:virtual=) resource.stubs(:ref) @compiler.stubs(:resources).returns([]) @scope.stubs(:findresource).returns(nil) @compiler.stubs(:add_resource) @collector.evaluate end it "should fail if an equivalent resource already exists in the compile" do stub_rails Puppet::Rails::Host.stubs(:find_by_name).returns(nil) rails = stub 'one', :restype => "Mytype", :title => "one", :virtual? => true, :exported? => true, :id => 1, :ref => "yay" inmemory = stub 'one', :type => "Mytype", :virtual? => true, :exported? => true, :rails_id => 2 Puppet::Rails::Resource.stubs(:find).returns([rails]) resource = mock 'resource' @compiler.stubs(:resources).returns([]) @scope.stubs(:findresource).returns(inmemory) @compiler.stubs(:add_resource) proc { @collector.evaluate }.should raise_error(Puppet::ParseError) end it "should ignore exported resources that match already-collected resources" do stub_rails Puppet::Rails::Host.stubs(:find_by_name).returns(nil) rails = stub 'one', :restype => "Mytype", :title => "one", :virtual? => true, :exported? => true, :id => 1, :ref => "yay" inmemory = stub 'one', :type => "Mytype", :virtual? => true, :exported? => true, :rails_id => 1 Puppet::Rails::Resource.stubs(:find).returns([rails]) resource = mock 'resource' @compiler.stubs(:resources).returns([]) @scope.stubs(:findresource).returns(inmemory) @compiler.stubs(:add_resource) proc { @collector.evaluate }.should_not raise_error(Puppet::ParseError) end end describe Puppet::Parser::Collector, "when building its ActiveRecord query for collecting exported resources", :if => Puppet.features.rails? do before do @scope = stub 'scope', :host => "myhost", :debug => nil @compiler = mock 'compile' @scope.stubs(:compiler).returns(@compiler) @resource_type = "Mytype" @equery = nil @vquery = proc { |r| true } @resource = stub_everything 'collected' @collector = Puppet::Parser::Collector.new(@scope, @resource_type, @equery, @vquery, :exported) @collector.stubs(:exported_resource).with(@resource).returns(@resource) @compiler.stubs(:resources).returns([]) ActiveRecord::Base.stubs(:connected?).returns(false) Puppet::Rails.stubs(:init) Puppet::Rails::Host.stubs(:find_by_name).returns(nil) Puppet::Rails::Resource.stubs(:find).returns([]) Puppet.settings.stubs(:value).with(:storeconfigs).returns true end it "should exclude all resources from the host if ActiveRecord contains information for this host" do @host = mock 'host' @host.stubs(:id).returns 5 Puppet::Rails::Host.expects(:find_by_name).with(@scope.host).returns(@host) Puppet::Rails::Resource.stubs(:find).with { |*arguments| options = arguments[1] options[:conditions][0] =~ /^host_id != \?/ and options[:conditions][1] == 5 }.returns([@resource]) @collector.evaluate.should == [@resource] end it "should join with parameter names, parameter values when querying ActiveRecord" do @collector.equery = "param_names.name = title" Puppet::Rails::Resource.stubs(:find).with { |*arguments| options = arguments[1] options[:joins] == {:param_values => :param_name} }.returns([@resource]) @collector.evaluate.should == [@resource] end it "should join with tag tables when querying ActiveRecord with a tag exported query" do @collector.equery = "puppet_tags.name = test" Puppet::Rails::Resource.stubs(:find).with { |*arguments| options = arguments[1] options[:joins] == {:resource_tags => :puppet_tag} }.returns([@resource]) @collector.evaluate.should == [@resource] end it "should not join parameters when querying ActiveRecord with a tag exported query" do @collector.equery = "puppet_tags.name = test" Puppet::Rails::Resource.stubs(:find).with { |*arguments| options = arguments[1] options[:joins] == {:param_values => :param_name} }.returns([@resource]) @collector.evaluate.should be_false end it "should only search for exported resources with the matching type" do Puppet::Rails::Resource.stubs(:find).with { |*arguments| options = arguments[1] options[:conditions][0].include?("(exported=? AND restype=?)") and options[:conditions][1] == true and options[:conditions][2] == "Mytype" }.returns([@resource]) @collector.evaluate.should == [@resource] end it "should include the export query if one is provided" do @collector.equery = "test = true" Puppet::Rails::Resource.stubs(:find).with { |*arguments| options = arguments[1] options[:conditions][0].include?("test = true") }.returns([@resource]) @collector.evaluate.should == [@resource] end end diff --git a/spec/unit/parser/compiler_spec.rb b/spec/unit/parser/compiler_spec.rb index de4bee3e9..ced760b76 100755 --- a/spec/unit/parser/compiler_spec.rb +++ b/spec/unit/parser/compiler_spec.rb @@ -1,832 +1,831 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' class CompilerTestResource attr_accessor :builtin, :virtual, :evaluated, :type, :title def initialize(type, title) @type = type @title = title end def [](attr) return nil if attr == :stage :main end def ref "#{type.to_s.capitalize}[#{title}]" end def evaluated? @evaluated end def builtin_type? @builtin end def virtual? @virtual end def evaluate end end describe Puppet::Parser::Compiler do def resource(type, title) Puppet::Parser::Resource.new(type, title, :scope => @scope) end before :each do @node = Puppet::Node.new "testnode" @known_resource_types = Puppet::Resource::TypeCollection.new "development" @compiler = Puppet::Parser::Compiler.new(@node) @scope = Puppet::Parser::Scope.new(:compiler => @compiler, :source => stub('source')) @scope_resource = Puppet::Parser::Resource.new(:file, "/my/file", :scope => @scope) @scope.resource = @scope_resource @compiler.environment.stubs(:known_resource_types).returns @known_resource_types end it "should have a class method that compiles, converts, and returns a catalog" do compiler = stub 'compiler' Puppet::Parser::Compiler.expects(:new).with(@node).returns compiler catalog = stub 'catalog' compiler.expects(:compile).returns catalog converted_catalog = stub 'converted_catalog' catalog.expects(:to_resource).returns converted_catalog Puppet::Parser::Compiler.compile(@node).should equal(converted_catalog) end it "should fail intelligently when a class-level compile fails" do Puppet::Parser::Compiler.expects(:new).raises ArgumentError lambda { Puppet::Parser::Compiler.compile(@node) }.should raise_error(Puppet::Error) end it "should use the node's environment as its environment" do @compiler.environment.should equal(@node.environment) end it "should include the resource type collection helper" do Puppet::Parser::Compiler.ancestors.should be_include(Puppet::Resource::TypeCollectionHelper) end it "should be able to return a class list containing all added classes" do @compiler.add_class "" @compiler.add_class "one" @compiler.add_class "two" @compiler.classlist.sort.should == %w{one two}.sort end describe "when initializing" do it "should set its node attribute" do @compiler.node.should equal(@node) end it "should detect when ast nodes are absent" do @compiler.ast_nodes?.should be_false end it "should detect when ast nodes are present" do @known_resource_types.expects(:nodes?).returns true @compiler.ast_nodes?.should be_true end it "should copy the known_resource_types version to the catalog" do @compiler.catalog.version.should == @known_resource_types.version end it "should copy any node classes into the class list" do node = Puppet::Node.new("mynode") node.classes = %w{foo bar} compiler = Puppet::Parser::Compiler.new(node) compiler.classlist.should =~ ['foo', 'bar'] end it "should transform node class hashes into a class list" do node = Puppet::Node.new("mynode") node.classes = {'foo'=>{'one'=>'1'}, 'bar'=>{'two'=>'2'}} compiler = Puppet::Parser::Compiler.new(node) compiler.classlist.should =~ ['foo', 'bar'] end it "should add a 'main' stage to the catalog" do @compiler.catalog.resource(:stage, :main).should be_instance_of(Puppet::Parser::Resource) end end describe "when managing scopes" do it "should create a top scope" do @compiler.topscope.should be_instance_of(Puppet::Parser::Scope) end it "should be able to create new scopes" do @compiler.newscope(@compiler.topscope).should be_instance_of(Puppet::Parser::Scope) end it "should set the parent scope of the new scope to be the passed-in parent" do scope = mock 'scope' newscope = @compiler.newscope(scope) newscope.parent.should equal(scope) end it "should set the parent scope of the new scope to its topscope if the parent passed in is nil" do scope = mock 'scope' newscope = @compiler.newscope(nil) newscope.parent.should equal(@compiler.topscope) end end describe "when compiling" do def compile_methods [:set_node_parameters, :evaluate_main, :evaluate_ast_node, :evaluate_node_classes, :evaluate_generators, :fail_on_unevaluated, :finish, :store, :extract, :evaluate_relationships] end # Stub all of the main compile methods except the ones we're specifically interested in. def compile_stub(*except) (compile_methods - except).each { |m| @compiler.stubs(m) } end it "should set node parameters as variables in the top scope" do params = {"a" => "b", "c" => "d"} @node.stubs(:parameters).returns(params) compile_stub(:set_node_parameters) @compiler.compile @compiler.topscope.lookupvar("a").should == "b" @compiler.topscope.lookupvar("c").should == "d" end it "should set the client and server versions on the catalog" do params = {"clientversion" => "2", "serverversion" => "3"} @node.stubs(:parameters).returns(params) compile_stub(:set_node_parameters) @compiler.compile @compiler.catalog.client_version.should == "2" @compiler.catalog.server_version.should == "3" end it "should evaluate any existing classes named in the node" do classes = %w{one two three four} main = stub 'main' one = stub 'one', :name => "one" three = stub 'three', :name => "three" @node.stubs(:name).returns("whatever") @node.stubs(:classes).returns(classes) @compiler.expects(:evaluate_classes).with(classes, @compiler.topscope) @compiler.class.publicize_methods(:evaluate_node_classes) { @compiler.evaluate_node_classes } end it "should evaluate any parameterized classes named in the node" do classes = {'foo'=>{'1'=>'one'}, 'bar'=>{'2'=>'two'}} @node.stubs(:classes).returns(classes) @compiler.expects(:evaluate_classes).with(classes, @compiler.topscope) @compiler.compile end it "should evaluate the main class if it exists" do compile_stub(:evaluate_main) main_class = @known_resource_types.add Puppet::Resource::Type.new(:hostclass, "") main_class.expects(:evaluate_code).with { |r| r.is_a?(Puppet::Parser::Resource) } @compiler.topscope.expects(:source=).with(main_class) @compiler.compile end it "should create a new, empty 'main' if no main class exists" do compile_stub(:evaluate_main) @compiler.compile @known_resource_types.find_hostclass([""], "").should be_instance_of(Puppet::Resource::Type) end it "should add an edge between the main stage and main class" do @compiler.compile (stage = @compiler.catalog.resource(:stage, "main")).should be_instance_of(Puppet::Parser::Resource) (klass = @compiler.catalog.resource(:class, "")).should be_instance_of(Puppet::Parser::Resource) @compiler.catalog.edge?(stage, klass).should be_true end it "should evaluate any node classes" do @node.stubs(:classes).returns(%w{one two three four}) @compiler.expects(:evaluate_classes).with(%w{one two three four}, @compiler.topscope) @compiler.send(:evaluate_node_classes) end it "should evaluate all added collections" do colls = [] # And when the collections fail to evaluate. colls << mock("coll1-false") colls << mock("coll2-false") colls.each { |c| c.expects(:evaluate).returns(false) } @compiler.add_collection(colls[0]) @compiler.add_collection(colls[1]) compile_stub(:evaluate_generators) @compiler.compile end it "should ignore builtin resources" do resource = resource(:file, "testing") @compiler.add_resource(@scope, resource) resource.expects(:evaluate).never @compiler.compile end it "should evaluate unevaluated resources" do resource = CompilerTestResource.new(:file, "testing") @compiler.add_resource(@scope, resource) # We have to now mark the resource as evaluated resource.expects(:evaluate).with { |*whatever| resource.evaluated = true } @compiler.compile end it "should not evaluate already-evaluated resources" do resource = resource(:file, "testing") resource.stubs(:evaluated?).returns true @compiler.add_resource(@scope, resource) resource.expects(:evaluate).never @compiler.compile end it "should evaluate unevaluated resources created by evaluating other resources" do resource = CompilerTestResource.new(:file, "testing") @compiler.add_resource(@scope, resource) resource2 = CompilerTestResource.new(:file, "other") # We have to now mark the resource as evaluated resource.expects(:evaluate).with { |*whatever| resource.evaluated = true; @compiler.add_resource(@scope, resource2) } resource2.expects(:evaluate).with { |*whatever| resource2.evaluated = true } @compiler.compile end describe "when finishing" do before do @compiler.send(:evaluate_main) @catalog = @compiler.catalog end def add_resource(name, parent = nil) resource = Puppet::Parser::Resource.new "file", name, :scope => @scope @compiler.add_resource(@scope, resource) @catalog.add_edge(parent, resource) if parent resource end it "should call finish() on all resources" do # Add a resource that does respond to :finish resource = Puppet::Parser::Resource.new "file", "finish", :scope => @scope resource.expects(:finish) @compiler.add_resource(@scope, resource) # And one that does not dnf_resource = stub_everything "dnf", :ref => "File[dnf]", :type => "file" @compiler.add_resource(@scope, dnf_resource) @compiler.send(:finish) end it "should call finish() in add_resource order" do resources = sequence('resources') resource1 = add_resource("finish1") resource1.expects(:finish).in_sequence(resources) resource2 = add_resource("finish2") resource2.expects(:finish).in_sequence(resources) @compiler.send(:finish) end it "should add each container's metaparams to its contained resources" do main = @catalog.resource(:class, :main) main[:noop] = true resource1 = add_resource("meh", main) @compiler.send(:finish) resource1[:noop].should be_true end it "should add metaparams recursively" do main = @catalog.resource(:class, :main) main[:noop] = true resource1 = add_resource("meh", main) resource2 = add_resource("foo", resource1) @compiler.send(:finish) resource2[:noop].should be_true end it "should prefer metaparams from immediate parents" do main = @catalog.resource(:class, :main) main[:noop] = true resource1 = add_resource("meh", main) resource2 = add_resource("foo", resource1) resource1[:noop] = false @compiler.send(:finish) resource2[:noop].should be_false end it "should merge tags downward" do main = @catalog.resource(:class, :main) main.tag("one") resource1 = add_resource("meh", main) resource1.tag "two" resource2 = add_resource("foo", resource1) @compiler.send(:finish) resource2.tags.should be_include("one") resource2.tags.should be_include("two") end it "should work if only middle resources have metaparams set" do main = @catalog.resource(:class, :main) resource1 = add_resource("meh", main) resource1[:noop] = true resource2 = add_resource("foo", resource1) @compiler.send(:finish) resource2[:noop].should be_true end end it "should return added resources in add order" do resource1 = resource(:file, "yay") @compiler.add_resource(@scope, resource1) resource2 = resource(:file, "youpi") @compiler.add_resource(@scope, resource2) @compiler.resources.should == [resource1, resource2] end it "should add resources that do not conflict with existing resources" do resource = resource(:file, "yay") @compiler.add_resource(@scope, resource) @compiler.catalog.should be_vertex(resource) end it "should fail to add resources that conflict with existing resources" do path = Puppet.features.posix? ? "/foo" : "C:/foo" file1 = Puppet::Type.type(:file).new :path => path file2 = Puppet::Type.type(:file).new :path => path @compiler.add_resource(@scope, file1) lambda { @compiler.add_resource(@scope, file2) }.should raise_error(Puppet::Resource::Catalog::DuplicateResourceError) end it "should add an edge from the scope resource to the added resource" do resource = resource(:file, "yay") @compiler.add_resource(@scope, resource) @compiler.catalog.should be_edge(@scope.resource, resource) end it "should add an edge to any specified stage for class resources" do other_stage = resource(:stage, "other") @compiler.add_resource(@scope, other_stage) resource = resource(:class, "foo") resource[:stage] = 'other' @compiler.add_resource(@scope, resource) @compiler.catalog.edge?(other_stage, resource).should be_true end it "should fail if a non-class resource attempts to set a stage" do other_stage = resource(:stage, "other") @compiler.add_resource(@scope, other_stage) resource = resource(:file, "foo") resource[:stage] = 'other' lambda { @compiler.add_resource(@scope, resource) }.should raise_error(ArgumentError) end it "should fail if an unknown stage is specified" do resource = resource(:class, "foo") resource[:stage] = 'other' lambda { @compiler.add_resource(@scope, resource) }.should raise_error(ArgumentError) end it "should add edges from the class resources to the parent's stage if no stage is specified" do main = @compiler.catalog.resource(:stage, :main) foo_stage = resource(:stage, :foo_stage) @compiler.add_resource(@scope, foo_stage) resource = resource(:class, "foo") @scope.stubs(:resource).returns(:stage => :foo_stage) @compiler.add_resource(@scope, resource) @compiler.catalog.should be_edge(foo_stage, resource) end it "should add edges from top-level class resources to the main stage if no stage is specified" do main = @compiler.catalog.resource(:stage, :main) resource = resource(:class, "foo") @compiler.add_resource(@scope, resource) @compiler.catalog.should be_edge(main, resource) end it "should not add non-class resources that don't specify a stage to the 'main' stage" do main = @compiler.catalog.resource(:stage, :main) resource = resource(:file, "foo") @compiler.add_resource(@scope, resource) @compiler.catalog.should_not be_edge(main, resource) end it "should not add any parent-edges to stages" do stage = resource(:stage, "other") @compiler.add_resource(@scope, stage) @scope.resource = resource(:class, "foo") @compiler.catalog.edge?(@scope.resource, stage).should be_false end it "should not attempt to add stages to other stages" do other_stage = resource(:stage, "other") second_stage = resource(:stage, "second") @compiler.add_resource(@scope, other_stage) @compiler.add_resource(@scope, second_stage) second_stage[:stage] = "other" @compiler.catalog.edge?(other_stage, second_stage).should be_false end it "should have a method for looking up resources" do resource = resource(:yay, "foo") @compiler.add_resource(@scope, resource) @compiler.findresource("Yay[foo]").should equal(resource) end it "should be able to look resources up by type and title" do resource = resource(:yay, "foo") @compiler.add_resource(@scope, resource) @compiler.findresource("Yay", "foo").should equal(resource) end it "should not evaluate virtual defined resources" do resource = resource(:file, "testing") resource.virtual = true @compiler.add_resource(@scope, resource) resource.expects(:evaluate).never @compiler.compile end end describe "when evaluating collections" do it "should evaluate each collection" do 2.times { |i| coll = mock 'coll%s' % i @compiler.add_collection(coll) # This is the hard part -- we have to emulate the fact that # collections delete themselves if they are done evaluating. coll.expects(:evaluate).with do @compiler.delete_collection(coll) end } @compiler.class.publicize_methods(:evaluate_collections) { @compiler.evaluate_collections } end it "should not fail when there are unevaluated resource collections that do not refer to specific resources" do coll = stub 'coll', :evaluate => false coll.expects(:resources).returns(nil) @compiler.add_collection(coll) lambda { @compiler.compile }.should_not raise_error end it "should fail when there are unevaluated resource collections that refer to a specific resource" do coll = stub 'coll', :evaluate => false coll.expects(:resources).returns(:something) @compiler.add_collection(coll) lambda { @compiler.compile }.should raise_error Puppet::ParseError, 'Failed to realize virtual resources something' end it "should fail when there are unevaluated resource collections that refer to multiple specific resources" do coll = stub 'coll', :evaluate => false coll.expects(:resources).returns([:one, :two]) @compiler.add_collection(coll) lambda { @compiler.compile }.should raise_error Puppet::ParseError, 'Failed to realize virtual resources one, two' end end describe "when evaluating relationships" do it "should evaluate each relationship with its catalog" do dep = stub 'dep' dep.expects(:evaluate).with(@compiler.catalog) @compiler.add_relationship dep @compiler.evaluate_relationships end end describe "when told to evaluate missing classes" do it "should fail if there's no source listed for the scope" do scope = stub 'scope', :source => nil proc { @compiler.evaluate_classes(%w{one two}, scope) }.should raise_error(Puppet::DevError) end it "should raise an error if a class is not found" do @scope.expects(:find_hostclass).with("notfound").returns(nil) lambda{ @compiler.evaluate_classes(%w{notfound}, @scope) }.should raise_error(Puppet::Error, /Could not find class/) end it "should raise an error when it can't find class" do klasses = {'foo'=>nil} @node.classes = klasses @compiler.topscope.stubs(:find_hostclass).with('foo').returns(nil) lambda{ @compiler.compile }.should raise_error(Puppet::Error, /Could not find class foo for testnode/) end end describe "when evaluating found classes" do before do @class = stub 'class', :name => "my::class" @scope.stubs(:find_hostclass).with("myclass").returns(@class) @resource = stub 'resource', :ref => "Class[myclass]", :type => "file" end it "should evaluate each class" do @compiler.catalog.stubs(:tag) @class.expects(:ensure_in_catalog).with(@scope) @scope.stubs(:class_scope).with(@class) @compiler.evaluate_classes(%w{myclass}, @scope) end it "should ensure each node class hash is in catalog and have appropriate parameters" do klasses = {'foo'=>{'1'=>'one'}, 'bar::foo'=>{'2'=>'two'}, 'bar'=>{'1'=> [1,2,3], '2'=>{'foo'=>'bar'}}} @node.classes = klasses ast_obj = Puppet::Parser::AST::String.new(:value => 'foo') klasses.each do |name, params| klass = Puppet::Resource::Type.new(:hostclass, name, :arguments => {'1' => ast_obj, '2' => ast_obj}) @compiler.topscope.known_resource_types.add klass end catalog = @compiler.compile catalog.classes.should =~ ['foo', 'bar::foo', 'settings', 'bar'] r1 = catalog.resources.detect {|r| r.title == 'Foo' } r1.to_hash.should == {:'1' => 'one', :'2' => 'foo'} r1.tags. should =~ ['class', 'foo'] r2 = catalog.resources.detect {|r| r.title == 'Bar::Foo' } r2.to_hash.should == {:'1' => 'foo', :'2' => 'two'} r2.tags.should =~ ['bar::foo', 'class', 'bar', 'foo'] r2 = catalog.resources.detect {|r| r.title == 'Bar' } r2.to_hash.should == {:'1' => [1,2,3], :'2' => {'foo'=>'bar'}} r2.tags.should =~ ['class', 'bar'] end it "should ensure each node class is in catalog and has appropriate tags" do klasses = ['bar::foo'] @node.classes = klasses ast_obj = Puppet::Parser::AST::String.new(:value => 'foo') klasses.each do |name| klass = Puppet::Resource::Type.new(:hostclass, name, :arguments => {'1' => ast_obj, '2' => ast_obj}) @compiler.topscope.known_resource_types.add klass end catalog = @compiler.compile r2 = catalog.resources.detect {|r| r.title == 'Bar::Foo' } r2.tags.should =~ ['bar::foo', 'class', 'bar', 'foo'] end it "should fail if required parameters are missing" do klass = {'foo'=>{'1'=>'one'}} @node.classes = klass klass = Puppet::Resource::Type.new(:hostclass, 'foo', :arguments => {'1' => nil, '2' => nil}) @compiler.topscope.known_resource_types.add klass lambda { @compiler.compile }.should raise_error Puppet::ParseError, "Must pass 2 to Class[Foo]" end it "should fail if invalid parameters are passed" do klass = {'foo'=>{'3'=>'one'}} @node.classes = klass klass = Puppet::Resource::Type.new(:hostclass, 'foo', :arguments => {'1' => nil, '2' => nil}) @compiler.topscope.known_resource_types.add klass lambda { @compiler.compile }.should raise_error Puppet::ParseError, "Invalid parameter 3" end it "should ensure class is in catalog without params" do @node.classes = klasses = {'foo'=>nil} foo = Puppet::Resource::Type.new(:hostclass, 'foo') @compiler.topscope.known_resource_types.add foo catalog = @compiler.compile catalog.classes.should include 'foo' end it "should not evaluate the resources created for found classes unless asked" do @compiler.catalog.stubs(:tag) @resource.expects(:evaluate).never @class.expects(:ensure_in_catalog).returns(@resource) @scope.stubs(:class_scope).with(@class) @compiler.evaluate_classes(%w{myclass}, @scope) end it "should immediately evaluate the resources created for found classes when asked" do @compiler.catalog.stubs(:tag) @resource.expects(:evaluate) @class.expects(:ensure_in_catalog).returns(@resource) @scope.stubs(:class_scope).with(@class) @compiler.evaluate_classes(%w{myclass}, @scope, false) end it "should skip classes that have already been evaluated" do @compiler.catalog.stubs(:tag) @scope.stubs(:class_scope).with(@class).returns("something") @compiler.expects(:add_resource).never @resource.expects(:evaluate).never Puppet::Parser::Resource.expects(:new).never @compiler.evaluate_classes(%w{myclass}, @scope, false) end it "should skip classes previously evaluated with different capitalization" do @compiler.catalog.stubs(:tag) @scope.stubs(:find_hostclass).with("MyClass").returns(@class) @scope.stubs(:class_scope).with(@class).returns("something") @compiler.expects(:add_resource).never @resource.expects(:evaluate).never Puppet::Parser::Resource.expects(:new).never @compiler.evaluate_classes(%w{MyClass}, @scope, false) end end describe "when evaluating AST nodes with no AST nodes present" do it "should do nothing" do @compiler.expects(:ast_nodes?).returns(false) @compiler.known_resource_types.expects(:nodes).never Puppet::Parser::Resource.expects(:new).never @compiler.send(:evaluate_ast_node) end end describe "when evaluating AST nodes with AST nodes present" do before do @compiler.known_resource_types.stubs(:nodes?).returns true # Set some names for our test @node.stubs(:names).returns(%w{a b c}) @compiler.known_resource_types.stubs(:node).with("a").returns(nil) @compiler.known_resource_types.stubs(:node).with("b").returns(nil) @compiler.known_resource_types.stubs(:node).with("c").returns(nil) # It should check this last, of course. @compiler.known_resource_types.stubs(:node).with("default").returns(nil) end it "should fail if the named node cannot be found" do proc { @compiler.send(:evaluate_ast_node) }.should raise_error(Puppet::ParseError) end it "should evaluate the first node class matching the node name" do node_class = stub 'node', :name => "c", :evaluate_code => nil @compiler.known_resource_types.stubs(:node).with("c").returns(node_class) node_resource = stub 'node resource', :ref => "Node[c]", :evaluate => nil, :type => "node" node_class.expects(:ensure_in_catalog).returns(node_resource) @compiler.compile end it "should match the default node if no matching node can be found" do node_class = stub 'node', :name => "default", :evaluate_code => nil @compiler.known_resource_types.stubs(:node).with("default").returns(node_class) node_resource = stub 'node resource', :ref => "Node[default]", :evaluate => nil, :type => "node" node_class.expects(:ensure_in_catalog).returns(node_resource) @compiler.compile end it "should evaluate the node resource immediately rather than using lazy evaluation" do node_class = stub 'node', :name => "c" @compiler.known_resource_types.stubs(:node).with("c").returns(node_class) node_resource = stub 'node resource', :ref => "Node[c]", :type => "node" node_class.expects(:ensure_in_catalog).returns(node_resource) node_resource.expects(:evaluate) @compiler.send(:evaluate_ast_node) end it "should set the node's scope as the top scope" do node_resource = stub 'node resource', :ref => "Node[c]", :evaluate => nil, :type => "node" node_class = stub 'node', :name => "c", :ensure_in_catalog => node_resource @compiler.known_resource_types.stubs(:node).with("c").returns(node_class) # The #evaluate method normally does this. scope = stub 'scope', :source => "mysource" @compiler.topscope.expects(:class_scope).with(node_class).returns(scope) node_resource.stubs(:evaluate) @compiler.stubs :create_settings_scope @compiler.compile @compiler.topscope.should equal(scope) end end describe "when managing resource overrides" do before do @override = stub 'override', :ref => "File[/foo]", :type => "my" @resource = resource(:file, "/foo") end it "should be able to store overrides" do lambda { @compiler.add_override(@override) }.should_not raise_error end it "should apply overrides to the appropriate resources" do @compiler.add_resource(@scope, @resource) @resource.expects(:merge).with(@override) @compiler.add_override(@override) @compiler.compile end it "should accept overrides before the related resource has been created" do @resource.expects(:merge).with(@override) # First store the override @compiler.add_override(@override) # Then the resource @compiler.add_resource(@scope, @resource) # And compile, so they get resolved @compiler.compile end it "should fail if the compile is finished and resource overrides have not been applied" do @compiler.add_override(@override) lambda { @compiler.compile }.should raise_error Puppet::ParseError, 'Could not find resource(s) File[/foo] for overriding' end end end diff --git a/spec/unit/parser/files_spec.rb b/spec/unit/parser/files_spec.rb index 7710871dc..04777f0ec 100755 --- a/spec/unit/parser/files_spec.rb +++ b/spec/unit/parser/files_spec.rb @@ -1,201 +1,200 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/parser/files' describe Puppet::Parser::Files do before do @basepath = Puppet.features.posix? ? "/somepath" : "C:/somepath" end it "should have a method for finding a template" do Puppet::Parser::Files.should respond_to(:find_template) end it "should have a method for finding manifests" do Puppet::Parser::Files.should respond_to(:find_manifests) end describe "when searching for templates" do it "should return fully-qualified templates directly" do Puppet::Parser::Files.expects(:modulepath).never Puppet::Parser::Files.find_template(@basepath + "/my/template").should == @basepath + "/my/template" end it "should return the template from the first found module" do mod = mock 'module' Puppet::Node::Environment.new.expects(:module).with("mymod").returns mod mod.expects(:template).returns("/one/mymod/templates/mytemplate") Puppet::Parser::Files.find_template("mymod/mytemplate").should == "/one/mymod/templates/mytemplate" end it "should return the file in the templatedir if it exists" do Puppet.settings.expects(:value).with(:templatedir, nil).returns("/my/templates") Puppet[:modulepath] = "/one:/two" File.stubs(:directory?).returns(true) FileTest.stubs(:exist?).returns(true) Puppet::Parser::Files.find_template("mymod/mytemplate").should == "/my/templates/mymod/mytemplate" end it "should not raise an error if no valid templatedir exists and the template exists in a module" do mod = mock 'module' Puppet::Node::Environment.new.expects(:module).with("mymod").returns mod mod.expects(:template).returns("/one/mymod/templates/mytemplate") Puppet::Parser::Files.stubs(:templatepath).with(nil).returns(nil) Puppet::Parser::Files.find_template("mymod/mytemplate").should == "/one/mymod/templates/mytemplate" end it "should return unqualified templates if they exist in the template dir" do FileTest.stubs(:exist?).returns true Puppet::Parser::Files.stubs(:templatepath).with(nil).returns(["/my/templates"]) Puppet::Parser::Files.find_template("mytemplate").should == "/my/templates/mytemplate" end it "should only return templates if they actually exist" do FileTest.expects(:exist?).with("/my/templates/mytemplate").returns true Puppet::Parser::Files.stubs(:templatepath).with(nil).returns(["/my/templates"]) Puppet::Parser::Files.find_template("mytemplate").should == "/my/templates/mytemplate" end it "should return nil when asked for a template that doesn't exist" do FileTest.expects(:exist?).with("/my/templates/mytemplate").returns false Puppet::Parser::Files.stubs(:templatepath).with(nil).returns(["/my/templates"]) Puppet::Parser::Files.find_template("mytemplate").should be_nil end it "should search in the template directories before modules" do FileTest.stubs(:exist?).returns true Puppet::Parser::Files.stubs(:templatepath).with(nil).returns(["/my/templates"]) Puppet::Module.expects(:find).never Puppet::Parser::Files.find_template("mytemplate") end it "should accept relative templatedirs" do FileTest.stubs(:exist?).returns true Puppet[:templatedir] = "my/templates" File.expects(:directory?).with(File.join(Dir.getwd,"my/templates")).returns(true) Puppet::Parser::Files.find_template("mytemplate").should == File.join(Dir.getwd,"my/templates/mytemplate") end it "should use the environment templatedir if no module is found and an environment is specified" do FileTest.stubs(:exist?).returns true Puppet::Parser::Files.stubs(:templatepath).with("myenv").returns(["/myenv/templates"]) Puppet::Parser::Files.find_template("mymod/mytemplate", "myenv").should == "/myenv/templates/mymod/mytemplate" end it "should use first dir from environment templatedir if no module is found and an environment is specified" do FileTest.stubs(:exist?).returns true Puppet::Parser::Files.stubs(:templatepath).with("myenv").returns(["/myenv/templates", "/two/templates"]) Puppet::Parser::Files.find_template("mymod/mytemplate", "myenv").should == "/myenv/templates/mymod/mytemplate" end it "should use a valid dir when templatedir is a path for unqualified templates and the first dir contains template" do Puppet::Parser::Files.stubs(:templatepath).returns(["/one/templates", "/two/templates"]) FileTest.expects(:exist?).with("/one/templates/mytemplate").returns(true) Puppet::Parser::Files.find_template("mytemplate").should == "/one/templates/mytemplate" end it "should use a valid dir when templatedir is a path for unqualified templates and only second dir contains template" do Puppet::Parser::Files.stubs(:templatepath).returns(["/one/templates", "/two/templates"]) FileTest.expects(:exist?).with("/one/templates/mytemplate").returns(false) FileTest.expects(:exist?).with("/two/templates/mytemplate").returns(true) Puppet::Parser::Files.find_template("mytemplate").should == "/two/templates/mytemplate" end it "should use the node environment if specified" do mod = mock 'module' Puppet::Node::Environment.new("myenv").expects(:module).with("mymod").returns mod mod.expects(:template).returns("/my/modules/mymod/templates/envtemplate") Puppet::Parser::Files.find_template("mymod/envtemplate", "myenv").should == "/my/modules/mymod/templates/envtemplate" end it "should return nil if no template can be found" do Puppet::Parser::Files.find_template("foomod/envtemplate", "myenv").should be_nil end after { Puppet.settings.clear } end describe "when searching for manifests" do it "should ignore invalid modules" do mod = mock 'module' Puppet::Node::Environment.new.expects(:module).with("mymod").raises(Puppet::Module::InvalidName, "name is invalid") Puppet.expects(:value).with(:modulepath).never Dir.stubs(:glob).returns %w{foo} Puppet::Parser::Files.find_manifests("mymod/init.pp") end end describe "when searching for manifests when no module is found" do before do File.stubs(:find).returns(nil) end it "should not look for modules when paths are fully qualified" do Puppet.expects(:value).with(:modulepath).never file = @basepath + "/fully/qualified/file.pp" Dir.stubs(:glob).with(file).returns([file]) Puppet::Parser::Files.find_manifests(file) end it "should return nil and an array of fully qualified files" do file = @basepath + "/fully/qualified/file.pp" Dir.stubs(:glob).with(file).returns([file]) Puppet::Parser::Files.find_manifests(file).should == [nil, [file]] end it "should match against provided fully qualified patterns" do pattern = @basepath + "/fully/qualified/pattern/*" Dir.expects(:glob).with(pattern+'{.pp,.rb}').returns(%w{my file list}) Puppet::Parser::Files.find_manifests(pattern)[1].should == %w{my file list} end it "should look for files relative to the current directory" do cwd = Dir.getwd Dir.expects(:glob).with("#{cwd}/foobar/init.pp").returns(["#{cwd}/foobar/init.pp"]) Puppet::Parser::Files.find_manifests("foobar/init.pp")[1].should == ["#{cwd}/foobar/init.pp"] end it "should only return files, not directories" do pattern = @basepath + "/fully/qualified/pattern/*" file = @basepath + "/my/file" dir = @basepath + "/my/directory" Dir.expects(:glob).with(pattern+'{.pp,.rb}').returns([file, dir]) FileTest.expects(:directory?).with(file).returns(false) FileTest.expects(:directory?).with(dir).returns(true) Puppet::Parser::Files.find_manifests(pattern)[1].should == [file] end it "should return files once only" do pattern = @basepath + "/fully/qualified/pattern/*" Dir.expects(:glob).with(pattern+'{.pp,.rb}').returns(%w{one two one}) Puppet::Parser::Files.find_manifests(pattern)[1].should == %w{one two} end end describe "when searching for manifests in a found module" do it "should return the name of the module and the manifests from the first found module" do mod = Puppet::Module.new("mymod") Puppet::Node::Environment.new.expects(:module).with("mymod").returns mod mod.expects(:match_manifests).with("init.pp").returns(%w{/one/mymod/manifests/init.pp}) Puppet::Parser::Files.find_manifests("mymod/init.pp").should == ["mymod", ["/one/mymod/manifests/init.pp"]] end it "should use the node environment if specified" do mod = Puppet::Module.new("mymod") Puppet::Node::Environment.new("myenv").expects(:module).with("mymod").returns mod mod.expects(:match_manifests).with("init.pp").returns(%w{/one/mymod/manifests/init.pp}) Puppet::Parser::Files.find_manifests("mymod/init.pp", :environment => "myenv")[1].should == ["/one/mymod/manifests/init.pp"] end after { Puppet.settings.clear } end end diff --git a/spec/unit/parser/functions/defined_spec.rb b/spec/unit/parser/functions/defined_spec.rb index 8b0fb4e2f..0651864fb 100755 --- a/spec/unit/parser/functions/defined_spec.rb +++ b/spec/unit/parser/functions/defined_spec.rb @@ -1,53 +1,52 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe "the 'defined' function" do before :all do Puppet::Parser::Functions.autoloader.loadall end before :each do Puppet::Node::Environment.stubs(:current).returns(nil) @compiler = Puppet::Parser::Compiler.new(Puppet::Node.new("foo")) @scope = Puppet::Parser::Scope.new(:compiler => @compiler) end it "should exist" do Puppet::Parser::Functions.function("defined").should == "function_defined" end it "should be true when the name is defined as a class" do @scope.known_resource_types.add Puppet::Resource::Type.new(:hostclass, "yayness") @scope.function_defined("yayness").should be_true end it "should be true when the name is defined as a definition" do @scope.known_resource_types.add Puppet::Resource::Type.new(:definition, "yayness") @scope.function_defined("yayness").should be_true end it "should be true when the name is defined as a builtin type" do @scope.function_defined("file").should be_true end it "should be true when any of the provided names are defined" do @scope.known_resource_types.add Puppet::Resource::Type.new(:definition, "yayness") @scope.function_defined(["meh", "yayness", "booness"]).should be_true end it "should be false when a single given name is not defined" do @scope.function_defined("meh").should be_false end it "should be false when none of the names are defined" do @scope.function_defined(["meh", "yayness", "booness"]).should be_false end it "should be true when a resource reference is provided and the resource is in the catalog" do resource = Puppet::Resource.new("file", "/my/file") @compiler.add_resource(@scope, resource) @scope.function_defined(resource).should be_true end end diff --git a/spec/unit/parser/functions/extlookup_spec.rb b/spec/unit/parser/functions/extlookup_spec.rb index ad89f6575..f68daaf3f 100755 --- a/spec/unit/parser/functions/extlookup_spec.rb +++ b/spec/unit/parser/functions/extlookup_spec.rb @@ -1,96 +1,95 @@ -#! /usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'tempfile' describe "the extlookup function" do before :all do Puppet::Parser::Functions.autoloader.loadall end before :each do @scope = Puppet::Parser::Scope.new @scope.stubs(:environment).returns(Puppet::Node::Environment.new('production')) end it "should exist" do Puppet::Parser::Functions.function("extlookup").should == "function_extlookup" end it "should raise a ParseError if there is less than 1 arguments" do lambda { @scope.function_extlookup([]) }.should( raise_error(Puppet::ParseError)) end it "should raise a ParseError if there is more than 3 arguments" do lambda { @scope.function_extlookup(["foo", "bar", "baz", "gazonk"]) }.should( raise_error(Puppet::ParseError)) end it "should return the default" do result = @scope.function_extlookup([ "key", "default"]) result.should == "default" end it "should lookup the key in a supplied datafile" do t = Tempfile.new('extlookup.csv') do t.puts 'key,value' t.puts 'nonkey,nonvalue' t.close result = @scope.function_extlookup([ "key", "default", t.path]) result.should == "value" end end it "should return an array if the datafile contains more than two columns" do t = Tempfile.new('extlookup.csv') do t.puts 'key,value1,value2' t.puts 'nonkey,nonvalue,nonvalue' t.close result = @scope.function_extlookup([ "key", "default", t.path]) result.should == ["value1", "value2"] end end it "should raise an error if there's no matching key and no default" do t = Tempfile.new('extlookup.csv') do t.puts 'key,value' t.puts 'nonkey,nonvalue' t.close result = @scope.function_extlookup([ "key", nil, t.path]) result.should == "value" end end describe "should look in $extlookup_datadir for data files listed by $extlookup_precedence" do before do @scope.stubs(:lookupvar).with('::extlookup_datadir').returns("/tmp") File.open("/tmp/one.csv","w"){|one| one.puts "key,value1" } File.open("/tmp/two.csv","w") do |two| two.puts "key,value2" two.puts "key2,value_two" end end it "when the key is in the first file" do @scope.stubs(:lookupvar).with('::extlookup_precedence').returns(["one","two"]) result = @scope.function_extlookup([ "key" ]) result.should == "value1" end it "when the key is in the second file" do @scope.stubs(:lookupvar).with('::extlookup_precedence').returns(["one","two"]) result = @scope.function_extlookup([ "key2" ]) result.should == "value_two" end it "should not modify extlookup_precedence data" do variable = '%{fqdn}' @scope.stubs(:lookupvar).with('::extlookup_precedence').returns([variable,"one"]) @scope.stubs(:lookupvar).with('::fqdn').returns('myfqdn') result = @scope.function_extlookup([ "key" ]) variable.should == '%{fqdn}' end end end diff --git a/spec/unit/parser/functions/fqdn_rand_spec.rb b/spec/unit/parser/functions/fqdn_rand_spec.rb index 90792e182..90fc0ef41 100755 --- a/spec/unit/parser/functions/fqdn_rand_spec.rb +++ b/spec/unit/parser/functions/fqdn_rand_spec.rb @@ -1,65 +1,64 @@ -#! /usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe "the fqdn_rand function" do before :all do Puppet::Parser::Functions.autoloader.loadall end before :each do @scope = Puppet::Parser::Scope.new end it "should exist" do Puppet::Parser::Functions.function("fqdn_rand").should == "function_fqdn_rand" end it "should handle 0 arguments" do @scope.expects(:lookupvar).with("::fqdn").returns("127.0.0.1") lambda { @scope.function_fqdn_rand([]) }.should_not raise_error(Puppet::ParseError) end it "should handle 1 argument'}" do @scope.expects(:lookupvar).with("::fqdn").returns("127.0.0.1") lambda { @scope.function_fqdn_rand([3]) }.should_not raise_error(Puppet::ParseError) end (1..10).each { |n| it "should handle #{n} additional arguments" do @scope.expects(:lookupvar).with("::fqdn").returns("127.0.0.1") lambda { @scope.function_fqdn_rand([3,1,2,3,4,5,6,7,8,9,10][0..n]) }.should_not raise_error(Puppet::ParseError) end it "should handle #{n} additional string arguments" do @scope.expects(:lookupvar).with("::fqdn").returns("127.0.0.1") lambda { @scope.function_fqdn_rand([3,%w{ 1 2 3 4 5 6 7 8 9 10}].flatten[0..n]) }.should_not raise_error(Puppet::ParseError) end } it "should return a value less than max" do @scope.expects(:lookupvar).with("::fqdn").returns("127.0.0.1") @scope.function_fqdn_rand([3]).should satisfy {|n| n.to_i < 3 } end it "should return the same values on subsequent invocations for the same host" do @scope.expects(:lookupvar).with("::fqdn").returns("127.0.0.1").twice @scope.function_fqdn_rand([3,4]).should eql(@scope.function_fqdn_rand([3, 4])) end it "should return different sequences of value for different hosts" do @scope.expects(:lookupvar).with("::fqdn").returns("127.0.0.1") val1 = @scope.function_fqdn_rand([10000000,4]) @scope.expects(:lookupvar).with("::fqdn").returns("127.0.0.2") val2 = @scope.function_fqdn_rand([10000000,4]) val1.should_not eql(val2) end it "should return different values for the same hosts with different seeds" do @scope.expects(:lookupvar).with("::fqdn").returns("127.0.0.1") val1 = @scope.function_fqdn_rand([10000000,4]) @scope.expects(:lookupvar).with("::fqdn").returns("127.0.0.1") val2 = @scope.function_fqdn_rand([10000000,42]) val1.should_not eql(val2) end end diff --git a/spec/unit/parser/functions/generate_spec.rb b/spec/unit/parser/functions/generate_spec.rb index 3351291d5..6c90ae531 100755 --- a/spec/unit/parser/functions/generate_spec.rb +++ b/spec/unit/parser/functions/generate_spec.rb @@ -1,44 +1,43 @@ -#! /usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe "the generate function" do before :all do Puppet::Parser::Functions.autoloader.loadall end before :each do @scope = Puppet::Parser::Scope.new end it "should exist" do Puppet::Parser::Functions.function("generate").should == "function_generate" end it "should accept a fully-qualified path as a command" do command = File::SEPARATOR + "command" Puppet::Util.expects(:execute).with([command]).returns("yay") lambda { @scope.function_generate([command]) }.should_not raise_error(Puppet::ParseError) end it "should not accept a relative path as a command" do command = "command" lambda { @scope.function_generate([command]) }.should raise_error(Puppet::ParseError) end # Really not sure how to implement this test, just sure it needs # to be implemented. it "should not accept a command containing illegal characters" it "should not accept a command containing '..'" do command = File::SEPARATOR + "command#{File::SEPARATOR}..#{File::SEPARATOR}" lambda { @scope.function_generate([command]) }.should raise_error(Puppet::ParseError) end it "should execute the generate script with the correct working directory" do command = File::SEPARATOR + "command" Dir.expects(:chdir).with(File.dirname(command)).yields Puppet::Util.expects(:execute).with([command]).returns("yay") lambda { @scope.function_generate([command]) }.should_not raise_error(Puppet::ParseError) end end diff --git a/spec/unit/parser/functions/include_spec.rb b/spec/unit/parser/functions/include_spec.rb index b477f1439..15206cd7c 100755 --- a/spec/unit/parser/functions/include_spec.rb +++ b/spec/unit/parser/functions/include_spec.rb @@ -1,36 +1,35 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe "the 'include' function" do before :all do Puppet::Parser::Functions.autoloader.loadall end before :each do Puppet::Node::Environment.stubs(:current).returns(nil) @compiler = Puppet::Parser::Compiler.new(Puppet::Node.new("foo")) @scope = Puppet::Parser::Scope.new(:compiler => @compiler) end it "should exist" do Puppet::Parser::Functions.function("include").should == "function_include" end it "should include a single class" do inc = "foo" @compiler.expects(:evaluate_classes).with {|klasses,parser,lazy| klasses == [inc]}.returns([inc]) @scope.function_include("foo") end it "should include multiple classes" do inc = ["foo","bar"] @compiler.expects(:evaluate_classes).with {|klasses,parser,lazy| klasses == inc}.returns(inc) @scope.function_include(["foo","bar"]) end it "should not lazily evaluate the included class" do @compiler.expects(:evaluate_classes).with {|klasses,parser,lazy| lazy == false}.returns("foo") @scope.function_include("foo") end end diff --git a/spec/unit/parser/functions/inline_template_spec.rb b/spec/unit/parser/functions/inline_template_spec.rb index e009870c5..a9ac0c2d0 100755 --- a/spec/unit/parser/functions/inline_template_spec.rb +++ b/spec/unit/parser/functions/inline_template_spec.rb @@ -1,62 +1,61 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe "the inline_template function" do before :all do Puppet::Parser::Functions.autoloader.loadall end before :each do @scope = Puppet::Parser::Scope.new end it "should exist" do Puppet::Parser::Functions.function("inline_template").should == "function_inline_template" end it "should create a TemplateWrapper when called" do tw = stub_everything 'template_wrapper' Puppet::Parser::TemplateWrapper.expects(:new).returns(tw) @scope.function_inline_template("test") end it "should pass the template string to TemplateWrapper.result" do tw = stub_everything 'template_wrapper' Puppet::Parser::TemplateWrapper.stubs(:new).returns(tw) tw.expects(:result).with("test") @scope.function_inline_template("test") end it "should return what TemplateWrapper.result returns" do tw = stub_everything 'template_wrapper' Puppet::Parser::TemplateWrapper.stubs(:new).returns(tw) tw.expects(:result).returns("template contents evaluated") @scope.function_inline_template("test").should == "template contents evaluated" end it "should concatenate template wrapper outputs for multiple templates" do tw1 = stub_everything "template_wrapper1" tw2 = stub_everything "template_wrapper2" Puppet::Parser::TemplateWrapper.stubs(:new).returns(tw1,tw2) tw1.stubs(:result).returns("result1") tw2.stubs(:result).returns("result2") @scope.function_inline_template(["1","2"]).should == "result1result2" end it "should raise an error if the template raises an error" do tw = stub_everything 'template_wrapper' Puppet::Parser::TemplateWrapper.stubs(:new).returns(tw) tw.stubs(:result).raises lambda { @scope.function_inline_template("1") }.should raise_error(Puppet::ParseError) end end diff --git a/spec/unit/parser/functions/realize_spec.rb b/spec/unit/parser/functions/realize_spec.rb index 7a039c002..159805cbd 100755 --- a/spec/unit/parser/functions/realize_spec.rb +++ b/spec/unit/parser/functions/realize_spec.rb @@ -1,54 +1,53 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe "the realize function" do before :all do Puppet::Parser::Functions.autoloader.loadall end before :each do @collector = stub_everything 'collector' @scope = Puppet::Parser::Scope.new @compiler = stub 'compiler' @compiler.stubs(:add_collection).with(@collector) @scope.stubs(:compiler).returns(@compiler) end it "should exist" do Puppet::Parser::Functions.function("realize").should == "function_realize" end it "should create a Collector when called" do Puppet::Parser::Collector.expects(:new).returns(@collector) @scope.function_realize("test") end it "should assign the passed-in resources to the collector" do Puppet::Parser::Collector.stubs(:new).returns(@collector) @collector.expects(:resources=).with(["test"]) @scope.function_realize("test") end it "should flatten the resources assigned to the collector" do Puppet::Parser::Collector.stubs(:new).returns(@collector) @collector.expects(:resources=).with(["test"]) @scope.function_realize([["test"]]) end it "should let the compiler know this collector" do Puppet::Parser::Collector.stubs(:new).returns(@collector) @collector.stubs(:resources=).with(["test"]) @compiler.expects(:add_collection).with(@collector) @scope.function_realize("test") end end diff --git a/spec/unit/parser/functions/regsubst_spec.rb b/spec/unit/parser/functions/regsubst_spec.rb index 0cab3d18c..4ed3bcf68 100755 --- a/spec/unit/parser/functions/regsubst_spec.rb +++ b/spec/unit/parser/functions/regsubst_spec.rb @@ -1,195 +1,194 @@ -#! /usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe "the regsubst function" do before :all do Puppet::Parser::Functions.autoloader.loadall end before :each do @scope = Puppet::Parser::Scope.new end it "should exist" do Puppet::Parser::Functions.function("regsubst").should == "function_regsubst" end it "should raise a ParseError if there is less than 3 arguments" do lambda { @scope.function_regsubst(["foo", "bar"]) }.should( raise_error(Puppet::ParseError)) end it "should raise a ParseError if there is more than 5 arguments" do lambda { @scope.function_regsubst(["foo", "bar", "gazonk", "del", "x", "y"]) }.should( raise_error(Puppet::ParseError)) end it "should raise a ParseError when given a bad flag" do lambda { @scope.function_regsubst(["foo", "bar", "gazonk", "X"]) }.should( raise_error(Puppet::ParseError)) end it "should raise a ParseError for non-string and non-array target" do lambda { @scope.function_regsubst([4711, "bar", "gazonk"]) }.should( raise_error(Puppet::ParseError)) end it "should raise a ParseError for array target with non-string element" do lambda { @scope.function_regsubst([["x", ["y"], "z"], "bar", "gazonk"]) }.should( raise_error(Puppet::ParseError)) end it "should raise a ParseError for a bad regular expression" do lambda { @scope.function_regsubst(["foo", "(bar", "gazonk"]) }.should( raise_error(Puppet::ParseError)) end it "should raise a ParseError for a non-string regular expression" do lambda { @scope.function_regsubst(["foo", ["bar"], "gazonk"]) }.should( raise_error(Puppet::ParseError)) end it "should handle groups" do result = @scope.function_regsubst( [ '130.236.254.10', '^([0-9]+)[.]([0-9]+)[.]([0-9]+)[.]([0-9]+)$', '\4-\3-\2-\1' ]) result.should(eql("10-254-236-130")) end it "should handle simple regexps" do result = @scope.function_regsubst( [ "the monkey breaks banana trees", "b[an]*a", "coconut" ]) result.should(eql("the monkey breaks coconut trees")) end it "should handle case-sensitive regexps" do result = @scope.function_regsubst( [ "the monkey breaks baNAna trees", "b[an]+a", "coconut" ]) result.should(eql("the monkey breaks baNAna trees")) end it "should handle case-insensitive regexps" do result = @scope.function_regsubst( [ "the monkey breaks baNAna trees", "b[an]+a", "coconut", "I" ]) result.should(eql("the monkey breaks coconut trees")) end it "should handle global substitutions" do result = @scope.function_regsubst( [ "the monkey breaks\tbanana trees", "[ \t]", "--", "G" ]) result.should(eql("the--monkey--breaks--banana--trees")) end it "should handle global substitutions with groups" do result = @scope.function_regsubst( [ '130.236.254.10', '([0-9]+)', '<\1>', 'G' ]) result.should(eql('<130>.<236>.<254>.<10>')) end it "should apply on all elements of an array" do data = ['130.236.254.10', 'foo.example.com', 'coconut', '10.20.30.40'] result = @scope.function_regsubst([ data, '[.]', '-']) result.should(eql( ['130-236.254.10', 'foo-example.com', 'coconut', '10-20.30.40'])) end it "should apply global substitutions on all elements of an array" do data = ['130.236.254.10', 'foo.example.com', 'coconut', '10.20.30.40'] result = @scope.function_regsubst([ data, '[.]', '-', 'G']) result.should(eql( ['130-236-254-10', 'foo-example-com', 'coconut', '10-20-30-40'])) end it "should handle groups on all elements of an array" do data = ['130.236.254.10', 'foo.example.com', 'coconut', '10.20.30.40'] result = @scope.function_regsubst( [ data, '^([0-9]+)[.]([0-9]+)[.]([0-9]+)[.]([0-9]+)$', '\4-\3-\2-\1' ]) result.should(eql( ['10-254-236-130', 'foo.example.com', 'coconut', '40-30-20-10'])) end it "should handle global substitutions with groups on all elements of an array" do data = ['130.236.254.10', 'foo.example.com', 'coconut', '10.20.30.40'] result = @scope.function_regsubst( [ data, '([^.]+)', '<\1>', 'G' ]) result.should(eql( ['<130>.<236>.<254>.<10>', '..', '', '<10>.<20>.<30>.<40>'])) end it "should return an array (not a string) for a single element array parameter" do data = ['130.236.254.10'] result = @scope.function_regsubst( [ data, '([^.]+)', '<\1>', 'G' ]) result.should(eql(['<130>.<236>.<254>.<10>'])) end it "should return a string (not a one element array) for a simple string parameter" do data = '130.236.254.10' result = @scope.function_regsubst( [ data, '([^.]+)', '<\1>', 'G' ]) result.should(eql('<130>.<236>.<254>.<10>')) end end diff --git a/spec/unit/parser/functions/require_spec.rb b/spec/unit/parser/functions/require_spec.rb index cb89db3a1..692b35305 100755 --- a/spec/unit/parser/functions/require_spec.rb +++ b/spec/unit/parser/functions/require_spec.rb @@ -1,77 +1,76 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe "the require function" do before :all do Puppet::Parser::Functions.autoloader.loadall end before :each do @catalog = stub 'catalog' @compiler = stub 'compiler', :catalog => @catalog, :environment => nil @scope = Puppet::Parser::Scope.new @scope.stubs(:findresource) @scope.stubs(:compiler).returns(@compiler) @klass = stub 'class', :name => "myclass" @scope.stubs(:find_hostclass).returns(@klass) @resource = Puppet::Parser::Resource.new(:file, "/my/file", :scope => @scope, :source => "source") @resource.stubs(:metaparam_compatibility_mode?).returns false @scope.stubs(:resource).returns @resource end it "should exist" do Puppet::Parser::Functions.function("require").should == "function_require" end it "should delegate to the 'include' puppet function" do @scope.expects(:function_include).with("myclass") @scope.function_require("myclass") end it "should set the 'require' prarameter on the resource to a resource reference" do @scope.stubs(:function_include) @scope.function_require("myclass") @resource["require"].should be_instance_of(Array) @resource["require"][0].should be_instance_of(Puppet::Resource) end it "should verify the 'include' function is loaded" do Puppet::Parser::Functions.expects(:function).with(:include).returns(:function_include) @scope.stubs(:function_include) @scope.function_require("myclass") end it "should include the class but not add a dependency if used on a client not at least version 0.25" do @resource.expects(:metaparam_compatibility_mode?).returns true @scope.expects(:warning) @resource.expects(:set_parameter).never @scope.expects(:function_include) @scope.function_require("myclass") end it "should lookup the absolute class path" do @scope.stubs(:function_include) @scope.expects(:find_hostclass).with("myclass").returns(@klass) @klass.expects(:name).returns("myclass") @scope.function_require("myclass") end it "should append the required class to the require parameter" do @scope.stubs(:function_include) one = Puppet::Resource.new(:file, "/one") @resource[:require] = one @scope.function_require("myclass") @resource[:require].should be_include(one) @resource[:require].detect { |r| r.to_s == "Class[Myclass]" }.should be_instance_of(Puppet::Resource) end end diff --git a/spec/unit/parser/functions/shellquote_spec.rb b/spec/unit/parser/functions/shellquote_spec.rb index 86181dee0..b100b4913 100755 --- a/spec/unit/parser/functions/shellquote_spec.rb +++ b/spec/unit/parser/functions/shellquote_spec.rb @@ -1,84 +1,83 @@ -#! /usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe "the shellquote function" do before :all do Puppet::Parser::Functions.autoloader.loadall end before :each do @scope = Puppet::Parser::Scope.new end it "should exist" do Puppet::Parser::Functions.function("shellquote").should == "function_shellquote" end it "should handle no arguments" do result = @scope.function_shellquote([]) result.should(eql("")) end it "should handle several simple arguments" do result = @scope.function_shellquote( ['foo', 'bar@example.com', 'localhost:/dev/null', 'xyzzy+-4711,23']) result.should(eql( 'foo bar@example.com localhost:/dev/null xyzzy+-4711,23')) end it "should handle array arguments" do result = @scope.function_shellquote( ['foo', ['bar@example.com', 'localhost:/dev/null'], 'xyzzy+-4711,23']) result.should(eql( 'foo bar@example.com localhost:/dev/null xyzzy+-4711,23')) end it "should quote unsafe characters" do result = @scope.function_shellquote( ['/etc/passwd ', '(ls)', '*', '[?]', "'&'"]) result.should(eql( '"/etc/passwd " "(ls)" "*" "[?]" "\'&\'"')) end it "should deal with double quotes" do result = @scope.function_shellquote( ['"foo"bar"']) result.should(eql( '\'"foo"bar"\'')) end it "should cope with dollar signs" do result = @scope.function_shellquote( ['$PATH', 'foo$bar', '"x$"']) result.should(eql( "'$PATH' 'foo$bar' '\"x$\"'")) end it "should deal with apostrophes (single quotes)" do result = @scope.function_shellquote( ["'foo'bar'", "`$'EDITOR'`"]) result.should(eql( '"\'foo\'bar\'" "\\`\\$\'EDITOR\'\\`"')) end it "should cope with grave accents (backquotes)" do result = @scope.function_shellquote( ['`echo *`', '`ls "$MAILPATH"`']) result.should(eql( "'`echo *`' '`ls \"$MAILPATH\"`'")) end it "should deal with both single and double quotes" do result = @scope.function_shellquote( ['\'foo"bar"xyzzy\'', '"foo\'bar\'xyzzy"']) result.should(eql( '"\'foo\\"bar\\"xyzzy\'" "\\"foo\'bar\'xyzzy\\""')) end it "should handle multiple quotes *and* dollars and backquotes" do result = @scope.function_shellquote( ['\'foo"$x`bar`"xyzzy\'']) result.should(eql( '"\'foo\\"\\$x\\`bar\\`\\"xyzzy\'"')) end it "should handle linefeeds" do result = @scope.function_shellquote( ["foo \n bar"]) result.should(eql( "\"foo \n bar\"")) end end diff --git a/spec/unit/parser/functions/split_spec.rb b/spec/unit/parser/functions/split_spec.rb index e321b6d9f..18a21a0cf 100755 --- a/spec/unit/parser/functions/split_spec.rb +++ b/spec/unit/parser/functions/split_spec.rb @@ -1,52 +1,51 @@ -#! /usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe "the split function" do before :all do Puppet::Parser::Functions.autoloader.loadall end before :each do @scope = Puppet::Parser::Scope.new end it "should exist" do Puppet::Parser::Functions.function("split").should == "function_split" end it "should raise a ParseError if there is less than 2 arguments" do lambda { @scope.function_split(["foo"]) }.should( raise_error(Puppet::ParseError)) end it "should raise a ParseError if there is more than 2 arguments" do lambda { @scope.function_split(["foo", "bar", "gazonk"]) }.should( raise_error(Puppet::ParseError)) end it "should raise a RegexpError if the regexp is malformed" do lambda { @scope.function_split(["foo", "("]) }.should( raise_error(RegexpError)) end it "should handle simple string without metacharacters" do result = @scope.function_split([ "130;236;254;10", ";"]) result.should(eql(["130", "236", "254", "10"])) end it "should handle simple regexps" do result = @scope.function_split([ "130.236;254.;10", "[.;]+"]) result.should(eql(["130", "236", "254", "10"])) end it "should handle groups" do result = @scope.function_split([ "130.236;254.;10", "([.;]+)"]) result.should(eql(["130", ".", "236", ";", "254", ".;", "10"])) end it "should handle simple string without metacharacters" do result = @scope.function_split([ "130.236.254.10", ";"]) result.should(eql(["130.236.254.10"])) end end diff --git a/spec/unit/parser/functions/sprintf_spec.rb b/spec/unit/parser/functions/sprintf_spec.rb index 49c5324f8..bd4863f23 100755 --- a/spec/unit/parser/functions/sprintf_spec.rb +++ b/spec/unit/parser/functions/sprintf_spec.rb @@ -1,44 +1,43 @@ -#! /usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe "the sprintf function" do before :all do Puppet::Parser::Functions.autoloader.loadall end before :each do @scope = Puppet::Parser::Scope.new end it "should exist" do Puppet::Parser::Functions.function("sprintf").should == "function_sprintf" end it "should raise a ParseError if there is less than 1 argument" do lambda { @scope.function_sprintf([]) }.should( raise_error(Puppet::ParseError)) end it "should format integers" do result = @scope.function_sprintf(["%+05d", "23"]) result.should(eql("+0023")) end it "should format floats" do result = @scope.function_sprintf(["%+.2f", "2.7182818284590451"]) result.should(eql("+2.72")) end it "should format large floats" do result = @scope.function_sprintf(["%+.2e", "27182818284590451"]) result.should(eql("+2.72e+16")) end it "should perform more complex formatting" do result = @scope.function_sprintf( [ "<%.8s:%#5o %#8X (%-8s)>", "overlongstring", "23", "48879", "foo" ]) result.should(eql("")) end end diff --git a/spec/unit/parser/functions/tag_spec.rb b/spec/unit/parser/functions/tag_spec.rb index a8c57b7a4..e8a07e1bb 100755 --- a/spec/unit/parser/functions/tag_spec.rb +++ b/spec/unit/parser/functions/tag_spec.rb @@ -1,28 +1,27 @@ -#! /usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe "the 'tag' function" do before :all do Puppet::Parser::Functions.autoloader.loadall end before :each do @scope = Puppet::Parser::Scope.new @scope.stubs(:environment).returns(nil) end it "should exist" do Puppet::Parser::Functions.function(:tag).should == "function_tag" end it "should tag the resource with any provided tags" do resource = Puppet::Parser::Resource.new(:file, "/file", :scope => @scope) @scope.expects(:resource).returns resource @scope.function_tag ["one", "two"] resource.should be_tagged("one") resource.should be_tagged("two") end end diff --git a/spec/unit/parser/functions/template_spec.rb b/spec/unit/parser/functions/template_spec.rb index 64d992297..e7ee974d3 100755 --- a/spec/unit/parser/functions/template_spec.rb +++ b/spec/unit/parser/functions/template_spec.rb @@ -1,65 +1,64 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe "the template function" do before :all do Puppet::Parser::Functions.autoloader.loadall end before :each do @scope = Puppet::Parser::Scope.new end it "should exist" do Puppet::Parser::Functions.function("template").should == "function_template" end it "should create a TemplateWrapper when called" do tw = stub_everything 'template_wrapper' Puppet::Parser::TemplateWrapper.expects(:new).returns(tw) @scope.function_template("test") end it "should give the template filename to the TemplateWrapper" do tw = stub_everything 'template_wrapper' Puppet::Parser::TemplateWrapper.stubs(:new).returns(tw) tw.expects(:file=).with("test") @scope.function_template("test") end it "should return what TemplateWrapper.result returns" do tw = stub_everything 'template_wrapper' Puppet::Parser::TemplateWrapper.stubs(:new).returns(tw) tw.stubs(:file=).with("test") tw.expects(:result).returns("template contents evaluated") @scope.function_template("test").should == "template contents evaluated" end it "should concatenate template wrapper outputs for multiple templates" do tw1 = stub_everything "template_wrapper1" tw2 = stub_everything "template_wrapper2" Puppet::Parser::TemplateWrapper.stubs(:new).returns(tw1,tw2) tw1.stubs(:file=).with("1") tw2.stubs(:file=).with("2") tw1.stubs(:result).returns("result1") tw2.stubs(:result).returns("result2") @scope.function_template(["1","2"]).should == "result1result2" end it "should raise an error if the template raises an error" do tw = stub_everything 'template_wrapper' Puppet::Parser::TemplateWrapper.stubs(:new).returns(tw) tw.stubs(:result).raises lambda { @scope.function_template("1") }.should raise_error(Puppet::ParseError) end end diff --git a/spec/unit/parser/functions/versioncmp_spec.rb b/spec/unit/parser/functions/versioncmp_spec.rb index d7ae0152a..6fc724c38 100755 --- a/spec/unit/parser/functions/versioncmp_spec.rb +++ b/spec/unit/parser/functions/versioncmp_spec.rb @@ -1,32 +1,31 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe "the versioncmp function" do before :all do Puppet::Parser::Functions.autoloader.loadall end before :each do @scope = Puppet::Parser::Scope.new end it "should exist" do Puppet::Parser::Functions.function("versioncmp").should == "function_versioncmp" end it "should raise a ParseError if there is less than 2 arguments" do lambda { @scope.function_versioncmp(["1.2"]) }.should raise_error(Puppet::ParseError) end it "should raise a ParseError if there is more than 2 arguments" do lambda { @scope.function_versioncmp(["1.2", "2.4.5", "3.5.6"]) }.should raise_error(Puppet::ParseError) end it "should call Puppet::Util::Package.versioncmp (included in scope)" do Puppet::Util::Package.expects(:versioncmp).with("1.2", "1.3").returns(-1) @scope.function_versioncmp(["1.2", "1.3"]) end end diff --git a/spec/unit/parser/functions_spec.rb b/spec/unit/parser/functions_spec.rb index 79585f12d..8240a184c 100755 --- a/spec/unit/parser/functions_spec.rb +++ b/spec/unit/parser/functions_spec.rb @@ -1,102 +1,101 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe Puppet::Parser::Functions do after(:each) do # Rationale: # our various tests will almost all register to Pupet::Parser::Functions # a new function called "name". All tests are required to stub Puppet::Parser::Scope # so that +no+ new real ruby method are defined. # After each test, we want to leave the whole Puppet::Parser::Functions environment # as it was before we were called, hence we call rmfunction (which might not succeed # if the function hasn't been registered in the test). It is also important in this # section to stub +remove_method+ here so that we don't pollute the scope. Puppet::Parser::Scope.stubs(:remove_method) begin Puppet::Parser::Functions.rmfunction("name") rescue end end it "should have a method for returning an environment-specific module" do Puppet::Parser::Functions.environment_module("myenv").should be_instance_of(Module) end it "should use the current default environment if no environment is provided" do Puppet::Parser::Functions.environment_module.should be_instance_of(Module) end describe "when calling newfunction" do before do @module = Module.new Puppet::Parser::Functions.stubs(:environment_module).returns @module end it "should create the function in the environment module" do @module.expects(:define_method).with { |name,block| name == "function_name" } Puppet::Parser::Functions.newfunction("name", :type => :rvalue) end it "should raise an error if the function already exists" do @module.expects(:define_method).with { |name,block| name == "function_name" }.once Puppet::Parser::Functions.newfunction("name", :type => :rvalue) lambda { Puppet::Parser::Functions.newfunction("name", :type => :rvalue) }.should raise_error end it "should raise an error if the function type is not correct" do @module.expects(:define_method).with { |name,block| name == "function_name" }.never lambda { Puppet::Parser::Functions.newfunction("name", :type => :unknown) }.should raise_error end end describe "when calling rmfunction" do before do @module = Module.new Puppet::Parser::Functions.stubs(:environment_module).returns @module end it "should remove the function in the scope class" do @module.expects(:define_method).with { |name,block| name == "function_name" } Puppet::Parser::Functions.newfunction("name", :type => :rvalue) @module.expects(:remove_method).with("function_name").once Puppet::Parser::Functions.rmfunction("name") end it "should raise an error if the function doesn't exists" do lambda { Puppet::Parser::Functions.rmfunction("name") }.should raise_error end end describe "when calling function to test function existance" do before do @module = Module.new Puppet::Parser::Functions.stubs(:environment_module).returns @module end it "should return false if the function doesn't exist" do Puppet::Parser::Functions.autoloader.stubs(:load) Puppet::Parser::Functions.function("name").should be_false end it "should return its name if the function exists" do @module.expects(:define_method).with { |name,block| name == "function_name" } Puppet::Parser::Functions.newfunction("name", :type => :rvalue) Puppet::Parser::Functions.function("name").should == "function_name" end it "should try to autoload the function if it doesn't exist yet" do Puppet::Parser::Functions.autoloader.expects(:load) Puppet::Parser::Functions.function("name") end end end diff --git a/spec/unit/parser/lexer_spec.rb b/spec/unit/parser/lexer_spec.rb index 2eb2581a2..6cdb0553a 100755 --- a/spec/unit/parser/lexer_spec.rb +++ b/spec/unit/parser/lexer_spec.rb @@ -1,690 +1,689 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/parser/lexer' # This is a special matcher to match easily lexer output RSpec::Matchers.define :be_like do |*expected| match do |actual| expected.zip(actual).all? { |e,a| !e or a[0] == e or (e.is_a? Array and a[0] == e[0] and (a[1] == e[1] or (a[1].is_a?(Hash) and a[1][:value] == e[1]))) } end end __ = nil describe Puppet::Parser::Lexer do describe "when reading strings" do before { @lexer = Puppet::Parser::Lexer.new } it "should increment the line count for every carriage return in the string" do @lexer.line = 10 @lexer.string = "this\nis\natest'" @lexer.slurpstring("'") @lexer.line.should == 12 end it "should not increment the line count for escapes in the string" do @lexer.line = 10 @lexer.string = "this\\nis\\natest'" @lexer.slurpstring("'") @lexer.line.should == 10 end it "should not think the terminator is escaped, when preceeded by an even number of backslashes" do @lexer.line = 10 @lexer.string = "here\nis\nthe\nstring\\\\'with\nextra\njunk" @lexer.slurpstring("'") @lexer.line.should == 13 end end end describe Puppet::Parser::Lexer::Token do before do @token = Puppet::Parser::Lexer::Token.new(%r{something}, :NAME) end [:regex, :name, :string, :skip, :incr_line, :skip_text, :accumulate].each do |param| it "should have a #{param.to_s} reader" do @token.should be_respond_to(param) end it "should have a #{param.to_s} writer" do @token.should be_respond_to(param.to_s + "=") end end end describe Puppet::Parser::Lexer::Token, "when initializing" do it "should create a regex if the first argument is a string" do Puppet::Parser::Lexer::Token.new("something", :NAME).regex.should == %r{something} end it "should set the string if the first argument is one" do Puppet::Parser::Lexer::Token.new("something", :NAME).string.should == "something" end it "should set the regex if the first argument is one" do Puppet::Parser::Lexer::Token.new(%r{something}, :NAME).regex.should == %r{something} end end describe Puppet::Parser::Lexer::TokenList do before do @list = Puppet::Parser::Lexer::TokenList.new end it "should have a method for retrieving tokens by the name" do token = @list.add_token :name, "whatever" @list[:name].should equal(token) end it "should have a method for retrieving string tokens by the string" do token = @list.add_token :name, "whatever" @list.lookup("whatever").should equal(token) end it "should add tokens to the list when directed" do token = @list.add_token :name, "whatever" @list[:name].should equal(token) end it "should have a method for adding multiple tokens at once" do @list.add_tokens "whatever" => :name, "foo" => :bar @list[:name].should_not be_nil @list[:bar].should_not be_nil end it "should fail to add tokens sharing a name with an existing token" do @list.add_token :name, "whatever" lambda { @list.add_token :name, "whatever" }.should raise_error(ArgumentError) end it "should set provided options on tokens being added" do token = @list.add_token :name, "whatever", :skip_text => true token.skip_text.should == true end it "should define any provided blocks as a :convert method" do token = @list.add_token(:name, "whatever") do "foo" end token.convert.should == "foo" end it "should store all string tokens in the :string_tokens list" do one = @list.add_token(:name, "1") @list.string_tokens.should be_include(one) end it "should store all regex tokens in the :regex_tokens list" do one = @list.add_token(:name, %r{one}) @list.regex_tokens.should be_include(one) end it "should not store string tokens in the :regex_tokens list" do one = @list.add_token(:name, "1") @list.regex_tokens.should_not be_include(one) end it "should not store regex tokens in the :string_tokens list" do one = @list.add_token(:name, %r{one}) @list.string_tokens.should_not be_include(one) end it "should sort the string tokens inversely by length when asked" do one = @list.add_token(:name, "1") two = @list.add_token(:other, "12") @list.sort_tokens @list.string_tokens.should == [two, one] end end describe Puppet::Parser::Lexer::TOKENS do before do @lexer = Puppet::Parser::Lexer.new end { :LBRACK => '[', :RBRACK => ']', :LBRACE => '{', :RBRACE => '}', :LPAREN => '(', :RPAREN => ')', :EQUALS => '=', :ISEQUAL => '==', :GREATEREQUAL => '>=', :GREATERTHAN => '>', :LESSTHAN => '<', :LESSEQUAL => '<=', :NOTEQUAL => '!=', :NOT => '!', :COMMA => ',', :DOT => '.', :COLON => ':', :AT => '@', :LLCOLLECT => '<<|', :RRCOLLECT => '|>>', :LCOLLECT => '<|', :RCOLLECT => '|>', :SEMIC => ';', :QMARK => '?', :BACKSLASH => '\\', :FARROW => '=>', :PARROW => '+>', :APPENDS => '+=', :PLUS => '+', :MINUS => '-', :DIV => '/', :TIMES => '*', :LSHIFT => '<<', :RSHIFT => '>>', :MATCH => '=~', :NOMATCH => '!~', :IN_EDGE => '->', :OUT_EDGE => '<-', :IN_EDGE_SUB => '~>', :OUT_EDGE_SUB => '<~', }.each do |name, string| it "should have a token named #{name.to_s}" do Puppet::Parser::Lexer::TOKENS[name].should_not be_nil end it "should match '#{string}' for the token #{name.to_s}" do Puppet::Parser::Lexer::TOKENS[name].string.should == string end end { "case" => :CASE, "class" => :CLASS, "default" => :DEFAULT, "define" => :DEFINE, "import" => :IMPORT, "if" => :IF, "elsif" => :ELSIF, "else" => :ELSE, "inherits" => :INHERITS, "node" => :NODE, "and" => :AND, "or" => :OR, "undef" => :UNDEF, "false" => :FALSE, "true" => :TRUE, "in" => :IN, }.each do |string, name| it "should have a keyword named #{name.to_s}" do Puppet::Parser::Lexer::KEYWORDS[name].should_not be_nil end it "should have the keyword for #{name.to_s} set to #{string}" do Puppet::Parser::Lexer::KEYWORDS[name].string.should == string end end # These tokens' strings don't matter, just that the tokens exist. [:STRING, :DQPRE, :DQMID, :DQPOST, :BOOLEAN, :NAME, :NUMBER, :COMMENT, :MLCOMMENT, :RETURN, :SQUOTE, :DQUOTE, :VARIABLE].each do |name| it "should have a token named #{name.to_s}" do Puppet::Parser::Lexer::TOKENS[name].should_not be_nil end end end describe Puppet::Parser::Lexer::TOKENS[:CLASSNAME] do before { @token = Puppet::Parser::Lexer::TOKENS[:CLASSNAME] } it "should match against lower-case alpha-numeric terms separated by double colons" do @token.regex.should =~ "one::two" end it "should match against many lower-case alpha-numeric terms separated by double colons" do @token.regex.should =~ "one::two::three::four::five" end it "should match against lower-case alpha-numeric terms prefixed by double colons" do @token.regex.should =~ "::one" end end describe Puppet::Parser::Lexer::TOKENS[:CLASSREF] do before { @token = Puppet::Parser::Lexer::TOKENS[:CLASSREF] } it "should match against single upper-case alpha-numeric terms" do @token.regex.should =~ "One" end it "should match against upper-case alpha-numeric terms separated by double colons" do @token.regex.should =~ "One::Two" end it "should match against many upper-case alpha-numeric terms separated by double colons" do @token.regex.should =~ "One::Two::Three::Four::Five" end it "should match against upper-case alpha-numeric terms prefixed by double colons" do @token.regex.should =~ "::One" end end describe Puppet::Parser::Lexer::TOKENS[:NAME] do before { @token = Puppet::Parser::Lexer::TOKENS[:NAME] } it "should match against lower-case alpha-numeric terms" do @token.regex.should =~ "one-two" end it "should return itself and the value if the matched term is not a keyword" do Puppet::Parser::Lexer::KEYWORDS.expects(:lookup).returns(nil) @token.convert(stub("lexer"), "myval").should == [Puppet::Parser::Lexer::TOKENS[:NAME], "myval"] end it "should return the keyword token and the value if the matched term is a keyword" do keyword = stub 'keyword', :name => :testing Puppet::Parser::Lexer::KEYWORDS.expects(:lookup).returns(keyword) @token.convert(stub("lexer"), "myval").should == [keyword, "myval"] end it "should return the BOOLEAN token and 'true' if the matched term is the string 'true'" do keyword = stub 'keyword', :name => :TRUE Puppet::Parser::Lexer::KEYWORDS.expects(:lookup).returns(keyword) @token.convert(stub('lexer'), "true").should == [Puppet::Parser::Lexer::TOKENS[:BOOLEAN], true] end it "should return the BOOLEAN token and 'false' if the matched term is the string 'false'" do keyword = stub 'keyword', :name => :FALSE Puppet::Parser::Lexer::KEYWORDS.expects(:lookup).returns(keyword) @token.convert(stub('lexer'), "false").should == [Puppet::Parser::Lexer::TOKENS[:BOOLEAN], false] end end describe Puppet::Parser::Lexer::TOKENS[:NUMBER] do before do @token = Puppet::Parser::Lexer::TOKENS[:NUMBER] @regex = @token.regex end it "should match against numeric terms" do @regex.should =~ "2982383139" end it "should match against float terms" do @regex.should =~ "29823.235" end it "should match against hexadecimal terms" do @regex.should =~ "0xBEEF0023" end it "should match against float with exponent terms" do @regex.should =~ "10e23" end it "should match against float terms with negative exponents" do @regex.should =~ "10e-23" end it "should match against float terms with fractional parts and exponent" do @regex.should =~ "1.234e23" end it "should return the NAME token and the value" do @token.convert(stub("lexer"), "myval").should == [Puppet::Parser::Lexer::TOKENS[:NAME], "myval"] end end describe Puppet::Parser::Lexer::TOKENS[:COMMENT] do before { @token = Puppet::Parser::Lexer::TOKENS[:COMMENT] } it "should match against lines starting with '#'" do @token.regex.should =~ "# this is a comment" end it "should be marked to get skipped" do @token.skip?.should be_true end it "should be marked to accumulate" do @token.accumulate?.should be_true end it "'s block should return the comment without the #" do @token.convert(@lexer,"# this is a comment")[1].should == "this is a comment" end end describe Puppet::Parser::Lexer::TOKENS[:MLCOMMENT] do before do @token = Puppet::Parser::Lexer::TOKENS[:MLCOMMENT] @lexer = stub 'lexer', :line => 0 end it "should match against lines enclosed with '/*' and '*/'" do @token.regex.should =~ "/* this is a comment */" end it "should match multiple lines enclosed with '/*' and '*/'" do @token.regex.should =~ """/* this is a comment */""" end it "should increase the lexer current line number by the amount of lines spanned by the comment" do @lexer.expects(:line=).with(2) @token.convert(@lexer, "1\n2\n3") end it "should not greedily match comments" do match = @token.regex.match("/* first */ word /* second */") match[1].should == " first " end it "should be marked to accumulate" do @token.accumulate?.should be_true end it "'s block should return the comment without the comment marks" do @lexer.stubs(:line=).with(0) @token.convert(@lexer,"/* this is a comment */")[1].should == "this is a comment" end end describe Puppet::Parser::Lexer::TOKENS[:RETURN] do before { @token = Puppet::Parser::Lexer::TOKENS[:RETURN] } it "should match against carriage returns" do @token.regex.should =~ "\n" end it "should be marked to initiate text skipping" do @token.skip_text.should be_true end it "should be marked to increment the line" do @token.incr_line.should be_true end end def tokens_scanned_from(s) lexer = Puppet::Parser::Lexer.new lexer.string = s lexer.fullscan[0..-2] end describe Puppet::Parser::Lexer,"when lexing strings" do { %q{'single quoted string')} => [[:STRING,'single quoted string']], %q{"double quoted string"} => [[:STRING,'double quoted string']], %q{'single quoted string with an escaped "\\'"'} => [[:STRING,'single quoted string with an escaped "\'"']], %q{'single quoted string with an escaped "\$"'} => [[:STRING,'single quoted string with an escaped "\$"']], %q{'single quoted string with an escaped "\."'} => [[:STRING,'single quoted string with an escaped "\."']], %q{'single quoted string with an escaped "\n"'} => [[:STRING,'single quoted string with an escaped "\n"']], %q{'single quoted string with an escaped "\\\\"'} => [[:STRING,'single quoted string with an escaped "\\\\"']], %q{"string with an escaped '\\"'"} => [[:STRING,"string with an escaped '\"'"]], %q{"string with an escaped '\\$'"} => [[:STRING,"string with an escaped '$'"]], %Q{"string with a line ending with a backslash: \\\nfoo"} => [[:STRING,"string with a line ending with a backslash: foo"]], %q{"string with $v (but no braces)"} => [[:DQPRE,"string with "],[:VARIABLE,'v'],[:DQPOST,' (but no braces)']], %q["string with ${v} in braces"] => [[:DQPRE,"string with "],[:VARIABLE,'v'],[:DQPOST,' in braces']], %q["string with ${qualified::var} in braces"] => [[:DQPRE,"string with "],[:VARIABLE,'qualified::var'],[:DQPOST,' in braces']], %q{"string with $v and $v (but no braces)"} => [[:DQPRE,"string with "],[:VARIABLE,"v"],[:DQMID," and "],[:VARIABLE,"v"],[:DQPOST," (but no braces)"]], %q["string with ${v} and ${v} in braces"] => [[:DQPRE,"string with "],[:VARIABLE,"v"],[:DQMID," and "],[:VARIABLE,"v"],[:DQPOST," in braces"]], %q["string with ${'a nested single quoted string'} inside it."] => [[:DQPRE,"string with "],[:STRING,'a nested single quoted string'],[:DQPOST,' inside it.']], %q["string with ${['an array ',$v2]} in it."] => [[:DQPRE,"string with "],:LBRACK,[:STRING,"an array "],:COMMA,[:VARIABLE,"v2"],:RBRACK,[:DQPOST," in it."]], %q{a simple "scanner" test} => [[:NAME,"a"],[:NAME,"simple"], [:STRING,"scanner"],[:NAME,"test"]], %q{a simple 'single quote scanner' test} => [[:NAME,"a"],[:NAME,"simple"], [:STRING,"single quote scanner"],[:NAME,"test"]], %q{a harder 'a $b \c"'} => [[:NAME,"a"],[:NAME,"harder"], [:STRING,'a $b \c"']], %q{a harder "scanner test"} => [[:NAME,"a"],[:NAME,"harder"], [:STRING,"scanner test"]], %q{a hardest "scanner \"test\""} => [[:NAME,"a"],[:NAME,"hardest"],[:STRING,'scanner "test"']], %Q{a hardestest "scanner \\"test\\"\n"} => [[:NAME,"a"],[:NAME,"hardestest"],[:STRING,%Q{scanner "test"\n}]], %q{function("call")} => [[:NAME,"function"],[:LPAREN,"("],[:STRING,'call'],[:RPAREN,")"]], %q["string with ${(3+5)/4} nested math."] => [[:DQPRE,"string with "],:LPAREN,[:NAME,"3"],:PLUS,[:NAME,"5"],:RPAREN,:DIV,[:NAME,"4"],[:DQPOST," nested math."]], %q["$$$$"] => [[:STRING,"$$$$"]], %q["$variable"] => [[:DQPRE,""],[:VARIABLE,"variable"],[:DQPOST,""]], %q["$var$other"] => [[:DQPRE,""],[:VARIABLE,"var"],[:DQMID,""],[:VARIABLE,"other"],[:DQPOST,""]], %q["foo$bar$"] => [[:DQPRE,"foo"],[:VARIABLE,"bar"],[:DQPOST,"$"]], %q["foo$$bar"] => [[:DQPRE,"foo$"],[:VARIABLE,"bar"],[:DQPOST,""]], %q[""] => [[:STRING,""]], }.each { |src,expected_result| it "should handle #{src} correctly" do tokens_scanned_from(src).should be_like(*expected_result) end } end describe Puppet::Parser::Lexer::TOKENS[:DOLLAR_VAR] do before { @token = Puppet::Parser::Lexer::TOKENS[:DOLLAR_VAR] } it "should match against alpha words prefixed with '$'" do @token.regex.should =~ '$this_var' end it "should return the VARIABLE token and the variable name stripped of the '$'" do @token.convert(stub("lexer"), "$myval").should == [Puppet::Parser::Lexer::TOKENS[:VARIABLE], "myval"] end end describe Puppet::Parser::Lexer::TOKENS[:REGEX] do before { @token = Puppet::Parser::Lexer::TOKENS[:REGEX] } it "should match against any expression enclosed in //" do @token.regex.should =~ '/this is a regex/' end it 'should not match if there is \n in the regex' do @token.regex.should_not =~ "/this is \n a regex/" end describe "when scanning" do it "should not consider escaped slashes to be the end of a regex" do tokens_scanned_from("$x =~ /this \\/ foo/").should be_like(__,__,[:REGEX,%r{this / foo}]) end it "should not lex chained division as a regex" do tokens_scanned_from("$x = $a/$b/$c").collect { |name, data| name }.should_not be_include( :REGEX ) end it "should accept a regular expression after NODE" do tokens_scanned_from("node /www.*\.mysite\.org/").should be_like(__,[:REGEX,Regexp.new("www.*\.mysite\.org")]) end it "should accept regular expressions in a CASE" do s = %q{case $variable { "something": {$othervar = 4096 / 2} /regex/: {notice("this notably sucks")} } } tokens_scanned_from(s).should be_like( :CASE,:VARIABLE,:LBRACE,:STRING,:COLON,:LBRACE,:VARIABLE,:EQUALS,:NAME,:DIV,:NAME,:RBRACE,[:REGEX,/regex/],:COLON,:LBRACE,:NAME,:LPAREN,:STRING,:RPAREN,:RBRACE,:RBRACE ) end end it "should return the REGEX token and a Regexp" do @token.convert(stub("lexer"), "/myregex/").should == [Puppet::Parser::Lexer::TOKENS[:REGEX], Regexp.new(/myregex/)] end end describe Puppet::Parser::Lexer, "when lexing comments" do before { @lexer = Puppet::Parser::Lexer.new } it "should accumulate token in munge_token" do token = stub 'token', :skip => true, :accumulate? => true, :incr_line => nil, :skip_text => false token.stubs(:convert).with(@lexer, "# this is a comment").returns([token, " this is a comment"]) @lexer.munge_token(token, "# this is a comment") @lexer.munge_token(token, "# this is a comment") @lexer.getcomment.should == " this is a comment\n this is a comment\n" end it "should add a new comment stack level on LBRACE" do @lexer.string = "{" @lexer.expects(:commentpush) @lexer.fullscan end it "should add a new comment stack level on LPAREN" do @lexer.string = "(" @lexer.expects(:commentpush) @lexer.fullscan end it "should pop the current comment on RPAREN" do @lexer.string = ")" @lexer.expects(:commentpop) @lexer.fullscan end it "should return the current comments on getcomment" do @lexer.string = "# comment" @lexer.fullscan @lexer.getcomment.should == "comment\n" end it "should discard the previous comments on blank line" do @lexer.string = "# 1\n\n# 2" @lexer.fullscan @lexer.getcomment.should == "2\n" end it "should skip whitespace before lexing the next token after a non-token" do tokens_scanned_from("/* 1\n\n */ \ntest").should be_like([:NAME, "test"]) end it "should not return comments seen after the current line" do @lexer.string = "# 1\n\n# 2" @lexer.fullscan @lexer.getcomment(1).should == "" end it "should return a comment seen before the current line" do @lexer.string = "# 1\n# 2" @lexer.fullscan @lexer.getcomment(2).should == "1\n2\n" end end # FIXME: We need to rewrite all of these tests, but I just don't want to take the time right now. describe "Puppet::Parser::Lexer in the old tests" do before { @lexer = Puppet::Parser::Lexer.new } it "should do simple lexing" do { %q{\\} => [[:BACKSLASH,"\\"]], %q{simplest scanner test} => [[:NAME,"simplest"],[:NAME,"scanner"],[:NAME,"test"]], %Q{returned scanner test\n} => [[:NAME,"returned"],[:NAME,"scanner"],[:NAME,"test"]] }.each { |source,expected| tokens_scanned_from(source).should be_like(*expected) } end it "should fail usefully" do lambda { tokens_scanned_from('^') }.should raise_error(RuntimeError) end it "should fail if the string is not set" do lambda { @lexer.fullscan }.should raise_error(Puppet::LexError) end it "should correctly identify keywords" do tokens_scanned_from("case").should be_like([:CASE, "case"]) end it "should correctly parse class references" do %w{Many Different Words A Word}.each { |t| tokens_scanned_from(t).should be_like([:CLASSREF,t])} end # #774 it "should correctly parse namespaced class refernces token" do %w{Foo ::Foo Foo::Bar ::Foo::Bar}.each { |t| tokens_scanned_from(t).should be_like([:CLASSREF, t]) } end it "should correctly parse names" do %w{this is a bunch of names}.each { |t| tokens_scanned_from(t).should be_like([:NAME,t]) } end it "should correctly parse names with numerals" do %w{1name name1 11names names11}.each { |t| tokens_scanned_from(t).should be_like([:NAME,t]) } end it "should correctly parse empty strings" do lambda { tokens_scanned_from('$var = ""') }.should_not raise_error end it "should correctly parse virtual resources" do tokens_scanned_from("@type {").should be_like([:AT, "@"], [:NAME, "type"], [:LBRACE, "{"]) end it "should correctly deal with namespaces" do @lexer.string = %{class myclass} @lexer.fullscan @lexer.namespace.should == "myclass" @lexer.namepop @lexer.namespace.should == "" @lexer.string = "class base { class sub { class more" @lexer.fullscan @lexer.namespace.should == "base::sub::more" @lexer.namepop @lexer.namespace.should == "base::sub" end it "should not put class instantiation on the namespace" do @lexer.string = "class base { class sub { class { mode" @lexer.fullscan @lexer.namespace.should == "base::sub" end it "should correctly handle fully qualified names" do @lexer.string = "class base { class sub::more {" @lexer.fullscan @lexer.namespace.should == "base::sub::more" @lexer.namepop @lexer.namespace.should == "base" end it "should correctly lex variables" do ["$variable", "$::variable", "$qualified::variable", "$further::qualified::variable"].each do |string| tokens_scanned_from(string).should be_like([:VARIABLE,string.sub(/^\$/,'')]) end end end describe "Puppet::Parser::Lexer in the old tests when lexing example files" do my_fixtures('*.pp') do |file| it "should correctly lex #{file}" do lexer = Puppet::Parser::Lexer.new lexer.file = file lambda { lexer.fullscan }.should_not raise_error end end end describe "when trying to lex an non-existent file" do include PuppetSpec::Files it "should return an empty list of tokens" do lexer = Puppet::Parser::Lexer.new lexer.file = nofile = tmpfile('lexer') File.exists?(nofile).should == false lexer.fullscan.should == [[false,false]] end end diff --git a/spec/unit/parser/parser_spec.rb b/spec/unit/parser/parser_spec.rb index cb90939fa..78adc30ee 100755 --- a/spec/unit/parser/parser_spec.rb +++ b/spec/unit/parser/parser_spec.rb @@ -1,425 +1,424 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe Puppet::Parser do Puppet::Parser::AST before :each do @known_resource_types = Puppet::Resource::TypeCollection.new("development") @parser = Puppet::Parser::Parser.new "development" @parser.stubs(:known_resource_types).returns @known_resource_types @true_ast = Puppet::Parser::AST::Boolean.new :value => true end it "should require an environment at initialization" do lambda { Puppet::Parser::Parser.new }.should raise_error(ArgumentError) end it "should set the environment" do env = Puppet::Node::Environment.new Puppet::Parser::Parser.new(env).environment.should == env end it "should convert the environment into an environment instance if a string is provided" do env = Puppet::Node::Environment.new("testing") Puppet::Parser::Parser.new("testing").environment.should == env end it "should be able to look up the environment-specific resource type collection" do rtc = Puppet::Node::Environment.new("development").known_resource_types parser = Puppet::Parser::Parser.new "development" parser.known_resource_types.should equal(rtc) end it "should delegate importing to the known resource type loader" do parser = Puppet::Parser::Parser.new "development" parser.known_resource_types.loader.expects(:import).with("newfile", "current_file") parser.lexer.expects(:file).returns "current_file" parser.import("newfile") end describe "when parsing files" do before do FileTest.stubs(:exist?).returns true File.stubs(:read).returns "" @parser.stubs(:watch_file) end it "should treat files ending in 'rb' as ruby files" do @parser.expects(:parse_ruby_file) @parser.file = "/my/file.rb" @parser.parse end end describe "when parsing append operator" do it "should not raise syntax errors" do lambda { @parser.parse("$var += something") }.should_not raise_error end it "shouldraise syntax error on incomplete syntax " do lambda { @parser.parse("$var += ") }.should raise_error end it "should create ast::VarDef with append=true" do vardef = @parser.parse("$var += 2").code[0] vardef.should be_a(Puppet::Parser::AST::VarDef) vardef.append.should == true end it "should work with arrays too" do vardef = @parser.parse("$var += ['test']").code[0] vardef.should be_a(Puppet::Parser::AST::VarDef) vardef.append.should == true end end describe "when parsing selector" do it "should support hash access on the left hand side" do lambda { @parser.parse("$h = { 'a' => 'b' } $a = $h['a'] ? { 'b' => 'd', default => undef }") }.should_not raise_error end end describe "when parsing 'if'" do it "not, it should create the correct ast objects" do Puppet::Parser::AST::Not.expects(:new).with { |h| h[:value].is_a?(Puppet::Parser::AST::Boolean) } @parser.parse("if ! true { $var = 1 }") end it "boolean operation, it should create the correct ast objects" do Puppet::Parser::AST::BooleanOperator.expects(:new).with { |h| h[:rval].is_a?(Puppet::Parser::AST::Boolean) and h[:lval].is_a?(Puppet::Parser::AST::Boolean) and h[:operator]=="or" } @parser.parse("if true or true { $var = 1 }") end it "comparison operation, it should create the correct ast objects" do Puppet::Parser::AST::ComparisonOperator.expects(:new).with { |h| h[:lval].is_a?(Puppet::Parser::AST::Name) and h[:rval].is_a?(Puppet::Parser::AST::Name) and h[:operator]=="<" } @parser.parse("if 1 < 2 { $var = 1 }") end end describe "when parsing if complex expressions" do it "should create a correct ast tree" do aststub = stub_everything 'ast' Puppet::Parser::AST::ComparisonOperator.expects(:new).with { |h| h[:rval].is_a?(Puppet::Parser::AST::Name) and h[:lval].is_a?(Puppet::Parser::AST::Name) and h[:operator]==">" }.returns(aststub) Puppet::Parser::AST::ComparisonOperator.expects(:new).with { |h| h[:rval].is_a?(Puppet::Parser::AST::Name) and h[:lval].is_a?(Puppet::Parser::AST::Name) and h[:operator]=="==" }.returns(aststub) Puppet::Parser::AST::BooleanOperator.expects(:new).with { |h| h[:rval]==aststub and h[:lval]==aststub and h[:operator]=="and" } @parser.parse("if (1 > 2) and (1 == 2) { $var = 1 }") end it "should raise an error on incorrect expression" do lambda { @parser.parse("if (1 > 2 > ) or (1 == 2) { $var = 1 }") }.should raise_error end end describe "when parsing resource references" do it "should not raise syntax errors" do lambda { @parser.parse('exec { test: param => File["a"] }') }.should_not raise_error end it "should not raise syntax errors with multiple references" do lambda { @parser.parse('exec { test: param => File["a","b"] }') }.should_not raise_error end it "should create an ast::ResourceReference" do Puppet::Parser::AST::ResourceReference.expects(:new).with { |arg| arg[:line]==1 and arg[:type]=="File" and arg[:title].is_a?(Puppet::Parser::AST::ASTArray) } @parser.parse('exec { test: command => File["a","b"] }') end end describe "when parsing resource overrides" do it "should not raise syntax errors" do lambda { @parser.parse('Resource["title"] { param => value }') }.should_not raise_error end it "should not raise syntax errors with multiple overrides" do lambda { @parser.parse('Resource["title1","title2"] { param => value }') }.should_not raise_error end it "should create an ast::ResourceOverride" do #Puppet::Parser::AST::ResourceOverride.expects(:new).with { |arg| # arg[:line]==1 and arg[:object].is_a?(Puppet::Parser::AST::ResourceReference) and arg[:parameters].is_a?(Puppet::Parser::AST::ResourceParam) #} ro = @parser.parse('Resource["title1","title2"] { param => value }').code[0] ro.should be_a(Puppet::Parser::AST::ResourceOverride) ro.line.should == 1 ro.object.should be_a(Puppet::Parser::AST::ResourceReference) ro.parameters[0].should be_a(Puppet::Parser::AST::ResourceParam) end end describe "when parsing if statements" do it "should not raise errors with empty if" do lambda { @parser.parse("if true { }") }.should_not raise_error end it "should not raise errors with empty else" do lambda { @parser.parse("if false { notice('if') } else { }") }.should_not raise_error end it "should not raise errors with empty if and else" do lambda { @parser.parse("if false { } else { }") }.should_not raise_error end it "should create a nop node for empty branch" do Puppet::Parser::AST::Nop.expects(:new) @parser.parse("if true { }") end it "should create a nop node for empty else branch" do Puppet::Parser::AST::Nop.expects(:new) @parser.parse("if true { notice('test') } else { }") end it "should build a chain of 'ifs' if there's an 'elsif'" do lambda { @parser.parse(<<-PP) }.should_not raise_error if true { notice('test') } elsif true {} else { } PP end end describe "when parsing function calls" do it "should not raise errors with no arguments" do lambda { @parser.parse("tag()") }.should_not raise_error end it "should not raise errors with rvalue function with no args" do lambda { @parser.parse("$a = template()") }.should_not raise_error end it "should not raise errors with arguments" do lambda { @parser.parse("notice(1)") }.should_not raise_error end it "should not raise errors with multiple arguments" do lambda { @parser.parse("notice(1,2)") }.should_not raise_error end it "should not raise errors with multiple arguments and a trailing comma" do lambda { @parser.parse("notice(1,2,)") }.should_not raise_error end end describe "when parsing arrays with trailing comma" do it "should not raise errors with a trailing comma" do lambda { @parser.parse("$a = [1,2,]") }.should_not raise_error end end describe "when providing AST context" do before do @lexer = stub 'lexer', :line => 50, :file => "/foo/bar", :getcomment => "whev" @parser.stubs(:lexer).returns @lexer end it "should include the lexer's line" do @parser.ast_context[:line].should == 50 end it "should include the lexer's file" do @parser.ast_context[:file].should == "/foo/bar" end it "should include the docs if directed to do so" do @parser.ast_context(true)[:doc].should == "whev" end it "should not include the docs when told not to" do @parser.ast_context(false)[:doc].should be_nil end it "should not include the docs by default" do @parser.ast_context[:doc].should be_nil end end describe "when building ast nodes" do before do @lexer = stub 'lexer', :line => 50, :file => "/foo/bar", :getcomment => "whev" @parser.stubs(:lexer).returns @lexer @class = Puppet::Resource::Type.new(:hostclass, "myclass", :use_docs => false) end it "should return a new instance of the provided class created with the provided options" do @class.expects(:new).with { |opts| opts[:foo] == "bar" } @parser.ast(@class, :foo => "bar") end it "should merge the ast context into the provided options" do @class.expects(:new).with { |opts| opts[:file] == "/foo" } @parser.expects(:ast_context).returns :file => "/foo" @parser.ast(@class, :foo => "bar") end it "should prefer provided options over AST context" do @class.expects(:new).with { |opts| opts[:file] == "/bar" } @lexer.expects(:file).returns "/foo" @parser.ast(@class, :file => "/bar") end it "should include docs when the AST class uses them" do @class.expects(:use_docs).returns true @class.stubs(:new) @parser.expects(:ast_context).with{ |docs, line| docs == true }.returns({}) @parser.ast(@class, :file => "/bar") end it "should get docs from lexer using the correct AST line number" do @class.expects(:use_docs).returns true @class.stubs(:new).with{ |a| a[:doc] == "doc" } @lexer.expects(:getcomment).with(12).returns "doc" @parser.ast(@class, :file => "/bar", :line => 12) end end describe "when retrieving a specific node" do it "should delegate to the known_resource_types node" do @known_resource_types.expects(:node).with("node") @parser.node("node") end end describe "when retrieving a specific class" do it "should delegate to the loaded code" do @known_resource_types.expects(:hostclass).with("class") @parser.hostclass("class") end end describe "when retrieving a specific definitions" do it "should delegate to the loaded code" do @known_resource_types.expects(:definition).with("define") @parser.definition("define") end end describe "when determining the configuration version" do it "should determine it from the resource type collection" do @parser.known_resource_types.expects(:version).returns "foo" @parser.version.should == "foo" end end describe "when looking up definitions" do it "should use the known resource types to check for them by name" do @parser.known_resource_types.stubs(:find_or_load).with("namespace","name",:definition).returns(:this_value) @parser.find_definition("namespace","name").should == :this_value end end describe "when looking up hostclasses" do it "should use the known resource types to check for them by name" do @parser.known_resource_types.stubs(:find_or_load).with("namespace","name",:hostclass).returns(:this_value) @parser.find_hostclass("namespace","name").should == :this_value end end describe "when parsing classes" do before :each do @krt = Puppet::Resource::TypeCollection.new("development") @parser = Puppet::Parser::Parser.new "development" @parser.stubs(:known_resource_types).returns @krt end it "should not create new classes" do @parser.parse("class foobar {}").code[0].should be_a(Puppet::Parser::AST::Hostclass) @krt.hostclass("foobar").should be_nil end it "should correctly set the parent class when one is provided" do @parser.parse("class foobar inherits yayness {}").code[0].instantiate('')[0].parent.should == "yayness" end it "should correctly set the parent class for multiple classes at a time" do statements = @parser.parse("class foobar inherits yayness {}\nclass boo inherits bar {}").code statements[0].instantiate('')[0].parent.should == "yayness" statements[1].instantiate('')[0].parent.should == "bar" end it "should define the code when some is provided" do @parser.parse("class foobar { $var = val }").code[0].code.should_not be_nil end it "should define parameters when provided" do foobar = @parser.parse("class foobar($biz,$baz) {}").code[0].instantiate('')[0] foobar.arguments.should == {"biz" => nil, "baz" => nil} end end describe "when parsing resources" do before :each do @krt = Puppet::Resource::TypeCollection.new("development") @parser = Puppet::Parser::Parser.new "development" @parser.stubs(:known_resource_types).returns @krt end it "should be able to parse class resources" do @krt.add(Puppet::Resource::Type.new(:hostclass, "foobar", :arguments => {"biz" => nil})) lambda { @parser.parse("class { foobar: biz => stuff }") }.should_not raise_error end it "should correctly mark exported resources as exported" do @parser.parse("@@file { '/file': }").code[0].exported.should be_true end it "should correctly mark virtual resources as virtual" do @parser.parse("@file { '/file': }").code[0].virtual.should be_true end end describe "when parsing nodes" do it "should be able to parse a node with a single name" do node = @parser.parse("node foo { }").code[0] node.should be_a Puppet::Parser::AST::Node node.names.length.should == 1 node.names[0].value.should == "foo" end it "should be able to parse a node with two names" do node = @parser.parse("node foo, bar { }").code[0] node.should be_a Puppet::Parser::AST::Node node.names.length.should == 2 node.names[0].value.should == "foo" node.names[1].value.should == "bar" end it "should be able to parse a node with three names" do node = @parser.parse("node foo, bar, baz { }").code[0] node.should be_a Puppet::Parser::AST::Node node.names.length.should == 3 node.names[0].value.should == "foo" node.names[1].value.should == "bar" node.names[2].value.should == "baz" end end end diff --git a/spec/unit/parser/relationship_spec.rb b/spec/unit/parser/relationship_spec.rb index f44a5c844..5a49831e1 100755 --- a/spec/unit/parser/relationship_spec.rb +++ b/spec/unit/parser/relationship_spec.rb @@ -1,70 +1,69 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/parser/relationship' describe Puppet::Parser::Relationship do before do @source = Puppet::Resource.new(:mytype, "source") @target = Puppet::Resource.new(:mytype, "target") @dep = Puppet::Parser::Relationship.new(@source, @target, :relationship) end describe "when evaluating" do before do @catalog = Puppet::Resource::Catalog.new @catalog.add_resource(@source) @catalog.add_resource(@target) end it "should fail if the source resource cannot be found" do @catalog = Puppet::Resource::Catalog.new @catalog.add_resource @target lambda { @dep.evaluate(@catalog) }.should raise_error(ArgumentError) end it "should fail if the target resource cannot be found" do @catalog = Puppet::Resource::Catalog.new @catalog.add_resource @source lambda { @dep.evaluate(@catalog) }.should raise_error(ArgumentError) end it "should add the target as a 'before' value if the type is 'relationship'" do @dep.type = :relationship @dep.evaluate(@catalog) @source[:before].should be_include("Mytype[target]") end it "should add the target as a 'notify' value if the type is 'subscription'" do @dep.type = :subscription @dep.evaluate(@catalog) @source[:notify].should be_include("Mytype[target]") end it "should supplement rather than clobber existing relationship values" do @source[:before] = "File[/bar]" @dep.evaluate(@catalog) @source[:before].should be_include("Mytype[target]") @source[:before].should be_include("File[/bar]") end it "should use the collected retargets if the target is a Collector" do orig_target = @target @target = Puppet::Parser::Collector.new(stub("scope"), :file, "equery", "vquery", :virtual) @target.collected[:foo] = @target @dep.evaluate(@catalog) @source[:before].should be_include("Mytype[target]") end it "should use the collected resources if the source is a Collector" do orig_source = @source @source = Puppet::Parser::Collector.new(stub("scope"), :file, "equery", "vquery", :virtual) @source.collected[:foo] = @source @dep.evaluate(@catalog) orig_source[:before].should be_include("Mytype[target]") end end end diff --git a/spec/unit/parser/resource_spec.rb b/spec/unit/parser/resource_spec.rb index 078b7de95..b03c18e5f 100755 --- a/spec/unit/parser/resource_spec.rb +++ b/spec/unit/parser/resource_spec.rb @@ -1,558 +1,557 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' # LAK: FIXME This is just new tests for resources; I have # not moved all tests over yet. describe Puppet::Parser::Resource do before do @node = Puppet::Node.new("yaynode") @known_resource_types = Puppet::Resource::TypeCollection.new("env") @compiler = Puppet::Parser::Compiler.new(@node) @compiler.environment.stubs(:known_resource_types).returns @known_resource_types @source = newclass "" @scope = @compiler.topscope end def mkresource(args = {}) args[:source] ||= @source args[:scope] ||= @scope params = args[:parameters] || {:one => "yay", :three => "rah"} if args[:parameters] == :none args.delete(:parameters) elsif not args[:parameters].is_a? Array args[:parameters] = paramify(args[:source], params) end Puppet::Parser::Resource.new("resource", "testing", args) end def param(name, value, source) Puppet::Parser::Resource::Param.new(:name => name, :value => value, :source => source) end def paramify(source, hash) hash.collect do |name, value| Puppet::Parser::Resource::Param.new( :name => name, :value => value, :source => source ) end end def newclass(name) @known_resource_types.add Puppet::Resource::Type.new(:hostclass, name) end def newdefine(name) @known_resource_types.add Puppet::Resource::Type.new(:definition, name) end def newnode(name) @known_resource_types.add Puppet::Resource::Type.new(:node, name) end it "should use the file lookup module" do Puppet::Parser::Resource.ancestors.should be_include(Puppet::FileCollection::Lookup) end it "should get its environment from its scope" do scope = stub 'scope', :source => stub("source"), :namespaces => nil scope.expects(:environment).returns("foo").at_least_once Puppet::Parser::Resource.new("file", "whatever", :scope => scope).environment.should == "foo" end it "should use the resource type collection helper module" do Puppet::Parser::Resource.ancestors.should be_include(Puppet::Resource::TypeCollectionHelper) end it "should use the scope's environment as its environment" do @scope.expects(:environment).returns("myenv").at_least_once Puppet::Parser::Resource.new("file", "whatever", :scope => @scope).environment.should == "myenv" end it "should be isomorphic if it is builtin and models an isomorphic type" do Puppet::Type.type(:file).expects(:isomorphic?).returns(true) @resource = Puppet::Parser::Resource.new("file", "whatever", :scope => @scope, :source => @source).isomorphic?.should be_true end it "should not be isomorphic if it is builtin and models a non-isomorphic type" do Puppet::Type.type(:file).expects(:isomorphic?).returns(false) @resource = Puppet::Parser::Resource.new("file", "whatever", :scope => @scope, :source => @source).isomorphic?.should be_false end it "should be isomorphic if it is not builtin" do newdefine "whatever" @resource = Puppet::Parser::Resource.new("whatever", "whatever", :scope => @scope, :source => @source).isomorphic?.should be_true end it "should have a array-indexing method for retrieving parameter values" do @resource = mkresource @resource[:one].should == "yay" end it "should use a Puppet::Resource for converting to a ral resource" do trans = mock 'resource', :to_ral => "yay" @resource = mkresource @resource.expects(:to_resource).returns trans @resource.to_ral.should == "yay" end it "should be able to use the indexing operator to access parameters" do resource = Puppet::Parser::Resource.new("resource", "testing", :source => "source", :scope => @scope) resource["foo"] = "bar" resource["foo"].should == "bar" end it "should return the title when asked for a parameter named 'title'" do Puppet::Parser::Resource.new("resource", "testing", :source => @source, :scope => @scope)[:title].should == "testing" end describe "when initializing" do before do @arguments = {:scope => @scope} end it "should fail unless #{name.to_s} is specified" do lambda { Puppet::Parser::Resource.new('file', '/my/file') }.should raise_error(ArgumentError) end it "should set the reference correctly" do res = Puppet::Parser::Resource.new("resource", "testing", @arguments) res.ref.should == "Resource[testing]" end it "should be tagged with user tags" do tags = [ "tag1", "tag2" ] @arguments[:parameters] = [ param(:tag, tags , :source) ] res = Puppet::Parser::Resource.new("resource", "testing", @arguments) (res.tags & tags).should == tags end end describe "when evaluating" do it "should evaluate the associated AST definition" do definition = newdefine "mydefine" res = Puppet::Parser::Resource.new("mydefine", "whatever", :scope => @scope, :source => @source) definition.expects(:evaluate_code).with(res) res.evaluate end it "should evaluate the associated AST class" do @class = newclass "myclass" res = Puppet::Parser::Resource.new("class", "myclass", :scope => @scope, :source => @source) @class.expects(:evaluate_code).with(res) res.evaluate end it "should evaluate the associated AST node" do nodedef = newnode("mynode") res = Puppet::Parser::Resource.new("node", "mynode", :scope => @scope, :source => @source) nodedef.expects(:evaluate_code).with(res) res.evaluate end end describe "when finishing" do before do @class = newclass "myclass" @nodedef = newnode("mynode") @resource = Puppet::Parser::Resource.new("file", "whatever", :scope => @scope, :source => @source) end it "should do nothing if it has already been finished" do @resource.finish @resource.expects(:add_metaparams).never @resource.finish end it "should add all defaults available from the scope" do @resource.scope.expects(:lookupdefaults).with(@resource.type).returns(:owner => param(:owner, "default", @resource.source)) @resource.finish @resource[:owner].should == "default" end it "should not replace existing parameters with defaults" do @resource.set_parameter :owner, "oldvalue" @resource.scope.expects(:lookupdefaults).with(@resource.type).returns(:owner => :replaced) @resource.finish @resource[:owner].should == "oldvalue" end it "should add a copy of each default, rather than the actual default parameter instance" do newparam = param(:owner, "default", @resource.source) other = newparam.dup other.value = "other" newparam.expects(:dup).returns(other) @resource.scope.expects(:lookupdefaults).with(@resource.type).returns(:owner => newparam) @resource.finish @resource[:owner].should == "other" end it "should be running in metaparam compatibility mode if running a version below 0.25" do catalog = stub 'catalog', :client_version => "0.24.8" @resource.stubs(:catalog).returns catalog @resource.should be_metaparam_compatibility_mode end it "should be running in metaparam compatibility mode if running no client version is available" do catalog = stub 'catalog', :client_version => nil @resource.stubs(:catalog).returns catalog @resource.should be_metaparam_compatibility_mode end it "should not be running in metaparam compatibility mode if running a version at or above 0.25" do catalog = stub 'catalog', :client_version => "0.25.0" @resource.stubs(:catalog).returns catalog @resource.should_not be_metaparam_compatibility_mode end it "should not copy relationship metaparams when not in metaparam compatibility mode" do @scope.setvar("require", "bar") @resource.stubs(:metaparam_compatibility_mode?).returns false @resource.class.publicize_methods(:add_metaparams) { @resource.add_metaparams } @resource["require"].should be_nil end it "should copy relationship metaparams when in metaparam compatibility mode" do @scope.setvar("require", "bar") @resource.stubs(:metaparam_compatibility_mode?).returns true @resource.class.publicize_methods(:add_metaparams) { @resource.add_metaparams } @resource["require"].should == "bar" end it "should stack relationship metaparams when in metaparam compatibility mode" do @resource.set_parameter("require", "foo") @scope.setvar("require", "bar") @resource.stubs(:metaparam_compatibility_mode?).returns true @resource.class.publicize_methods(:add_metaparams) { @resource.add_metaparams } @resource["require"].should == ["foo", "bar"] end end describe "when being tagged" do before do @scope_resource = stub 'scope_resource', :tags => %w{srone srtwo} @scope.stubs(:resource).returns @scope_resource @resource = Puppet::Parser::Resource.new("file", "yay", :scope => @scope, :source => mock('source')) end it "should get tagged with the resource type" do @resource.tags.should be_include("file") end it "should get tagged with the title" do @resource.tags.should be_include("yay") end it "should get tagged with each name in the title if the title is a qualified class name" do resource = Puppet::Parser::Resource.new("file", "one::two", :scope => @scope, :source => mock('source')) resource.tags.should be_include("one") resource.tags.should be_include("two") end it "should get tagged with each name in the type if the type is a qualified class name" do resource = Puppet::Parser::Resource.new("one::two", "whatever", :scope => @scope, :source => mock('source')) resource.tags.should be_include("one") resource.tags.should be_include("two") end it "should not get tagged with non-alphanumeric titles" do resource = Puppet::Parser::Resource.new("file", "this is a test", :scope => @scope, :source => mock('source')) resource.tags.should_not be_include("this is a test") end it "should fail on tags containing '*' characters" do lambda { @resource.tag("bad*tag") }.should raise_error(Puppet::ParseError) end it "should fail on tags starting with '-' characters" do lambda { @resource.tag("-badtag") }.should raise_error(Puppet::ParseError) end it "should fail on tags containing ' ' characters" do lambda { @resource.tag("bad tag") }.should raise_error(Puppet::ParseError) end it "should allow alpha tags" do lambda { @resource.tag("good_tag") }.should_not raise_error(Puppet::ParseError) end end describe "when merging overrides" do before do @source = "source1" @resource = mkresource :source => @source @override = mkresource :source => @source end it "should fail when the override was not created by a parent class" do @override.source = "source2" @override.source.expects(:child_of?).with("source1").returns(false) lambda { @resource.merge(@override) }.should raise_error(Puppet::ParseError) end it "should succeed when the override was created in the current scope" do @resource.source = "source3" @override.source = @resource.source @override.source.expects(:child_of?).with("source3").never params = {:a => :b, :c => :d} @override.expects(:parameters).returns(params) @resource.expects(:override_parameter).with(:b) @resource.expects(:override_parameter).with(:d) @resource.merge(@override) end it "should succeed when a parent class created the override" do @resource.source = "source3" @override.source = "source4" @override.source.expects(:child_of?).with("source3").returns(true) params = {:a => :b, :c => :d} @override.expects(:parameters).returns(params) @resource.expects(:override_parameter).with(:b) @resource.expects(:override_parameter).with(:d) @resource.merge(@override) end it "should add new parameters when the parameter is not set" do @source.stubs(:child_of?).returns true @override.set_parameter(:testing, "value") @resource.merge(@override) @resource[:testing].should == "value" end it "should replace existing parameter values" do @source.stubs(:child_of?).returns true @resource.set_parameter(:testing, "old") @override.set_parameter(:testing, "value") @resource.merge(@override) @resource[:testing].should == "value" end it "should add values to the parameter when the override was created with the '+>' syntax" do @source.stubs(:child_of?).returns true param = Puppet::Parser::Resource::Param.new(:name => :testing, :value => "testing", :source => @resource.source) param.add = true @override.set_parameter(param) @resource.set_parameter(:testing, "other") @resource.merge(@override) @resource[:testing].should == %w{other testing} end it "should not merge parameter values when multiple resources are overriden with '+>' at once " do @resource_2 = mkresource :source => @source @resource. set_parameter(:testing, "old_val_1") @resource_2.set_parameter(:testing, "old_val_2") @source.stubs(:child_of?).returns true param = Puppet::Parser::Resource::Param.new(:name => :testing, :value => "new_val", :source => @resource.source) param.add = true @override.set_parameter(param) @resource. merge(@override) @resource_2.merge(@override) @resource [:testing].should == %w{old_val_1 new_val} @resource_2[:testing].should == %w{old_val_2 new_val} end it "should promote tag overrides to real tags" do @source.stubs(:child_of?).returns true param = Puppet::Parser::Resource::Param.new(:name => :tag, :value => "testing", :source => @resource.source) @override.set_parameter(param) @resource.merge(@override) @resource.tagged?("testing").should be_true end end it "should be able to be converted to a normal resource" do @source = stub 'scope', :name => "myscope" @resource = mkresource :source => @source @resource.should respond_to(:to_resource) end it "should use its resource converter to convert to a transportable resource" do @source = stub 'scope', :name => "myscope" @resource = mkresource :source => @source newresource = Puppet::Resource.new(:file, "/my") Puppet::Resource.expects(:new).returns(newresource) newresource.expects(:to_trans).returns "mytrans" @resource.to_trans.should == "mytrans" end it "should return nil if converted to a transportable resource and it is virtual" do @source = stub 'scope', :name => "myscope" @resource = mkresource :source => @source @resource.expects(:virtual?).returns true @resource.to_trans.should be_nil end describe "when being converted to a resource" do before do @parser_resource = mkresource :scope => @scope, :parameters => {:foo => "bar", :fee => "fum"} end it "should create an instance of Puppet::Resource" do @parser_resource.to_resource.should be_instance_of(Puppet::Resource) end it "should set the type correctly on the Puppet::Resource" do @parser_resource.to_resource.type.should == @parser_resource.type end it "should set the title correctly on the Puppet::Resource" do @parser_resource.to_resource.title.should == @parser_resource.title end it "should copy over all of the parameters" do result = @parser_resource.to_resource.to_hash # The name will be in here, also. result[:foo].should == "bar" result[:fee].should == "fum" end it "should copy over the tags" do @parser_resource.tag "foo" @parser_resource.tag "bar" @parser_resource.to_resource.tags.should == @parser_resource.tags end it "should copy over the line" do @parser_resource.line = 40 @parser_resource.to_resource.line.should == 40 end it "should copy over the file" do @parser_resource.file = "/my/file" @parser_resource.to_resource.file.should == "/my/file" end it "should copy over the 'exported' value" do @parser_resource.exported = true @parser_resource.to_resource.exported.should be_true end it "should copy over the 'virtual' value" do @parser_resource.virtual = true @parser_resource.to_resource.virtual.should be_true end it "should convert any parser resource references to Puppet::Resource instances" do ref = Puppet::Resource.new("file", "/my/file") @parser_resource = mkresource :source => @source, :parameters => {:foo => "bar", :fee => ref} result = @parser_resource.to_resource result[:fee].should == Puppet::Resource.new(:file, "/my/file") end it "should convert any parser resource references to Puppet::Resource instances even if they are in an array" do ref = Puppet::Resource.new("file", "/my/file") @parser_resource = mkresource :source => @source, :parameters => {:foo => "bar", :fee => ["a", ref]} result = @parser_resource.to_resource result[:fee].should == ["a", Puppet::Resource.new(:file, "/my/file")] end it "should convert any parser resource references to Puppet::Resource instances even if they are in an array of array, and even deeper" do ref1 = Puppet::Resource.new("file", "/my/file1") ref2 = Puppet::Resource.new("file", "/my/file2") @parser_resource = mkresource :source => @source, :parameters => {:foo => "bar", :fee => ["a", [ref1,ref2]]} result = @parser_resource.to_resource result[:fee].should == ["a", Puppet::Resource.new(:file, "/my/file1"), Puppet::Resource.new(:file, "/my/file2")] end it "should fail if the same param is declared twice" do lambda do @parser_resource = mkresource :source => @source, :parameters => [ Puppet::Parser::Resource::Param.new( :name => :foo, :value => "bar", :source => @source ), Puppet::Parser::Resource::Param.new( :name => :foo, :value => "baz", :source => @source ) ] end.should raise_error(Puppet::ParseError) end end describe "when validating" do it "should check each parameter" do resource = Puppet::Parser::Resource.new :foo, "bar", :scope => @scope, :source => stub("source") resource[:one] = :two resource[:three] = :four resource.expects(:validate_parameter).with(:one) resource.expects(:validate_parameter).with(:three) resource.send(:validate) end it "should raise a parse error when there's a failure" do resource = Puppet::Parser::Resource.new :foo, "bar", :scope => @scope, :source => stub("source") resource[:one] = :two resource.expects(:validate_parameter).with(:one).raises ArgumentError lambda { resource.send(:validate) }.should raise_error(Puppet::ParseError) end end describe "when setting parameters" do before do @source = newclass "foobar" @resource = Puppet::Parser::Resource.new :foo, "bar", :scope => @scope, :source => @source end it "should accept Param instances and add them to the parameter list" do param = Puppet::Parser::Resource::Param.new :name => "foo", :value => "bar", :source => @source @resource.set_parameter(param) @resource["foo"].should == "bar" end it "should fail when provided a parameter name but no value" do lambda { @resource.set_parameter("myparam") }.should raise_error(ArgumentError) end it "should allow parameters to be set to 'false'" do @resource.set_parameter("myparam", false) @resource["myparam"].should be_false end it "should use its source when provided a parameter name and value" do @resource.set_parameter("myparam", "myvalue") @resource["myparam"].should == "myvalue" end end # part of #629 -- the undef keyword. Make sure 'undef' params get skipped. it "should not include 'undef' parameters when converting itself to a hash" do resource = Puppet::Parser::Resource.new "file", "/tmp/testing", :source => mock("source"), :scope => mock("scope") resource[:owner] = :undef resource[:mode] = "755" resource.to_hash[:owner].should be_nil end end diff --git a/spec/unit/parser/scope_spec.rb b/spec/unit/parser/scope_spec.rb index 8215535dd..bf4d1e29e 100755 --- a/spec/unit/parser/scope_spec.rb +++ b/spec/unit/parser/scope_spec.rb @@ -1,485 +1,484 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe Puppet::Parser::Scope do before :each do @topscope = Puppet::Parser::Scope.new # This is necessary so we don't try to use the compiler to discover our parent. @topscope.parent = nil @scope = Puppet::Parser::Scope.new @scope.compiler = Puppet::Parser::Compiler.new(Puppet::Node.new("foo")) @scope.parent = @topscope end it "should be able to store references to class scopes" do lambda { @scope.class_set "myname", "myscope" }.should_not raise_error end it "should be able to retrieve class scopes by name" do @scope.class_set "myname", "myscope" @scope.class_scope("myname").should == "myscope" end it "should be able to retrieve class scopes by object" do klass = mock 'ast_class' klass.expects(:name).returns("myname") @scope.class_set "myname", "myscope" @scope.class_scope(klass).should == "myscope" end it "should be able to retrieve its parent module name from the source of its parent type" do @topscope.source = Puppet::Resource::Type.new(:hostclass, :foo, :module_name => "foo") @scope.parent_module_name.should == "foo" end it "should return a nil parent module name if it has no parent" do @topscope.parent_module_name.should be_nil end it "should return a nil parent module name if its parent has no source" do @scope.parent_module_name.should be_nil end it "should get its environment from its compiler" do env = stub 'environment' compiler = stub 'compiler', :environment => env scope = Puppet::Parser::Scope.new :compiler => compiler scope.environment.should equal(env) end it "should use the resource type collection helper to find its known resource types" do Puppet::Parser::Scope.ancestors.should include(Puppet::Resource::TypeCollectionHelper) end describe "when initializing" do it "should extend itself with its environment's Functions module as well as the default" do env = Puppet::Node::Environment.new("myenv") compiler = stub 'compiler', :environment => env mod = Module.new root_mod = Module.new Puppet::Parser::Functions.expects(:environment_module).with(Puppet::Node::Environment.root).returns root_mod Puppet::Parser::Functions.expects(:environment_module).with(env).returns mod Puppet::Parser::Scope.new(:compiler => compiler).singleton_class.ancestors.should be_include(mod) end it "should extend itself with the default Functions module if it has no environment" do mod = Module.new Puppet::Parser::Functions.expects(:environment_module).with(Puppet::Node::Environment.root).returns(mod) Puppet::Parser::Functions.expects(:environment_module).with(nil).returns mod Puppet::Parser::Scope.new.singleton_class.ancestors.should be_include(mod) end it "should remember if it is dynamic" do (!!Puppet::Parser::Scope.new(:dynamic => true).dynamic).should == true end it "should assume it is not dynamic" do (!Puppet::Parser::Scope.new.dynamic).should == true end end describe "when looking up a variable" do it "should return ':undefined' for unset variables" do @scope.lookupvar("var").should == :undefined end it "should be able to look up values" do @scope.setvar("var", "yep") @scope.lookupvar("var").should == "yep" end it "should be able to look up hashes" do @scope.setvar("var", {"a" => "b"}) @scope.lookupvar("var").should == {"a" => "b"} end it "should be able to look up variables in parent scopes" do @topscope.setvar("var", "parentval") @scope.lookupvar("var").should == "parentval" end it "should prefer its own values to parent values" do @topscope.setvar("var", "parentval") @scope.setvar("var", "childval") @scope.lookupvar("var").should == "childval" end describe "and the variable is qualified" do before do @compiler = Puppet::Parser::Compiler.new(Puppet::Node.new("foonode")) @scope.compiler = @compiler @known_resource_types = @scope.known_resource_types end def newclass(name) @known_resource_types.add Puppet::Resource::Type.new(:hostclass, name) end def create_class_scope(name) klass = newclass(name) Puppet::Parser::Resource.new("class", name, :scope => @scope, :source => mock('source')).evaluate @scope.class_scope(klass) end it "should be able to look up explicitly fully qualified variables from main" do other_scope = create_class_scope("") other_scope.setvar("othervar", "otherval") @scope.lookupvar("::othervar").should == "otherval" end it "should be able to look up explicitly fully qualified variables from other scopes" do other_scope = create_class_scope("other") other_scope.setvar("var", "otherval") @scope.lookupvar("::other::var").should == "otherval" end it "should be able to look up deeply qualified variables" do other_scope = create_class_scope("other::deep::klass") other_scope.setvar("var", "otherval") @scope.lookupvar("other::deep::klass::var").should == "otherval" end it "should return ':undefined' for qualified variables that cannot be found in other classes" do other_scope = create_class_scope("other::deep::klass") @scope.lookupvar("other::deep::klass::var").should == :undefined end it "should warn and return ':undefined' for qualified variables whose classes have not been evaluated" do klass = newclass("other::deep::klass") @scope.expects(:warning) @scope.lookupvar("other::deep::klass::var").should == :undefined end it "should warn and return ':undefined' for qualified variables whose classes do not exist" do @scope.expects(:warning) @scope.lookupvar("other::deep::klass::var").should == :undefined end it "should return ':undefined' when asked for a non-string qualified variable from a class that does not exist" do @scope.stubs(:warning) @scope.lookupvar("other::deep::klass::var").should == :undefined end it "should return ':undefined' when asked for a non-string qualified variable from a class that has not been evaluated" do @scope.stubs(:warning) klass = newclass("other::deep::klass") @scope.lookupvar("other::deep::klass::var").should == :undefined end end end describe "when setvar is called with append=true" do it "should raise error if the variable is already defined in this scope" do @scope.setvar("var","1", :append => false) lambda { @scope.setvar("var","1", :append => true) }.should raise_error(Puppet::ParseError) end it "should lookup current variable value" do @scope.expects(:lookupvar).with("var").returns("2") @scope.setvar("var","1", :append => true) end it "should store the concatenated string '42'" do @topscope.setvar("var","4", :append => false) @scope.setvar("var","2", :append => true) @scope.lookupvar("var").should == "42" end it "should store the concatenated array [4,2]" do @topscope.setvar("var",[4], :append => false) @scope.setvar("var",[2], :append => true) @scope.lookupvar("var").should == [4,2] end it "should store the merged hash {a => b, c => d}" do @topscope.setvar("var",{"a" => "b"}, :append => false) @scope.setvar("var",{"c" => "d"}, :append => true) @scope.lookupvar("var").should == {"a" => "b", "c" => "d"} end it "should raise an error when appending a hash with something other than another hash" do @topscope.setvar("var",{"a" => "b"}, :append => false) lambda { @scope.setvar("var","not a hash", :append => true) }.should raise_error end end describe "when calling number?" do it "should return nil if called with anything not a number" do Puppet::Parser::Scope.number?([2]).should be_nil end it "should return a Fixnum for a Fixnum" do Puppet::Parser::Scope.number?(2).should be_an_instance_of(Fixnum) end it "should return a Float for a Float" do Puppet::Parser::Scope.number?(2.34).should be_an_instance_of(Float) end it "should return 234 for '234'" do Puppet::Parser::Scope.number?("234").should == 234 end it "should return nil for 'not a number'" do Puppet::Parser::Scope.number?("not a number").should be_nil end it "should return 23.4 for '23.4'" do Puppet::Parser::Scope.number?("23.4").should == 23.4 end it "should return 23.4e13 for '23.4e13'" do Puppet::Parser::Scope.number?("23.4e13").should == 23.4e13 end it "should understand negative numbers" do Puppet::Parser::Scope.number?("-234").should == -234 end it "should know how to convert exponential float numbers ala '23e13'" do Puppet::Parser::Scope.number?("23e13").should == 23e13 end it "should understand hexadecimal numbers" do Puppet::Parser::Scope.number?("0x234").should == 0x234 end it "should understand octal numbers" do Puppet::Parser::Scope.number?("0755").should == 0755 end it "should return nil on malformed integers" do Puppet::Parser::Scope.number?("0.24.5").should be_nil end it "should convert strings with leading 0 to integer if they are not octal" do Puppet::Parser::Scope.number?("0788").should == 788 end it "should convert strings of negative integers" do Puppet::Parser::Scope.number?("-0788").should == -788 end it "should return nil on malformed hexadecimal numbers" do Puppet::Parser::Scope.number?("0x89g").should be_nil end end describe "when using ephemeral variables" do it "should store the variable value" do @scope.setvar("1", :value, :ephemeral => true) @scope.lookupvar("1").should == :value end it "should remove the variable value when unset_ephemeral_var is called" do @scope.setvar("1", :value, :ephemeral => true) @scope.stubs(:parent).returns(nil) @scope.unset_ephemeral_var @scope.lookupvar("1").should == :undefined end it "should not remove classic variables when unset_ephemeral_var is called" do @scope.setvar("myvar", :value1) @scope.setvar("1", :value2, :ephemeral => true) @scope.stubs(:parent).returns(nil) @scope.unset_ephemeral_var @scope.lookupvar("myvar").should == :value1 end it "should raise an error when setting it again" do @scope.setvar("1", :value2, :ephemeral => true) lambda { @scope.setvar("1", :value3, :ephemeral => true) }.should raise_error end it "should declare ephemeral number only variable names" do @scope.ephemeral?("0").should be_true end it "should not declare ephemeral other variable names" do @scope.ephemeral?("abc0").should be_nil end describe "with more than one level" do it "should prefer latest ephemeral scopes" do @scope.setvar("0", :earliest, :ephemeral => true) @scope.new_ephemeral @scope.setvar("0", :latest, :ephemeral => true) @scope.lookupvar("0").should == :latest end it "should be able to report the current level" do @scope.ephemeral_level.should == 1 @scope.new_ephemeral @scope.ephemeral_level.should == 2 end it "should check presence of an ephemeral variable accross multiple levels" do @scope.new_ephemeral @scope.setvar("1", :value1, :ephemeral => true) @scope.new_ephemeral @scope.setvar("0", :value2, :ephemeral => true) @scope.new_ephemeral @scope.ephemeral_include?("1").should be_true end it "should return false when an ephemeral variable doesn't exist in any ephemeral scope" do @scope.new_ephemeral @scope.setvar("1", :value1, :ephemeral => true) @scope.new_ephemeral @scope.setvar("0", :value2, :ephemeral => true) @scope.new_ephemeral @scope.ephemeral_include?("2").should be_false end it "should get ephemeral values from earlier scope when not in later" do @scope.setvar("1", :value1, :ephemeral => true) @scope.new_ephemeral @scope.setvar("0", :value2, :ephemeral => true) @scope.lookupvar("1").should == :value1 end describe "when calling unset_ephemeral_var without a level" do it "should remove all the variables values" do @scope.setvar("1", :value1, :ephemeral => true) @scope.new_ephemeral @scope.setvar("1", :value2, :ephemeral => true) @scope.unset_ephemeral_var @scope.lookupvar("1").should == :undefined end end describe "when calling unset_ephemeral_var with a level" do it "should remove ephemeral scopes up to this level" do @scope.setvar("1", :value1, :ephemeral => true) @scope.new_ephemeral @scope.setvar("1", :value2, :ephemeral => true) @scope.new_ephemeral @scope.setvar("1", :value3, :ephemeral => true) @scope.unset_ephemeral_var(2) @scope.lookupvar("1").should == :value2 end end end end describe "when setting ephemeral vars from matches" do before :each do @match = stub 'match', :is_a? => true @match.stubs(:[]).with(0).returns("this is a string") @match.stubs(:captures).returns([]) @scope.stubs(:setvar) end it "should accept only MatchData" do lambda { @scope.ephemeral_from("match") }.should raise_error end it "should set $0 with the full match" do @scope.expects(:setvar).with { |*arg| arg[0] == "0" and arg[1] == "this is a string" and arg[2][:ephemeral] } @scope.ephemeral_from(@match) end it "should set every capture as ephemeral var" do @match.stubs(:captures).returns([:capture1,:capture2]) @scope.expects(:setvar).with { |*arg| arg[0] == "1" and arg[1] == :capture1 and arg[2][:ephemeral] } @scope.expects(:setvar).with { |*arg| arg[0] == "2" and arg[1] == :capture2 and arg[2][:ephemeral] } @scope.ephemeral_from(@match) end it "should create a new ephemeral level" do @scope.expects(:new_ephemeral) @scope.ephemeral_from(@match) end end describe "when unsetting variables" do it "should be able to unset normal variables" do @scope.setvar("foo", "bar") @scope.unsetvar("foo") @scope.lookupvar("foo").should == :undefined end it "should be able to unset ephemeral variables" do @scope.setvar("0", "bar", :ephemeral => true) @scope.unsetvar("0") @scope.lookupvar("0").should == :undefined end it "should not unset ephemeral variables in previous ephemeral scope" do @scope.setvar("0", "bar", :ephemeral => true) @scope.new_ephemeral @scope.unsetvar("0") @scope.lookupvar("0").should == "bar" end end it "should use its namespaces to find hostclasses" do klass = @scope.known_resource_types.add Puppet::Resource::Type.new(:hostclass, "a::b::c") @scope.add_namespace "a::b" @scope.find_hostclass("c").should equal(klass) end it "should use its namespaces to find definitions" do define = @scope.known_resource_types.add Puppet::Resource::Type.new(:definition, "a::b::c") @scope.add_namespace "a::b" @scope.find_definition("c").should equal(define) end describe "when managing defaults" do it "should be able to set and lookup defaults" do param = Puppet::Parser::Resource::Param.new(:name => :myparam, :value => "myvalue", :source => stub("source")) @scope.setdefaults(:mytype, param) @scope.lookupdefaults(:mytype).should == {:myparam => param} end it "should fail if a default is already defined and a new default is being defined" do param = Puppet::Parser::Resource::Param.new(:name => :myparam, :value => "myvalue", :source => stub("source")) @scope.setdefaults(:mytype, param) lambda { @scope.setdefaults(:mytype, param) }.should raise_error(Puppet::ParseError) end it "should return multiple defaults at once" do param1 = Puppet::Parser::Resource::Param.new(:name => :myparam, :value => "myvalue", :source => stub("source")) @scope.setdefaults(:mytype, param1) param2 = Puppet::Parser::Resource::Param.new(:name => :other, :value => "myvalue", :source => stub("source")) @scope.setdefaults(:mytype, param2) @scope.lookupdefaults(:mytype).should == {:myparam => param1, :other => param2} end it "should look up defaults defined in parent scopes" do param1 = Puppet::Parser::Resource::Param.new(:name => :myparam, :value => "myvalue", :source => stub("source")) @scope.setdefaults(:mytype, param1) child_scope = @scope.newscope param2 = Puppet::Parser::Resource::Param.new(:name => :other, :value => "myvalue", :source => stub("source")) child_scope.setdefaults(:mytype, param2) child_scope.lookupdefaults(:mytype).should == {:myparam => param1, :other => param2} end end end diff --git a/spec/unit/parser/templatewrapper_spec.rb b/spec/unit/parser/templatewrapper_spec.rb index 0c7199ba1..600293bbf 100755 --- a/spec/unit/parser/templatewrapper_spec.rb +++ b/spec/unit/parser/templatewrapper_spec.rb @@ -1,143 +1,142 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/parser/templatewrapper' describe Puppet::Parser::TemplateWrapper do before(:each) do @known_resource_types = Puppet::Resource::TypeCollection.new("env") @compiler = Puppet::Parser::Compiler.new(Puppet::Node.new("mynode")) @compiler.environment.stubs(:known_resource_types).returns @known_resource_types @scope = Puppet::Parser::Scope.new :compiler => @compiler @file = "fake_template" Puppet::Parser::Files.stubs(:find_template).returns("/tmp/fake_template") FileTest.stubs(:exists?).returns("true") File.stubs(:read).with("/tmp/fake_template").returns("template content") @tw = Puppet::Parser::TemplateWrapper.new(@scope) end def mock_template(source=nil) template_mock = mock("template", :result => "woot!") ERB.expects(:new).with("template contents", 0, "-").returns(template_mock) template_mock.expects(:filename=).with(source) end it "should create a new object TemplateWrapper from a scope" do tw = Puppet::Parser::TemplateWrapper.new(@scope) tw.should be_a_kind_of(Puppet::Parser::TemplateWrapper) end it "should check template file existance and read its content" do Puppet::Parser::Files.expects(:find_template).with("fake_template", @scope.environment.to_s).returns("/tmp/fake_template") File.expects(:read).with("/tmp/fake_template").returns("template content") @tw.file = @file end it "should mark the file for watching" do Puppet::Parser::Files.expects(:find_template).returns("/tmp/fake_template") File.stubs(:read) @known_resource_types.expects(:watch_file).with("/tmp/fake_template") @tw.file = @file end it "should fail if a template cannot be found" do Puppet::Parser::Files.expects(:find_template).returns nil lambda { @tw.file = @file }.should raise_error(Puppet::ParseError) end it "should turn into a string like template[name] for file based template" do @tw.file = @file @tw.to_s.should eql("template[/tmp/fake_template]") end it "should turn into a string like template[inline] for string-based template" do @tw.to_s.should eql("template[inline]") end it "should return the processed template contents with a call to result" do mock_template("/tmp/fake_template") File.expects(:read).with("/tmp/fake_template").returns("template contents") @tw.file = @file @tw.result.should eql("woot!") end it "should return the processed template contents with a call to result and a string" do mock_template @tw.result("template contents").should eql("woot!") end it "should return the contents of a variable if called via method_missing" do @scope.expects(:lookupvar).with { |name,options| name == "chicken"}.returns("is good") tw = Puppet::Parser::TemplateWrapper.new(@scope) tw.chicken.should eql("is good") end it "should throw an exception if a variable is called via method_missing and it does not exist" do @scope.expects(:lookupvar).with { |name,options| name == "chicken"}.returns(:undefined) tw = Puppet::Parser::TemplateWrapper.new(@scope) lambda { tw.chicken }.should raise_error(Puppet::ParseError) end it "should allow you to check whether a variable is defined with has_variable?" do @scope.expects(:lookupvar).with { |name,options| name == "chicken"}.returns("is good") tw = Puppet::Parser::TemplateWrapper.new(@scope) tw.has_variable?("chicken").should eql(true) end it "should allow you to check whether a variable is not defined with has_variable?" do @scope.expects(:lookupvar).with { |name,options| name == "chicken"}.returns(:undefined) tw = Puppet::Parser::TemplateWrapper.new(@scope) tw.has_variable?("chicken").should eql(false) end it "should allow you to retrieve the defined classes with classes" do catalog = mock 'catalog', :classes => ["class1", "class2"] @scope.expects(:catalog).returns( catalog ) tw = Puppet::Parser::TemplateWrapper.new(@scope) tw.classes.should == ["class1", "class2"] end it "should allow you to retrieve all the tags with all_tags" do catalog = mock 'catalog', :tags => ["tag1", "tag2"] @scope.expects(:catalog).returns( catalog ) tw = Puppet::Parser::TemplateWrapper.new(@scope) tw.all_tags.should == ["tag1","tag2"] end it "should allow you to retrieve the tags defined in the current scope" do @scope.expects(:tags).returns( ["tag1", "tag2"] ) tw = Puppet::Parser::TemplateWrapper.new(@scope) tw.tags.should == ["tag1","tag2"] end it "should set all of the scope's variables as instance variables" do mock_template @scope.expects(:to_hash).returns("one" => "foo") @tw.result("template contents") @tw.instance_variable_get("@one").should == "foo" end it "should not error out if one of the variables is a symbol" do mock_template @scope.expects(:to_hash).returns(:_timestamp => "1234") @tw.result("template contents") end %w{! . ; :}.each do |badchar| it "should translate #{badchar} to _ when setting the instance variables" do mock_template @scope.expects(:to_hash).returns("one#{badchar}" => "foo") @tw.result("template contents") @tw.instance_variable_get("@one_").should == "foo" end end end diff --git a/spec/unit/parser/type_loader_spec.rb b/spec/unit/parser/type_loader_spec.rb index dfbd2f278..9367b61c8 100755 --- a/spec/unit/parser/type_loader_spec.rb +++ b/spec/unit/parser/type_loader_spec.rb @@ -1,231 +1,230 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/parser/type_loader' require 'puppet_spec/files' describe Puppet::Parser::TypeLoader do include PuppetSpec::Files before do @loader = Puppet::Parser::TypeLoader.new(:myenv) end it "should support an environment" do loader = Puppet::Parser::TypeLoader.new(:myenv) loader.environment.name.should == :myenv end it "should include the Environment Helper" do @loader.class.ancestors.should be_include(Puppet::Node::Environment::Helper) end it "should delegate its known resource types to its environment" do @loader.known_resource_types.should be_instance_of(Puppet::Resource::TypeCollection) end describe "when loading names from namespaces" do it "should do nothing if the name to import is an empty string" do @loader.expects(:name2files).never @loader.try_load_fqname(:hostclass, "") { |filename, modname| raise :should_not_occur }.should be_nil end it "should attempt to import each generated name" do @loader.expects(:import).with("foo/bar",nil).returns([]) @loader.expects(:import).with("foo",nil).returns([]) @loader.try_load_fqname(:hostclass, "foo::bar") { |f| false } end end describe "when importing" do before do Puppet::Parser::Files.stubs(:find_manifests).returns ["modname", %w{file}] Puppet::Parser::Parser.any_instance.stubs(:parse).returns(Puppet::Parser::AST::Hostclass.new('')) Puppet::Parser::Parser.any_instance.stubs(:file=) end it "should return immediately when imports are being ignored" do Puppet::Parser::Files.expects(:find_manifests).never Puppet[:ignoreimport] = true @loader.import("foo").should be_nil end it "should find all manifests matching the file or pattern" do Puppet::Parser::Files.expects(:find_manifests).with { |pat, opts| pat == "myfile" }.returns ["modname", %w{one}] @loader.import("myfile") end it "should use the directory of the current file if one is set" do Puppet::Parser::Files.expects(:find_manifests).with { |pat, opts| opts[:cwd] == "/current" }.returns ["modname", %w{one}] @loader.import("myfile", "/current/file") end it "should pass the environment when looking for files" do Puppet::Parser::Files.expects(:find_manifests).with { |pat, opts| opts[:environment] == @loader.environment }.returns ["modname", %w{one}] @loader.import("myfile") end it "should fail if no files are found" do Puppet::Parser::Files.expects(:find_manifests).returns [nil, []] lambda { @loader.import("myfile") }.should raise_error(Puppet::ImportError) end it "should parse each found file" do Puppet::Parser::Files.expects(:find_manifests).returns ["modname", %w{/one}] @loader.expects(:parse_file).with("/one").returns(Puppet::Parser::AST::Hostclass.new('')) @loader.import("myfile") end it "should make each file qualified before attempting to parse it" do Puppet::Parser::Files.expects(:find_manifests).returns ["modname", %w{one}] @loader.expects(:parse_file).with("/current/one").returns(Puppet::Parser::AST::Hostclass.new('')) @loader.import("myfile", "/current/file") end it "should not attempt to import files that have already been imported" do Puppet::Parser::Files.expects(:find_manifests).returns ["modname", %w{/one}] Puppet::Parser::Parser.any_instance.expects(:parse).once.returns(Puppet::Parser::AST::Hostclass.new('')) @loader.import("myfile") # This will fail if it tries to reimport the file. @loader.import("myfile") end end describe "when importing all" do before do @base = tmpdir("base") # Create two module path directories @modulebase1 = File.join(@base, "first") FileUtils.mkdir_p(@modulebase1) @modulebase2 = File.join(@base, "second") FileUtils.mkdir_p(@modulebase2) Puppet[:modulepath] = "#{@modulebase1}:#{@modulebase2}" end def mk_module(basedir, name) module_dir = File.join(basedir, name) # Go ahead and make our manifest directory FileUtils.mkdir_p(File.join(module_dir, "manifests")) return Puppet::Module.new(name) end # We have to pass the base path so that we can # write to modules that are in the second search path def mk_manifests(base, mod, type, files) exts = {"ruby" => ".rb", "puppet" => ".pp"} files.collect do |file| name = mod.name + "::" + file.gsub("/", "::") path = File.join(base, mod.name, "manifests", file + exts[type]) FileUtils.mkdir_p(File.split(path)[0]) # write out the class if type == "ruby" File.open(path, "w") { |f| f.print "hostclass '#{name}' do\nend" } else File.open(path, "w") { |f| f.print "class #{name} {}" } end name end end it "should load all puppet manifests from all modules in the specified environment" do @module1 = mk_module(@modulebase1, "one") @module2 = mk_module(@modulebase2, "two") mk_manifests(@modulebase1, @module1, "puppet", %w{a b}) mk_manifests(@modulebase2, @module2, "puppet", %w{c d}) @loader.import_all @loader.environment.known_resource_types.hostclass("one::a").should be_instance_of(Puppet::Resource::Type) @loader.environment.known_resource_types.hostclass("one::b").should be_instance_of(Puppet::Resource::Type) @loader.environment.known_resource_types.hostclass("two::c").should be_instance_of(Puppet::Resource::Type) @loader.environment.known_resource_types.hostclass("two::d").should be_instance_of(Puppet::Resource::Type) end it "should load all ruby manifests from all modules in the specified environment" do @module1 = mk_module(@modulebase1, "one") @module2 = mk_module(@modulebase2, "two") mk_manifests(@modulebase1, @module1, "ruby", %w{a b}) mk_manifests(@modulebase2, @module2, "ruby", %w{c d}) @loader.import_all @loader.environment.known_resource_types.hostclass("one::a").should be_instance_of(Puppet::Resource::Type) @loader.environment.known_resource_types.hostclass("one::b").should be_instance_of(Puppet::Resource::Type) @loader.environment.known_resource_types.hostclass("two::c").should be_instance_of(Puppet::Resource::Type) @loader.environment.known_resource_types.hostclass("two::d").should be_instance_of(Puppet::Resource::Type) end it "should not load manifests from duplicate modules later in the module path" do @module1 = mk_module(@modulebase1, "one") # duplicate @module2 = mk_module(@modulebase2, "one") mk_manifests(@modulebase1, @module1, "puppet", %w{a}) mk_manifests(@modulebase2, @module2, "puppet", %w{c}) @loader.import_all @loader.environment.known_resource_types.hostclass("one::c").should be_nil end it "should load manifests from subdirectories" do @module1 = mk_module(@modulebase1, "one") mk_manifests(@modulebase1, @module1, "puppet", %w{a a/b a/b/c}) @loader.import_all @loader.environment.known_resource_types.hostclass("one::a::b").should be_instance_of(Puppet::Resource::Type) @loader.environment.known_resource_types.hostclass("one::a::b::c").should be_instance_of(Puppet::Resource::Type) end end describe "when parsing a file" do before do @parser = Puppet::Parser::Parser.new(@loader.environment) @parser.stubs(:parse).returns(Puppet::Parser::AST::Hostclass.new('')) @parser.stubs(:file=) Puppet::Parser::Parser.stubs(:new).with(@loader.environment).returns @parser end it "should create a new parser instance for each file using the current environment" do Puppet::Parser::Parser.expects(:new).with(@loader.environment).returns @parser @loader.parse_file("/my/file") end it "should assign the parser its file and parse" do @parser.expects(:file=).with("/my/file") @parser.expects(:parse).returns(Puppet::Parser::AST::Hostclass.new('')) @loader.parse_file("/my/file") end end it "should be able to add classes to the current resource type collection" do file = tmpfile("simple_file.pp") File.open(file, "w") { |f| f.puts "class foo {}" } @loader.import(file) @loader.known_resource_types.hostclass("foo").should be_instance_of(Puppet::Resource::Type) end describe "when deciding where to look for files" do { 'foo' => ['foo'], 'foo::bar' => ['foo/bar', 'foo'], 'foo::bar::baz' => ['foo/bar/baz', 'foo/bar', 'foo'] }.each do |fqname, expected_paths| it "should look for #{fqname.inspect} in #{expected_paths.inspect}" do @loader.instance_eval { name2files(fqname) }.should == expected_paths end end end end diff --git a/spec/unit/property/ensure_spec.rb b/spec/unit/property/ensure_spec.rb index e1e0f0c52..35151553b 100755 --- a/spec/unit/property/ensure_spec.rb +++ b/spec/unit/property/ensure_spec.rb @@ -1,13 +1,12 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/property/ensure' klass = Puppet::Property::Ensure describe klass do it "should be a subclass of Property" do klass.superclass.must == Puppet::Property end end diff --git a/spec/unit/property/keyvalue_spec.rb b/spec/unit/property/keyvalue_spec.rb index 9310934ea..821c61799 100755 --- a/spec/unit/property/keyvalue_spec.rb +++ b/spec/unit/property/keyvalue_spec.rb @@ -1,168 +1,167 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/property/keyvalue' klass = Puppet::Property::KeyValue describe klass do it "should be a subclass of Property" do klass.superclass.must == Puppet::Property end describe "as an instance" do before do # Wow that's a messy interface to the resource. klass.initvars @resource = stub 'resource', :[]= => nil, :property => nil @property = klass.new(:resource => @resource) end it "should have a , as default delimiter" do @property.delimiter.should == ";" end it "should have a = as default separator" do @property.separator.should == "=" end it "should have a :membership as default membership" do @property.membership.should == :key_value_membership end it "should return the same value passed into should_to_s" do @property.should_to_s({:foo => "baz", :bar => "boo"}) == "foo=baz;bar=boo" end it "should return the passed in array values joined with the delimiter from is_to_s" do @property.is_to_s({"foo" => "baz" , "bar" => "boo"}).should == "foo=baz;bar=boo" end describe "when calling inclusive?" do it "should use the membership method to look up on the @resource" do @property.expects(:membership).returns(:key_value_membership) @resource.expects(:[]).with(:key_value_membership) @property.inclusive? end it "should return true when @resource[membership] == inclusive" do @property.stubs(:membership).returns(:key_value_membership) @resource.stubs(:[]).with(:key_value_membership).returns(:inclusive) @property.inclusive?.must == true end it "should return false when @resource[membership] != inclusive" do @property.stubs(:membership).returns(:key_value_membership) @resource.stubs(:[]).with(:key_value_membership).returns(:minimum) @property.inclusive?.must == false end end describe "when calling process_current_hash" do it "should return {} if hash is :absent" do @property.process_current_hash(:absent).must == {} end it "should set every key to nil if inclusive?" do @property.stubs(:inclusive?).returns(true) @property.process_current_hash({:foo => "bar", :do => "re"}).must == { :foo => nil, :do => nil } end it "should return the hash if !inclusive?" do @property.stubs(:inclusive?).returns(false) @property.process_current_hash({:foo => "bar", :do => "re"}).must == {:foo => "bar", :do => "re"} end end describe "when calling should" do it "should return nil if @should is nil" do @property.should.must == nil end it "should call process_current_hash" do @property.should = ["foo=baz", "bar=boo"] @property.stubs(:retrieve).returns({:do => "re", :mi => "fa" }) @property.expects(:process_current_hash).returns({}) @property.should end it "should return the hashed values of @should and the nilled values of retrieve if inclusive" do @property.should = ["foo=baz", "bar=boo"] @property.expects(:retrieve).returns({:do => "re", :mi => "fa" }) @property.expects(:inclusive?).returns(true) @property.should.must == { :foo => "baz", :bar => "boo", :do => nil, :mi => nil } end it "should return the hashed @should + the unique values of retrieve if !inclusive" do @property.should = ["foo=baz", "bar=boo"] @property.expects(:retrieve).returns({:foo => "diff", :do => "re", :mi => "fa"}) @property.expects(:inclusive?).returns(false) @property.should.must == { :foo => "baz", :bar => "boo", :do => "re", :mi => "fa" } end end describe "when calling retrieve" do before do @provider = mock("provider") @property.stubs(:provider).returns(@provider) end it "should send 'name' to the provider" do @provider.expects(:send).with(:keys) @property.expects(:name).returns(:keys) @property.retrieve end it "should return a hash with the provider returned info" do @provider.stubs(:send).with(:keys).returns({"do" => "re", "mi" => "fa" }) @property.stubs(:name).returns(:keys) @property.retrieve == {"do" => "re", "mi" => "fa" } end it "should return :absent when the provider returns :absent" do @provider.stubs(:send).with(:keys).returns(:absent) @property.stubs(:name).returns(:keys) @property.retrieve == :absent end end describe "when calling hashify" do it "should return the array hashified" do @property.hashify(["foo=baz", "bar=boo"]).must == { :foo => "baz", :bar => "boo" } end end describe "when calling safe_insync?" do before do @provider = mock("provider") @property.stubs(:provider).returns(@provider) @property.stubs(:name).returns(:prop_name) end it "should return true unless @should is defined and not nil" do @property.safe_insync?("foo") == true end it "should return true if the passed in values is nil" do @property.should = "foo" @property.safe_insync?(nil) == true end it "should return true if hashified should value == (retrieved) value passed in" do @provider.stubs(:prop_name).returns({ :foo => "baz", :bar => "boo" }) @property.should = ["foo=baz", "bar=boo"] @property.expects(:inclusive?).returns(true) @property.safe_insync?({ :foo => "baz", :bar => "boo" }).must == true end it "should return false if prepared value != should value" do @provider.stubs(:prop_name).returns({ "foo" => "bee", "bar" => "boo" }) @property.should = ["foo=baz", "bar=boo"] @property.expects(:inclusive?).returns(true) @property.safe_insync?({ "foo" => "bee", "bar" => "boo" }).must == false end end end end diff --git a/spec/unit/property/list_spec.rb b/spec/unit/property/list_spec.rb index 9dc8fdae4..a29d65751 100755 --- a/spec/unit/property/list_spec.rb +++ b/spec/unit/property/list_spec.rb @@ -1,166 +1,165 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/property/list' list_class = Puppet::Property::List describe list_class do it "should be a subclass of Property" do list_class.superclass.must == Puppet::Property end describe "as an instance" do before do # Wow that's a messy interface to the resource. list_class.initvars @resource = stub 'resource', :[]= => nil, :property => nil @property = list_class.new(:resource => @resource) end it "should have a , as default delimiter" do @property.delimiter.should == "," end it "should have a :membership as default membership" do @property.membership.should == :membership end it "should return the same value passed into should_to_s" do @property.should_to_s("foo") == "foo" end it "should return the passed in array values joined with the delimiter from is_to_s" do @property.is_to_s(["foo","bar"]).should == "foo,bar" end it "should be able to correctly convert ':absent' to a string" do @property.is_to_s(:absent).should == "absent" end describe "when adding should to current" do it "should add the arrays when current is an array" do @property.add_should_with_current(["foo"], ["bar"]).should == ["foo", "bar"] end it "should return should if current is not a array" do @property.add_should_with_current(["foo"], :absent).should == ["foo"] end it "should return only the uniq elements" do @property.add_should_with_current(["foo", "bar"], ["foo", "baz"]).should == ["foo", "bar", "baz"] end end describe "when calling inclusive?" do it "should use the membership method to look up on the @resource" do @property.expects(:membership).returns(:membership) @resource.expects(:[]).with(:membership) @property.inclusive? end it "should return true when @resource[membership] == inclusive" do @property.stubs(:membership).returns(:membership) @resource.stubs(:[]).with(:membership).returns(:inclusive) @property.inclusive?.must == true end it "should return false when @resource[membership] != inclusive" do @property.stubs(:membership).returns(:membership) @resource.stubs(:[]).with(:membership).returns(:minimum) @property.inclusive?.must == false end end describe "when calling should" do it "should return nil if @should is nil" do @property.should.must == nil end it "should return the sorted values of @should as a string if inclusive" do @property.should = ["foo", "bar"] @property.expects(:inclusive?).returns(true) @property.should.must == "bar,foo" end it "should return the uniq sorted values of @should + retrieve as a string if !inclusive" do @property.should = ["foo", "bar"] @property.expects(:inclusive?).returns(false) @property.expects(:retrieve).returns(["foo","baz"]) @property.should.must == "bar,baz,foo" end end describe "when calling retrieve" do before do @provider = mock("provider") @property.stubs(:provider).returns(@provider) end it "should send 'name' to the provider" do @provider.expects(:send).with(:group) @property.expects(:name).returns(:group) @property.retrieve end it "should return an array with the provider returned info" do @provider.stubs(:send).with(:group).returns("foo,bar,baz") @property.stubs(:name).returns(:group) @property.retrieve == ["foo", "bar", "baz"] end it "should return :absent when the provider returns :absent" do @provider.stubs(:send).with(:group).returns(:absent) @property.stubs(:name).returns(:group) @property.retrieve == :absent end end describe "when calling safe_insync?" do it "should return true unless @should is defined and not nil" do @property.must be_safe_insync("foo") end it "should return true unless the passed in values is not nil" do @property.should = "foo" @property.must be_safe_insync(nil) end it "should call prepare_is_for_comparison with value passed in and should" do @property.should = "foo" @property.expects(:prepare_is_for_comparison).with("bar") @property.expects(:should) @property.safe_insync?("bar") end it "should return true if 'is' value is array of comma delimited should values" do @property.should = "bar,foo" @property.expects(:inclusive?).returns(true) @property.must be_safe_insync(["bar","foo"]) end it "should return true if 'is' value is :absent and should value is empty string" do @property.should = "" @property.expects(:inclusive?).returns(true) @property.must be_safe_insync([]) end it "should return false if prepared value != should value" do @property.should = "bar,baz,foo" @property.expects(:inclusive?).returns(true) @property.must_not be_safe_insync(["bar","foo"]) end end describe "when calling dearrayify" do it "should sort and join the array with 'delimiter'" do array = mock "array" array.expects(:sort).returns(array) array.expects(:join).with(@property.delimiter) @property.dearrayify(array) end end end end diff --git a/spec/unit/property/ordered_list_spec.rb b/spec/unit/property/ordered_list_spec.rb index 7a09edb68..2ad05367c 100755 --- a/spec/unit/property/ordered_list_spec.rb +++ b/spec/unit/property/ordered_list_spec.rb @@ -1,64 +1,63 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/property/ordered_list' ordered_list_class = Puppet::Property::OrderedList describe ordered_list_class do it "should be a subclass of List" do ordered_list_class.superclass.must == Puppet::Property::List end describe "as an instance" do before do # Wow that's a messy interface to the resource. ordered_list_class.initvars @resource = stub 'resource', :[]= => nil, :property => nil @property = ordered_list_class.new(:resource => @resource) end describe "when adding should to current" do it "should add the arrays when current is an array" do @property.add_should_with_current(["should"], ["current"]).should == ["should", "current"] end it "should return 'should' if current is not a array" do @property.add_should_with_current(["should"], :absent).should == ["should"] end it "should return only the uniq elements leading with the order of 'should'" do @property.add_should_with_current(["this", "is", "should"], ["is", "this", "current"]).should == ["this", "is", "should", "current"] end end describe "when calling should" do it "should return nil if @should is nil" do @property.should.must == nil end it "should return the values of @should (without sorting) as a string if inclusive" do @property.should = ["foo", "bar"] @property.expects(:inclusive?).returns(true) @property.should.must == "foo,bar" end it "should return the uniq values of @should + retrieve as a string if !inclusive with the @ values leading" do @property.should = ["foo", "bar"] @property.expects(:inclusive?).returns(false) @property.expects(:retrieve).returns(["foo","baz"]) @property.should.must == "foo,bar,baz" end end describe "when calling dearrayify" do it "should join the array with the delimiter" do array = mock "array" array.expects(:join).with(@property.delimiter) @property.dearrayify(array) end end end end diff --git a/spec/unit/property_spec.rb b/spec/unit/property_spec.rb index f3cc79eca..7728b5d40 100755 --- a/spec/unit/property_spec.rb +++ b/spec/unit/property_spec.rb @@ -1,410 +1,409 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/property' describe Puppet::Property do before do @class = Class.new(Puppet::Property) do @name = :foo end @class.initvars @provider = mock 'provider' @resource = stub 'resource', :provider => @provider @resource.stub_everything @property = @class.new :resource => @resource end it "should return its name as a string when converted to a string" do @property.to_s.should == @property.name.to_s end it "should be able to look up the modified name for a given value" do @class.newvalue(:foo) @class.value_name("foo").should == :foo end it "should be able to look up the modified name for a given value matching a regex" do @class.newvalue(%r{.}) @class.value_name("foo").should == %r{.} end it "should be able to look up a given value option" do @class.newvalue(:foo, :event => :whatever) @class.value_option(:foo, :event).should == :whatever end it "should be able to specify required features" do @class.should respond_to(:required_features=) end {"one" => [:one],:one => [:one],%w{a} => [:a],[:b] => [:b],%w{one two} => [:one,:two],[:a,:b] => [:a,:b]}.each { |in_value,out_value| it "should always convert required features into an array of symbols (e.g. #{in_value.inspect} --> #{out_value.inspect})" do @class.required_features = in_value @class.required_features.should == out_value end } it "should be able to shadow metaparameters" do @property.must respond_to(:shadow) end describe "when returning the default event name" do before do @resource = stub 'resource' @instance = @class.new(:resource => @resource) @instance.stubs(:should).returns "myval" end it "should use the current 'should' value to pick the event name" do @instance.expects(:should).returns "myvalue" @class.expects(:value_option).with('myvalue', :event).returns :event_name @instance.event_name end it "should return any event defined with the specified value" do @instance.expects(:should).returns :myval @class.expects(:value_option).with(:myval, :event).returns :event_name @instance.event_name.should == :event_name end describe "and the property is 'ensure'" do before do @instance.stubs(:name).returns :ensure @resource.expects(:type).returns :mytype end it "should use _created if the 'should' value is 'present'" do @instance.expects(:should).returns :present @instance.event_name.should == :mytype_created end it "should use _removed if the 'should' value is 'absent'" do @instance.expects(:should).returns :absent @instance.event_name.should == :mytype_removed end it "should use _changed if the 'should' value is not 'absent' or 'present'" do @instance.expects(:should).returns :foo @instance.event_name.should == :mytype_changed end it "should use _changed if the 'should value is nil" do @instance.expects(:should).returns nil @instance.event_name.should == :mytype_changed end end it "should use _changed if the property is not 'ensure'" do @instance.stubs(:name).returns :myparam @instance.expects(:should).returns :foo @instance.event_name.should == :myparam_changed end it "should use _changed if no 'should' value is set" do @instance.stubs(:name).returns :myparam @instance.expects(:should).returns nil @instance.event_name.should == :myparam_changed end end describe "when creating an event" do before do @event = Puppet::Transaction::Event.new # Use a real resource so we can test the event creation integration @resource = Puppet::Type.type(:mount).new :name => "foo" @instance = @class.new(:resource => @resource) @instance.stubs(:should).returns "myval" end it "should use an event from the resource as the base event" do event = Puppet::Transaction::Event.new @resource.expects(:event).returns event @instance.event.should equal(event) end it "should have the default event name" do @instance.expects(:event_name).returns :my_event @instance.event.name.should == :my_event end it "should have the property's name" do @instance.event.property.should == @instance.name.to_s end it "should have the 'should' value set" do @instance.stubs(:should).returns "foo" @instance.event.desired_value.should == "foo" end it "should provide its path as the source description" do @instance.stubs(:path).returns "/my/param" @instance.event.source_description.should == "/my/param" end end describe "when shadowing metaparameters" do before do @shadow_class = Class.new(Puppet::Property) do @name = :alias end @shadow_class.initvars end it "should create an instance of the metaparameter at initialization" do Puppet::Type.metaparamclass(:alias).expects(:new).with(:resource => @resource) @shadow_class.new :resource => @resource end it "should munge values using the shadow's munge method" do shadow = mock 'shadow' Puppet::Type.metaparamclass(:alias).expects(:new).returns shadow shadow.expects(:munge).with "foo" property = @shadow_class.new :resource => @resource property.munge("foo") end end describe "when defining new values" do it "should define a method for each value created with a block that's not a regex" do @class.newvalue(:foo) { } @property.must respond_to(:set_foo) end end describe "when assigning the value" do it "should just set the 'should' value" do @property.value = "foo" @property.should.must == "foo" end it "should validate each value separately" do @property.expects(:validate).with("one") @property.expects(:validate).with("two") @property.value = %w{one two} end it "should munge each value separately and use any result as the actual value" do @property.expects(:munge).with("one").returns :one @property.expects(:munge).with("two").returns :two # Do this so we get the whole array back. @class.array_matching = :all @property.value = %w{one two} @property.should.must == [:one, :two] end it "should return any set value" do (@property.value = :one).should == :one end end describe "when returning the value" do it "should return nil if no value is set" do @property.should.must be_nil end it "should return the first set 'should' value if :array_matching is set to :first" do @class.array_matching = :first @property.should = %w{one two} @property.should.must == "one" end it "should return all set 'should' values as an array if :array_matching is set to :all" do @class.array_matching = :all @property.should = %w{one two} @property.should.must == %w{one two} end it "should default to :first array_matching" do @class.array_matching.should == :first end it "should unmunge the returned value if :array_matching is set to :first" do @property.class.unmunge do |v| v.to_sym end @class.array_matching = :first @property.should = %w{one two} @property.should.must == :one end it "should unmunge all the returned values if :array_matching is set to :all" do @property.class.unmunge do |v| v.to_sym end @class.array_matching = :all @property.should = %w{one two} @property.should.must == [:one, :two] end end describe "when validating values" do it "should do nothing if no values or regexes have been defined" do lambda { @property.should = "foo" }.should_not raise_error end it "should fail if the value is not a defined value or alias and does not match a regex" do @class.newvalue(:foo) lambda { @property.should = "bar" }.should raise_error end it "should succeeed if the value is one of the defined values" do @class.newvalue(:foo) lambda { @property.should = :foo }.should_not raise_error end it "should succeeed if the value is one of the defined values even if the definition uses a symbol and the validation uses a string" do @class.newvalue(:foo) lambda { @property.should = "foo" }.should_not raise_error end it "should succeeed if the value is one of the defined values even if the definition uses a string and the validation uses a symbol" do @class.newvalue("foo") lambda { @property.should = :foo }.should_not raise_error end it "should succeed if the value is one of the defined aliases" do @class.newvalue("foo") @class.aliasvalue("bar", "foo") lambda { @property.should = :bar }.should_not raise_error end it "should succeed if the value matches one of the regexes" do @class.newvalue(/./) lambda { @property.should = "bar" }.should_not raise_error end it "should validate that all required features are present" do @class.newvalue(:foo, :required_features => [:a, :b]) @provider.expects(:satisfies?).with([:a, :b]).returns true @property.should = :foo end it "should fail if required features are missing" do @class.newvalue(:foo, :required_features => [:a, :b]) @provider.expects(:satisfies?).with([:a, :b]).returns false lambda { @property.should = :foo }.should raise_error(Puppet::Error) end it "should internally raise an ArgumentError if required features are missing" do @class.newvalue(:foo, :required_features => [:a, :b]) @provider.expects(:satisfies?).with([:a, :b]).returns false lambda { @property.validate_features_per_value :foo }.should raise_error(ArgumentError) end it "should validate that all required features are present for regexes" do value = @class.newvalue(/./, :required_features => [:a, :b]) @provider.expects(:satisfies?).with([:a, :b]).returns true @property.should = "foo" end it "should support specifying an individual required feature" do value = @class.newvalue(/./, :required_features => :a) @provider.expects(:satisfies?).returns true @property.should = "foo" end end describe "when munging values" do it "should do nothing if no values or regexes have been defined" do @property.munge("foo").should == "foo" end it "should return return any matching defined values" do @class.newvalue(:foo) @property.munge("foo").should == :foo end it "should return any matching aliases" do @class.newvalue(:foo) @class.aliasvalue(:bar, :foo) @property.munge("bar").should == :foo end it "should return the value if it matches a regex" do @class.newvalue(/./) @property.munge("bar").should == "bar" end it "should return the value if no other option is matched" do @class.newvalue(:foo) @property.munge("bar").should == "bar" end end describe "when syncing the 'should' value" do it "should set the value" do @class.newvalue(:foo) @property.should = :foo @property.expects(:set).with(:foo) @property.sync end end describe "when setting a value" do it "should catch exceptions and raise Puppet::Error" do @class.newvalue(:foo) { raise "eh" } lambda { @property.set(:foo) }.should raise_error(Puppet::Error) end describe "that was defined without a block" do it "should call the settor on the provider" do @class.newvalue(:bar) @provider.expects(:foo=).with :bar @property.set(:bar) end end describe "that was defined with a block" do it "should call the method created for the value if the value is not a regex" do @class.newvalue(:bar) {} @property.expects(:set_bar) @property.set(:bar) end it "should call the provided block if the value is a regex" do @class.newvalue(/./) { self.test } @property.expects(:test) @property.set("foo") end end end describe "when producing a change log" do it "should say 'defined' when the current value is 'absent'" do @property.change_to_s(:absent, "foo").should =~ /^defined/ end it "should say 'undefined' when the new value is 'absent'" do @property.change_to_s("foo", :absent).should =~ /^undefined/ end it "should say 'changed' when neither value is 'absent'" do @property.change_to_s("foo", "bar").should =~ /changed/ end end end diff --git a/spec/unit/provider/augeas/augeas_spec.rb b/spec/unit/provider/augeas/augeas_spec.rb index a7823f21f..5bb98eadf 100755 --- a/spec/unit/provider/augeas/augeas_spec.rb +++ b/spec/unit/provider/augeas/augeas_spec.rb @@ -1,491 +1,490 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' provider_class = Puppet::Type.type(:augeas).provider(:augeas) describe provider_class do describe "command parsing" do before do @resource = stub("resource") @provider = provider_class.new(@resource) end it "should break apart a single line into three tokens and clean up the context" do @resource.stubs(:[]).returns("/context") tokens = @provider.parse_commands("set Jar/Jar Binks") tokens.size.should == 1 tokens[0].size.should == 3 tokens[0][0].should == "set" tokens[0][1].should == "/context/Jar/Jar" tokens[0][2].should == "Binks" end it "should break apart a multiple line into six tokens" do @resource.stubs(:[]).returns("") tokens = @provider.parse_commands("set /Jar/Jar Binks\nrm anakin") tokens.size.should == 2 tokens[0].size.should == 3 tokens[1].size.should == 2 tokens[0][0].should == "set" tokens[0][1].should == "/Jar/Jar" tokens[0][2].should == "Binks" tokens[1][0].should == "rm" tokens[1][1].should == "anakin" end it "should strip whitespace and ignore blank lines" do @resource.stubs(:[]).returns("") tokens = @provider.parse_commands(" set /Jar/Jar Binks \t\n \n\n rm anakin ") tokens.size.should == 2 tokens[0].size.should == 3 tokens[1].size.should == 2 tokens[0][0].should == "set" tokens[0][1].should == "/Jar/Jar" tokens[0][2].should == "Binks" tokens[1][0].should == "rm" tokens[1][1].should == "anakin" end it "should handle arrays" do @resource.stubs(:[]).returns("/foo/") commands = ["set /Jar/Jar Binks", "rm anakin"] tokens = @provider.parse_commands(commands) tokens.size.should == 2 tokens[0].size.should == 3 tokens[1].size.should == 2 tokens[0][0].should == "set" tokens[0][1].should == "/Jar/Jar" tokens[0][2].should == "Binks" tokens[1][0].should == "rm" tokens[1][1].should == "/foo/anakin" end # This is not supported in the new parsing class #it "should concat the last values" do # provider = provider_class.new # tokens = provider.parse_commands("set /Jar/Jar Binks is my copilot") # tokens.size.should == 1 # tokens[0].size.should == 3 # tokens[0][0].should == "set" # tokens[0][1].should == "/Jar/Jar" # tokens[0][2].should == "Binks is my copilot" #end it "should accept spaces in the value and single ticks" do @resource.stubs(:[]).returns("/foo/") tokens = @provider.parse_commands("set JarJar 'Binks is my copilot'") tokens.size.should == 1 tokens[0].size.should == 3 tokens[0][0].should == "set" tokens[0][1].should == "/foo/JarJar" tokens[0][2].should == "Binks is my copilot" end it "should accept spaces in the value and double ticks" do @resource.stubs(:[]).returns("/foo/") tokens = @provider.parse_commands('set /JarJar "Binks is my copilot"') tokens.size.should == 1 tokens[0].size.should == 3 tokens[0][0].should == "set" tokens[0][1].should == '/JarJar' tokens[0][2].should == 'Binks is my copilot' end it "should accept mixed ticks" do @resource.stubs(:[]).returns("/foo/") tokens = @provider.parse_commands('set JarJar "Some \'Test\'"') tokens.size.should == 1 tokens[0].size.should == 3 tokens[0][0].should == "set" tokens[0][1].should == '/foo/JarJar' tokens[0][2].should == "Some \'Test\'" end it "should handle predicates with literals" do @resource.stubs(:[]).returns("/foo/") tokens = @provider.parse_commands("rm */*[module='pam_console.so']") tokens.should == [["rm", "/foo/*/*[module='pam_console.so']"]] end it "should handle whitespace in predicates" do @resource.stubs(:[]).returns("/foo/") tokens = @provider.parse_commands("ins 42 before /files/etc/hosts/*/ipaddr[ . = '127.0.0.1' ]") tokens.should == [["ins", "42", "before","/files/etc/hosts/*/ipaddr[ . = '127.0.0.1' ]"]] end it "should handle multiple predicates" do @resource.stubs(:[]).returns("/foo/") tokens = @provider.parse_commands("clear pam.d/*/*[module = 'system-auth'][type = 'account']") tokens.should == [["clear", "/foo/pam.d/*/*[module = 'system-auth'][type = 'account']"]] end it "should handle nested predicates" do @resource.stubs(:[]).returns("/foo/") args = ["clear", "/foo/pam.d/*/*[module[ ../type = 'type] = 'system-auth'][type[last()] = 'account']"] tokens = @provider.parse_commands(args.join(" ")) tokens.should == [ args ] end it "should handle escaped doublequotes in doublequoted string" do @resource.stubs(:[]).returns("/foo/") tokens = @provider.parse_commands("set /foo \"''\\\"''\"") tokens.should == [[ "set", "/foo", "''\\\"''" ]] end it "should allow escaped spaces and brackets in paths" do @resource.stubs(:[]).returns("/foo/") args = [ "set", "/white\\ space/\\[section", "value" ] tokens = @provider.parse_commands(args.join(" \t ")) tokens.should == [ args ] end it "should allow single quoted escaped spaces in paths" do @resource.stubs(:[]).returns("/foo/") args = [ "set", "'/white\\ space/key'", "value" ] tokens = @provider.parse_commands(args.join(" \t ")) tokens.should == [[ "set", "/white\\ space/key", "value" ]] end it "should allow double quoted escaped spaces in paths" do @resource.stubs(:[]).returns("/foo/") args = [ "set", '"/white\\ space/key"', "value" ] tokens = @provider.parse_commands(args.join(" \t ")) tokens.should == [[ "set", "/white\\ space/key", "value" ]] end it "should remove trailing slashes" do @resource.stubs(:[]).returns("/foo/") tokens = @provider.parse_commands("set foo/ bar") tokens.should == [[ "set", "/foo/foo", "bar" ]] end end describe "get filters" do before do augeas_stub = stub("augeas", :get => "value") @provider = provider_class.new @provider.aug= augeas_stub end it "should return false for a = nonmatch" do command = ["get", "fake value", "==", "value"] @provider.process_get(command).should == true end it "should return true for a != match" do command = ["get", "fake value", "!=", "value"] @provider.process_get(command).should == false end it "should return true for a =~ match" do command = ["get", "fake value", "=~", "val*"] @provider.process_get(command).should == true end it "should return false for a == nonmatch" do command = ["get", "fake value", "=~", "num*"] @provider.process_get(command).should == false end end describe "match filters" do before do resource = stub("resource", :[] => "") augeas_stub = stub("augeas", :match => ["set", "of", "values"]) @provider = provider_class.new(resource) @provider.aug= augeas_stub end it "should return true for size match" do command = ["match", "fake value", "size == 3"] @provider.process_match(command).should == true end it "should return false for a size non match" do command = ["match", "fake value", "size < 3"] @provider.process_match(command).should == false end it "should return true for includes match" do command = ["match", "fake value", "include values"] @provider.process_match(command).should == true end it "should return false for includes non match" do command = ["match", "fake value", "include JarJar"] @provider.process_match(command).should == false end it "should return true for includes match" do command = ["match", "fake value", "not_include JarJar"] @provider.process_match(command).should == true end it "should return false for includes non match" do command = ["match", "fake value", "not_include values"] @provider.process_match(command).should == false end it "should return true for an array match" do command = ["match", "fake value", "== ['set', 'of', 'values']"] @provider.process_match(command).should == true end it "should return false for an array non match" do command = ["match", "fake value", "== ['this', 'should', 'not', 'match']"] @provider.process_match(command).should == false end it "should return false for an array match with noteq" do command = ["match", "fake value", "!= ['set', 'of', 'values']"] @provider.process_match(command).should == false end it "should return true for an array non match with noteq" do command = ["match", "fake value", "!= ['this', 'should', 'not', 'match']"] @provider.process_match(command).should == true end end describe "need to run" do it "should handle no filters" do resource = stub("resource") resource.stubs(:[]).returns(false).then.returns("").then.returns("") augeas_stub = stub("augeas", :match => ["set", "of", "values"]) augeas_stub.stubs("close") provider = provider_class.new(resource) provider.aug= augeas_stub provider.stubs(:get_augeas_version).returns("0.3.5") provider.need_to_run?.should == true end it "should return true when a get filter matches" do resource = stub("resource") resource.stubs(:[]).returns(false).then.returns("get path == value").then.returns("") provider = provider_class.new(resource) augeas_stub = stub("augeas", :get => "value") augeas_stub.stubs("close") provider.aug= augeas_stub provider.stubs(:get_augeas_version).returns("0.3.5") provider.need_to_run?.should == true end it "should return false when a get filter does not match" do resource = stub("resource") resource.stubs(:[]).returns(false).then.returns("get path == another value").then.returns("") provider = provider_class.new(resource) augeas_stub = stub("augeas", :get => "value") augeas_stub.stubs("close") provider.aug= augeas_stub provider.stubs(:get_augeas_version).returns("0.3.5") provider.need_to_run?.should == false end it "should return true when a match filter matches" do resource = stub("resource") resource.stubs(:[]).returns(false).then.returns("match path size == 3").then.returns("") provider = provider_class.new(resource) augeas_stub = stub("augeas", :match => ["set", "of", "values"]) augeas_stub.stubs("close") provider.aug= augeas_stub provider.stubs(:get_augeas_version).returns("0.3.5") provider.need_to_run?.should == true end it "should return false when a match filter does not match" do resource = stub("resource") resource.stubs(:[]).returns(false).then.returns("match path size == 2").then.returns("") provider = provider_class.new(resource) augeas_stub = stub("augeas", :match => ["set", "of", "values"]) augeas_stub.stubs("close") provider.aug= augeas_stub provider.stubs(:get_augeas_version).returns("0.3.5") provider.need_to_run?.should == false end #This is a copy of the last one, with setting the force to true it "setting force should not change the above logic" do resource = stub("resource") resource.stubs(:[]).returns(true).then.returns("match path size == 2").then.returns("") provider = provider_class.new(resource) augeas_stub = stub("augeas", :match => ["set", "of", "values"]) augeas_stub.stubs("close") provider.aug= augeas_stub provider.stubs(:get_augeas_version).returns("0.3.5") provider.need_to_run?.should == false end #Ticket 5211 testing it "should return true when a size != the provided value" do resource = stub("resource") resource.stubs(:[]).returns(false).then.returns("match path size != 17").then.returns("") provider = provider_class.new(resource) augeas_stub = stub("augeas", :match => ["set", "of", "values"]) augeas_stub.stubs("close") provider.aug= augeas_stub provider.stubs(:get_augeas_version).returns("0.3.5") provider.need_to_run?.should == true end #Ticket 5211 testing it "should return false when a size doeas equal the provided value" do resource = stub("resource") resource.stubs(:[]).returns(false).then.returns("match path size != 3").then.returns("") provider = provider_class.new(resource) augeas_stub = stub("augeas", :match => ["set", "of", "values"]) augeas_stub.stubs("close") provider.aug= augeas_stub provider.stubs(:get_augeas_version).returns("0.3.5") provider.need_to_run?.should == false end end describe "augeas execution integration" do before do @resource = stub("resource") @provider = provider_class.new(@resource) @augeas = stub("augeas") @provider.aug= @augeas @provider.stubs(:get_augeas_version).returns("0.3.5") end it "should handle set commands" do command = "set JarJar Binks" context = "/some/path/" @resource.expects(:[]).times(2).returns(command).then.returns(context) @augeas.expects(:set).with("/some/path/JarJar", "Binks").returns(true) @augeas.expects(:save).returns(true) @augeas.expects(:close) @provider.execute_changes.should == :executed end it "should handle rm commands" do command = "rm /Jar/Jar" context = "" @resource.expects(:[]).times(2).returns(command).then.returns(context) @augeas.expects(:rm).with("/Jar/Jar") @augeas.expects(:save).returns(true) @augeas.expects(:close) @provider.execute_changes.should == :executed end it "should handle remove commands" do command = "remove /Jar/Jar" context = "" @resource.expects(:[]).times(2).returns(command).then.returns(context) @augeas.expects(:rm).with("/Jar/Jar") @augeas.expects(:save).returns(true) @augeas.expects(:close) @provider.execute_changes.should == :executed end it "should handle clear commands" do command = "clear Jar/Jar" context = "/foo/" @resource.expects(:[]).times(2).returns(command).then.returns(context) @augeas.expects(:clear).with("/foo/Jar/Jar").returns(true) @augeas.expects(:save).returns(true) @augeas.expects(:close) @provider.execute_changes.should == :executed end it "should handle ins commands with before" do command = "ins Binks before Jar/Jar" context = "/foo" @resource.expects(:[]).times(2).returns(command).then.returns(context) @augeas.expects(:insert).with("/foo/Jar/Jar", "Binks", true) @augeas.expects(:save).returns(true) @augeas.expects(:close) @provider.execute_changes.should == :executed end it "should handle ins commands with after" do command = "ins Binks after /Jar/Jar" context = "/foo" @resource.expects(:[]).times(2).returns(command).then.returns(context) @augeas.expects(:insert).with("/Jar/Jar", "Binks", false) @augeas.expects(:save).returns(true) @augeas.expects(:close) @provider.execute_changes.should == :executed end it "should handle ins with no context" do command = "ins Binks after /Jar/Jar" context = "" # this is the default @resource.expects(:[]).times(2).returns(command).then.returns(context) @augeas.expects(:insert).with("/Jar/Jar", "Binks", false) @augeas.expects(:save).returns(true) @augeas.expects(:close) @provider.execute_changes.should == :executed end it "should handle multiple commands" do command = ["ins Binks after /Jar/Jar", "clear Jar/Jar"] context = "/foo/" @resource.expects(:[]).times(2).returns(command).then.returns(context) @augeas.expects(:insert).with("/Jar/Jar", "Binks", false) @augeas.expects(:clear).with("/foo/Jar/Jar").returns(true) @augeas.expects(:save).returns(true) @augeas.expects(:close) @provider.execute_changes.should == :executed end it "should handle defvar commands" do command = "defvar myjar Jar/Jar" context = "/foo/" @resource.expects(:[]).times(2).returns(command).then.returns(context) @augeas.expects(:defvar).with("myjar", "/foo/Jar/Jar").returns(true) @augeas.expects(:save).returns(true) @augeas.expects(:close) @provider.execute_changes.should == :executed end it "should pass through augeas variables without context" do command = ["defvar myjar Jar/Jar","set $myjar/Binks 1"] context = "/foo/" @resource.expects(:[]).times(2).returns(command).then.returns(context) @augeas.expects(:defvar).with("myjar", "/foo/Jar/Jar").returns(true) # this is the important bit, shouldn't be /foo/$myjar/Binks @augeas.expects(:set).with("$myjar/Binks", "1").returns(true) @augeas.expects(:save).returns(true) @augeas.expects(:close) @provider.execute_changes.should == :executed end it "should handle defnode commands" do command = "defnode newjar Jar/Jar[last()+1] Binks" context = "/foo/" @resource.expects(:[]).times(2).returns(command).then.returns(context) @augeas.expects(:defnode).with("newjar", "/foo/Jar/Jar[last()+1]", "Binks").returns(true) @augeas.expects(:save).returns(true) @augeas.expects(:close) @provider.execute_changes.should == :executed end it "should handle mv commands" do command = "mv Jar/Jar Binks" context = "/foo/" @resource.expects(:[]).times(2).returns(command).then.returns(context) @augeas.expects(:mv).with("/foo/Jar/Jar", "/foo/Binks").returns(true) @augeas.expects(:save).returns(true) @augeas.expects(:close) @provider.execute_changes.should == :executed end it "should handle setm commands" do command = ["set test[1]/Jar/Jar Foo","set test[2]/Jar/Jar Bar","setm test Jar/Jar Binks"] context = "/foo/" @resource.expects(:[]).times(2).returns(command).then.returns(context) @augeas.expects(:set).with("/foo/test[1]/Jar/Jar", "Foo").returns(true) @augeas.expects(:set).with("/foo/test[2]/Jar/Jar", "Bar").returns(true) @augeas.expects(:setm).with("/foo/test", "Jar/Jar", "Binks").returns(true) @augeas.expects(:save).returns(true) @augeas.expects(:close) @provider.execute_changes.should == :executed end end end diff --git a/spec/unit/provider/confine/exists_spec.rb b/spec/unit/provider/confine/exists_spec.rb index 9ab307eb3..1e2d7f86f 100755 --- a/spec/unit/provider/confine/exists_spec.rb +++ b/spec/unit/provider/confine/exists_spec.rb @@ -1,74 +1,73 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/provider/confine/exists' describe Puppet::Provider::Confine::Exists do before do @confine = Puppet::Provider::Confine::Exists.new("/my/file") @confine.label = "eh" end it "should be named :exists" do Puppet::Provider::Confine::Exists.name.should == :exists end it "should use the 'pass?' method to test validity" do @confine.expects(:pass?).with("/my/file") @confine.valid? end it "should return false if the value is false" do @confine.pass?(false).should be_false end it "should return false if the value does not point to a file" do FileTest.expects(:exist?).with("/my/file").returns false @confine.pass?("/my/file").should be_false end it "should return true if the value points to a file" do FileTest.expects(:exist?).with("/my/file").returns true @confine.pass?("/my/file").should be_true end it "should produce a message saying that a file is missing" do @confine.message("/my/file").should be_include("does not exist") end describe "and the confine is for binaries" do before { @confine.stubs(:for_binary).returns true } it "should use its 'which' method to look up the full path of the file" do @confine.expects(:which).returns nil @confine.pass?("/my/file") end it "should return false if no executable can be found" do @confine.expects(:which).with("/my/file").returns nil @confine.pass?("/my/file").should be_false end it "should return true if the executable can be found" do @confine.expects(:which).with("/my/file").returns "/my/file" @confine.pass?("/my/file").should be_true end end it "should produce a summary containing all missing files" do FileTest.stubs(:exist?).returns true FileTest.expects(:exist?).with("/two").returns false FileTest.expects(:exist?).with("/four").returns false confine = Puppet::Provider::Confine::Exists.new %w{/one /two /three /four} confine.summary.should == %w{/two /four} end it "should summarize multiple instances by returning a flattened array of their summaries" do c1 = mock '1', :summary => %w{one} c2 = mock '2', :summary => %w{two} c3 = mock '3', :summary => %w{three} Puppet::Provider::Confine::Exists.summarize([c1, c2, c3]).should == %w{one two three} end end diff --git a/spec/unit/provider/confine/false_spec.rb b/spec/unit/provider/confine/false_spec.rb index 1b4c69f2a..1afa57cbc 100755 --- a/spec/unit/provider/confine/false_spec.rb +++ b/spec/unit/provider/confine/false_spec.rb @@ -1,53 +1,52 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/provider/confine/false' describe Puppet::Provider::Confine::False do it "should be named :false" do Puppet::Provider::Confine::False.name.should == :false end it "should require a value" do lambda { Puppet::Provider::Confine.new }.should raise_error(ArgumentError) end describe "when testing values" do before { @confine = Puppet::Provider::Confine::False.new("foo") } it "should use the 'pass?' method to test validity" do @confine = Puppet::Provider::Confine::False.new("foo") @confine.label = "eh" @confine.expects(:pass?).with("foo") @confine.valid? end it "should return true if the value is false" do @confine.pass?(false).should be_true end it "should return false if the value is not false" do @confine.pass?("else").should be_false end it "should produce a message that a value is true" do @confine = Puppet::Provider::Confine::False.new("foo") @confine.message("eh").should be_include("true") end end it "should be able to produce a summary with the number of incorrectly true values" do confine = Puppet::Provider::Confine::False.new %w{one two three four} confine.expects(:pass?).times(4).returns(true).returns(false).returns(true).returns(false) confine.summary.should == 2 end it "should summarize multiple instances by summing their summaries" do c1 = mock '1', :summary => 1 c2 = mock '2', :summary => 2 c3 = mock '3', :summary => 3 Puppet::Provider::Confine::False.summarize([c1, c2, c3]).should == 6 end end diff --git a/spec/unit/provider/confine/feature_spec.rb b/spec/unit/provider/confine/feature_spec.rb index 88ce496a1..959c7a3bb 100755 --- a/spec/unit/provider/confine/feature_spec.rb +++ b/spec/unit/provider/confine/feature_spec.rb @@ -1,60 +1,59 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/provider/confine/feature' describe Puppet::Provider::Confine::Feature do it "should be named :feature" do Puppet::Provider::Confine::Feature.name.should == :feature end it "should require a value" do lambda { Puppet::Provider::Confine::Feature.new }.should raise_error(ArgumentError) end it "should always convert values to an array" do Puppet::Provider::Confine::Feature.new("/some/file").values.should be_instance_of(Array) end describe "when testing values" do before do @features = mock 'features' Puppet.stubs(:features).returns @features @confine = Puppet::Provider::Confine::Feature.new("myfeature") @confine.label = "eh" end it "should use the Puppet features instance to test validity" do @features.expects(:myfeature?) @confine.valid? end it "should return true if the feature is present" do @features.expects(:myfeature?).returns true @confine.pass?("myfeature").should be_true end it "should return false if the value is false" do @features.expects(:myfeature?).returns false @confine.pass?("myfeature").should be_false end it "should log that a feature is missing" do @confine.message("myfeat").should be_include("missing") end end it "should summarize multiple instances by returning a flattened array of all missing features" do confines = [] confines << Puppet::Provider::Confine::Feature.new(%w{one two}) confines << Puppet::Provider::Confine::Feature.new(%w{two}) confines << Puppet::Provider::Confine::Feature.new(%w{three four}) features = mock 'feature' features.stub_everything Puppet.stubs(:features).returns features Puppet::Provider::Confine::Feature.summarize(confines).sort.should == %w{one two three four}.sort end end diff --git a/spec/unit/provider/confine/true_spec.rb b/spec/unit/provider/confine/true_spec.rb index c26c2ca75..795819bd3 100755 --- a/spec/unit/provider/confine/true_spec.rb +++ b/spec/unit/provider/confine/true_spec.rb @@ -1,53 +1,52 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/provider/confine/true' describe Puppet::Provider::Confine::True do it "should be named :true" do Puppet::Provider::Confine::True.name.should == :true end it "should require a value" do lambda { Puppet::Provider::Confine::True.new }.should raise_error(ArgumentError) end describe "when testing values" do before do @confine = Puppet::Provider::Confine::True.new("foo") @confine.label = "eh" end it "should use the 'pass?' method to test validity" do @confine.expects(:pass?).with("foo") @confine.valid? end it "should return true if the value is not false" do @confine.pass?("else").should be_true end it "should return false if the value is false" do @confine.pass?(nil).should be_false end it "should produce the message that a value is false" do @confine.message("eh").should be_include("false") end end it "should produce the number of false values when asked for a summary" do @confine = Puppet::Provider::Confine::True.new %w{one two three four} @confine.expects(:pass?).times(4).returns(true).returns(false).returns(true).returns(false) @confine.summary.should == 2 end it "should summarize multiple instances by summing their summaries" do c1 = mock '1', :summary => 1 c2 = mock '2', :summary => 2 c3 = mock '3', :summary => 3 Puppet::Provider::Confine::True.summarize([c1, c2, c3]).should == 6 end end diff --git a/spec/unit/provider/confine/variable_spec.rb b/spec/unit/provider/confine/variable_spec.rb index 9156bc4cc..7b9f53c3d 100755 --- a/spec/unit/provider/confine/variable_spec.rb +++ b/spec/unit/provider/confine/variable_spec.rb @@ -1,107 +1,106 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/provider/confine/variable' describe Puppet::Provider::Confine::Variable do it "should be named :variable" do Puppet::Provider::Confine::Variable.name.should == :variable end it "should require a value" do lambda { Puppet::Provider::Confine::Variable.new }.should raise_error(ArgumentError) end it "should always convert values to an array" do Puppet::Provider::Confine::Variable.new("/some/file").values.should be_instance_of(Array) end it "should have an accessor for its name" do Puppet::Provider::Confine::Variable.new(:bar).should respond_to(:name) end describe "when testing values" do before do @confine = Puppet::Provider::Confine::Variable.new("foo") @confine.name = :myvar end it "should use settings if the variable name is a valid setting" do Puppet.settings.expects(:valid?).with(:myvar).returns true Puppet.settings.expects(:value).with(:myvar).returns "foo" @confine.valid? end it "should use Facter if the variable name is not a valid setting" do Puppet.settings.expects(:valid?).with(:myvar).returns false Facter.expects(:value).with(:myvar).returns "foo" @confine.valid? end it "should be valid if the value matches the facter value" do @confine.expects(:test_value).returns "foo" @confine.should be_valid end it "should return false if the value does not match the facter value" do @confine.expects(:test_value).returns "fee" @confine.should_not be_valid end it "should be case insensitive" do @confine.expects(:test_value).returns "FOO" @confine.should be_valid end it "should not care whether the value is a string or symbol" do @confine.expects(:test_value).returns "FOO" @confine.should be_valid end it "should produce a message that the fact value is not correct" do @confine = Puppet::Provider::Confine::Variable.new(%w{bar bee}) @confine.name = "eh" message = @confine.message("value") message.should be_include("facter") message.should be_include("bar,bee") end it "should be valid if the test value matches any of the provided values" do @confine = Puppet::Provider::Confine::Variable.new(%w{bar bee}) @confine.expects(:test_value).returns "bee" @confine.should be_valid end end describe "when summarizing multiple instances" do it "should return a hash of failing variables and their values" do c1 = Puppet::Provider::Confine::Variable.new("one") c1.name = "uno" c1.expects(:valid?).returns false c2 = Puppet::Provider::Confine::Variable.new("two") c2.name = "dos" c2.expects(:valid?).returns true c3 = Puppet::Provider::Confine::Variable.new("three") c3.name = "tres" c3.expects(:valid?).returns false Puppet::Provider::Confine::Variable.summarize([c1, c2, c3]).should == {"uno" => %w{one}, "tres" => %w{three}} end it "should combine the values of multiple confines with the same fact" do c1 = Puppet::Provider::Confine::Variable.new("one") c1.name = "uno" c1.expects(:valid?).returns false c2 = Puppet::Provider::Confine::Variable.new("two") c2.name = "uno" c2.expects(:valid?).returns false Puppet::Provider::Confine::Variable.summarize([c1, c2]).should == {"uno" => %w{one two}} end end end diff --git a/spec/unit/provider/confine_collection_spec.rb b/spec/unit/provider/confine_collection_spec.rb index ffc905b3d..f1dbaf35d 100755 --- a/spec/unit/provider/confine_collection_spec.rb +++ b/spec/unit/provider/confine_collection_spec.rb @@ -1,134 +1,133 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/provider/confine_collection' describe Puppet::Provider::ConfineCollection do it "should be able to add confines" do Puppet::Provider::ConfineCollection.new("label").should respond_to(:confine) end it "should require a label at initialization" do lambda { Puppet::Provider::ConfineCollection.new }.should raise_error(ArgumentError) end it "should make its label available" do Puppet::Provider::ConfineCollection.new("mylabel").label.should == "mylabel" end describe "when creating confine instances" do it "should create an instance of the named test with the provided values" do test_class = mock 'test_class' test_class.expects(:new).with(%w{my values}).returns(stub('confine', :label= => nil)) Puppet::Provider::Confine.expects(:test).with(:foo).returns test_class Puppet::Provider::ConfineCollection.new("label").confine :foo => %w{my values} end it "should copy its label to the confine instance" do confine = mock 'confine' test_class = mock 'test_class' test_class.expects(:new).returns confine Puppet::Provider::Confine.expects(:test).returns test_class confine.expects(:label=).with("label") Puppet::Provider::ConfineCollection.new("label").confine :foo => %w{my values} end describe "and the test cannot be found" do it "should create a Facter test with the provided values and set the name to the test name" do confine = Puppet::Provider::Confine.test(:variable).new(%w{my values}) confine.expects(:name=).with(:foo) confine.class.expects(:new).with(%w{my values}).returns confine Puppet::Provider::ConfineCollection.new("label").confine(:foo => %w{my values}) end end describe "and the 'for_binary' option was provided" do it "should mark the test as a binary confine" do confine = Puppet::Provider::Confine.test(:exists).new(:bar) confine.expects(:for_binary=).with true Puppet::Provider::Confine.test(:exists).expects(:new).with(:bar).returns confine Puppet::Provider::ConfineCollection.new("label").confine :exists => :bar, :for_binary => true end end end it "should be valid if no confines are present" do Puppet::Provider::ConfineCollection.new("label").should be_valid end it "should be valid if all confines pass" do c1 = stub 'c1', :valid? => true, :label= => nil c2 = stub 'c2', :valid? => true, :label= => nil Puppet::Provider::Confine.test(:true).expects(:new).returns(c1) Puppet::Provider::Confine.test(:false).expects(:new).returns(c2) confiner = Puppet::Provider::ConfineCollection.new("label") confiner.confine :true => :bar, :false => :bee confiner.should be_valid end it "should not be valid if any confines fail" do c1 = stub 'c1', :valid? => true, :label= => nil c2 = stub 'c2', :valid? => false, :label= => nil Puppet::Provider::Confine.test(:true).expects(:new).returns(c1) Puppet::Provider::Confine.test(:false).expects(:new).returns(c2) confiner = Puppet::Provider::ConfineCollection.new("label") confiner.confine :true => :bar, :false => :bee confiner.should_not be_valid end describe "when providing a summary" do before do @confiner = Puppet::Provider::ConfineCollection.new("label") end it "should return a hash" do @confiner.summary.should be_instance_of(Hash) end it "should return an empty hash if the confiner is valid" do @confiner.summary.should == {} end it "should add each test type's summary to the hash" do @confiner.confine :true => :bar, :false => :bee Puppet::Provider::Confine.test(:true).expects(:summarize).returns :tsumm Puppet::Provider::Confine.test(:false).expects(:summarize).returns :fsumm @confiner.summary.should == {:true => :tsumm, :false => :fsumm} end it "should not include tests that return 0" do @confiner.confine :true => :bar, :false => :bee Puppet::Provider::Confine.test(:true).expects(:summarize).returns 0 Puppet::Provider::Confine.test(:false).expects(:summarize).returns :fsumm @confiner.summary.should == {:false => :fsumm} end it "should not include tests that return empty arrays" do @confiner.confine :true => :bar, :false => :bee Puppet::Provider::Confine.test(:true).expects(:summarize).returns [] Puppet::Provider::Confine.test(:false).expects(:summarize).returns :fsumm @confiner.summary.should == {:false => :fsumm} end it "should not include tests that return empty hashes" do @confiner.confine :true => :bar, :false => :bee Puppet::Provider::Confine.test(:true).expects(:summarize).returns({}) Puppet::Provider::Confine.test(:false).expects(:summarize).returns :fsumm @confiner.summary.should == {:false => :fsumm} end end end diff --git a/spec/unit/provider/confine_spec.rb b/spec/unit/provider/confine_spec.rb index 060ae8dc3..ade444276 100755 --- a/spec/unit/provider/confine_spec.rb +++ b/spec/unit/provider/confine_spec.rb @@ -1,78 +1,77 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/provider/confine' describe Puppet::Provider::Confine do it "should require a value" do lambda { Puppet::Provider::Confine.new }.should raise_error(ArgumentError) end it "should always convert values to an array" do Puppet::Provider::Confine.new("/some/file").values.should be_instance_of(Array) end it "should have a 'true' test" do Puppet::Provider::Confine.test(:true).should be_instance_of(Class) end it "should have a 'false' test" do Puppet::Provider::Confine.test(:false).should be_instance_of(Class) end it "should have a 'feature' test" do Puppet::Provider::Confine.test(:feature).should be_instance_of(Class) end it "should have an 'exists' test" do Puppet::Provider::Confine.test(:exists).should be_instance_of(Class) end it "should have a 'variable' test" do Puppet::Provider::Confine.test(:variable).should be_instance_of(Class) end describe "when testing all values" do before do @confine = Puppet::Provider::Confine.new(%w{a b c}) @confine.label = "foo" end it "should be invalid if any values fail" do @confine.stubs(:pass?).returns true @confine.expects(:pass?).with("b").returns false @confine.should_not be_valid end it "should be valid if all values pass" do @confine.stubs(:pass?).returns true @confine.should be_valid end it "should short-cut at the first failing value" do @confine.expects(:pass?).once.returns false @confine.valid? end it "should log failing confines with the label and message" do @confine.stubs(:pass?).returns false @confine.expects(:message).returns "My message" @confine.expects(:label).returns "Mylabel" Puppet.expects(:debug).with("Mylabel: My message") @confine.valid? end end describe "when testing the result of the values" do before { @confine = Puppet::Provider::Confine.new(%w{a b c d}) } it "should return an array with the result of the test for each value" do @confine.stubs(:pass?).returns true @confine.expects(:pass?).with("b").returns false @confine.expects(:pass?).with("d").returns false @confine.result.should == [true, false, true, false] end end end diff --git a/spec/unit/provider/confiner_spec.rb b/spec/unit/provider/confiner_spec.rb index fe1ffd86f..23ec162a5 100755 --- a/spec/unit/provider/confiner_spec.rb +++ b/spec/unit/provider/confiner_spec.rb @@ -1,63 +1,62 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/provider/confiner' describe Puppet::Provider::Confiner do before do @object = Object.new @object.extend(Puppet::Provider::Confiner) end it "should have a method for defining confines" do @object.should respond_to(:confine) end it "should have a method for returning its confine collection" do @object.should respond_to(:confine_collection) end it "should have a method for testing suitability" do @object.should respond_to(:suitable?) end it "should delegate its confine method to its confine collection" do coll = mock 'collection' @object.stubs(:confine_collection).returns coll coll.expects(:confine).with(:foo => :bar, :bee => :baz) @object.confine(:foo => :bar, :bee => :baz) end it "should create a new confine collection if one does not exist" do Puppet::Provider::ConfineCollection.expects(:new).with("mylabel").returns "mycoll" @object.expects(:to_s).returns "mylabel" @object.confine_collection.should == "mycoll" end it "should reuse the confine collection" do @object.confine_collection.should equal(@object.confine_collection) end describe "when testing suitability" do before do @coll = mock 'collection' @object.stubs(:confine_collection).returns @coll end it "should return true if the confine collection is valid" do @coll.expects(:valid?).returns true @object.should be_suitable end it "should return false if the confine collection is invalid" do @coll.expects(:valid?).returns false @object.should_not be_suitable end it "should return the summary of the confine collection if a long result is asked for" do @coll.expects(:summary).returns "myresult" @object.suitable?(false).should == "myresult" end end end diff --git a/spec/unit/provider/exec/posix_spec.rb b/spec/unit/provider/exec/posix_spec.rb index a1d887215..50697d826 100755 --- a/spec/unit/provider/exec/posix_spec.rb +++ b/spec/unit/provider/exec/posix_spec.rb @@ -1,120 +1,120 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec require 'spec_helper' provider_class = Puppet::Type.type(:exec).provider(:posix) describe provider_class do before :each do @resource = Puppet::Resource.new(:exec, 'foo') @provider = provider_class.new(@resource) end ["posix", "microsoft_windows"].each do |feature| describe "when in #{feature} environment" do before :each do if feature == "microsoft_windows" Puppet.features.stubs(:microsoft_windows?).returns(true) Puppet.features.stubs(:posix?).returns(false) else Puppet.features.stubs(:posix?).returns(true) Puppet.features.stubs(:microsoft_windows?).returns(false) end end describe "#validatecmd" do it "should fail if no path is specified and the command is not fully qualified" do lambda { @provider.validatecmd("foo") }.should raise_error( Puppet::Error, "'foo' is not qualified and no path was specified. Please qualify the command or specify a path." ) end it "should pass if a path is given" do @provider.resource[:path] = ['/bogus/bin'] @provider.validatecmd("../foo") end it "should pass if command is fully qualifed" do @provider.resource[:path] = ['/bogus/bin'] @provider.validatecmd("/bin/blah/foo") end end describe "#run" do it "should fail if no path is specified and command does not exist" do lambda { @provider.run("foo") }.should raise_error(ArgumentError, "Could not find command 'foo'") end it "should fail if the command isn't in the path" do @provider.resource[:path] = ['/bogus/bin'] lambda { @provider.run("foo") }.should raise_error(ArgumentError, "Could not find command 'foo'") end it "should fail if the command isn't executable" do @provider.resource[:path] = ['/bogus/bin'] File.stubs(:exists?).with("foo").returns(true) lambda { @provider.run("foo") }.should raise_error(ArgumentError, "'foo' is not executable") end it "should not be able to execute shell builtins" do @provider.resource[:path] = ['/bin'] lambda { @provider.run("cd ..") }.should raise_error(ArgumentError, "Could not find command 'cd'") end it "should execute the command if the command given includes arguments or subcommands" do @provider.resource[:path] = ['/bogus/bin'] File.stubs(:exists?).returns(false) File.stubs(:exists?).with("foo").returns(true) File.stubs(:executable?).with("foo").returns(true) Puppet::Util.expects(:execute).with() { |command, arguments| (command == ['foo bar --sillyarg=true --blah']) && (arguments.is_a? Hash) } @provider.run("foo bar --sillyarg=true --blah") end it "should fail if quoted command doesn't exist" do @provider.resource[:path] = ['/bogus/bin'] File.stubs(:exists?).returns(false) File.stubs(:exists?).with("foo").returns(true) File.stubs(:executable?).with("foo").returns(true) lambda { @provider.run('"foo bar --sillyarg=true --blah"') }.should raise_error(ArgumentError, "Could not find command 'foo bar --sillyarg=true --blah'") end it "should execute the command if it finds it in the path and is executable" do @provider.resource[:path] = ['/bogus/bin'] File.stubs(:exists?).with("foo").returns(true) File.stubs(:executable?).with("foo").returns(true) Puppet::Util.expects(:execute).with() { |command, arguments| (command == ['foo']) && (arguments.is_a? Hash) } @provider.run("foo") end if feature == "microsoft_windows" [".exe", ".ps1", ".bat", ".com", ""].each do |extension| it "should check file extension #{extension} when it can't find the executable" do @provider.resource[:path] = ['/bogus/bin'] File.stubs(:exists?).returns(false) File.stubs(:exists?).with("/bogus/bin/foo#{extension}").returns(true) File.stubs(:executable?).with("foo").returns(true) Puppet::Util.expects(:execute).with() { |command, arguments| (command == ['foo']) && (arguments.is_a? Hash) } @provider.run("foo") end end end it "should warn if you're overriding something in environment" do @provider.resource[:environment] = ['WHATEVER=/something/else', 'WHATEVER=/foo'] File.stubs(:exists?).returns(false) File.stubs(:exists?).with("foo").returns(true) File.stubs(:executable?).with("foo").returns(true) Puppet::Util.expects(:execute).with() { |command, arguments| (command == ['foo']) && (arguments.is_a? Hash) } @provider.run("foo") @logs.map {|l| "#{l.level}: #{l.message}" }.should == ["warning: Overriding environment setting 'WHATEVER' with '/foo'"] end end end end end diff --git a/spec/unit/provider/exec/shell_spec.rb b/spec/unit/provider/exec/shell_spec.rb index b84f48fe3..90047b9d6 100755 --- a/spec/unit/provider/exec/shell_spec.rb +++ b/spec/unit/provider/exec/shell_spec.rb @@ -1,50 +1,50 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec require 'spec_helper' provider_class = Puppet::Type.type(:exec).provider(:shell) describe provider_class do before :each do @resource = Puppet::Resource.new(:exec, 'foo') @provider = provider_class.new(@resource) end describe "#run" do it "should be able to run builtin shell commands" do output, status = @provider.run("if [ 1 = 1 ]; then echo 'blah'; fi") status.exitstatus.should == 0 output.should == "blah\n" end it "should be able to run commands with single quotes in them" do output, status = @provider.run("echo 'foo bar'") status.exitstatus.should == 0 output.should == "foo bar\n" end it "should be able to run commands with double quotes in them" do output, status = @provider.run('echo "foo bar"') status.exitstatus.should == 0 output.should == "foo bar\n" end it "should be able to run multiple commands separated by a semicolon" do output, status = @provider.run("echo 'foo' ; echo 'bar'") status.exitstatus.should == 0 output.should == "foo\nbar\n" end it "should be able to read values from the environment parameter" do @resource[:environment] = "FOO=bar" output, status = @provider.run("echo $FOO") status.exitstatus.should == 0 output.should == "bar\n" end end describe "#validatecmd" do it "should always return true because builtins don't need path or to be fully qualified" do @provider.validatecmd('whateverdoesntmatter').should == true end end end diff --git a/spec/unit/provider/group/groupadd_spec.rb b/spec/unit/provider/group/groupadd_spec.rb index 65cb14503..8709fe7f8 100755 --- a/spec/unit/provider/group/groupadd_spec.rb +++ b/spec/unit/provider/group/groupadd_spec.rb @@ -1,31 +1,30 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' provider_class = Puppet::Type.type(:group).provider(:groupadd) describe provider_class do before do @resource = stub("resource", :name => "mygroup") @provider = provider_class.new(@resource) end # #1360 it "should add -o when allowdupe is enabled and the group is being created" do @resource.stubs(:should).returns "fakeval" @resource.stubs(:[]).returns "fakeval" @resource.expects(:allowdupe?).returns true @provider.expects(:execute).with { |args| args.include?("-o") } @provider.create end it "should add -o when allowdupe is enabled and the gid is being modified" do @resource.stubs(:should).returns "fakeval" @resource.stubs(:[]).returns "fakeval" @resource.expects(:allowdupe?).returns true @provider.expects(:execute).with { |args| args.include?("-o") } @provider.gid = 150 end end diff --git a/spec/unit/provider/group/ldap_spec.rb b/spec/unit/provider/group/ldap_spec.rb index 00c42ea40..947007f10 100755 --- a/spec/unit/provider/group/ldap_spec.rb +++ b/spec/unit/provider/group/ldap_spec.rb @@ -1,105 +1,105 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Created by Luke Kanies on 2008-3-10. # Copyright (c) 2006. All rights reserved. require 'spec_helper' provider_class = Puppet::Type.type(:group).provider(:ldap) describe provider_class do it "should have the Ldap provider class as its baseclass" do provider_class.superclass.should equal(Puppet::Provider::Ldap) end it "should manage :posixGroup objectclass" do provider_class.manager.objectclasses.should == [:posixGroup] end it "should use 'ou=Groups' as its relative base" do provider_class.manager.location.should == "ou=Groups" end it "should use :cn as its rdn" do provider_class.manager.rdn.should == :cn end it "should map :name to 'cn'" do provider_class.manager.ldap_name(:name).should == 'cn' end it "should map :gid to 'gidNumber'" do provider_class.manager.ldap_name(:gid).should == 'gidNumber' end it "should map :members to 'memberUid', to be used by the user ldap provider" do provider_class.manager.ldap_name(:members).should == 'memberUid' end describe "when being created" do before do # So we don't try to actually talk to ldap @connection = mock 'connection' provider_class.manager.stubs(:connect).yields @connection end describe "with no gid specified" do it "should pick the first available GID after the largest existing GID" do low = {:name=>["luke"], :gid=>["600"]} high = {:name=>["testing"], :gid=>["640"]} provider_class.manager.expects(:search).returns([low, high]) resource = stub 'resource', :should => %w{whatever} resource.stubs(:should).with(:gid).returns nil resource.stubs(:should).with(:ensure).returns :present instance = provider_class.new(:name => "luke", :ensure => :absent) instance.stubs(:resource).returns resource @connection.expects(:add).with { |dn, attrs| attrs["gidNumber"] == ["641"] } instance.create instance.flush end it "should pick '501' as its GID if no groups are found" do provider_class.manager.expects(:search).returns nil resource = stub 'resource', :should => %w{whatever} resource.stubs(:should).with(:gid).returns nil resource.stubs(:should).with(:ensure).returns :present instance = provider_class.new(:name => "luke", :ensure => :absent) instance.stubs(:resource).returns resource @connection.expects(:add).with { |dn, attrs| attrs["gidNumber"] == ["501"] } instance.create instance.flush end end end it "should have a method for converting group names to GIDs" do provider_class.should respond_to(:name2id) end describe "when converting from a group name to GID" do it "should use the ldap manager to look up the GID" do provider_class.manager.expects(:search).with("cn=foo") provider_class.name2id("foo") end it "should return nil if no group is found" do provider_class.manager.expects(:search).with("cn=foo").returns nil provider_class.name2id("foo").should be_nil provider_class.manager.expects(:search).with("cn=bar").returns [] provider_class.name2id("bar").should be_nil end # We shouldn't ever actually have more than one gid, but it doesn't hurt # to test for the possibility. it "should return the first gid from the first returned group" do provider_class.manager.expects(:search).with("cn=foo").returns [{:name => "foo", :gid => [10, 11]}, {:name => :bar, :gid => [20, 21]}] provider_class.name2id("foo").should == 10 end end end diff --git a/spec/unit/provider/host/parsed_spec.rb b/spec/unit/provider/host/parsed_spec.rb index b6a78e411..9cb5890cc 100755 --- a/spec/unit/provider/host/parsed_spec.rb +++ b/spec/unit/provider/host/parsed_spec.rb @@ -1,198 +1,197 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'shared_behaviours/all_parsedfile_providers' require 'puppet_spec/files' provider_class = Puppet::Type.type(:host).provider(:parsed) describe provider_class do include PuppetSpec::Files before do @host_class = Puppet::Type.type(:host) @provider = @host_class.provider(:parsed) @hostfile = tmpfile('hosts') @provider.any_instance.stubs(:target).returns @hostfile end after :each do @provider.initvars end def mkhost(args) hostresource = Puppet::Type::Host.new(:name => args[:name]) hostresource.stubs(:should).with(:target).returns @hostfile # Using setters of provider to build our testobject # Note: We already proved, that in case of host_aliases # the provider setter "host_aliases=(value)" will be # called with the joined array, so we just simulate that host = @provider.new(hostresource) args.each do |property,value| value = value.join(" ") if property == :host_aliases and value.is_a?(Array) host.send("#{property}=", value) end host end def genhost(host) @provider.stubs(:filetype).returns(Puppet::Util::FileType::FileTypeRam) File.stubs(:chown) File.stubs(:chmod) Puppet::Util::SUIDManager.stubs(:asuser).yields host.flush @provider.target_object(@hostfile).read end describe "when parsing a line with ip and hostname" do it "should parse an ipv4 from the first field" do @provider.parse_line("127.0.0.1 localhost")[:ip].should == "127.0.0.1" end it "should parse an ipv6 from the first field" do @provider.parse_line("::1 localhost")[:ip].should == "::1" end it "should parse the name from the second field" do @provider.parse_line("::1 localhost")[:name].should == "localhost" end it "should set an empty comment" do @provider.parse_line("::1 localhost")[:comment].should == "" end it "should set host_aliases to :absent" do @provider.parse_line("::1 localhost")[:host_aliases].should == :absent end end describe "when parsing a line with ip, hostname and comment" do before do @testline = "127.0.0.1 localhost # A comment with a #-char" end it "should parse the ip from the first field" do @provider.parse_line(@testline)[:ip].should == "127.0.0.1" end it "should parse the hostname from the second field" do @provider.parse_line(@testline)[:name].should == "localhost" end it "should parse the comment after the first '#' character" do @provider.parse_line(@testline)[:comment].should == 'A comment with a #-char' end end describe "when parsing a line with ip, hostname and aliases" do it "should parse alias from the third field" do @provider.parse_line("127.0.0.1 localhost localhost.localdomain")[:host_aliases].should == "localhost.localdomain" end it "should parse multiple aliases" do @provider.parse_line("127.0.0.1 host alias1 alias2")[:host_aliases].should == 'alias1 alias2' @provider.parse_line("127.0.0.1 host alias1\talias2")[:host_aliases].should == 'alias1 alias2' @provider.parse_line("127.0.0.1 host alias1\talias2 alias3")[:host_aliases].should == 'alias1 alias2 alias3' end end describe "when parsing a line with ip, hostname, aliases and comment" do before do # Just playing with a few different delimiters @testline = "127.0.0.1\t host alias1\talias2 alias3 # A comment with a #-char" end it "should parse the ip from the first field" do @provider.parse_line(@testline)[:ip].should == "127.0.0.1" end it "should parse the hostname from the second field" do @provider.parse_line(@testline)[:name].should == "host" end it "should parse all host_aliases from the third field" do @provider.parse_line(@testline)[:host_aliases].should == 'alias1 alias2 alias3' end it "should parse the comment after the first '#' character" do @provider.parse_line(@testline)[:comment].should == 'A comment with a #-char' end end describe "when operating on /etc/hosts like files" do it_should_behave_like "all parsedfile providers", provider_class, my_fixtures('valid*') it "should be able to generate a simple hostfile entry" do host = mkhost( :name => 'localhost', :ip => '127.0.0.1', :ensure => :present ) genhost(host).should == "127.0.0.1\tlocalhost\n" end it "should be able to generate an entry with one alias" do host = mkhost( :name => 'localhost.localdomain', :ip => '127.0.0.1', :host_aliases => 'localhost', :ensure => :present ) genhost(host).should == "127.0.0.1\tlocalhost.localdomain\tlocalhost\n" end it "should be able to generate an entry with more than one alias" do host = mkhost( :name => 'host', :ip => '192.0.0.1', :host_aliases => [ 'a1','a2','a3','a4' ], :ensure => :present ) genhost(host).should == "192.0.0.1\thost\ta1 a2 a3 a4\n" end it "should be able to generate a simple hostfile entry with comments" do host = mkhost( :name => 'localhost', :ip => '127.0.0.1', :comment => 'Bazinga!', :ensure => :present ) genhost(host).should == "127.0.0.1\tlocalhost\t# Bazinga!\n" end it "should be able to generate an entry with one alias and a comment" do host = mkhost( :name => 'localhost.localdomain', :ip => '127.0.0.1', :host_aliases => 'localhost', :comment => 'Bazinga!', :ensure => :present ) genhost(host).should == "127.0.0.1\tlocalhost.localdomain\tlocalhost\t# Bazinga!\n" end it "should be able to generate an entry with more than one alias and a comment" do host = mkhost( :name => 'host', :ip => '192.0.0.1', :host_aliases => [ 'a1','a2','a3','a4' ], :comment => 'Bazinga!', :ensure => :present ) genhost(host).should == "192.0.0.1\thost\ta1 a2 a3 a4\t# Bazinga!\n" end end end diff --git a/spec/unit/provider/interface/cisco_spec.rb b/spec/unit/provider/interface/cisco_spec.rb old mode 100644 new mode 100755 index 7904711f5..d1f70609f --- a/spec/unit/provider/interface/cisco_spec.rb +++ b/spec/unit/provider/interface/cisco_spec.rb @@ -1,64 +1,64 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec require File.dirname(__FILE__) + '/../../../spec_helper' require 'puppet/provider/interface/cisco' provider_class = Puppet::Type.type(:interface).provider(:cisco) describe provider_class do before do @resource = stub("resource", :name => "Fa0/1") @provider = provider_class.new(@resource) end it "should have a parent of Puppet::Provider::NetworkDevice" do provider_class.should < Puppet::Provider::NetworkDevice end it "should have an instances method" do provider_class.should respond_to(:instances) end describe "when looking up instances at prefetch" do before do @device = stub_everything 'device' Puppet::Util::NetworkDevice::Cisco::Device.stubs(:new).returns(@device) @device.stubs(:command).yields(@device) end it "should initialize the network device with the given url" do Puppet::Util::NetworkDevice::Cisco::Device.expects(:new).with(:url).returns(@device) provider_class.lookup(:url, "Fa0/1") end it "should delegate to the device interface fetcher" do @device.expects(:interface) provider_class.lookup("", "Fa0/1") end it "should return the given interface data" do @device.expects(:interface).returns({ :description => "thisone", :mode => :access}) provider_class.lookup("", "Fa0").should == {:description => "thisone", :mode => :access } end end describe "when an instance is being flushed" do it "should call the device interface update method with current and past properties" do @instance = provider_class.new(:ensure => :present, :name => "Fa0/1", :description => "myinterface") @instance.description = "newdesc" @instance.resource = @resource @resource.stubs(:[]).with(:name).returns("Fa0/1") device = stub_everything 'device' @instance.stubs(:device).returns(device) device.expects(:command).yields(device) interface = stub 'interface' device.expects(:new_interface).with("Fa0/1").returns(interface) interface.expects(:update).with( {:ensure => :present, :name => "Fa0/1", :description => "myinterface"}, {:ensure => :present, :name => "Fa0/1", :description => "newdesc"}) @instance.flush end end end diff --git a/spec/unit/provider/ldap_spec.rb b/spec/unit/provider/ldap_spec.rb index 3e0562b73..012a22b99 100755 --- a/spec/unit/provider/ldap_spec.rb +++ b/spec/unit/provider/ldap_spec.rb @@ -1,248 +1,248 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Created by Luke Kanies on 2008-3-21. # Copyright (c) 2006. All rights reserved. require 'spec_helper' require 'puppet/provider/ldap' describe Puppet::Provider::Ldap do before do @class = Class.new(Puppet::Provider::Ldap) end it "should be able to define its manager" do manager = mock 'manager' Puppet::Util::Ldap::Manager.expects(:new).returns manager @class.stubs :mk_resource_methods manager.expects(:manages).with(:one) @class.manages(:one).should equal(manager) @class.manager.should equal(manager) end it "should be able to prefetch instances from ldap" do @class.should respond_to(:prefetch) end it "should create its resource getter/setter methods when the manager is defined" do manager = mock 'manager' Puppet::Util::Ldap::Manager.expects(:new).returns manager @class.expects :mk_resource_methods manager.stubs(:manages) @class.manages(:one).should equal(manager) end it "should have an instances method" do @class.should respond_to(:instances) end describe "when providing a list of instances" do it "should convert all results returned from the manager's :search method into provider instances" do manager = mock 'manager' @class.stubs(:manager).returns manager manager.expects(:search).returns %w{one two three} @class.expects(:new).with("one").returns(1) @class.expects(:new).with("two").returns(2) @class.expects(:new).with("three").returns(3) @class.instances.should == [1,2,3] end end it "should have a prefetch method" do @class.should respond_to(:prefetch) end describe "when prefetching" do before do @manager = mock 'manager' @class.stubs(:manager).returns @manager @resource = mock 'resource' @resources = {"one" => @resource} end it "should find an entry for each passed resource" do @manager.expects(:find).with("one").returns nil @class.stubs(:new) @resource.stubs(:provider=) @class.prefetch(@resources) end describe "resources that do not exist" do it "should create a provider with :ensure => :absent" do result = mock 'result' @manager.expects(:find).with("one").returns nil @class.expects(:new).with(:ensure => :absent).returns "myprovider" @resource.expects(:provider=).with("myprovider") @class.prefetch(@resources) end end describe "resources that exist" do it "should create a provider with the results of the find" do @manager.expects(:find).with("one").returns("one" => "two") @class.expects(:new).with("one" => "two", :ensure => :present).returns "myprovider" @resource.expects(:provider=).with("myprovider") @class.prefetch(@resources) end it "should set :ensure to :present in the returned values" do @manager.expects(:find).with("one").returns("one" => "two") @class.expects(:new).with("one" => "two", :ensure => :present).returns "myprovider" @resource.expects(:provider=).with("myprovider") @class.prefetch(@resources) end end end describe "when being initialized" do it "should fail if no manager has been defined" do lambda { @class.new }.should raise_error(Puppet::DevError) end it "should fail if the manager is invalid" do manager = stub "manager", :valid? => false @class.stubs(:manager).returns manager lambda { @class.new }.should raise_error(Puppet::DevError) end describe "with a hash" do before do @manager = stub "manager", :valid? => true @class.stubs(:manager).returns @manager @resource_class = mock 'resource_class' @class.stubs(:resource_type).returns @resource_class @property_class = stub 'property_class', :array_matching => :all, :superclass => Puppet::Property @resource_class.stubs(:attrclass).with(:one).returns(@property_class) @resource_class.stubs(:valid_parameter?).returns true end it "should store a copy of the hash as its ldap_properties" do instance = @class.new(:one => :two) instance.ldap_properties.should == {:one => :two} end it "should only store the first value of each value array for those attributes that do not match all values" do @property_class.expects(:array_matching).returns :first instance = @class.new(:one => %w{two three}) instance.properties.should == {:one => "two"} end it "should store the whole value array for those attributes that match all values" do @property_class.expects(:array_matching).returns :all instance = @class.new(:one => %w{two three}) instance.properties.should == {:one => %w{two three}} end it "should only use the first value for attributes that are not properties" do # Yay. hackish, but easier than mocking everything. @resource_class.expects(:attrclass).with(:a).returns Puppet::Type.type(:user).attrclass(:name) @property_class.stubs(:array_matching).returns :all instance = @class.new(:one => %w{two three}, :a => %w{b c}) instance.properties.should == {:one => %w{two three}, :a => "b"} end it "should discard any properties not valid in the resource class" do @resource_class.expects(:valid_parameter?).with(:a).returns false @property_class.stubs(:array_matching).returns :all instance = @class.new(:one => %w{two three}, :a => %w{b}) instance.properties.should == {:one => %w{two three}} end end end describe "when an instance" do before do @manager = stub "manager", :valid? => true @class.stubs(:manager).returns @manager @instance = @class.new @property_class = stub 'property_class', :array_matching => :all, :superclass => Puppet::Property @resource_class = stub 'resource_class', :attrclass => @property_class, :valid_parameter? => true, :validproperties => [:one, :two] @class.stubs(:resource_type).returns @resource_class end it "should have a method for creating the ldap entry" do @instance.should respond_to(:create) end it "should have a method for removing the ldap entry" do @instance.should respond_to(:delete) end it "should have a method for returning the class's manager" do @instance.manager.should equal(@manager) end it "should indicate when the ldap entry already exists" do @instance = @class.new(:ensure => :present) @instance.exists?.should be_true end it "should indicate when the ldap entry does not exist" do @instance = @class.new(:ensure => :absent) @instance.exists?.should be_false end describe "is being flushed" do it "should call the manager's :update method with its name, current attributes, and desired attributes" do @instance.stubs(:name).returns "myname" @instance.stubs(:ldap_properties).returns(:one => :two) @instance.stubs(:properties).returns(:three => :four) @manager.expects(:update).with(@instance.name, {:one => :two}, {:three => :four}) @instance.flush end end describe "is being created" do before do @rclass = mock 'resource_class' @rclass.stubs(:validproperties).returns([:one, :two]) @resource = mock 'resource' @resource.stubs(:class).returns @rclass @resource.stubs(:should).returns nil @instance.stubs(:resource).returns @resource end it "should set its :ensure value to :present" do @instance.create @instance.properties[:ensure].should == :present end it "should set all of the other attributes from the resource" do @resource.expects(:should).with(:one).returns "oneval" @resource.expects(:should).with(:two).returns "twoval" @instance.create @instance.properties[:one].should == "oneval" @instance.properties[:two].should == "twoval" end end describe "is being deleted" do it "should set its :ensure value to :absent" do @instance.delete @instance.properties[:ensure].should == :absent end end end end diff --git a/spec/unit/provider/macauthorization_spec.rb b/spec/unit/provider/macauthorization_spec.rb index cb546edbe..a76f917f7 100755 --- a/spec/unit/provider/macauthorization_spec.rb +++ b/spec/unit/provider/macauthorization_spec.rb @@ -1,147 +1,147 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Unit testing for the macauthorization provider # require 'spec_helper' require 'puppet' require 'facter/util/plist' provider_class = Puppet::Type.type(:macauthorization).provider(:macauthorization) describe provider_class do before :each do # Create a mock resource @resource = stub 'resource' @authname = "foo.spam.eggs.puppettest" @authplist = {} @rules = {@authname => @authplist} authdb = {} authdb["rules"] = { "foorule" => "foo" } authdb["rights"] = { "fooright" => "foo" } # Stub out Plist::parse_xml Plist.stubs(:parse_xml).returns(authdb) # A catch all; no parameters set @resource.stubs(:[]).returns(nil) # But set name, ensure @resource.stubs(:[]).with(:name).returns @authname @resource.stubs(:[]).with(:ensure).returns :present @resource.stubs(:ref).returns "MacAuthorization[#{@authname}]" @provider = provider_class.new(@resource) end it "should have a create method" do @provider.should respond_to(:create) end it "should have a destroy method" do @provider.should respond_to(:destroy) end it "should have an exists? method" do @provider.should respond_to(:exists?) end it "should have a flush method" do @provider.should respond_to(:flush) end properties = [ :allow_root, :authenticate_user, :auth_class, :comment, :group, :k_of_n, :mechanisms, :rule, :session_owner, :shared, :timeout, :tries, :auth_type ] properties.each do |prop| it "should have a #{prop.to_s} method" do @provider.should respond_to(prop.to_s) end it "should have a #{prop.to_s}= method" do @provider.should respond_to(prop.to_s + "=") end end describe "when destroying a right" do before :each do @resource.stubs(:[]).with(:auth_type).returns(:right) end it "should call the internal method destroy_right" do @provider.expects(:destroy_right) @provider.destroy end it "should call the external command 'security authorizationdb remove @authname" do @provider.expects(:security).with("authorizationdb", :remove, @authname) @provider.destroy end end describe "when destroying a rule" do before :each do @resource.stubs(:[]).with(:auth_type).returns(:rule) end it "should call the internal method destroy_rule" do @provider.expects(:destroy_rule) @provider.destroy end end describe "when flushing a right" do before :each do @resource.stubs(:[]).with(:auth_type).returns(:right) end it "should call the internal method flush_right" do @provider.expects(:flush_right) @provider.flush end it "should call the internal method set_right" do @provider.expects(:set_right) @provider.flush end it "should read and write to the auth database with the right arguments" do @provider.expects(:execute).with { |cmds, args| cmds.include?("read") and cmds.include?(@authname) and args[:combine] == false }.once @provider.expects(:execute).with { |cmds, args| cmds.include?("write") and cmds.include?(@authname) and args[:combine] == false and args[:stdinfile] != nil }.once @provider.flush end end describe "when flushing a rule" do before :each do @resource.stubs(:[]).with(:auth_type).returns(:rule) end it "should call the internal method flush_rule" do @provider.expects(:flush_rule) @provider.flush end it "should call the internal method set_rule" do @provider.expects(:set_rule) @provider.flush end end end diff --git a/spec/unit/provider/mcx/mcxcontent_spec.rb b/spec/unit/provider/mcx/mcxcontent_spec.rb index 27aae6807..4676575be 100755 --- a/spec/unit/provider/mcx/mcxcontent_spec.rb +++ b/spec/unit/provider/mcx/mcxcontent_spec.rb @@ -1,157 +1,156 @@ -#! /usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' provider_class = Puppet::Type.type(:mcx).provider(:mcxcontent) # describe creates a new ExampleGroup object. describe provider_class do # :each executes before each test. # :all executes once for the test group and before :each. before :each do # Create a mock resource @resource = stub 'resource' @provider = provider_class.new @attached_to = "/Users/foobar" @ds_path = "/Local/Default/Users/foobar" # A catch all; no parameters set @resource.stubs(:[]).returns(nil) # But set name, ensure and enable @resource.stubs(:[]).with(:name).returns @attached_to @resource.stubs(:[]).with(:ensure).returns :present @resource.stubs(:ref).returns "Mcx[#{@attached_to}]" # stub out the provider methods that actually touch the filesystem # or execute commands @provider.class.stubs(:execute).returns('') @provider.stubs(:execute).returns('') @provider.stubs(:resource).returns @resource end it "should have a create method." do @provider.should respond_to(:create) end it "should have a destroy method." do @provider.should respond_to(:destroy) end it "should have an exists? method." do @provider.should respond_to(:exists?) end it "should have an content method." do @provider.should respond_to(:content) end it "should have an content= method." do @provider.should respond_to(:content=) end describe "when managing the resource" do it "should execute external command dscl from :create" do @provider.class.expects(:dscl).returns('').once @provider.create end it "should execute external command dscl from :destroy" do @provider.class.expects(:dscl).with('localhost', '-mcxdelete', @ds_path).returns('').once @provider.destroy end it "should execute external command dscl from :exists?" do @provider.class.expects(:dscl).with('localhost', '-mcxexport', @ds_path).returns('').once @provider.exists? end it "should execute external command dscl from :content" do @provider.class.expects(:dscl).with('localhost', '-mcxexport', @ds_path).returns('') @provider.content end it "should execute external command dscl from :content=" do @provider.class.expects(:dscl).returns('') @provider.content='' end end describe "when creating and parsing the name for ds_type" do before :each do @resource.stubs(:[]).with(:name).returns "/Foo/bar" end it "should not accept /Foo/bar" do lambda { @provider.create }.should raise_error(MCXContentProviderException) end it "should accept /Foo/bar with ds_type => user" do @resource.stubs(:[]).with(:ds_type).returns "user" lambda { @provider.create }.should_not raise_error(MCXContentProviderException) end it "should accept /Foo/bar with ds_type => group" do @resource.stubs(:[]).with(:ds_type).returns "group" lambda { @provider.create }.should_not raise_error(MCXContentProviderException) end it "should accept /Foo/bar with ds_type => computer" do @resource.stubs(:[]).with(:ds_type).returns "computer" lambda { @provider.create }.should_not raise_error(MCXContentProviderException) end it "should accept :name => /Foo/bar with ds_type => computerlist" do @resource.stubs(:[]).with(:ds_type).returns "computerlist" lambda { @provider.create }.should_not raise_error(MCXContentProviderException) end end describe "when creating and :name => foobar" do before :each do @resource.stubs(:[]).with(:name).returns "foobar" end it "should not accept unspecified :ds_type and :ds_name" do lambda { @provider.create }.should raise_error(MCXContentProviderException) end it "should not accept unspecified :ds_type" do @resource.stubs(:[]).with(:ds_type).returns "user" lambda { @provider.create }.should raise_error(MCXContentProviderException) end it "should not accept unspecified :ds_name" do @resource.stubs(:[]).with(:ds_name).returns "foo" lambda { @provider.create }.should raise_error(MCXContentProviderException) end it "should accept :ds_type => user, ds_name => foo" do @resource.stubs(:[]).with(:ds_type).returns "user" @resource.stubs(:[]).with(:ds_name).returns "foo" lambda { @provider.create }.should_not raise_error(MCXContentProviderException) end it "should accept :ds_type => group, ds_name => foo" do @resource.stubs(:[]).with(:ds_type).returns "group" @resource.stubs(:[]).with(:ds_name).returns "foo" lambda { @provider.create }.should_not raise_error(MCXContentProviderException) end it "should accept :ds_type => computer, ds_name => foo" do @resource.stubs(:[]).with(:ds_type).returns "computer" @resource.stubs(:[]).with(:ds_name).returns "foo" lambda { @provider.create }.should_not raise_error(MCXContentProviderException) end it "should accept :ds_type => computerlist, ds_name => foo" do @resource.stubs(:[]).with(:ds_type).returns "computerlist" @resource.stubs(:[]).with(:ds_name).returns "foo" lambda { @provider.create }.should_not raise_error(MCXContentProviderException) end it "should not accept :ds_type => bogustype, ds_name => foo" do @resource.stubs(:[]).with(:ds_type).returns "bogustype" @resource.stubs(:[]).with(:ds_name).returns "foo" lambda { @provider.create }.should raise_error(MCXContentProviderException) end end describe "when gathering existing instances" do it "should define an instances class method." do @provider.class.should respond_to(:instances) end it "should call external command dscl -list /Local/Default/ on each known ds_type" do @provider.class.expects(:dscl).with('localhost', '-list', "/Local/Default/Users").returns('') @provider.class.expects(:dscl).with('localhost', '-list', "/Local/Default/Groups").returns('') @provider.class.expects(:dscl).with('localhost', '-list', "/Local/Default/Computers").returns('') @provider.class.expects(:dscl).with('localhost', '-list', "/Local/Default/ComputerLists").returns('') @provider.class.instances end end end diff --git a/spec/unit/provider/mount/parsed_spec.rb b/spec/unit/provider/mount/parsed_spec.rb index 86c35f7da..0293e0758 100755 --- a/spec/unit/provider/mount/parsed_spec.rb +++ b/spec/unit/provider/mount/parsed_spec.rb @@ -1,252 +1,252 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Created by Luke Kanies on 2007-9-12. # Copyright (c) 2006. All rights reserved. require 'spec_helper' require 'shared_behaviours/all_parsedfile_providers' provider_class = Puppet::Type.type(:mount).provider(:parsed) describe provider_class do before :each do @mount_class = Puppet::Type.type(:mount) @provider = @mount_class.provider(:parsed) end # LAK:FIXME I can't mock Facter because this test happens at parse-time. it "should default to /etc/vfstab on Solaris" do pending "This test only works on Solaris" unless Facter.value(:operatingsystem) == 'Solaris' Puppet::Type.type(:mount).provider(:parsed).default_target.should == '/etc/vfstab' end it "should default to /etc/fstab on anything else" do pending "This test does not work on Solaris" if Facter.value(:operatingsystem) == 'Solaris' Puppet::Type.type(:mount).provider(:parsed).default_target.should == '/etc/fstab' end describe "when parsing a line" do it "should not crash on incomplete lines in fstab" do parse = @provider.parse <<-FSTAB /dev/incomplete /dev/device name FSTAB lambda{ @provider.to_line(parse[0]) }.should_not raise_error end # it_should_behave_like "all parsedfile providers", # provider_class, my_fixtures('*.fstab') describe "on Solaris", :if => Facter.value(:operatingsystem) == 'Solaris' do before :each do @example_line = "/dev/dsk/c0d0s0 /dev/rdsk/c0d0s0 \t\t / \t ufs 1 no\t-" end it "should extract device from the first field" do @provider.parse_line(@example_line)[:device].should == '/dev/dsk/c0d0s0' end it "should extract blockdevice from second field" do @provider.parse_line(@example_line)[:blockdevice].should == "/dev/rdsk/c0d0s0" end it "should extract name from third field" do @provider.parse_line(@example_line)[:name].should == "/" end it "should extract fstype from fourth field" do @provider.parse_line(@example_line)[:fstype].should == "ufs" end it "should extract pass from fifth field" do @provider.parse_line(@example_line)[:pass].should == "1" end it "should extract atboot from sixth field" do @provider.parse_line(@example_line)[:atboot].should == "no" end it "should extract options from seventh field" do @provider.parse_line(@example_line)[:options].should == "-" end end describe "on other platforms than Solaris", :if => Facter.value(:operatingsystem) != 'Solaris' do before :each do @example_line = "/dev/vg00/lv01\t/spare \t \t ext3 defaults\t1 2" end it "should extract device from the first field" do @provider.parse_line(@example_line)[:device].should == '/dev/vg00/lv01' end it "should extract name from second field" do @provider.parse_line(@example_line)[:name].should == "/spare" end it "should extract fstype from third field" do @provider.parse_line(@example_line)[:fstype].should == "ext3" end it "should extract options from fourth field" do @provider.parse_line(@example_line)[:options].should == "defaults" end it "should extract dump from fifth field" do @provider.parse_line(@example_line)[:dump].should == "1" end it "should extract options from sixth field" do @provider.parse_line(@example_line)[:pass].should == "2" end end end describe "mountinstances" do it "should get name from mountoutput found on Solaris" do Facter.stubs(:value).with(:operatingsystem).returns 'Solaris' @provider.stubs(:mountcmd).returns(File.read(my_fixture('solaris.mount'))) mounts = @provider.mountinstances mounts.size.should == 6 mounts[0].should == { :name => '/', :mounted => :yes } mounts[1].should == { :name => '/proc', :mounted => :yes } mounts[2].should == { :name => '/etc/mnttab', :mounted => :yes } mounts[3].should == { :name => '/tmp', :mounted => :yes } mounts[4].should == { :name => '/export/home', :mounted => :yes } mounts[5].should == { :name => '/ghost', :mounted => :yes } end it "should get name from mountoutput found on HP-UX" do Facter.stubs(:value).with(:operatingsystem).returns 'HP-UX' @provider.stubs(:mountcmd).returns(File.read(my_fixture('hpux.mount'))) mounts = @provider.mountinstances mounts.size.should == 17 mounts[0].should == { :name => '/', :mounted => :yes } mounts[1].should == { :name => '/devices', :mounted => :yes } mounts[2].should == { :name => '/dev', :mounted => :yes } mounts[3].should == { :name => '/system/contract', :mounted => :yes } mounts[4].should == { :name => '/proc', :mounted => :yes } mounts[5].should == { :name => '/etc/mnttab', :mounted => :yes } mounts[6].should == { :name => '/etc/svc/volatile', :mounted => :yes } mounts[7].should == { :name => '/system/object', :mounted => :yes } mounts[8].should == { :name => '/etc/dfs/sharetab', :mounted => :yes } mounts[9].should == { :name => '/lib/libc.so.1', :mounted => :yes } mounts[10].should == { :name => '/dev/fd', :mounted => :yes } mounts[11].should == { :name => '/tmp', :mounted => :yes } mounts[12].should == { :name => '/var/run', :mounted => :yes } mounts[13].should == { :name => '/export', :mounted => :yes } mounts[14].should == { :name => '/export/home', :mounted => :yes } mounts[15].should == { :name => '/rpool', :mounted => :yes } mounts[16].should == { :name => '/ghost', :mounted => :yes } end it "should get name from mountoutput found on Darwin" do Facter.stubs(:value).with(:operatingsystem).returns 'Darwin' @provider.stubs(:mountcmd).returns(File.read(my_fixture('darwin.mount'))) mounts = @provider.mountinstances mounts.size.should == 6 mounts[0].should == { :name => '/', :mounted => :yes } mounts[1].should == { :name => '/dev', :mounted => :yes } mounts[2].should == { :name => '/net', :mounted => :yes } mounts[3].should == { :name => '/home', :mounted => :yes } mounts[4].should == { :name => '/usr', :mounted => :yes } mounts[5].should == { :name => '/ghost', :mounted => :yes } end it "should get name from mountoutput found on Linux" do Facter.stubs(:value).with(:operatingsystem).returns 'Gentoo' @provider.stubs(:mountcmd).returns(File.read(my_fixture('linux.mount'))) mounts = @provider.mountinstances mounts[0].should == { :name => '/', :mounted => :yes } mounts[1].should == { :name => '/lib64/rc/init.d', :mounted => :yes } mounts[2].should == { :name => '/sys', :mounted => :yes } mounts[3].should == { :name => '/usr/portage', :mounted => :yes } mounts[4].should == { :name => '/ghost', :mounted => :yes } end it "should get name from mountoutput found on AIX" do Facter.stubs(:value).with(:operatingsystem).returns 'AIX' @provider.stubs(:mountcmd).returns(File.read(my_fixture('aix.mount'))) mounts = @provider.mountinstances mounts[0].should == { :name => '/', :mounted => :yes } mounts[1].should == { :name => '/tmp', :mounted => :yes } mounts[2].should == { :name => '/home', :mounted => :yes } mounts[3].should == { :name => '/usr', :mounted => :yes } mounts[4].should == { :name => '/usr/code', :mounted => :yes } end it "should raise an error if a line is not understandable" do @provider.stubs(:mountcmd).returns("bazinga!") lambda { @provider.mountinstances }.should raise_error Puppet::Error end end it "should support AIX's paragraph based /etc/filesystems" my_fixtures('*.fstab').each do |fstab| platform = File.basename(fstab, '.fstab') describe "when prefetching on #{platform}" do before :each do if Facter[:operatingsystem] == "Solaris" then platform == 'solaris' or pending "We need to stub the operatingsystem fact at load time, but can't" else platform != 'solaris' or pending "We need to stub the operatingsystem fact at load time, but can't" end # Stub the mount output to our fixture. begin mount = my_fixture(platform + '.mount') @provider.stubs(:mountcmd).returns File.read(mount) rescue pending "is #{platform}.mount missing at this point?" end # Note: we have to stub default_target before creating resources # because it is used by Puppet::Type::Mount.new to populate the # :target property. @provider.stubs(:default_target).returns fstab @res_ghost = Puppet::Type::Mount.new(:name => '/ghost') # in no fake fstab @res_mounted = Puppet::Type::Mount.new(:name => '/') # in every fake fstab @res_unmounted = Puppet::Type::Mount.new(:name => '/boot') # in every fake fstab @res_absent = Puppet::Type::Mount.new(:name => '/absent') # in no fake fstab # Simulate transaction.rb:prefetch @resource_hash = {} [@res_ghost, @res_mounted, @res_unmounted, @res_absent].each do |resource| @resource_hash[resource.name] = resource end end it "should set :ensure to :unmounted if found in fstab but not mounted" do @provider.prefetch(@resource_hash) @res_unmounted.provider.get(:ensure).should == :unmounted end it "should set :ensure to :ghost if not found in fstab but mounted" do @provider.prefetch(@resource_hash) @res_ghost.provider.get(:ensure).should == :ghost end it "should set :ensure to :mounted if found in fstab and mounted" do @provider.prefetch(@resource_hash) @res_mounted.provider.get(:ensure).should == :mounted end it "should set :ensure to :absent if not found in fstab and not mounted" do @provider.prefetch(@resource_hash) @res_absent.provider.get(:ensure).should == :absent end end end end diff --git a/spec/unit/provider/mount_spec.rb b/spec/unit/provider/mount_spec.rb index 0db4ae918..963bfba7c 100755 --- a/spec/unit/provider/mount_spec.rb +++ b/spec/unit/provider/mount_spec.rb @@ -1,146 +1,145 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/provider/mount' describe Puppet::Provider::Mount do before :each do @mounter = Object.new @mounter.extend(Puppet::Provider::Mount) @name = "/" @resource = stub 'resource' @resource.stubs(:[]).with(:name).returns(@name) @mounter.stubs(:resource).returns(@resource) end describe Puppet::Provider::Mount, " when mounting" do before :each do @mounter.stubs(:get).with(:ensure).returns(:mounted) end it "should use the 'mountcmd' method to mount" do @mounter.stubs(:options).returns(nil) @mounter.expects(:mountcmd) @mounter.mount end it "should add the options following '-o' if they exist and are not set to :absent" do @mounter.stubs(:options).returns("ro") @mounter.expects(:mountcmd).with { |*ary| ary[0] == "-o" and ary[1] == "ro" } @mounter.mount end it "should specify the filesystem name to the mount command" do @mounter.stubs(:options).returns(nil) @mounter.expects(:mountcmd).with { |*ary| ary[-1] == @name } @mounter.mount end it "should update the :ensure state to :mounted if it was :unmounted before" do @mounter.expects(:mountcmd) @mounter.stubs(:options).returns(nil) @mounter.expects(:get).with(:ensure).returns(:unmounted) @mounter.expects(:set).with(:ensure => :mounted) @mounter.mount end it "should update the :ensure state to :ghost if it was :absent before" do @mounter.expects(:mountcmd) @mounter.stubs(:options).returns(nil) @mounter.expects(:get).with(:ensure).returns(:absent) @mounter.expects(:set).with(:ensure => :ghost) @mounter.mount end end describe Puppet::Provider::Mount, " when remounting" do it "should use '-o remount' if the resource specifies it supports remounting" do @mounter.stubs(:info) @resource.stubs(:[]).with(:remounts).returns(:true) @mounter.expects(:mountcmd).with("-o", "remount", @name) @mounter.remount end it "should unmount and mount if the resource does not specify it supports remounting" do @mounter.stubs(:info) @resource.stubs(:[]).with(:remounts).returns(false) @mounter.expects(:unmount) @mounter.expects(:mount) @mounter.remount end it "should log that it is remounting" do @resource.stubs(:[]).with(:remounts).returns(:true) @mounter.stubs(:mountcmd) @mounter.expects(:info).with("Remounting") @mounter.remount end end describe Puppet::Provider::Mount, " when unmounting" do before :each do @mounter.stubs(:get).with(:ensure).returns(:unmounted) end it "should call the :umount command with the resource name" do @mounter.expects(:umount).with(@name) @mounter.unmount end it "should update the :ensure state to :absent if it was :ghost before" do @mounter.expects(:umount).with(@name).returns true @mounter.expects(:get).with(:ensure).returns(:ghost) @mounter.expects(:set).with(:ensure => :absent) @mounter.unmount end it "should update the :ensure state to :unmounted if it was :mounted before" do @mounter.expects(:umount).with(@name).returns true @mounter.expects(:get).with(:ensure).returns(:mounted) @mounter.expects(:set).with(:ensure => :unmounted) @mounter.unmount end end describe Puppet::Provider::Mount, " when determining if it is mounted" do it "should query the property_hash" do @mounter.expects(:get).with(:ensure).returns(:mounted) @mounter.mounted? end it "should return true if prefetched value is :mounted" do @mounter.stubs(:get).with(:ensure).returns(:mounted) @mounter.mounted? == true end it "should return true if prefetched value is :ghost" do @mounter.stubs(:get).with(:ensure).returns(:ghost) @mounter.mounted? == true end it "should return false if prefetched value is :absent" do @mounter.stubs(:get).with(:ensure).returns(:absent) @mounter.mounted? == false end it "should return false if prefetched value is :unmounted" do @mounter.stubs(:get).with(:ensure).returns(:unmounted) @mounter.mounted? == false end end end diff --git a/spec/unit/provider/naginator_spec.rb b/spec/unit/provider/naginator_spec.rb index 5841bc012..1d8e78015 100755 --- a/spec/unit/provider/naginator_spec.rb +++ b/spec/unit/provider/naginator_spec.rb @@ -1,58 +1,57 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/provider/naginator' describe Puppet::Provider::Naginator do before do @resource_type = stub 'resource_type', :name => :nagios_test @class = Class.new(Puppet::Provider::Naginator) @class.stubs(:resource_type).returns @resource_type end it "should be able to look up the associated Nagios type" do nagios_type = mock "nagios_type" nagios_type.stubs :attr_accessor Nagios::Base.expects(:type).with(:test).returns nagios_type @class.nagios_type.should equal(nagios_type) end it "should use the Nagios type to determine whether an attribute is valid" do nagios_type = mock "nagios_type" nagios_type.stubs :attr_accessor Nagios::Base.expects(:type).with(:test).returns nagios_type nagios_type.expects(:parameters).returns [:foo, :bar] @class.valid_attr?(:test, :foo).should be_true end it "should use Naginator to parse configuration snippets" do parser = mock 'parser' parser.expects(:parse).with("my text").returns "my instances" Nagios::Parser.expects(:new).returns(parser) @class.parse("my text").should == "my instances" end it "should join Nagios::Base records with '\\n' when asked to convert them to text" do @class.expects(:header).returns "myheader\n" @class.to_file([:one, :two]).should == "myheader\none\ntwo" end it "should be able to prefetch instance from configuration files" do @class.should respond_to(:prefetch) end it "should be able to generate a list of instances" do @class.should respond_to(:instances) end it "should never skip records" do @class.should_not be_skip_record("foo") end end diff --git a/spec/unit/provider/nameservice/directoryservice_spec.rb b/spec/unit/provider/nameservice/directoryservice_spec.rb index 798d511c0..47f2ad0cd 100755 --- a/spec/unit/provider/nameservice/directoryservice_spec.rb +++ b/spec/unit/provider/nameservice/directoryservice_spec.rb @@ -1,38 +1,37 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' # We use this as a reasonable way to obtain all the support infrastructure. [:user, :group].each do |type_for_this_round| provider_class = Puppet::Type.type(type_for_this_round).provider(:directoryservice) describe provider_class do before do @resource = stub("resource") @provider = provider_class.new(@resource) end it "[#6009] should handle nested arrays of members" do current = ["foo", "bar", "baz"] desired = ["foo", ["quux"], "qorp"] group = 'example' @resource.stubs(:[]).with(:name).returns(group) @resource.stubs(:[]).with(:auth_membership).returns(true) @provider.instance_variable_set(:@property_value_cache_hash, { :members => current }) %w{bar baz}.each do |del| @provider.expects(:execute).once. with([:dseditgroup, '-o', 'edit', '-n', '.', '-d', del, group]) end %w{quux qorp}.each do |add| @provider.expects(:execute).once. with([:dseditgroup, '-o', 'edit', '-n', '.', '-a', add, group]) end expect { @provider.set(:members, desired) }.should_not raise_error end end end diff --git a/spec/unit/provider/network_device_spec.rb b/spec/unit/provider/network_device_spec.rb old mode 100644 new mode 100755 index 3e6d382ee..83d2bdc01 --- a/spec/unit/provider/network_device_spec.rb +++ b/spec/unit/provider/network_device_spec.rb @@ -1,148 +1,148 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec require File.dirname(__FILE__) + '/../../spec_helper' require 'puppet/provider/network_device' Puppet::Type.type(:vlan).provide :test, :parent => Puppet::Provider::NetworkDevice do mk_resource_methods def self.lookup(device_url, name) end end provider_class = Puppet::Type.type(:vlan).provider(:test) describe provider_class do before do @resource = stub("resource", :name => "test") @provider = provider_class.new(@resource) end it "should be able to prefetch instances from the device" do provider_class.should respond_to(:prefetch) end it "should have an instances method" do provider_class.should respond_to(:instances) end describe "when prefetching" do before do @resource = stub_everything 'resource' @resources = {"200" => @resource} provider_class.stubs(:lookup) end it "should lookup an entry for each passed resource" do provider_class.expects(:lookup).with(nil, "200").returns nil provider_class.stubs(:new) @resource.stubs(:provider=) provider_class.prefetch(@resources) end describe "resources that do not exist" do it "should create a provider with :ensure => :absent" do provider_class.stubs(:lookup).returns(nil) provider_class.expects(:new).with(:ensure => :absent).returns "myprovider" @resource.expects(:provider=).with("myprovider") provider_class.prefetch(@resources) end end describe "resources that exist" do it "should create a provider with the results of the find and ensure at present" do provider_class.stubs(:lookup).returns({ :name => "200", :description => "myvlan"}) provider_class.expects(:new).with(:name => "200", :description => "myvlan", :ensure => :present).returns "myprovider" @resource.expects(:provider=).with("myprovider") provider_class.prefetch(@resources) end end end describe "when being initialized" do describe "with a hash" do before do @resource_class = mock 'resource_class' provider_class.stubs(:resource_type).returns @resource_class @property_class = stub 'property_class', :array_matching => :all, :superclass => Puppet::Property @resource_class.stubs(:attrclass).with(:one).returns(@property_class) @resource_class.stubs(:valid_parameter?).returns true end it "should store a copy of the hash as its vlan_properties" do instance = provider_class.new(:one => :two) instance.former_properties.should == {:one => :two} end end end describe "when an instance" do before do @instance = provider_class.new @property_class = stub 'property_class', :array_matching => :all, :superclass => Puppet::Property @resource_class = stub 'resource_class', :attrclass => @property_class, :valid_parameter? => true, :validproperties => [:description] provider_class.stubs(:resource_type).returns @resource_class end it "should have a method for creating the instance" do @instance.should respond_to(:create) end it "should have a method for removing the instance" do @instance.should respond_to(:destroy) end it "should indicate when the instance already exists" do @instance = provider_class.new(:ensure => :present) @instance.exists?.should be_true end it "should indicate when the instance does not exist" do @instance = provider_class.new(:ensure => :absent) @instance.exists?.should be_false end describe "is being flushed" do it "should flush properties" do @instance = provider_class.new(:ensure => :present, :name => "200", :description => "myvlan") @instance.flush @instance.properties.should be_empty end end describe "is being created" do before do @rclass = mock 'resource_class' @rclass.stubs(:validproperties).returns([:description]) @resource = stub_everything 'resource' @resource.stubs(:class).returns @rclass @resource.stubs(:should).returns nil @instance.stubs(:resource).returns @resource end it "should set its :ensure value to :present" do @instance.create @instance.properties[:ensure].should == :present end it "should set all of the other attributes from the resource" do @resource.expects(:should).with(:description).returns "myvlan" @instance.create @instance.properties[:description].should == "myvlan" end end describe "is being destroyed" do it "should set its :ensure value to :absent" do @instance.destroy @instance.properties[:ensure].should == :absent end end end end diff --git a/spec/unit/provider/package/aix_spec.rb b/spec/unit/provider/package/aix_spec.rb index 8feac3c55..fba29d7a7 100755 --- a/spec/unit/provider/package/aix_spec.rb +++ b/spec/unit/provider/package/aix_spec.rb @@ -1,66 +1,65 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' provider_class = Puppet::Type.type(:package).provider(:aix) describe provider_class do before(:each) do # Create a mock resource @resource = stub 'resource' # A catch all; no parameters set @resource.stubs(:[]).returns(nil) # But set name and source @resource.stubs(:[]).with(:name).returns "mypackage" @resource.stubs(:[]).with(:source).returns "mysource" @resource.stubs(:[]).with(:ensure).returns :installed @provider = provider_class.new @provider.resource = @resource end [:install, :uninstall, :latest, :query, :update].each do |method| it "should have a #{method} method" do @provider.should respond_to(method) end end it "should uninstall a package" do @provider.expects(:installp).with('-gu', 'mypackage') @provider.uninstall end describe "when installing" do it "should install a package" do @resource.stubs(:should).with(:ensure).returns(:installed) @provider.expects(:installp).with('-acgwXY', '-d', 'mysource', 'mypackage') @provider.install end it "should install a specific package version" do @resource.stubs(:should).with(:ensure).returns("1.2.3.4") @provider.expects(:installp).with('-acgwXY', '-d', 'mysource', 'mypackage 1.2.3.4') @provider.install end end describe "when finding the latest version" do it "should return the current version when no later version is present" do @provider.stubs(:latest_info).returns(nil) @provider.stubs(:properties).returns( { :ensure => "1.2.3.4" } ) @provider.latest.should == "1.2.3.4" end it "should return the latest version of a package" do @provider.stubs(:latest_info).returns( { :version => "1.2.3.5" } ) @provider.latest.should == "1.2.3.5" end end it "update should install a package" do @provider.expects(:install).with(false) @provider.update end end diff --git a/spec/unit/provider/package/apt_spec.rb b/spec/unit/provider/package/apt_spec.rb index 59342750e..b020b0f4f 100755 --- a/spec/unit/provider/package/apt_spec.rb +++ b/spec/unit/provider/package/apt_spec.rb @@ -1,145 +1,144 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' provider = Puppet::Type.type(:package).provider(:apt) describe provider do before do @resource = stub 'resource', :[] => "asdf" @provider = provider.new(@resource) @fakeresult = "install ok installed asdf 1.0\n" end it "should be versionable" do provider.should be_versionable end it "should use :install to update" do @provider.expects(:install) @provider.update end it "should use 'apt-get remove' to uninstall" do @provider.expects(:aptget).with("-y", "-q", :remove, "asdf") @provider.uninstall end it "should use 'apt-get purge' and 'dpkg purge' to purge" do @provider.expects(:aptget).with("-y", "-q", :remove, "--purge", "asdf") @provider.expects(:dpkg).with("--purge", "asdf") @provider.purge end it "should use 'apt-cache policy' to determine the latest version of a package" do @provider.expects(:aptcache).with(:policy, "asdf").returns "asdf: Installed: 1:1.0 Candidate: 1:1.1 Version table: 1:1.0 650 http://ftp.osuosl.org testing/main Packages *** 1:1.1 100 /var/lib/dpkg/status" @provider.latest.should == "1:1.1" end it "should print and error and return nil if no policy is found" do @provider.expects(:aptcache).with(:policy, "asdf").returns "asdf:" @provider.expects(:err) @provider.latest.should be_nil end it "should be able to preseed" do @provider.should respond_to(:run_preseed) end it "should preseed with the provided responsefile when preseeding is called for" do @resource.expects(:[]).with(:responsefile).returns "/my/file" FileTest.expects(:exist?).with("/my/file").returns true @provider.expects(:info) @provider.expects(:preseed).with("/my/file") @provider.run_preseed end it "should not preseed if no responsefile is provided" do @resource.expects(:[]).with(:responsefile).returns nil @provider.expects(:info) @provider.expects(:preseed).never @provider.run_preseed end it "should fail if a cdrom is listed in the sources list and :allowcdrom is not specified" describe "when installing" do it "should preseed if a responsefile is provided" do @resource.expects(:[]).with(:responsefile).returns "/my/file" @provider.expects(:run_preseed) @provider.stubs(:aptget) @provider.install end it "should check for a cdrom" do @provider.expects(:checkforcdrom) @provider.stubs(:aptget) @provider.install end it "should use 'apt-get install' with the package name if no version is asked for" do @resource.expects(:[]).with(:ensure).returns :installed @provider.expects(:aptget).with { |*command| command[-1] == "asdf" and command[-2] == :install } @provider.install end it "should specify the package version if one is asked for" do @resource.expects(:[]).with(:ensure).returns "1.0" @provider.expects(:aptget).with { |*command| command[-1] == "asdf=1.0" } @provider.install end it "should use --force-yes if a package version is specified" do @resource.expects(:[]).with(:ensure).returns "1.0" @provider.expects(:aptget).with { |*command| command.include?("--force-yes") } @provider.install end it "should do a quiet install" do @provider.expects(:aptget).with { |*command| command.include?("-q") } @provider.install end it "should default to 'yes' for all questions" do @provider.expects(:aptget).with { |*command| command.include?("-y") } @provider.install end it "should keep config files if asked" do @resource.expects(:[]).with(:configfiles).returns :keep @provider.expects(:aptget).with { |*command| command.include?("DPkg::Options::=--force-confold") } @provider.install end it "should replace config files if asked" do @resource.expects(:[]).with(:configfiles).returns :replace @provider.expects(:aptget).with { |*command| command.include?("DPkg::Options::=--force-confnew") } @provider.install end end end diff --git a/spec/unit/provider/package/dpkg_spec.rb b/spec/unit/provider/package/dpkg_spec.rb index 7c83f90ee..e64146056 100755 --- a/spec/unit/provider/package/dpkg_spec.rb +++ b/spec/unit/provider/package/dpkg_spec.rb @@ -1,225 +1,224 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' provider = Puppet::Type.type(:package).provider(:dpkg) describe provider do before do @resource = stub 'resource', :[] => "asdf" @provider = provider.new(@resource) @provider.expects(:execute).never # forbid "manual" executions @fakeresult = "install ok installed asdf 1.0\n" end it "should have documentation" do provider.doc.should be_instance_of(String) end describe "when listing all instances" do before do provider.stubs(:command).with(:dpkgquery).returns "myquery" end it "should use dpkg-query" do provider.expects(:command).with(:dpkgquery).returns "myquery" provider.expects(:execpipe).with("myquery -W --showformat '${Status} ${Package} ${Version}\\n'").returns @fakeresult provider.instances end it "should create and return an instance with each parsed line from dpkg-query" do pipe = mock 'pipe' pipe.expects(:each).yields @fakeresult provider.expects(:execpipe).yields pipe asdf = mock 'pkg1' provider.expects(:new).with(:ensure => "1.0", :error => "ok", :desired => "install", :name => "asdf", :status => "installed", :provider => :dpkg).returns asdf provider.instances.should == [asdf] end it "should warn on and ignore any lines it does not understand" do pipe = mock 'pipe' pipe.expects(:each).yields "foobar" provider.expects(:execpipe).yields pipe Puppet.expects(:warning) provider.expects(:new).never provider.instances.should == [] end end describe "when querying the current state" do it "should use dpkg-query" do @provider.expects(:dpkgquery).with("-W", "--showformat",'${Status} ${Package} ${Version}\\n', "asdf").returns @fakeresult @provider.query end it "should consider the package purged if dpkg-query fails" do @provider.expects(:dpkgquery).raises Puppet::ExecutionFailure.new("eh") @provider.query[:ensure].should == :purged end it "should return a hash of the found status with the desired state, error state, status, name, and 'ensure'" do @provider.expects(:dpkgquery).returns @fakeresult @provider.query.should == {:ensure => "1.0", :error => "ok", :desired => "install", :name => "asdf", :status => "installed", :provider => :dpkg} end it "should consider the package absent if the dpkg-query result cannot be interpreted" do @provider.expects(:dpkgquery).returns "somebaddata" @provider.query[:ensure].should == :absent end it "should fail if an error is discovered" do @provider.expects(:dpkgquery).returns @fakeresult.sub("ok", "error") lambda { @provider.query }.should raise_error(Puppet::Error) end it "should consider the package purged if it is marked 'not-installed'" do @provider.expects(:dpkgquery).returns @fakeresult.sub("installed", "not-installed") @provider.query[:ensure].should == :purged end it "should consider the package absent if it is marked 'config-files'" do @provider.expects(:dpkgquery).returns @fakeresult.sub("installed", "config-files") @provider.query[:ensure].should == :absent end it "should consider the package absent if it is marked 'half-installed'" do @provider.expects(:dpkgquery).returns @fakeresult.sub("installed", "half-installed") @provider.query[:ensure].should == :absent end it "should consider the package absent if it is marked 'unpacked'" do @provider.expects(:dpkgquery).returns @fakeresult.sub("installed", "unpacked") @provider.query[:ensure].should == :absent end it "should consider the package absent if it is marked 'half-configured'" do @provider.expects(:dpkgquery).returns @fakeresult.sub("installed", "half-configured") @provider.query[:ensure].should == :absent end it "should consider the package held if its state is 'hold'" do @provider.expects(:dpkgquery).returns @fakeresult.sub("install", "hold") @provider.query[:ensure].should == :held end end it "should be able to install" do @provider.should respond_to(:install) end describe "when installing" do before do @resource.stubs(:[]).with(:source).returns "mypkg" end it "should fail to install if no source is specified in the resource" do @resource.expects(:[]).with(:source).returns nil lambda { @provider.install }.should raise_error(ArgumentError) end it "should use 'dpkg -i' to install the package" do @resource.expects(:[]).with(:source).returns "mypackagefile" @provider.expects(:unhold) @provider.expects(:dpkg).with { |*command| command[-1] == "mypackagefile" and command[-2] == "-i" } @provider.install end it "should keep old config files if told to do so" do @resource.expects(:[]).with(:configfiles).returns :keep @provider.expects(:unhold) @provider.expects(:dpkg).with { |*command| command[0] == "--force-confold" } @provider.install end it "should replace old config files if told to do so" do @resource.expects(:[]).with(:configfiles).returns :replace @provider.expects(:unhold) @provider.expects(:dpkg).with { |*command| command[0] == "--force-confnew" } @provider.install end it "should ensure any hold is removed" do @provider.expects(:unhold).once @provider.expects(:dpkg) @provider.install end end describe "when holding or unholding" do before do @tempfile = stub 'tempfile', :print => nil, :close => nil, :flush => nil, :path => "/other/file" @tempfile.stubs(:write) Tempfile.stubs(:new).returns @tempfile end it "should install first if holding" do @provider.stubs(:execute) @provider.expects(:install).once @provider.hold end it "should execute dpkg --set-selections when holding" do @provider.stubs(:install) @provider.expects(:execute).with([:dpkg, '--set-selections'], {:stdinfile => @tempfile.path}).once @provider.hold end it "should execute dpkg --set-selections when unholding" do @provider.stubs(:install) @provider.expects(:execute).with([:dpkg, '--set-selections'], {:stdinfile => @tempfile.path}).once @provider.hold end end it "should use :install to update" do @provider.expects(:install) @provider.update end describe "when determining latest available version" do it "should return the version found by dpkg-deb" do @resource.expects(:[]).with(:source).returns "myfile" @provider.expects(:dpkg_deb).with { |*command| command[-1] == "myfile" }.returns "asdf\t1.0" @provider.latest.should == "1.0" end it "should warn if the package file contains a different package" do @provider.expects(:dpkg_deb).returns("foo\tversion") @provider.expects(:warning) @provider.latest end it "should cope with names containing ++" do @resource = stub 'resource', :[] => "asdf++" @provider = provider.new(@resource) @provider.expects(:dpkg_deb).returns "asdf++\t1.0" @provider.latest.should == "1.0" end end it "should use 'dpkg -r' to uninstall" do @provider.expects(:dpkg).with("-r", "asdf") @provider.uninstall end it "should use 'dpkg --purge' to purge" do @provider.expects(:dpkg).with("--purge", "asdf") @provider.purge end end diff --git a/spec/unit/provider/package/freebsd_spec.rb b/spec/unit/provider/package/freebsd_spec.rb index 4229cba1f..9c8038791 100755 --- a/spec/unit/provider/package/freebsd_spec.rb +++ b/spec/unit/provider/package/freebsd_spec.rb @@ -1,55 +1,54 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' provider_class = Puppet::Type.type(:package).provider(:freebsd) describe provider_class do before :each do # Create a mock resource @resource = stub 'resource' # A catch all; no parameters set @resource.stubs(:[]).returns(nil) # But set name and source @resource.stubs(:[]).with(:name).returns "mypackage" @resource.stubs(:[]).with(:ensure).returns :installed @provider = provider_class.new @provider.resource = @resource end it "should have an install method" do @provider = provider_class.new @provider.should respond_to(:install) end describe "when installing" do before :each do @resource.stubs(:should).with(:ensure).returns(:installed) end it "should install a package from a path to a directory" do # For better or worse, trailing '/' is needed. --daniel 2011-01-26 path = '/path/to/directory/' @resource.stubs(:[]).with(:source).returns(path) Puppet::Util::Execution.expects(:withenv).once.with({:PKG_PATH => path}).yields @provider.expects(:pkgadd).once.with("mypackage") expect { @provider.install }.should_not raise_error end %w{http https ftp}.each do |protocol| it "should install a package via #{protocol}" do # For better or worse, trailing '/' is needed. --daniel 2011-01-26 path = "#{protocol}://localhost/" @resource.stubs(:[]).with(:source).returns(path) Puppet::Util::Execution.expects(:withenv).once.with({:PACKAGESITE => path}).yields @provider.expects(:pkgadd).once.with('-r', "mypackage") expect { @provider.install }.should_not raise_error end end end end diff --git a/spec/unit/provider/package/gem_spec.rb b/spec/unit/provider/package/gem_spec.rb index ef06ef5ba..284e63c23 100755 --- a/spec/unit/provider/package/gem_spec.rb +++ b/spec/unit/provider/package/gem_spec.rb @@ -1,97 +1,96 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' provider_class = Puppet::Type.type(:package).provider(:gem) describe provider_class do it "should have an install method" do @provider = provider_class.new @provider.should respond_to(:install) end describe "when installing" do before do # Create a mock resource @resource = stub 'resource' # A catch all; no parameters set @resource.stubs(:[]).returns nil # We have to set a name, though @resource.stubs(:[]).with(:name).returns "myresource" @resource.stubs(:[]).with(:ensure).returns :installed @provider = provider_class.new @provider.stubs(:resource).returns @resource end it "should use the path to the gem" do provider_class.stubs(:command).with(:gemcmd).returns "/my/gem" @provider.expects(:execute).with { |args| args[0] == "/my/gem" }.returns "" @provider.install end it "should specify that the gem is being installed" do @provider.expects(:execute).with { |args| args[1] == "install" }.returns "" @provider.install end it "should specify that dependencies should be included" do @provider.expects(:execute).with { |args| args[2] == "--include-dependencies" }.returns "" @provider.install end it "should specify that documentation should not be included" do @provider.expects(:execute).with { |args| args[3] == "--no-rdoc" }.returns "" @provider.install end it "should specify that RI should not be included" do @provider.expects(:execute).with { |args| args[4] == "--no-ri" }.returns "" @provider.install end it "should specify the package name" do @provider.expects(:execute).with { |args| args[5] == "myresource" }.returns "" @provider.install end describe "when a source is specified" do describe "as a normal file" do it "should use the file name instead of the gem name" do @resource.stubs(:[]).with(:source).returns "/my/file" @provider.expects(:execute).with { |args| args[3] == "/my/file" }.returns "" @provider.install end end describe "as a file url" do it "should use the file name instead of the gem name" do @resource.stubs(:[]).with(:source).returns "file:///my/file" @provider.expects(:execute).with { |args| args[3] == "/my/file" }.returns "" @provider.install end end describe "as a puppet url" do it "should fail" do @resource.stubs(:[]).with(:source).returns "puppet://my/file" lambda { @provider.install }.should raise_error(Puppet::Error) end end describe "as a non-file and non-puppet url" do it "should treat the source as a gem repository" do @resource.stubs(:[]).with(:source).returns "http://host/my/file" @provider.expects(:execute).with { |args| args[3..5] == ["--source", "http://host/my/file", "myresource"] }.returns "" @provider.install end end describe "with an invalid uri" do it "should fail" do URI.expects(:parse).raises(ArgumentError) @resource.stubs(:[]).with(:source).returns "http:::::uppet:/:/my/file" lambda { @provider.install }.should raise_error(Puppet::Error) end end end end end diff --git a/spec/unit/provider/package/hpux_spec.rb b/spec/unit/provider/package/hpux_spec.rb index 3c5b81c1b..b781f6540 100755 --- a/spec/unit/provider/package/hpux_spec.rb +++ b/spec/unit/provider/package/hpux_spec.rb @@ -1,52 +1,51 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' provider_class = Puppet::Type.type(:package).provider(:hpux) describe provider_class do before(:each) do # Create a mock resource @resource = stub 'resource' # A catch all; no parameters set @resource.stubs(:[]).returns(nil) # But set name and source @resource.stubs(:[]).with(:name).returns "mypackage" @resource.stubs(:[]).with(:source).returns "mysource" @resource.stubs(:[]).with(:ensure).returns :installed @provider = provider_class.new @provider.stubs(:resource).returns @resource end it "should have an install method" do @provider = provider_class.new @provider.should respond_to(:install) end it "should have an uninstall method" do @provider = provider_class.new @provider.should respond_to(:uninstall) end it "should have a swlist method" do @provider = provider_class.new @provider.should respond_to(:swlist) end describe "when installing" do it "should use a command-line like 'swinstall -x mount_all_filesystems=false -s SOURCE PACKAGE-NAME'" do @provider.expects(:swinstall).with('-x', 'mount_all_filesystems=false', '-s', 'mysource', 'mypackage') @provider.install end end describe "when uninstalling" do it "should use a command-line like 'swremove -x mount_all_filesystems=false PACKAGE-NAME'" do @provider.expects(:swremove).with('-x', 'mount_all_filesystems=false', 'mypackage') @provider.uninstall end end end diff --git a/spec/unit/provider/package/nim_spec.rb b/spec/unit/provider/package/nim_spec.rb index 69538e9b9..0fa9f580d 100755 --- a/spec/unit/provider/package/nim_spec.rb +++ b/spec/unit/provider/package/nim_spec.rb @@ -1,42 +1,41 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' provider_class = Puppet::Type.type(:package).provider(:nim) describe provider_class do before(:each) do # Create a mock resource @resource = stub 'resource' # A catch all; no parameters set @resource.stubs(:[]).returns(nil) # But set name and source @resource.stubs(:[]).with(:name).returns "mypackage" @resource.stubs(:[]).with(:source).returns "mysource" @resource.stubs(:[]).with(:ensure).returns :installed @provider = provider_class.new @provider.resource = @resource end it "should have an install method" do @provider = provider_class.new @provider.should respond_to(:install) end describe "when installing" do it "should install a package" do @resource.stubs(:should).with(:ensure).returns(:installed) @provider.expects(:nimclient).with("-o", "cust", "-a", "installp_flags=acgwXY", "-a", "lpp_source=mysource", "-a", "filesets='mypackage'") @provider.install end it "should install a versioned package" do @resource.stubs(:should).with(:ensure).returns("1.2.3.4") @provider.expects(:nimclient).with("-o", "cust", "-a", "installp_flags=acgwXY", "-a", "lpp_source=mysource", "-a", "filesets='mypackage 1.2.3.4'") @provider.install end end end diff --git a/spec/unit/provider/package/pip_spec.rb b/spec/unit/provider/package/pip_spec.rb index 2cca29b35..b56271029 100755 --- a/spec/unit/provider/package/pip_spec.rb +++ b/spec/unit/provider/package/pip_spec.rb @@ -1,177 +1,176 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' provider_class = Puppet::Type.type(:package).provider(:pip) describe provider_class do before do @resource = Puppet::Resource.new(:package, "sdsfdssdhdfyjymdgfcjdfjxdrssf") @provider = provider_class.new(@resource) end describe "parse" do it "should return a hash on valid input" do provider_class.parse("Django==1.2.5").should == { :ensure => "1.2.5", :name => "Django", :provider => :pip, } end it "should return nil on invalid input" do provider_class.parse("foo").should == nil end end describe "instances" do it "should return an array when pip is present" do provider_class.expects(:which).with('pip').returns("/fake/bin/pip") p = stub("process") p.expects(:collect).yields("Django==1.2.5") provider_class.expects(:execpipe).with("/fake/bin/pip freeze").yields(p) provider_class.instances end it "should return an empty array when pip is missing" do provider_class.expects(:which).with('pip').returns nil provider_class.instances.should == [] end end describe "query" do before do @resource[:name] = "Django" end it "should return a hash when pip and the package are present" do provider_class.expects(:instances).returns [provider_class.new({ :ensure => "1.2.5", :name => "Django", :provider => :pip, })] @provider.query.should == { :ensure => "1.2.5", :name => "Django", :provider => :pip, } end it "should return nil when the package is missing" do provider_class.expects(:instances).returns [] @provider.query.should == nil end end describe "latest" do it "should find a version number for Django" do @resource[:name] = "Django" @provider.latest.should_not == nil end it "should not find a version number for sdsfdssdhdfyjymdgfcjdfjxdrssf" do @resource[:name] = "sdsfdssdhdfyjymdgfcjdfjxdrssf" @provider.latest.should == nil end end describe "install" do before do @resource[:name] = "sdsfdssdhdfyjymdgfcjdfjxdrssf" @url = "git+https://example.com/sdsfdssdhdfyjymdgfcjdfjxdrssf.git" end it "should install" do @resource[:ensure] = :installed @resource[:source] = nil @provider.expects(:lazy_pip). with("install", '-q', "sdsfdssdhdfyjymdgfcjdfjxdrssf") @provider.install end it "should install from SCM" do @resource[:ensure] = :installed @resource[:source] = @url @provider.expects(:lazy_pip). with("install", '-q', '-e', "#{@url}#egg=sdsfdssdhdfyjymdgfcjdfjxdrssf") @provider.install end it "should install a particular SCM revision" do @resource[:ensure] = "0123456" @resource[:source] = @url @provider.expects(:lazy_pip). with("install", "-q", "-e", "#{@url}@0123456#egg=sdsfdssdhdfyjymdgfcjdfjxdrssf") @provider.install end it "should install a particular version" do @resource[:ensure] = "0.0.0" @resource[:source] = nil @provider.expects(:lazy_pip).with("install", "-q", "sdsfdssdhdfyjymdgfcjdfjxdrssf==0.0.0") @provider.install end it "should upgrade" do @resource[:ensure] = :latest @resource[:source] = nil @provider.expects(:lazy_pip). with("install", "-q", "--upgrade", "sdsfdssdhdfyjymdgfcjdfjxdrssf") @provider.install end end describe "uninstall" do it "should uninstall" do @resource[:name] = "sdsfdssdhdfyjymdgfcjdfjxdrssf" @provider.expects(:lazy_pip). with('uninstall', '-y', '-q', 'sdsfdssdhdfyjymdgfcjdfjxdrssf') @provider.uninstall end end describe "update" do it "should just call install" do @provider.expects(:install).returns(nil) @provider.update end end describe "lazy_pip" do it "should succeed if pip is present" do @provider.stubs(:pip).returns(nil) @provider.method(:lazy_pip).call "freeze" end it "should retry if pip has not yet been found" do @provider.expects(:pip).twice.with('freeze').raises(NoMethodError).then.returns(nil) @provider.expects(:which).with('pip').returns("/fake/bin/pip") @provider.method(:lazy_pip).call "freeze" end it "should fail if pip is missing" do @provider.expects(:pip).with('freeze').raises(NoMethodError) @provider.expects(:which).with('pip').returns(nil) expect { @provider.method(:lazy_pip).call("freeze") }.to raise_error(NoMethodError) end end end diff --git a/spec/unit/provider/package/pkg_spec.rb b/spec/unit/provider/package/pkg_spec.rb index 93aeac004..04a4ae607 100755 --- a/spec/unit/provider/package/pkg_spec.rb +++ b/spec/unit/provider/package/pkg_spec.rb @@ -1,63 +1,62 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' provider = Puppet::Type.type(:package).provider(:pkg) describe provider do before do @resource = stub 'resource', :[] => "dummy" @provider = provider.new(@resource) @fakeresult = "install ok installed dummy 1.0\n" end def self.it_should_respond_to(*actions) actions.each do |action| it "should respond to :#{action}" do @provider.should respond_to(action) end end end it_should_respond_to :install, :uninstall, :update, :query, :latest it "should be versionable" do provider.should_not be_versionable end it "should use :install to update" do @provider.expects(:install) @provider.update end it "should parse a line correctly" do result = provider.parse_line("dummy 1.0@1.0-1.0 installed ----") result.should == {:name => "dummy", :version => "1.0@1.0-1.0", :ensure => :present, :status => "installed", :provider => :pkg, :error => "ok"} end it "should fail to parse an incorrect line" do result = provider.parse_line("foo") result.should be_nil end it "should fail to list a missing package" do @provider.expects(:pkg).with(:list, "-H", "dummy").returns "1" @provider.query.should == {:status=>"missing", :ensure=>:absent, :name=>"dummy", :error=>"ok"} end it "should fail to list a package when it can't parse the output line" do @provider.expects(:pkg).with(:list, "-H", "dummy").returns "failed" @provider.query.should == {:status=>"missing", :ensure=>:absent, :name=>"dummy", :error=>"ok"} end it "should list package correctly" do @provider.expects(:pkg).with(:list, "-H", "dummy").returns "dummy 1.0@1.0-1.0 installed ----" @provider.query.should == {:name => "dummy", :version => "1.0@1.0-1.0", :ensure => :present, :status => "installed", :provider => :pkg, :error => "ok"} end end diff --git a/spec/unit/provider/package/pkgdmg_spec.rb b/spec/unit/provider/package/pkgdmg_spec.rb index c59a87ffd..155f12e7b 100755 --- a/spec/unit/provider/package/pkgdmg_spec.rb +++ b/spec/unit/provider/package/pkgdmg_spec.rb @@ -1,84 +1,83 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' provider = Puppet::Type.type(:package).provider(:pkgdmg) describe provider do before do @resource = stub 'resource', :[] => "dummypkgdmg" @provider = provider.new(@resource) @fakemountpoint = "/tmp/dmg.foo" @fakepkgfile = "/tmp/test.pkg" @fakehdiutilinfo = {"system-entities" => [{"mount-point" => @fakemountpoint}] } @fakehdiutilplist = Plist::Emit.dump(@fakehdiutilinfo) @hdiutilmountargs = ["mount", "-plist", "-nobrowse", "-readonly", "-noidme", "-mountrandom", "/tmp"] end it "should not be versionable" do provider.versionable?.should be_false end it "should not be uninstallable" do provider.uninstallable?.should be_false end describe "when installing it should fail when" do it "no source is specified" do @resource.stubs(:[]).with(:source).returns nil lambda { @provider.install }.should raise_error(Puppet::Error) end it "no name is specified" do @resource.stubs(:[]).with(:name).returns nil lambda { @provider.install }.should raise_error(Puppet::Error) end it "the source does not end in .dmg or .pkg" do @resource.stubs(:[]).with(:source).returns "notendingindotdmgorpkg" lambda { @provider.install }.should raise_error(Puppet::Error) end it "a disk image with no system entities is mounted" do @provider.stubs(:[]).with(:hdiutil).returns "" lambda { @provider.install }.should raise_error(Puppet::Error) end end # These tests shouldn't be this messy. The pkgdmg provider needs work... describe "when installing a pkgdmg" do before do fh = mock 'filehandle' fh.stubs(:path).yields "/tmp/foo" @resource.stubs(:[]).with(:source).returns "foo.dmg" File.stubs(:open).yields fh end it "should call hdiutil to mount and eject the disk image" do Dir.stubs(:entries).returns [] @provider.class.expects(:hdiutil).with("eject", @fakemountpoint).returns 0 @provider.class.expects(:hdiutil).with("mount", "-plist", "-nobrowse", "-readonly", "-noidme", "-mountrandom", "/tmp", nil).returns @fakehdiutilplist @provider.install end it "should call installpkg if a pkg/mpkg is found on the dmg" do Dir.stubs(:entries).returns ["foo.pkg"] @provider.class.stubs(:hdiutil).returns @fakehdiutilplist @provider.class.expects(:installpkg).with("#{@fakemountpoint}/foo.pkg", @resource[:name], "foo.dmg").returns "" @provider.install end end describe "when installing flat pkg file" do it "should call installpkg if a flat pkg file is found instead of a .dmg image" do @resource.stubs(:[]).with(:source).returns "/tmp/test.pkg" @resource.stubs(:[]).with(:name).returns "testpkg" @provider.class.expects(:installpkgdmg).with("#{@fakepkgfile}", "testpkg").returns "" @provider.install end end end diff --git a/spec/unit/provider/package/yum_spec.rb b/spec/unit/provider/package/yum_spec.rb index 1dd4a5231..601c24009 100755 --- a/spec/unit/provider/package/yum_spec.rb +++ b/spec/unit/provider/package/yum_spec.rb @@ -1,67 +1,66 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' provider = Puppet::Type.type(:package).provider(:yum) describe provider do before do # Create a mock resource @resource = stub 'resource' @resource.stubs(:[]).with(:name).returns 'mypackage' @provider = provider.new(@resource) @provider.stubs(:resource).returns @resource @provider.stubs(:yum).returns 'yum' @provider.stubs(:rpm).returns 'rpm' @provider.stubs(:get).with(:name).returns 'mypackage' @provider.stubs(:get).with(:version).returns '1' @provider.stubs(:get).with(:release).returns '1' @provider.stubs(:get).with(:arch).returns 'i386' end # provider should repond to the following methods [:install, :latest, :update, :purge].each do |method| it "should have a(n) #{method}" do @provider.should respond_to(method) end end describe 'when installing' do it 'should call yum install for :installed' do @resource.stubs(:should).with(:ensure).returns :installed @provider.expects(:yum).with('-d', '0', '-e', '0', '-y', :install, 'mypackage') @provider.install end it 'should use :install to update' do @provider.expects(:install) @provider.update end it 'should be able to set version' do @resource.stubs(:should).with(:ensure).returns '1.2' @provider.expects(:yum).with('-d', '0', '-e', '0', '-y', :install, 'mypackage-1.2') @provider.stubs(:query).returns :ensure => '1.2' @provider.install end it 'should be able to downgrade' do @resource.stubs(:should).with(:ensure).returns '1.0' @provider.expects(:yum).with('-d', '0', '-e', '0', '-y', :downgrade, 'mypackage-1.0') @provider.stubs(:query).returns(:ensure => '1.2').then.returns(:ensure => '1.0') @provider.install end end describe 'when uninstalling' do it 'should use erase to purge' do @provider.expects(:yum).with('-y', :erase, 'mypackage') @provider.purge end it 'should use rpm to uninstall' do @provider.expects(:rpm).with('-e', 'mypackage-1-1.i386') @provider.uninstall end end it 'should be versionable' do provider.should be_versionable end end diff --git a/spec/unit/provider/package/zypper_spec.rb b/spec/unit/provider/package/zypper_spec.rb index eb17de4dd..4218b14c7 100755 --- a/spec/unit/provider/package/zypper_spec.rb +++ b/spec/unit/provider/package/zypper_spec.rb @@ -1,81 +1,80 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' provider_class = Puppet::Type.type(:package).provider(:zypper) describe provider_class do before(:each) do # Create a mock resource @resource = stub 'resource' # A catch all; no parameters set @resource.stubs(:[]).returns(nil) # But set name and source @resource.stubs(:[]).with(:name).returns "mypackage" @resource.stubs(:[]).with(:ensure).returns :installed @resource.stubs(:command).with(:zypper).returns "/usr/bin/zypper" @provider = provider_class.new(@resource) end it "should have an install method" do @provider = provider_class.new @provider.should respond_to(:install) end it "should have a latest method" do @provider = provider_class.new @provider.should respond_to(:uninstall) end it "should have an update method" do @provider = provider_class.new @provider.should respond_to(:update) end it "should have a latest method" do @provider = provider_class.new @provider.should respond_to(:latest) end describe "when installing" do it "should use a command-line with versioned package'" do @resource.stubs(:should).with(:ensure).returns "1.2.3-4.5.6" @provider.expects(:zypper).with('--quiet', :install, '-l', '-y', 'mypackage-1.2.3-4.5.6') @provider.expects(:query).returns "mypackage 0 1.2.3 4.5.6 x86_64" @provider.install end it "should use a command-line without versioned package" do @resource.stubs(:should).with(:ensure).returns :latest @provider.expects(:zypper).with('--quiet', :install, '-l', '-y', 'mypackage') @provider.expects(:query).returns "mypackage 0 1.2.3 4.5.6 x86_64" @provider.install end end describe "when updating" do it "should call install method of instance" do @provider.expects(:install) @provider.update end end describe "when getting latest version" do it "should return a version string" do fake_data = "Loading repository data... Reading installed packages... S | Repository | Name | Version | Arch --+----------------+-----------------------+-----------------+------- v | SLES11-Updates | cups | 1.1.1 | x86_64 v | SLES11-Updates | mypackage | 1.3.9h-8.20.1 | x86_64" @provider.expects(:zypper).with("list-updates").returns fake_data @provider.latest.should == "1.3.9h-8.20.1" end end end diff --git a/spec/unit/provider/parsedfile_spec.rb b/spec/unit/provider/parsedfile_spec.rb index 4f70111f2..2ff904b7f 100755 --- a/spec/unit/provider/parsedfile_spec.rb +++ b/spec/unit/provider/parsedfile_spec.rb @@ -1,95 +1,94 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/provider/parsedfile' # Most of the tests for this are still in test/ral/provider/parsedfile.rb. describe Puppet::Provider::ParsedFile do before do @class = Class.new(Puppet::Provider::ParsedFile) end describe "when looking up records loaded from disk" do it "should return nil if no records have been loaded" do @class.record?("foo").should be_nil end end describe "when generating a list of instances" do it "should return an instance for each record parsed from all of the registered targets" do @class.expects(:targets).returns %w{/one /two} @class.stubs(:skip_record?).returns false one = [:uno1, :uno2] two = [:dos1, :dos2] @class.expects(:prefetch_target).with("/one").returns one @class.expects(:prefetch_target).with("/two").returns two results = [] (one + two).each do |inst| results << inst.to_s + "_instance" @class.expects(:new).with(inst).returns(results[-1]) end @class.instances.should == results end it "should skip specified records" do @class.expects(:targets).returns %w{/one} @class.expects(:skip_record?).with(:uno).returns false @class.expects(:skip_record?).with(:dos).returns true one = [:uno, :dos] @class.expects(:prefetch_target).returns one @class.expects(:new).with(:uno).returns "eh" @class.expects(:new).with(:dos).never @class.instances end end describe "when flushing a file's records to disk" do before do # This way we start with some @records, like we would in real life. @class.stubs(:retrieve).returns [] @class.default_target = "/foo/bar" @class.initvars @class.prefetch @filetype = Puppet::Util::FileType.filetype(:flat).new("/my/file") Puppet::Util::FileType.filetype(:flat).stubs(:new).with("/my/file").returns @filetype @filetype.stubs(:write) end it "should back up the file being written if the filetype can be backed up" do @filetype.expects(:backup) @class.flush_target("/my/file") end it "should not try to back up the file if the filetype cannot be backed up" do @filetype = Puppet::Util::FileType.filetype(:ram).new("/my/file") Puppet::Util::FileType.filetype(:flat).expects(:new).returns @filetype @filetype.stubs(:write) @class.flush_target("/my/file") end it "should not back up the file more than once between calls to 'prefetch'" do @filetype.expects(:backup).once @class.flush_target("/my/file") @class.flush_target("/my/file") end it "should back the file up again once the file has been reread" do @filetype.expects(:backup).times(2) @class.flush_target("/my/file") @class.prefetch @class.flush_target("/my/file") end end end diff --git a/spec/unit/provider/selboolean_spec.rb b/spec/unit/provider/selboolean_spec.rb index b45c3f713..64f925e1e 100755 --- a/spec/unit/provider/selboolean_spec.rb +++ b/spec/unit/provider/selboolean_spec.rb @@ -1,37 +1,36 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' provider_class = Puppet::Type.type(:selboolean).provider(:getsetsebool) describe provider_class do before :each do @resource = stub("resource", :name => "foo") @resource.stubs(:[]).returns "foo" @provider = provider_class.new(@resource) end it "should return :on when getsebool returns on" do @provider.expects(:getsebool).with("foo").returns "foo --> on\n" @provider.value.should == :on end it "should return :off when getsebool returns on" do @provider.expects(:getsebool).with("foo").returns "foo --> off\n" @provider.value.should == :off end it "should call execpipe when updating boolean setting" do @provider.expects(:command).with(:setsebool).returns "/usr/sbin/setsebool" @provider.expects(:execpipe).with("/usr/sbin/setsebool foo off") @provider.value = :off end it "should call execpipe with -P when updating persistent boolean setting" do @resource.stubs(:[]).with(:persistent).returns :true @provider.expects(:command).with(:setsebool).returns "/usr/sbin/setsebool" @provider.expects(:execpipe).with("/usr/sbin/setsebool -P foo off") @provider.value = :off end end diff --git a/spec/unit/provider/selmodule_spec.rb b/spec/unit/provider/selmodule_spec.rb index 9ac5a7a5d..67196667f 100755 --- a/spec/unit/provider/selmodule_spec.rb +++ b/spec/unit/provider/selmodule_spec.rb @@ -1,66 +1,66 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # Note: This unit test depends on having a sample SELinux policy file # in the same directory as this test called selmodule-example.pp # with version 1.5.0. The provided selmodule-example.pp is the first # 256 bytes taken from /usr/share/selinux/targeted/nagios.pp on Fedora 9 require 'spec_helper' provider_class = Puppet::Type.type(:selmodule).provider(:semodule) describe provider_class do before :each do @resource = stub("resource", :name => "foo") @resource.stubs(:[]).returns "foo" @provider = provider_class.new(@resource) end describe "exists? method" do it "should find a module if it is already loaded" do @provider.expects(:command).with(:semodule).returns "/usr/sbin/semodule" @provider.expects(:execpipe).with("/usr/sbin/semodule --list").yields ["bar\t1.2.3\n", "foo\t4.4.4\n", "bang\t1.0.0\n"] @provider.exists?.should == :true end it "should return nil if not loaded" do @provider.expects(:command).with(:semodule).returns "/usr/sbin/semodule" @provider.expects(:execpipe).with("/usr/sbin/semodule --list").yields ["bar\t1.2.3\n", "bang\t1.0.0\n"] @provider.exists?.should be_nil end it "should return nil if no modules are loaded" do @provider.expects(:command).with(:semodule).returns "/usr/sbin/semodule" @provider.expects(:execpipe).with("/usr/sbin/semodule --list").yields [] @provider.exists?.should be_nil end end describe "selmodversion_file" do it "should return 1.5.0 for the example policy file" do @provider.expects(:selmod_name_to_filename).returns "#{File.dirname(__FILE__)}/selmodule-example.pp" @provider.selmodversion_file.should == "1.5.0" end end describe "syncversion" do it "should return :true if loaded and file modules are in sync" do @provider.expects(:selmodversion_loaded).returns "1.5.0" @provider.expects(:selmodversion_file).returns "1.5.0" @provider.syncversion.should == :true end it "should return :false if loaded and file modules are not in sync" do @provider.expects(:selmodversion_loaded).returns "1.4.0" @provider.expects(:selmodversion_file).returns "1.5.0" @provider.syncversion.should == :false end it "should return before checking file version if no loaded policy" do @provider.expects(:selmodversion_loaded).returns nil @provider.syncversion.should == :false end end end diff --git a/spec/unit/provider/service/daemontools_spec.rb b/spec/unit/provider/service/daemontools_spec.rb index 98652cb88..64eeb9fa4 100755 --- a/spec/unit/provider/service/daemontools_spec.rb +++ b/spec/unit/provider/service/daemontools_spec.rb @@ -1,166 +1,166 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Unit testing for the Daemontools service Provider # # author Brice Figureau # require 'spec_helper' provider_class = Puppet::Type.type(:service).provider(:daemontools) describe provider_class do before(:each) do # Create a mock resource @resource = stub 'resource' @provider = provider_class.new @servicedir = "/etc/service" @provider.servicedir=@servicedir @daemondir = "/var/lib/service" @provider.class.defpath=@daemondir # A catch all; no parameters set @resource.stubs(:[]).returns(nil) # But set name, source and path (because we won't run # the thing that will fetch the resource path from the provider) @resource.stubs(:[]).with(:name).returns "myservice" @resource.stubs(:[]).with(:ensure).returns :enabled @resource.stubs(:[]).with(:path).returns @daemondir @resource.stubs(:ref).returns "Service[myservice]" @provider.resource = @resource @provider.stubs(:command).with(:svc).returns "svc" @provider.stubs(:command).with(:svstat).returns "svstat" @provider.stubs(:svc) @provider.stubs(:svstat) end it "should have a restart method" do @provider.should respond_to(:restart) end it "should have a start method" do @provider.should respond_to(:start) end it "should have a stop method" do @provider.should respond_to(:stop) end it "should have an enabled? method" do @provider.should respond_to(:enabled?) end it "should have an enable method" do @provider.should respond_to(:enable) end it "should have a disable method" do @provider.should respond_to(:disable) end describe "when starting" do it "should use 'svc' to start the service" do @provider.stubs(:enabled?).returns :true @provider.expects(:svc).with("-u", "/etc/service/myservice") @provider.start end it "should enable the service if it is not enabled" do @provider.stubs(:svc) @provider.expects(:enabled?).returns :false @provider.expects(:enable) @provider.start end end describe "when stopping" do it "should use 'svc' to stop the service" do @provider.stubs(:disable) @provider.expects(:svc).with("-d", "/etc/service/myservice") @provider.stop end end describe "when restarting" do it "should use 'svc' to restart the service" do @provider.expects(:svc).with("-t", "/etc/service/myservice") @provider.restart end end describe "when enabling" do it "should create a symlink between daemon dir and service dir" do FileTest.stubs(:symlink?).returns(false) File.expects(:symlink).with(File.join(@daemondir,"myservice"), File.join(@servicedir,"myservice")).returns(0) @provider.enable end end describe "when disabling" do it "should remove the symlink between daemon dir and service dir" do FileTest.stubs(:directory?).returns(false) FileTest.stubs(:symlink?).returns(true) File.expects(:unlink).with(File.join(@servicedir,"myservice")) @provider.stubs(:texecute).returns("") @provider.disable end it "should stop the service" do FileTest.stubs(:directory?).returns(false) FileTest.stubs(:symlink?).returns(true) File.stubs(:unlink) @provider.expects(:stop) @provider.disable end end describe "when checking if the service is enabled?" do it "should return true if it is running" do @provider.stubs(:status).returns(:running) @provider.enabled?.should == :true end [true, false].each do |t| it "should return #{t} if the symlink exists" do @provider.stubs(:status).returns(:stopped) FileTest.stubs(:symlink?).returns(t) @provider.enabled?.should == "#{t}".to_sym end end end describe "when checking status" do it "should call the external command 'svstat /etc/service/myservice'" do @provider.expects(:svstat).with(File.join(@servicedir,"myservice")) @provider.status end end describe "when checking status" do it "and svstat fails, properly raise a Puppet::Error" do @provider.expects(:svstat).with(File.join(@servicedir,"myservice")).raises(Puppet::ExecutionFailure, "failure") lambda { @provider.status }.should raise_error(Puppet::Error, 'Could not get status for service Service[myservice]: failure') end it "and svstat returns up, then return :running" do @provider.expects(:svstat).with(File.join(@servicedir,"myservice")).returns("/etc/service/myservice: up (pid 454) 954326 seconds") @provider.status.should == :running end it "and svstat returns not running, then return :stopped" do @provider.expects(:svstat).with(File.join(@servicedir,"myservice")).returns("/etc/service/myservice: supervise not running") @provider.status.should == :stopped end end end diff --git a/spec/unit/provider/service/debian_spec.rb b/spec/unit/provider/service/debian_spec.rb index 174aac9ff..4e3d30d61 100755 --- a/spec/unit/provider/service/debian_spec.rb +++ b/spec/unit/provider/service/debian_spec.rb @@ -1,101 +1,101 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Unit testing for the debian service provider # require 'spec_helper' provider_class = Puppet::Type.type(:service).provider(:debian) describe provider_class do before(:each) do # Create a mock resource @resource = stub 'resource' @provider = provider_class.new # A catch all; no parameters set @resource.stubs(:[]).returns(nil) # But set name, source and path @resource.stubs(:[]).with(:name).returns "myservice" @resource.stubs(:[]).with(:ensure).returns :enabled @resource.stubs(:ref).returns "Service[myservice]" @provider.resource = @resource @provider.stubs(:command).with(:update_rc).returns "update_rc" @provider.stubs(:command).with(:invoke_rc).returns "invoke_rc" @provider.stubs(:update_rc) @provider.stubs(:invoke_rc) end it "should have an enabled? method" do @provider.should respond_to(:enabled?) end it "should have an enable method" do @provider.should respond_to(:enable) end it "should have a disable method" do @provider.should respond_to(:disable) end describe "when enabling" do it "should call update-rc.d twice" do @provider.expects(:update_rc).twice @provider.enable end end describe "when disabling" do it "should be able to disable services with newer sysv-rc versions" do @provider.stubs(:`).with("dpkg --compare-versions $(dpkg-query -W --showformat '${Version}' sysv-rc) ge 2.88 ; echo $?").returns "0" @provider.expects(:update_rc).with(@resource[:name], "disable") @provider.disable end it "should be able to enable services with older sysv-rc versions" do @provider.stubs(:`).with("dpkg --compare-versions $(dpkg-query -W --showformat '${Version}' sysv-rc) ge 2.88 ; echo $?").returns "1" @provider.expects(:update_rc).with("-f", @resource[:name], "remove") @provider.expects(:update_rc).with(@resource[:name], "stop", "00", "1", "2", "3", "4", "5", "6", ".") @provider.disable end end describe "when checking whether it is enabled" do it "should call Kernel.system() with the appropriate parameters" do @provider.expects(:system).with("/usr/sbin/invoke-rc.d", "--quiet", "--query", @resource[:name], "start").once @provider.enabled? end it "should return true when invoke-rc.d exits with 104 status" do @provider.stubs(:system) $CHILD_STATUS.stubs(:exitstatus).returns(104) @provider.enabled?.should == :true end it "should return true when invoke-rc.d exits with 106 status" do @provider.stubs(:system) $CHILD_STATUS.stubs(:exitstatus).returns(106) @provider.enabled?.should == :true end # pick a range of non-[104.106] numbers, strings and booleans to test with. [-100, -1, 0, 1, 100, "foo", "", :true, :false].each do |exitstatus| it "should return false when invoke-rc.d exits with #{exitstatus} status" do @provider.stubs(:system) $CHILD_STATUS.stubs(:exitstatus).returns(exitstatus) @provider.enabled?.should == :false end end end end diff --git a/spec/unit/provider/service/freebsd_spec.rb b/spec/unit/provider/service/freebsd_spec.rb index 6c778f1dd..c1a6d26f7 100755 --- a/spec/unit/provider/service/freebsd_spec.rb +++ b/spec/unit/provider/service/freebsd_spec.rb @@ -1,50 +1,49 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' provider_class = Puppet::Type.type(:service).provider(:freebsd) describe provider_class do before :each do @provider = provider_class.new @provider.stubs(:initscript) end it "should correctly parse rcvar for FreeBSD < 7" do @provider.stubs(:execute).returns <= 8.1" do @provider.stubs(:execute).returns <= 7" do @provider.stubs(:rcvar).returns(['# ntpd', 'ntpd_enable="YES"', '# (default: "")']) @provider.rcvar_value.should == "YES" end end diff --git a/spec/unit/provider/service/init_spec.rb b/spec/unit/provider/service/init_spec.rb index 531f9901d..d64e0fc5d 100755 --- a/spec/unit/provider/service/init_spec.rb +++ b/spec/unit/provider/service/init_spec.rb @@ -1,170 +1,170 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Unit testing for the Init service Provider # require 'spec_helper' provider_class = Puppet::Type.type(:service).provider(:init) describe provider_class do before :each do @class = Puppet::Type.type(:service).provider(:init) @resource = stub 'resource' @resource.stubs(:[]).returns(nil) @resource.stubs(:[]).with(:name).returns "myservice" # @resource.stubs(:[]).with(:ensure).returns :enabled @resource.stubs(:[]).with(:path).returns ["/service/path","/alt/service/path"] # @resource.stubs(:ref).returns "Service[myservice]" File.stubs(:directory?).returns(true) @provider = provider_class.new @provider.resource = @resource end describe "when getting all service instances" do before :each do @services = ['one', 'two', 'three', 'four'] Dir.stubs(:entries).returns @services FileTest.stubs(:directory?).returns(true) FileTest.stubs(:executable?).returns(true) @class.stubs(:defpath).returns('tmp') end it "should return instances for all services" do @services.each do |inst| @class.expects(:new).with{|hash| hash[:name] == inst}.returns("#{inst}_instance") end results = @services.collect {|x| "#{x}_instance"} @class.instances.should == results end it "should omit an array of services from exclude list" do exclude = ['two', 'four'] (@services-exclude).each do |inst| @class.expects(:new).with{|hash| hash[:name] == inst}.returns("#{inst}_instance") end results = (@services-exclude).collect {|x| "#{x}_instance"} @class.get_services(@class.defpath, exclude).should == results end it "should omit a single service from the exclude list" do exclude = 'two' (@services-exclude.to_a).each do |inst| @class.expects(:new).with{|hash| hash[:name] == inst}.returns("#{inst}_instance") end results = @services.reject{|x| x==exclude }.collect {|x| "#{x}_instance"} @class.get_services(@class.defpath, exclude).should == results end it "should use defpath" do @services.each do |inst| @class.expects(:new).with{|hash| hash[:path] == @class.defpath}.returns("#{inst}_instance") end results = @services.sort.collect {|x| "#{x}_instance"} @class.instances.sort.should == results end it "should set hasstatus to true for providers" do @services.each do |inst| @class.expects(:new).with{|hash| hash[:name] == inst && hash[:hasstatus] == true}.returns("#{inst}_instance") end results = @services.collect {|x| "#{x}_instance"} @class.instances.should == results end end describe "when searching for the init script" do it "should discard paths that do not exist" do File.stubs(:exist?).returns(false) File.stubs(:directory?).returns(false) @provider.paths.should be_empty end it "should discard paths that are not directories" do File.stubs(:exist?).returns(true) File.stubs(:directory?).returns(false) @provider.paths.should be_empty end it "should be able to find the init script in the service path" do File.stubs(:stat).raises(Errno::ENOENT.new('No such file or directory')) File.expects(:stat).with("/service/path/myservice").returns true @provider.initscript.should == "/service/path/myservice" end it "should be able to find the init script in the service path" do File.stubs(:stat).raises(Errno::ENOENT.new('No such file or directory')) File.expects(:stat).with("/alt/service/path/myservice").returns true @provider.initscript.should == "/alt/service/path/myservice" end it "should fail if the service isn't there" do lambda { @provider.initscript }.should raise_error(Puppet::Error, "Could not find init script for 'myservice'") end end describe "if the init script is present" do before :each do File.stubs(:stat).with("/service/path/myservice").returns true end [:start, :stop, :status, :restart].each do |method| it "should have a #{method} method" do @provider.should respond_to(method) end describe "when running #{method}" do it "should use any provided explicit command" do @resource.stubs(:[]).with(method).returns "/user/specified/command" @provider.expects(:execute).with { |command, *args| command == ["/user/specified/command"] } @provider.send(method) end it "should pass #{method} to the init script when no explicit command is provided" do @resource.stubs(:[]).with("has#{method}".intern).returns :true @provider.expects(:execute).with { |command, *args| command == ["/service/path/myservice",method]} @provider.send(method) end end end describe "when checking status" do describe "when hasstatus is :true" do before :each do @resource.stubs(:[]).with(:hasstatus).returns :true end it "should execute the command" do @provider.expects(:texecute).with(:status, ['/service/path/myservice', :status], false).returns("") @provider.status end it "should consider the process running if the command returns 0" do @provider.expects(:texecute).with(:status, ['/service/path/myservice', :status], false).returns("") $CHILD_STATUS.stubs(:exitstatus).returns(0) @provider.status.should == :running end [-10,-1,1,10].each { |ec| it "should consider the process stopped if the command returns something non-0" do @provider.expects(:texecute).with(:status, ['/service/path/myservice', :status], false).returns("") $CHILD_STATUS.stubs(:exitstatus).returns(ec) @provider.status.should == :stopped end } end describe "when hasstatus is not :true" do it "should consider the service :running if it has a pid" do @provider.expects(:getpid).returns "1234" @provider.status.should == :running end it "should consider the service :stopped if it doesn't have a pid" do @provider.expects(:getpid).returns nil @provider.status.should == :stopped end end end describe "when restarting and hasrestart is not :true" do it "should stop and restart the process" do @provider.expects(:texecute).with(:stop, ['/service/path/myservice', :stop ], true).returns("") @provider.expects(:texecute).with(:start,['/service/path/myservice', :start], true).returns("") $CHILD_STATUS.stubs(:exitstatus).returns(0) @provider.restart end end end end diff --git a/spec/unit/provider/service/launchd_spec.rb b/spec/unit/provider/service/launchd_spec.rb index 9db9d5a19..8ae7f003d 100755 --- a/spec/unit/provider/service/launchd_spec.rb +++ b/spec/unit/provider/service/launchd_spec.rb @@ -1,203 +1,203 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Unit testing for the launchd service provider # require 'spec_helper' require 'puppet' provider_class = Puppet::Type.type(:service).provider(:launchd) describe provider_class do before :each do # Create a mock resource @resource = stub 'resource' @provider = provider_class.new @joblabel = "com.foo.food" @jobplist = {} # A catch all; no parameters set @resource.stubs(:[]).returns(nil) # But set name, ensure and enable @resource.stubs(:[]).with(:name).returns @joblabel @resource.stubs(:[]).with(:ensure).returns :enabled @resource.stubs(:[]).with(:enable).returns :true @resource.stubs(:ref).returns "Service[#{@joblabel}]" # stub out the provider methods that actually touch the filesystem # or execute commands @provider.stubs(:plist_from_label).returns([@joblabel, @jobplist]) @provider.stubs(:execute).returns("") @provider.stubs(:resource).returns @resource # We stub this out for the normal case as 10.6 is "special". provider_class.stubs(:get_macosx_version_major).returns("10.5") end it "should have a start method for #{@provider.object_id}" do @provider.should respond_to(:start) end it "should have a stop method" do @provider.should respond_to(:stop) end it "should have an enabled? method" do @provider.should respond_to(:enabled?) end it "should have an enable method" do @provider.should respond_to(:enable) end it "should have a disable method" do @provider.should respond_to(:disable) end it "should have a status method" do @provider.should respond_to(:status) end describe "when checking status" do it "should call the external command 'launchctl list' once" do @provider.expects(:launchctl).with(:list).returns("rotating-strawberry-madonnas") @provider.status end it "should return stopped if not listed in launchctl list output" do @provider.stubs(:launchctl).with(:list).returns("rotating-strawberry-madonnas") @provider.status.should == :stopped end it "should return running if listed in launchctl list output" do @provider.stubs(:launchctl).with(:list).returns(@joblabel) @provider.status.should == :running end end describe "when checking whether the service is enabled" do it "should return true if the job plist says disabled is false" do @provider.stubs(:plist_from_label).returns(["foo", {"Disabled" => false}]) @provider.enabled?.should == :true end it "should return true if the job plist has no disabled key" do @provider.stubs(:plist_from_label).returns(["foo", {}]) @provider.enabled?.should == :true end it "should return false if the job plist says disabled is true" do @provider.stubs(:plist_from_label).returns(["foo", {"Disabled" => true}]) @provider.enabled?.should == :false end end describe "when checking whether the service is enabled on OS X 10.6" do it "should return true if the job plist says disabled is true and the global overrides says disabled is false" do provider_class.stubs(:get_macosx_version_major).returns("10.6") @provider.stubs(:plist_from_label).returns(["foo", {"Disabled" => true}]) @provider.class.stubs(:read_plist).returns({@resource[:name] => {"Disabled" => false}}) FileTest.expects(:file?).with(Launchd_Overrides).returns(true) @provider.enabled?.should == :true end it "should return false if the job plist says disabled is false and the global overrides says disabled is true" do provider_class.stubs(:get_macosx_version_major).returns("10.6") @provider.stubs(:plist_from_label).returns(["foo", {"Disabled" => false}]) @provider.class.stubs(:read_plist).returns({@resource[:name] => {"Disabled" => true}}) FileTest.expects(:file?).with(Launchd_Overrides).returns(true) @provider.enabled?.should == :false end it "should return true if the job plist and the global overrides have no disabled keys" do provider_class.stubs(:get_macosx_version_major).returns("10.6") @provider.stubs(:plist_from_label).returns(["foo", {}]) @provider.class.stubs(:read_plist).returns({}) FileTest.expects(:file?).with(Launchd_Overrides).returns(true) @provider.enabled?.should == :true end end describe "when starting the service" do it "should look for the relevant plist once" do @provider.expects(:plist_from_label).once @provider.start end it "should execute 'launchctl load' once without writing to the plist if the job is enabled" do @provider.stubs(:enabled?).returns :true @provider.expects(:execute).with([:launchctl, :load, @resource[:name]]).once @provider.start end it "should execute 'launchctl load' with writing to the plist once if the job is disabled" do @provider.stubs(:enabled?).returns :false @provider.expects(:execute).with([:launchctl, :load, "-w", @resource[:name]]).once @provider.start end it "should disable the job once if the job is disabled and should be disabled at boot" do @provider.stubs(:enabled?).returns :false @resource.stubs(:[]).with(:enable).returns :false @provider.expects(:disable).once @provider.start end end describe "when stopping the service" do it "should look for the relevant plist once" do @provider.expects(:plist_from_label).once @provider.stop end it "should execute 'launchctl unload' once without writing to the plist if the job is disabled" do @provider.stubs(:enabled?).returns :false @provider.expects(:execute).with([:launchctl, :unload, @resource[:name]]).once @provider.stop end it "should execute 'launchctl unload' with writing to the plist once if the job is enabled" do @provider.stubs(:enabled?).returns :true @provider.expects(:execute).with([:launchctl, :unload, "-w", @resource[:name]]).once @provider.stop end it "should enable the job once if the job is enabled and should be enabled at boot" do @provider.stubs(:enabled?).returns :true @resource.stubs(:[]).with(:enable).returns :true @provider.expects(:enable).once @provider.stop end end describe "when enabling the service" do it "should look for the relevant plist once" do @provider.expects(:plist_from_label).once @provider.stop end it "should check if the job is enabled once" do @provider.expects(:enabled?).once @provider.stop end end describe "when disabling the service" do it "should look for the relevant plist once" do @provider.expects(:plist_from_label).once @provider.stop end end describe "when enabling the service on OS X 10.6" do it "should write to the global launchd overrides file once" do provider_class.stubs(:get_macosx_version_major).returns("10.6") @provider.class.stubs(:read_plist).returns({}) Plist::Emit.expects(:save_plist).once @provider.enable end end describe "when disabling the service on OS X 10.6" do it "should write to the global launchd overrides file once" do provider_class.stubs(:get_macosx_version_major).returns("10.6") @provider.class.stubs(:read_plist).returns({}) Plist::Emit.expects(:save_plist).once @provider.enable end end end diff --git a/spec/unit/provider/service/redhat_spec.rb b/spec/unit/provider/service/redhat_spec.rb index 0648772b4..b7f56e089 100755 --- a/spec/unit/provider/service/redhat_spec.rb +++ b/spec/unit/provider/service/redhat_spec.rb @@ -1,121 +1,121 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Unit testing for the RedHat service Provider # require 'spec_helper' provider_class = Puppet::Type.type(:service).provider(:redhat) describe provider_class do before :each do @class = Puppet::Type.type(:service).provider(:redhat) @resource = stub 'resource' @resource.stubs(:[]).returns(nil) @resource.stubs(:[]).with(:name).returns "myservice" @provider = provider_class.new @resource.stubs(:provider).returns @provider @provider.resource = @resource @provider.stubs(:get).with(:hasstatus).returns false FileTest.stubs(:file?).with('/sbin/service').returns true FileTest.stubs(:executable?).with('/sbin/service').returns true end # test self.instances describe "when getting all service instances" do before :each do @services = ['one', 'two', 'three', 'four', 'kudzu', 'functions', 'halt', 'killall', 'single', 'linuxconf'] @not_services = ['functions', 'halt', 'killall', 'single', 'linuxconf'] Dir.stubs(:entries).returns @services FileTest.stubs(:directory?).returns(true) FileTest.stubs(:executable?).returns(true) end it "should return instances for all services" do (@services-@not_services).each do |inst| @class.expects(:new).with{|hash| hash[:name] == inst && hash[:path] == '/etc/init.d'}.returns("#{inst}_instance") end results = (@services-@not_services).collect {|x| "#{x}_instance"} @class.instances.should == results end it "should call service status when initialized from provider" do @resource.stubs(:[]).with(:status).returns nil @provider.stubs(:get).with(:hasstatus).returns true @provider.expects(:execute).with{|command, *args| command == ['/sbin/service', 'myservice', 'status']} @provider.send(:status) end end it "should have an enabled? method" do @provider.should respond_to(:enabled?) end it "should have an enable method" do @provider.should respond_to(:enable) end it "should have a disable method" do @provider.should respond_to(:disable) end [:start, :stop, :status, :restart].each do |method| it "should have a #{method} method" do @provider.should respond_to(method) end describe "when running #{method}" do it "should use any provided explicit command" do @resource.stubs(:[]).with(method).returns "/user/specified/command" @provider.expects(:execute).with { |command, *args| command == ["/user/specified/command"] } @provider.send(method) end it "should execute the service script with #{method} when no explicit command is provided" do @resource.stubs(:[]).with("has#{method}".intern).returns :true @provider.expects(:execute).with { |command, *args| command == ['/sbin/service', 'myservice', method.to_s]} @provider.send(method) end end end describe "when checking status" do describe "when hasstatus is :true" do before :each do @resource.stubs(:[]).with(:hasstatus).returns :true end it "should execute the service script with fail_on_failure false" do @provider.expects(:texecute).with(:status, ['/sbin/service', 'myservice', 'status'], false) @provider.status end it "should consider the process running if the command returns 0" do @provider.expects(:texecute).with(:status, ['/sbin/service', 'myservice', 'status'], false) $CHILD_STATUS.stubs(:exitstatus).returns(0) @provider.status.should == :running end [-10,-1,1,10].each { |ec| it "should consider the process stopped if the command returns something non-0" do @provider.expects(:texecute).with(:status, ['/sbin/service', 'myservice', 'status'], false) $CHILD_STATUS.stubs(:exitstatus).returns(ec) @provider.status.should == :stopped end } end describe "when hasstatus is not :true" do it "should consider the service :running if it has a pid" do @provider.expects(:getpid).returns "1234" @provider.status.should == :running end it "should consider the service :stopped if it doesn't have a pid" do @provider.expects(:getpid).returns nil @provider.status.should == :stopped end end end describe "when restarting and hasrestart is not :true" do it "should stop and restart the process with the server script" do @provider.expects(:texecute).with(:stop, ['/sbin/service', 'myservice', 'stop'], true) @provider.expects(:texecute).with(:start, ['/sbin/service', 'myservice', 'start'], true) @provider.restart end end end diff --git a/spec/unit/provider/service/runit_spec.rb b/spec/unit/provider/service/runit_spec.rb index c184038d5..38855a451 100755 --- a/spec/unit/provider/service/runit_spec.rb +++ b/spec/unit/provider/service/runit_spec.rb @@ -1,140 +1,140 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Unit testing for the Runit service Provider # # author Brice Figureau # require 'spec_helper' provider_class = Puppet::Type.type(:service).provider(:runit) describe provider_class do before(:each) do # Create a mock resource @resource = stub 'resource' @provider = provider_class.new @servicedir = "/etc/service" @provider.servicedir=@servicedir @daemondir = "/etc/sv" @provider.class.defpath=@daemondir # A catch all; no parameters set @resource.stubs(:[]).returns(nil) # But set name, source and path (because we won't run # the thing that will fetch the resource path from the provider) @resource.stubs(:[]).with(:name).returns "myservice" @resource.stubs(:[]).with(:ensure).returns :enabled @resource.stubs(:[]).with(:path).returns @daemondir @resource.stubs(:ref).returns "Service[myservice]" @provider.stubs(:sv) @provider.stubs(:resource).returns @resource end it "should have a restart method" do @provider.should respond_to(:restart) end it "should have a restartcmd method" do @provider.should respond_to(:restartcmd) end it "should have a start method" do @provider.should respond_to(:start) end it "should have a stop method" do @provider.should respond_to(:stop) end it "should have an enabled? method" do @provider.should respond_to(:enabled?) end it "should have an enable method" do @provider.should respond_to(:enable) end it "should have a disable method" do @provider.should respond_to(:disable) end describe "when starting" do it "should enable the service if it is not enabled" do @provider.stubs(:sv) @provider.expects(:enabled?).returns :false @provider.expects(:enable) @provider.start end it "should execute external command 'sv start /etc/service/myservice'" do @provider.stubs(:enabled?).returns :true @provider.expects(:sv).with("start", "/etc/service/myservice") @provider.start end end describe "when stopping" do it "should execute external command 'sv stop /etc/service/myservice'" do @provider.expects(:sv).with("stop", "/etc/service/myservice") @provider.stop end end describe "when restarting" do it "should call 'sv restart /etc/service/myservice'" do @provider.expects(:sv).with("restart","/etc/service/myservice") @provider.restart end end describe "when enabling" do it "should create a symlink between daemon dir and service dir" do FileTest.stubs(:symlink?).returns(false) File.expects(:symlink).with(File.join(@daemondir,"myservice"), File.join(@servicedir,"myservice")).returns(0) @provider.enable end end describe "when disabling" do it "should remove the '/etc/service/myservice' symlink" do FileTest.stubs(:directory?).returns(false) FileTest.stubs(:symlink?).returns(true) File.expects(:unlink).with(File.join(@servicedir,"myservice")).returns(0) @provider.disable end end describe "when checking status" do it "should call the external command 'sv status /etc/sv/myservice'" do @provider.expects(:sv).with('status',File.join(@daemondir,"myservice")) @provider.status end end describe "when checking status" do it "and sv status fails, properly raise a Puppet::Error" do @provider.expects(:sv).with('status',File.join(@daemondir,"myservice")).raises(Puppet::ExecutionFailure, "fail: /etc/sv/myservice: file not found") lambda { @provider.status }.should raise_error(Puppet::Error, 'Could not get status for service Service[myservice]: fail: /etc/sv/myservice: file not found') end it "and sv status returns up, then return :running" do @provider.expects(:sv).with('status',File.join(@daemondir,"myservice")).returns("run: /etc/sv/myservice: (pid 9029) 6s") @provider.status.should == :running end it "and sv status returns not running, then return :stopped" do @provider.expects(:sv).with('status',File.join(@daemondir,"myservice")).returns("fail: /etc/sv/myservice: runsv not running") @provider.status.should == :stopped end it "and sv status returns a warning, then return :stopped" do @provider.expects(:sv).with('status',File.join(@daemondir,"myservice")).returns("warning: /etc/sv/myservice: unable to open supervise/ok: file does not exist") @provider.status.should == :stopped end end end diff --git a/spec/unit/provider/service/smf_spec.rb b/spec/unit/provider/service/smf_spec.rb index c78847631..5212d540a 100755 --- a/spec/unit/provider/service/smf_spec.rb +++ b/spec/unit/provider/service/smf_spec.rb @@ -1,137 +1,137 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Unit testing for the SMF service Provider # # author Dominic Cleal # require 'spec_helper' provider_class = Puppet::Type.type(:service).provider(:smf) describe provider_class do before(:each) do # Create a mock resource @resource = Puppet::Type.type(:service).new( :name => "/system/myservice", :ensure => :running, :enable => :true) @provider = provider_class.new(@resource) FileTest.stubs(:file?).with('/usr/sbin/svcadm').returns true FileTest.stubs(:executable?).with('/usr/sbin/svcadm').returns true FileTest.stubs(:file?).with('/usr/bin/svcs').returns true FileTest.stubs(:executable?).with('/usr/bin/svcs').returns true end it "should have a restart method" do @provider.should respond_to(:restart) end it "should have a restartcmd method" do @provider.should respond_to(:restartcmd) end it "should have a start method" do @provider.should respond_to(:start) end it "should have a stop method" do @provider.should respond_to(:stop) end it "should have an enabled? method" do @provider.should respond_to(:enabled?) end it "should have an enable method" do @provider.should respond_to(:enable) end it "should have a disable method" do @provider.should respond_to(:disable) end describe "when checking status" do it "should call the external command 'svcs /system/myservice' once" do @provider.expects(:svcs).with('-H', '-o', 'state,nstate', "/system/myservice").returns("online\t-") @provider.status end it "should return stopped if svcs can't find the service" do @provider.stubs(:svcs).raises(Puppet::ExecutionFailure.new("no svc found")) @provider.status.should == :stopped end it "should return running if online in svcs output" do @provider.stubs(:svcs).returns("online\t-") @provider.status.should == :running end it "should return stopped if disabled in svcs output" do @provider.stubs(:svcs).returns("disabled\t-") @provider.status.should == :stopped end it "should return maintenance if in maintenance in svcs output" do @provider.stubs(:svcs).returns("maintenance\t-") @provider.status.should == :maintenance end it "should return target state if transitioning in svcs output" do @provider.stubs(:svcs).returns("online\tdisabled") @provider.status.should == :stopped end it "should throw error if it's a legacy service in svcs output" do @provider.stubs(:svcs).returns("legacy_run\t-") lambda { @provider.status }.should raise_error(Puppet::Error, "Cannot manage legacy services through SMF") end end describe "when starting" do it "should enable the service if it is not enabled" do @provider.expects(:status).returns :stopped @provider.expects(:texecute) @provider.start end it "should always execute external command 'svcadm enable /system/myservice'" do @provider.stubs(:status).returns :running @provider.expects(:texecute).with(:start, ["/usr/sbin/svcadm", :enable, "/system/myservice"], true) @provider.start end it "should execute external command 'svcadm clear /system/myservice' if in maintenance" do @provider.stubs(:status).returns :maintenance @provider.expects(:texecute).with(:start, ["/usr/sbin/svcadm", :clear, "/system/myservice"], true) @provider.start end end describe "when starting a service with a manifest" do before(:each) do @resource = Puppet::Type.type(:service).new(:name => "/system/myservice", :ensure => :running, :enable => :true, :manifest => "/tmp/myservice.xml") @provider = provider_class.new(@resource) $CHILD_STATUS.stubs(:exitstatus).returns(1) end it "should import the manifest if service is missing" do @provider.expects(:svccfg).with(:import, "/tmp/myservice.xml") @provider.expects(:texecute).with(:start, ["/usr/sbin/svcadm", :enable, "/system/myservice"], true) @provider.start end it "should handle failures if importing a manifest" do @provider.expects(:svccfg).raises(Puppet::ExecutionFailure.new("can't svccfg import")) lambda { @provider.start }.should raise_error(Puppet::Error, "Cannot config /system/myservice to enable it: can't svccfg import") end end describe "when stopping" do it "should execute external command 'svcadm disable /system/myservice'" do @provider.expects(:texecute).with(:stop, ["/usr/sbin/svcadm", :disable, "/system/myservice"], true) @provider.stop end end describe "when restarting" do it "should call 'svcadm restart /system/myservice'" do @provider.expects(:texecute).with(:restart, ["/usr/sbin/svcadm", :restart, "/system/myservice"], true) @provider.restart end end end diff --git a/spec/unit/provider/service/src_spec.rb b/spec/unit/provider/service/src_spec.rb index 4502eb643..17f49994e 100755 --- a/spec/unit/provider/service/src_spec.rb +++ b/spec/unit/provider/service/src_spec.rb @@ -1,97 +1,97 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Unit testing for the AIX System Resource Controller (src) provider # require 'spec_helper' provider_class = Puppet::Type.type(:service).provider(:src) describe provider_class do before :each do @resource = stub 'resource' @resource.stubs(:[]).returns(nil) @resource.stubs(:[]).with(:name).returns "myservice" @provider = provider_class.new @provider.resource = @resource @provider.stubs(:command).with(:stopsrc).returns "/usr/bin/stopsrc" @provider.stubs(:command).with(:startsrc).returns "/usr/bin/startsrc" @provider.stubs(:command).with(:lssrc).returns "/usr/bin/lssrc" @provider.stubs(:command).with(:refresh).returns "/usr/bin/refresh" @provider.stubs(:stopsrc) @provider.stubs(:startsrc) @provider.stubs(:lssrc) @provider.stubs(:refresh) end [:start, :stop, :status, :restart].each do |method| it "should have a #{method} method" do @provider.should respond_to(method) end end it "should execute the startsrc command" do @provider.expects(:execute).with(['/usr/bin/startsrc', '-s', "myservice"], {:squelch => true, :failonfail => true}) @provider.start end it "should execute the stopsrc command" do @provider.expects(:execute).with(['/usr/bin/stopsrc', '-s', "myservice"], {:squelch => true, :failonfail => true}) @provider.stop end it "should execute status and return running if the subsystem is active" do sample_output = <<_EOF_ Subsystem Group PID Status myservice tcpip 1234 active _EOF_ @provider.expects(:execute).with(['/usr/bin/lssrc', '-s', "myservice"]).returns sample_output @provider.status.should == :running end it "should execute status and return stopped if the subsystem is inoperative" do sample_output = <<_EOF_ Subsystem Group PID Status myservice tcpip inoperative _EOF_ @provider.expects(:execute).with(['/usr/bin/lssrc', '-s', "myservice"]).returns sample_output @provider.status.should == :stopped end it "should execute status and return nil if the status is not known" do sample_output = <<_EOF_ Subsystem Group PID Status myservice tcpip randomdata _EOF_ @provider.expects(:execute).with(['/usr/bin/lssrc', '-s', "myservice"]).returns sample_output @provider.status.should == nil end it "should execute restart which runs refresh" do sample_output = <<_EOF_ #subsysname:synonym:cmdargs:path:uid:auditid:standin:standout:standerr:action:multi:contact:svrkey:svrmtype:priority:signorm:sigforce:display:waittime:grpname: myservice:::/usr/sbin/inetd:0:0:/dev/console:/dev/console:/dev/console:-O:-Q:-K:0:0:20:0:0:-d:20:tcpip: _EOF_ @provider.expects(:execute).with(['/usr/bin/lssrc', '-Ss', "myservice"]).returns sample_output @provider.expects(:execute).with(['/usr/bin/refresh', '-s', "myservice"]) @provider.restart end it "should execute restart which runs stopsrc then startsrc" do sample_output = <<_EOF_ #subsysname:synonym:cmdargs:path:uid:auditid:standin:standout:standerr:action:multi:contact:svrkey:svrmtype:priority:signorm:sigforce:display:waittime:grpname: myservice::--no-daemonize:/usr/sbin/puppetd:0:0:/dev/null:/var/log/puppet.log:/var/log/puppet.log:-O:-Q:-S:0:0:20:15:9:-d:20::" _EOF_ @provider.expects(:execute).with(['/usr/bin/lssrc', '-Ss', "myservice"]).returns sample_output @provider.expects(:execute).with(['/usr/bin/stopsrc', '-s', "myservice"], {:squelch => true, :failonfail => true}) @provider.expects(:execute).with(['/usr/bin/startsrc', '-s', "myservice"], {:squelch => true, :failonfail => true}) @provider.restart end end diff --git a/spec/unit/provider/service/upstart.rb b/spec/unit/provider/service/upstart.rb index 61e191b8a..0febc939d 100755 --- a/spec/unit/provider/service/upstart.rb +++ b/spec/unit/provider/service/upstart.rb @@ -1,49 +1,48 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' provider_class = Puppet::Type.type(:service).provider(:upstart) describe provider_class do describe "#instances" do it "should be able to find all instances" do processes = ["rc stop/waiting", "ssh start/running, process 712"] provider_class.stubs(:execpipe).yields(processes) provider_class.instances.map {|provider| provider.name}.should =~ ["rc","ssh"] end it "should attach the interface name for network interfaces" do processes = ["network-interface (eth0)"] provider_class.stubs(:execpipe).yields(processes) provider_class.instances.first.name.should == "network-interface INTERFACE=eth0" end end describe "#status" do it "should allow the user to override the status command" do resource = Puppet::Type.type(:service).new(:name => "foo", :provider => :upstart, :status => "/bin/foo") provider = provider_class.new(resource) provider.expects(:ucommand).with { `true`; true } provider.status.should == :running end it "should use the default status command if none is specified" do resource = Puppet::Type.type(:service).new(:name => "foo", :provider => :upstart) provider = provider_class.new(resource) provider.expects(:status_exec).with(["foo"]).returns("foo start/running, process 1000") Process::Status.any_instance.stubs(:exitstatus).returns(0) provider.status.should == :running end it "should properly handle services with 'start' in their name" do resource = Puppet::Type.type(:service).new(:name => "foostartbar", :provider => :upstart) provider = provider_class.new(resource) provider.expects(:status_exec).with(["foostartbar"]).returns("foostartbar stop/waiting") Process::Status.any_instance.stubs(:exitstatus).returns(0) provider.status.should == :stopped end end end diff --git a/spec/unit/provider/ssh_authorized_key/parsed_spec.rb b/spec/unit/provider/ssh_authorized_key/parsed_spec.rb index 0203014a4..69d29c674 100755 --- a/spec/unit/provider/ssh_authorized_key/parsed_spec.rb +++ b/spec/unit/provider/ssh_authorized_key/parsed_spec.rb @@ -1,212 +1,211 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'shared_behaviours/all_parsedfile_providers' require 'puppet_spec/files' provider_class = Puppet::Type.type(:ssh_authorized_key).provider(:parsed) describe provider_class do include PuppetSpec::Files before :each do @sshauthkey_class = Puppet::Type.type(:ssh_authorized_key) @provider = @sshauthkey_class.provider(:parsed) @keyfile = tmpfile('authorized_keys') @provider.any_instance.stubs(:target).returns @keyfile @user = 'random_bob' Puppet::Util.stubs(:uid).with(@user).returns 12345 end after :each do @provider.initvars end def mkkey(args) args[:target] = @keyfile args[:user] = @user resource = Puppet::Type.type(:ssh_authorized_key).new(args) key = @provider.new(resource) args.each do |p,v| key.send(p.to_s + "=", v) end key end def genkey(key) @provider.stubs(:filetype).returns(Puppet::Util::FileType::FileTypeRam) File.stubs(:chown) File.stubs(:chmod) Puppet::Util::SUIDManager.stubs(:asuser).yields key.flush @provider.target_object(@keyfile).read end it_should_behave_like "all parsedfile providers", provider_class it "should be able to generate a basic authorized_keys file" do key = mkkey(:name => "Just Testing", :key => "AAAAfsfddsjldjgksdflgkjsfdlgkj", :type => "ssh-dss", :ensure => :present, :options => [:absent] ) genkey(key).should == "ssh-dss AAAAfsfddsjldjgksdflgkjsfdlgkj Just Testing\n" end it "should be able to generate a authorized_keys file with options" do key = mkkey(:name => "root@localhost", :key => "AAAAfsfddsjldjgksdflgkjsfdlgkj", :type => "ssh-rsa", :ensure => :present, :options => ['from="192.168.1.1"', "no-pty", "no-X11-forwarding"] ) genkey(key).should == "from=\"192.168.1.1\",no-pty,no-X11-forwarding ssh-rsa AAAAfsfddsjldjgksdflgkjsfdlgkj root@localhost\n" end it "should be able to parse options containing commas via its parse_options method" do options = %w{from="host1.reductlivelabs.com,host.reductivelabs.com" command="/usr/local/bin/run" ssh-pty} optionstr = options.join(", ") @provider.parse_options(optionstr).should == options end it "should use '' as name for entries that lack a comment" do line = "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAut8aOSxenjOqF527dlsdHWV4MNoAsX14l9M297+SQXaQ5Z3BedIxZaoQthkDALlV/25A1COELrg9J2MqJNQc8Xe9XQOIkBQWWinUlD/BXwoOTWEy8C8zSZPHZ3getMMNhGTBO+q/O+qiJx3y5cA4MTbw2zSxukfWC87qWwcZ64UUlegIM056vPsdZWFclS9hsROVEa57YUMrehQ1EGxT4Z5j6zIopufGFiAPjZigq/vqgcAqhAKP6yu4/gwO6S9tatBeEjZ8fafvj1pmvvIplZeMr96gHE7xS3pEEQqnB3nd4RY7AF6j9kFixnsytAUO7STPh/M3pLiVQBN89TvWPQ==" @provider.parse(line)[0][:name].should == "" end end describe provider_class do before :each do @resource = stub("resource", :name => "foo") @resource.stubs(:[]).returns "foo" @resource.class.stubs(:key_attributes).returns( [:name] ) @provider = provider_class.new(@resource) provider_class.stubs(:filetype).returns(Puppet::Util::FileType::FileTypeRam) Puppet::Util::SUIDManager.stubs(:asuser).yields end describe "when flushing" do before :each do # Stub file and directory operations Dir.stubs(:mkdir) File.stubs(:chmod) File.stubs(:chown) end describe "and both a user and a target have been specified" do before :each do Puppet::Util.stubs(:uid).with("random_bob").returns 12345 @resource.stubs(:should).with(:user).returns "random_bob" target = "/tmp/.ssh_dir/place_to_put_authorized_keys" @resource.stubs(:should).with(:target).returns target end it "should create the directory" do File.stubs(:exist?).with("/tmp/.ssh_dir").returns false Dir.expects(:mkdir).with("/tmp/.ssh_dir", 0700) @provider.flush end it "should chown the directory to the user" do uid = Puppet::Util.uid("random_bob") File.expects(:chown).with(uid, nil, "/tmp/.ssh_dir") @provider.flush end it "should chown the key file to the user" do uid = Puppet::Util.uid("random_bob") File.expects(:chown).with(uid, nil, "/tmp/.ssh_dir/place_to_put_authorized_keys") @provider.flush end it "should chmod the key file to 0600" do File.expects(:chmod).with(0600, "/tmp/.ssh_dir/place_to_put_authorized_keys") @provider.flush end end describe "and a user has been specified with no target" do before :each do @resource.stubs(:should).with(:user).returns "nobody" @resource.stubs(:should).with(:target).returns nil # # I'd like to use random_bob here and something like # # File.stubs(:expand_path).with("~random_bob/.ssh").returns "/users/r/random_bob/.ssh" # # but mocha objects strenuously to stubbing File.expand_path # so I'm left with using nobody. @dir = File.expand_path("~nobody/.ssh") end it "should create the directory if it doesn't exist" do File.stubs(:exist?).with(@dir).returns false Dir.expects(:mkdir).with(@dir,0700) @provider.flush end it "should not create or chown the directory if it already exist" do File.stubs(:exist?).with(@dir).returns false Dir.expects(:mkdir).never @provider.flush end it "should chown the directory to the user if it creates it" do File.stubs(:exist?).with(@dir).returns false Dir.stubs(:mkdir).with(@dir,0700) uid = Puppet::Util.uid("nobody") File.expects(:chown).with(uid, nil, @dir) @provider.flush end it "should not create or chown the directory if it already exist" do File.stubs(:exist?).with(@dir).returns false Dir.expects(:mkdir).never File.expects(:chown).never @provider.flush end it "should chown the key file to the user" do uid = Puppet::Util.uid("nobody") File.expects(:chown).with(uid, nil, File.expand_path("~nobody/.ssh/authorized_keys")) @provider.flush end it "should chmod the key file to 0600" do File.expects(:chmod).with(0600, File.expand_path("~nobody/.ssh/authorized_keys")) @provider.flush end end describe "and a target has been specified with no user" do before :each do @resource.stubs(:should).with(:user).returns nil @resource.stubs(:should).with(:target).returns("/tmp/.ssh_dir/place_to_put_authorized_keys") end it "should raise an error" do proc { @provider.flush }.should raise_error end end describe "and a invalid user has been specified with no target" do before :each do @resource.stubs(:should).with(:user).returns "thisusershouldnotexist" @resource.stubs(:should).with(:target).returns nil end it "should catch an exception and raise a Puppet error" do lambda { @provider.flush }.should raise_error(Puppet::Error) end end end end diff --git a/spec/unit/provider/sshkey/parsed_spec.rb b/spec/unit/provider/sshkey/parsed_spec.rb index 664316f14..e66032bc4 100755 --- a/spec/unit/provider/sshkey/parsed_spec.rb +++ b/spec/unit/provider/sshkey/parsed_spec.rb @@ -1,38 +1,37 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' provider_class = Puppet::Type.type(:sshkey).provider(:parsed) describe provider_class do before do @sshkey_class = Puppet::Type.type(:sshkey) @provider_class = @sshkey_class.provider(:parsed) @key = 'AAAAB3NzaC1yc2EAAAABIwAAAQEAzwHhxXvIrtfIwrudFqc8yQcIfMudrgpnuh1F3AV6d2BrLgu/yQE7W5UyJMUjfj427sQudRwKW45O0Jsnr33F4mUw+GIMlAAmp9g24/OcrTiB8ZUKIjoPy/cO4coxGi8/NECtRzpD/ZUPFh6OEpyOwJPMb7/EC2Az6Otw4StHdXUYw22zHazBcPFnv6zCgPx1hA7QlQDWTu4YcL0WmTYQCtMUb3FUqrcFtzGDD0ytosgwSd+JyN5vj5UwIABjnNOHPZ62EY1OFixnfqX/+dUwrFSs5tPgBF/KkC6R7tmbUfnBON6RrGEmu+ajOTOLy23qUZB4CQ53V7nyAWhzqSK+hw==' end it "should parse the name from the first field" do @provider_class.parse_line('test ssh-rsa '+@key)[:name].should == "test" end it "should parse the first component of the first field as the name" do @provider_class.parse_line('test,alias ssh-rsa '+@key)[:name].should == "test" end it "should parse host_aliases from the remaining components of the first field" do @provider_class.parse_line('test,alias ssh-rsa '+@key)[:host_aliases].should == ["alias"] end it "should parse multiple host_aliases" do @provider_class.parse_line('test,alias1,alias2,alias3 ssh-rsa '+@key)[:host_aliases].should == ["alias1","alias2","alias3"] end it "should not drop an empty host_alias" do @provider_class.parse_line('test,alias, ssh-rsa '+@key)[:host_aliases].should == ["alias",""] end it "should recognise when there are no host aliases" do @provider_class.parse_line('test ssh-rsa '+@key)[:host_aliases].should == [] end end diff --git a/spec/unit/provider/user/hpux_spec.rb b/spec/unit/provider/user/hpux_spec.rb index def7f27ba..f7779a98d 100755 --- a/spec/unit/provider/user/hpux_spec.rb +++ b/spec/unit/provider/user/hpux_spec.rb @@ -1,25 +1,24 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' provider_class = Puppet::Type.type(:user).provider(:hpuxuseradd) describe provider_class do # left from the useradd test... I have no clue what I'm doing. before do @resource = stub("resource", :name => "myuser", :managehome? => nil, :should => "fakeval", :[] => "fakeval") @provider = provider_class.new(@resource) end it "should add -F when modifying a user" do @resource.expects(:allowdupe?).returns true @provider.expects(:execute).with { |args| args.include?("-F") } @provider.uid = 1000 end it "should add -F when deleting a user" do @provider.stubs(:exists?).returns(true) @provider.expects(:execute).with { |args| args.include?("-F") } @provider.delete end end diff --git a/spec/unit/provider/user/ldap_spec.rb b/spec/unit/provider/user/ldap_spec.rb index 97290c6e4..065b3b423 100755 --- a/spec/unit/provider/user/ldap_spec.rb +++ b/spec/unit/provider/user/ldap_spec.rb @@ -1,279 +1,279 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Created by Luke Kanies on 2008-3-10. # Copyright (c) 2006. All rights reserved. require 'spec_helper' provider_class = Puppet::Type.type(:user).provider(:ldap) describe provider_class do it "should have the Ldap provider class as its baseclass" do provider_class.superclass.should equal(Puppet::Provider::Ldap) end it "should manage :posixAccount and :person objectclasses" do provider_class.manager.objectclasses.should == [:posixAccount, :person] end it "should use 'ou=People' as its relative base" do provider_class.manager.location.should == "ou=People" end it "should use :uid as its rdn" do provider_class.manager.rdn.should == :uid end it "should be able to manage passwords" do provider_class.should be_manages_passwords end it "should use the ldap group provider to convert group names to numbers" do provider = provider_class.new(:name => "foo") Puppet::Type.type(:group).provider(:ldap).expects(:name2id).with("bar").returns 10 provider.gid = 'bar' provider.gid.should == 10 end {:name => "uid", :password => "userPassword", :comment => "cn", :uid => "uidNumber", :gid => "gidNumber", :home => "homeDirectory", :shell => "loginShell" }.each do |puppet, ldap| it "should map :#{puppet.to_s} to '#{ldap}'" do provider_class.manager.ldap_name(puppet).should == ldap end end describe "when being created" do before do # So we don't try to actually talk to ldap @connection = mock 'connection' provider_class.manager.stubs(:connect).yields @connection end it "should generate the sn as the last field of the cn" do resource = stub 'resource', :should => %w{whatever} resource.stubs(:should).with(:comment).returns ["Luke Kanies"] resource.stubs(:should).with(:ensure).returns :present instance = provider_class.new(:name => "luke", :ensure => :absent) instance.stubs(:resource).returns resource @connection.expects(:add).with { |dn, attrs| attrs["sn"] == ["Kanies"] } instance.create instance.flush end describe "with no uid specified" do it "should pick the first available UID after the largest existing UID" do low = {:name=>["luke"], :shell=>:absent, :uid=>["600"], :home=>["/h"], :gid=>["1000"], :password=>["blah"], :comment=>["l k"]} high = {:name=>["testing"], :shell=>:absent, :uid=>["640"], :home=>["/h"], :gid=>["1000"], :password=>["blah"], :comment=>["t u"]} provider_class.manager.expects(:search).returns([low, high]) resource = stub 'resource', :should => %w{whatever} resource.stubs(:should).with(:uid).returns nil resource.stubs(:should).with(:ensure).returns :present instance = provider_class.new(:name => "luke", :ensure => :absent) instance.stubs(:resource).returns resource @connection.expects(:add).with { |dn, attrs| attrs["uidNumber"] == ["641"] } instance.create instance.flush end it "should pick 501 of no users exist" do provider_class.manager.expects(:search).returns nil resource = stub 'resource', :should => %w{whatever} resource.stubs(:should).with(:uid).returns nil resource.stubs(:should).with(:ensure).returns :present instance = provider_class.new(:name => "luke", :ensure => :absent) instance.stubs(:resource).returns resource @connection.expects(:add).with { |dn, attrs| attrs["uidNumber"] == ["501"] } instance.create instance.flush end end end describe "when flushing" do before do provider_class.stubs(:suitable?).returns true @instance = provider_class.new(:name => "myname", :groups => %w{whatever}, :uid => "400") end it "should remove the :groups value before updating" do @instance.class.manager.expects(:update).with { |name, ldap, puppet| puppet[:groups].nil? } @instance.flush end it "should empty the property hash" do @instance.class.manager.stubs(:update) @instance.flush @instance.uid.should == :absent end it "should empty the ldap property hash" do @instance.class.manager.stubs(:update) @instance.flush @instance.ldap_properties[:uid].should be_nil end end describe "when checking group membership" do before do @groups = Puppet::Type.type(:group).provider(:ldap) @group_manager = @groups.manager provider_class.stubs(:suitable?).returns true @instance = provider_class.new(:name => "myname") end it "should show its group membership as the sorted list of all groups returned by an ldap query of group memberships" do one = {:name => "one"} two = {:name => "two"} @group_manager.expects(:search).with("memberUid=myname").returns([two, one]) @instance.groups.should == "one,two" end it "should show its group membership as :absent if no matching groups are found in ldap" do @group_manager.expects(:search).with("memberUid=myname").returns(nil) @instance.groups.should == :absent end it "should cache the group value" do @group_manager.expects(:search).with("memberUid=myname").once.returns nil @instance.groups @instance.groups.should == :absent end end describe "when modifying group membership" do before do @groups = Puppet::Type.type(:group).provider(:ldap) @group_manager = @groups.manager provider_class.stubs(:suitable?).returns true @one = {:name => "one", :gid => "500"} @group_manager.stubs(:find).with("one").returns(@one) @two = {:name => "one", :gid => "600"} @group_manager.stubs(:find).with("two").returns(@two) @instance = provider_class.new(:name => "myname") @instance.stubs(:groups).returns :absent end it "should fail if the group does not exist" do @group_manager.expects(:find).with("mygroup").returns nil lambda { @instance.groups = "mygroup" }.should raise_error(Puppet::Error) end it "should only pass the attributes it cares about to the group manager" do @group_manager.expects(:update).with { |name, attrs| attrs[:gid].nil? } @instance.groups = "one" end it "should always include :ensure => :present in the current values" do @group_manager.expects(:update).with { |name, is, should| is[:ensure] == :present } @instance.groups = "one" end it "should always include :ensure => :present in the desired values" do @group_manager.expects(:update).with { |name, is, should| should[:ensure] == :present } @instance.groups = "one" end it "should always pass the group's original member list" do @one[:members] = %w{yay ness} @group_manager.expects(:update).with { |name, is, should| is[:members] == %w{yay ness} } @instance.groups = "one" end it "should find the group again when resetting its member list, so it has the full member list" do @group_manager.expects(:find).with("one").returns(@one) @group_manager.stubs(:update) @instance.groups = "one" end describe "for groups that have no members" do it "should create a new members attribute with its value being the user's name" do @group_manager.expects(:update).with { |name, is, should| should[:members] == %w{myname} } @instance.groups = "one" end end describe "for groups it is being removed from" do it "should replace the group's member list with one missing the user's name" do @one[:members] = %w{myname a} @two[:members] = %w{myname b} @group_manager.expects(:update).with { |name, is, should| name == "two" and should[:members] == %w{b} } @instance.stubs(:groups).returns "one,two" @instance.groups = "one" end it "should mark the member list as empty if there are no remaining members" do @one[:members] = %w{myname} @two[:members] = %w{myname b} @group_manager.expects(:update).with { |name, is, should| name == "one" and should[:members] == :absent } @instance.stubs(:groups).returns "one,two" @instance.groups = "two" end end describe "for groups that already have members" do it "should replace each group's member list with a new list including the user's name" do @one[:members] = %w{a b} @group_manager.expects(:update).with { |name, is, should| should[:members] == %w{a b myname} } @two[:members] = %w{b c} @group_manager.expects(:update).with { |name, is, should| should[:members] == %w{b c myname} } @instance.groups = "one,two" end end describe "for groups of which it is a member" do it "should do nothing" do @one[:members] = %w{a b} @group_manager.expects(:update).with { |name, is, should| should[:members] == %w{a b myname} } @two[:members] = %w{c myname} @group_manager.expects(:update).with { |name, *other| name == "two" }.never @instance.stubs(:groups).returns "two" @instance.groups = "one,two" end end end end diff --git a/spec/unit/provider/user/user_role_add_spec.rb b/spec/unit/provider/user/user_role_add_spec.rb index a790c5669..b17ba68c8 100755 --- a/spec/unit/provider/user/user_role_add_spec.rb +++ b/spec/unit/provider/user/user_role_add_spec.rb @@ -1,267 +1,266 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' provider_class = Puppet::Type.type(:user).provider(:user_role_add) describe provider_class do before do @resource = stub("resource", :name => "myuser", :managehome? => nil) @resource.stubs(:should).returns "fakeval" @resource.stubs(:[]).returns "fakeval" @resource.stubs(:allowdupe?).returns false @provider = provider_class.new(@resource) end describe "when calling command" do before do klass = stub("provider") klass.stubs(:command).with(:foo).returns("userfoo") klass.stubs(:command).with(:role_foo).returns("rolefoo") @provider.stubs(:class).returns(klass) end it "should use the command if not a role and ensure!=role" do @provider.stubs(:is_role?).returns(false) @provider.stubs(:exists?).returns(false) @resource.stubs(:[]).with(:ensure).returns(:present) @provider.command(:foo).should == "userfoo" end it "should use the role command when a role" do @provider.stubs(:is_role?).returns(true) @provider.command(:foo).should == "rolefoo" end it "should use the role command when !exists and ensure=role" do @provider.stubs(:is_role?).returns(false) @provider.stubs(:exists?).returns(false) @resource.stubs(:[]).with(:ensure).returns(:role) @provider.command(:foo).should == "rolefoo" end end describe "when calling transition" do it "should return the type set to whatever is passed in" do @provider.expects(:command).with(:modify).returns("foomod") @provider.transition("bar").include?("type=bar") end end describe "when calling create" do before do @provider.stubs(:password=) end it "should use the add command when the user is not a role" do @provider.stubs(:is_role?).returns(false) @provider.expects(:addcmd).returns("useradd") @provider.expects(:run).at_least_once @provider.create end it "should use transition(normal) when the user is a role" do @provider.stubs(:is_role?).returns(true) @provider.expects(:transition).with("normal") @provider.expects(:run) @provider.create end it "should set password age rules" do @resource = Puppet::Type.type(:user).new :name => "myuser", :password_min_age => 5, :password_max_age => 10, :provider => :user_role_add @provider = provider_class.new(@resource) @provider.stubs(:user_attributes) @provider.stubs(:execute) @provider.expects(:execute).with { |cmd, *args| args == ["-n", 5, "-x", 10, "myuser"] } @provider.create end end describe "when calling destroy" do it "should use the delete command if the user exists and is not a role" do @provider.stubs(:exists?).returns(true) @provider.stubs(:is_role?).returns(false) @provider.expects(:deletecmd) @provider.expects(:run) @provider.destroy end it "should use the delete command if the user is a role" do @provider.stubs(:exists?).returns(true) @provider.stubs(:is_role?).returns(true) @provider.expects(:deletecmd) @provider.expects(:run) @provider.destroy end end describe "when calling create_role" do it "should use the transition(role) if the user exists" do @provider.stubs(:exists?).returns(true) @provider.stubs(:is_role?).returns(false) @provider.expects(:transition).with("role") @provider.expects(:run) @provider.create_role end it "should use the add command when role doesn't exists" do @provider.stubs(:exists?).returns(false) @provider.expects(:addcmd) @provider.expects(:run) @provider.create_role end end describe "when allow duplicate is enabled" do before do @resource.expects(:allowdupe?).returns true @resource.stubs(:system?) @provider.stubs(:is_role?).returns(false) @provider.stubs(:execute) @provider.expects(:execute).with { |args| args.include?("-o") } end it "should add -o when the user is being created" do @provider.stubs(:password=) @provider.create end it "should add -o when the uid is being modified" do @provider.uid = 150 end end [:roles, :auths, :profiles].each do |val| describe "when getting #{val}" do it "should get the user_attributes" do @provider.expects(:user_attributes) @provider.send(val) end it "should get the #{val} attribute" do attributes = mock("attributes") attributes.expects(:[]).with(val) @provider.stubs(:user_attributes).returns(attributes) @provider.send(val) end end end describe "when getting the keys" do it "should get the user_attributes" do @provider.expects(:user_attributes) @provider.keys end it "should call removed_managed_attributes" do @provider.stubs(:user_attributes).returns({ :type => "normal", :foo => "something" }) @provider.expects(:remove_managed_attributes) @provider.keys end it "should removed managed attribute (type, auths, roles, etc)" do @provider.stubs(:user_attributes).returns({ :type => "normal", :foo => "something" }) @provider.keys.should == { :foo => "something" } end end describe "when adding properties" do it "should call build_keys_cmd" do @resource.stubs(:should).returns "" @resource.expects(:should).with(:keys).returns({ :foo => "bar" }) @provider.expects(:build_keys_cmd).returns([]) @provider.add_properties end it "should add the elements of the keys hash to an array" do @resource.stubs(:should).returns "" @resource.expects(:should).with(:keys).returns({ :foo => "bar"}) @provider.add_properties.must == ["-K", "foo=bar"] end end describe "when calling build_keys_cmd" do it "should build cmd array with keypairs seperated by -K ending with user" do @provider.build_keys_cmd({"foo" => "bar", "baz" => "boo"}).should.eql? ["-K", "foo=bar", "-K", "baz=boo"] end end describe "when setting the keys" do before do @provider.stubs(:is_role?).returns(false) end it "should run a command" do @provider.expects(:run) @provider.keys=({}) end it "should build the command" do @resource.stubs(:[]).with(:name).returns("someuser") @provider.stubs(:command).returns("usermod") @provider.expects(:build_keys_cmd).returns(["-K", "foo=bar"]) @provider.expects(:run).with(["usermod", "-K", "foo=bar", "someuser"], "modify attribute key pairs") @provider.keys=({}) end end describe "when getting the hashed password" do before do @array = mock "array" end it "should readlines of /etc/shadow" do File.expects(:readlines).with("/etc/shadow").returns([]) @provider.password end it "should reject anything that doesn't start with alpha numerics" do @array.expects(:reject).returns([]) File.stubs(:readlines).with("/etc/shadow").returns(@array) @provider.password end it "should collect splitting on ':'" do @array.stubs(:reject).returns(@array) @array.expects(:collect).returns([]) File.stubs(:readlines).with("/etc/shadow").returns(@array) @provider.password end it "should find the matching user" do @resource.stubs(:[]).with(:name).returns("username") @array.stubs(:reject).returns(@array) @array.stubs(:collect).returns([["username", "hashedpassword"], ["someoneelse", "theirpassword"]]) File.stubs(:readlines).with("/etc/shadow").returns(@array) @provider.password.must == "hashedpassword" end it "should get the right password" do @resource.stubs(:[]).with(:name).returns("username") File.stubs(:readlines).with("/etc/shadow").returns(["#comment", " nonsense", " ", "username:hashedpassword:stuff:foo:bar:::", "other:pword:yay:::"]) @provider.password.must == "hashedpassword" end end describe "when setting the password" do #how can you mock these blocks up? it "should open /etc/shadow for reading and /etc/shadow_tmp for writing" do File.expects(:open).with("/etc/shadow", "r") File.stubs(:rename) @provider.password=("hashedpassword") end it "should rename the /etc/shadow_tmp to /etc/shadow" do File.stubs(:open).with("/etc/shadow", "r") File.expects(:rename).with("/etc/shadow_tmp", "/etc/shadow") @provider.password=("hashedpassword") end end describe "#shadow_entry" do it "should return the line for the right user" do File.stubs(:readlines).returns(["someuser:!:10:5:20:7:1::\n", "fakeval:*:20:10:30:7:2::\n", "testuser:*:30:15:40:7:3::\n"]) @provider.shadow_entry.should == ["fakeval", "*", "20", "10", "30", "7", "2"] end end end diff --git a/spec/unit/provider/user/useradd_spec.rb b/spec/unit/provider/user/useradd_spec.rb index e7d99ac2b..724fc12c0 100755 --- a/spec/unit/provider/user/useradd_spec.rb +++ b/spec/unit/provider/user/useradd_spec.rb @@ -1,216 +1,215 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' provider_class = Puppet::Type.type(:user).provider(:useradd) describe provider_class do before do @resource = stub("resource", :name => "myuser", :managehome? => nil) @resource.stubs(:should).returns "fakeval" @resource.stubs(:[]).returns "fakeval" @provider = provider_class.new(@resource) end # #1360 it "should add -o when allowdupe is enabled and the user is being created" do @resource.expects(:allowdupe?).returns true @resource.expects(:system?).returns true @provider.stubs(:execute) @provider.expects(:execute).with { |args| args.include?("-o") } @provider.create end it "should add -o when allowdupe is enabled and the uid is being modified" do @resource.expects(:allowdupe?).returns true @provider.expects(:execute).with { |args| args.include?("-o") } @provider.uid = 150 end it "should add -r when system is enabled" do @resource.expects(:allowdupe?).returns true @resource.expects(:system?).returns true @provider.stubs(:execute) @provider.expects(:execute).with { |args| args.include?("-r") } @provider.create end it "should set password age rules" do provider_class.has_feature :manages_password_age @resource = Puppet::Type.type(:user).new :name => "myuser", :password_min_age => 5, :password_max_age => 10, :provider => :useradd @provider = provider_class.new(@resource) @provider.stubs(:execute) @provider.expects(:execute).with { |cmd, *args| args == ["-m", 5, "-M", 10, "myuser"] } @provider.create end describe "when checking to add allow dup" do it "should check allow dup" do @resource.expects(:allowdupe?) @provider.check_allow_dup end it "should return an array with a flag if dup is allowed" do @resource.stubs(:allowdupe?).returns true @provider.check_allow_dup.must == ["-o"] end it "should return an empty array if no dup is allowed" do @resource.stubs(:allowdupe?).returns false @provider.check_allow_dup.must == [] end end describe "when checking to add system users" do it "should check system users" do @resource.expects(:system?) @provider.check_system_users end it "should return an array with a flag if it's a system user" do @resource.stubs(:system?).returns true @provider.check_system_users.must == ["-r"] end it "should return an empty array if it's not a system user" do @resource.stubs(:system?).returns false @provider.check_system_users.must == [] end end describe "when checking manage home" do it "should check manage home" do @resource.expects(:managehome?) @provider.check_manage_home end it "should return an array with -m flag if home is managed" do @resource.stubs(:managehome?).returns true @provider.check_manage_home.must == ["-m"] end it "should return an array with -M if home is not managed and on Redhat" do Facter.stubs(:value).with("operatingsystem").returns("RedHat") @resource.stubs(:managehome?).returns false @provider.check_manage_home.must == ["-M"] end it "should return an empty array if home is not managed and not on Redhat" do Facter.stubs(:value).with("operatingsystem").returns("some OS") @resource.stubs(:managehome?).returns false @provider.check_manage_home.must == [] end end describe "when adding properties" do it "should get the valid properties" it "should not add the ensure property" it "should add the flag and value to an array" it "should return and array of flags and values" end describe "when calling addcmd" do before do @resource.stubs(:allowdupe?).returns true @resource.stubs(:managehome?).returns true @resource.stubs(:system?).returns true end it "should call command with :add" do @provider.expects(:command).with(:add) @provider.addcmd end it "should add properties" do @provider.expects(:add_properties).returns([]) @provider.addcmd end it "should check and add if dup allowed" do @provider.expects(:check_allow_dup).returns([]) @provider.addcmd end it "should check and add if home is managed" do @provider.expects(:check_manage_home).returns([]) @provider.addcmd end it "should add the resource :name" do @resource.expects(:[]).with(:name) @provider.addcmd end it "should return an array with -r if system? is true" do resource = Puppet::Type.type(:user).new( :name => "bob", :system => true) provider_class.new( resource ).addcmd.should include("-r") end it "should return an array without -r if system? is false" do resource = Puppet::Type.type(:user).new( :name => "bob", :system => false) provider_class.new( resource ).addcmd.should_not include("-r") end it "should return an array with full command" do @provider.stubs(:command).with(:add).returns("useradd") @provider.stubs(:add_properties).returns(["-G", "somegroup"]) @resource.stubs(:[]).with(:name).returns("someuser") @resource.stubs(:[]).with(:expiry).returns("somedate") @provider.addcmd.must == ["useradd", "-G", "somegroup", "-o", "-m", '-e somedate', "-r", "someuser"] end it "should return an array without -e if expiry is undefined full command" do @provider.stubs(:command).with(:add).returns("useradd") @provider.stubs(:add_properties).returns(["-G", "somegroup"]) @resource.stubs(:[]).with(:name).returns("someuser") @resource.stubs(:[]).with(:expiry).returns nil @provider.addcmd.must == ["useradd", "-G", "somegroup", "-o", "-m", "-r", "someuser"] end end describe "when calling passcmd" do before do @resource.stubs(:allowdupe?).returns true @resource.stubs(:managehome?).returns true @resource.stubs(:system?).returns true end it "should call command with :pass" do @provider.expects(:command).with(:password) @provider.passcmd end it "should return nil if neither min nor max is set" do @resource.stubs(:should).with(:password_min_age).returns nil @resource.stubs(:should).with(:password_max_age).returns nil @provider.passcmd.must == nil end it "should return a chage command array with -m and the user name if password_min_age is set" do @provider.stubs(:command).with(:password).returns("chage") @resource.stubs(:[]).with(:name).returns("someuser") @resource.stubs(:should).with(:password_min_age).returns 123 @resource.stubs(:should).with(:password_max_age).returns nil @provider.passcmd.must == ['chage','-m',123,'someuser'] end it "should return a chage command array with -M if password_max_age is set" do @provider.stubs(:command).with(:password).returns("chage") @resource.stubs(:[]).with(:name).returns("someuser") @resource.stubs(:should).with(:password_min_age).returns nil @resource.stubs(:should).with(:password_max_age).returns 999 @provider.passcmd.must == ['chage','-M',999,'someuser'] end it "should return a chage command array with -M -m if both password_min_age and password_max_age are set" do @provider.stubs(:command).with(:password).returns("chage") @resource.stubs(:[]).with(:name).returns("someuser") @resource.stubs(:should).with(:password_min_age).returns 123 @resource.stubs(:should).with(:password_max_age).returns 999 @provider.passcmd.must == ['chage','-m',123,'-M',999,'someuser'] end end end diff --git a/spec/unit/provider/vlan/cisco_spec.rb b/spec/unit/provider/vlan/cisco_spec.rb old mode 100644 new mode 100755 index 0951367e6..bb243a75e --- a/spec/unit/provider/vlan/cisco_spec.rb +++ b/spec/unit/provider/vlan/cisco_spec.rb @@ -1,62 +1,62 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec require File.dirname(__FILE__) + '/../../../spec_helper' require 'puppet/provider/vlan/cisco' provider_class = Puppet::Type.type(:vlan).provider(:cisco) describe provider_class do before do @resource = stub("resource", :name => "200") @provider = provider_class.new(@resource) end it "should have a parent of Puppet::Provider::NetworkDevice" do provider_class.should < Puppet::Provider::NetworkDevice end it "should have an instances method" do provider_class.should respond_to(:instances) end describe "when looking up instances at prefetch" do before do @device = stub_everything 'device' Puppet::Util::NetworkDevice::Cisco::Device.stubs(:new).returns(@device) @device.stubs(:command).yields(@device) end it "should initialize the network device with the given url" do Puppet::Util::NetworkDevice::Cisco::Device.expects(:new).with(:url).returns(@device) provider_class.lookup(:url, "200") end it "should delegate to the device vlans" do @device.expects(:parse_vlans) provider_class.lookup("", "200") end it "should return only the given vlan" do @device.expects(:parse_vlans).returns({"200" => { :description => "thisone" }, "1" => { :description => "nothisone" }}) provider_class.lookup("", "200").should == {:description => "thisone" } end end describe "when an instance is being flushed" do it "should call the device update_vlan method with its vlan id, current attributes, and desired attributes" do @instance = provider_class.new(:ensure => :present, :name => "200", :description => "myvlan") @instance.description = "myvlan2" @instance.resource = @resource @resource.stubs(:[]).with(:name).returns("200") device = stub_everything 'device' @instance.stubs(:device).returns(device) device.expects(:command).yields(device) device.expects(:update_vlan).with(@instance.name, {:ensure => :present, :name => "200", :description => "myvlan"}, {:ensure => :present, :name => "200", :description => "myvlan2"}) @instance.flush end end end diff --git a/spec/unit/provider/zfs/solaris_spec.rb b/spec/unit/provider/zfs/solaris_spec.rb index 2e9b81b3c..8a0cd23b1 100755 --- a/spec/unit/provider/zfs/solaris_spec.rb +++ b/spec/unit/provider/zfs/solaris_spec.rb @@ -1,100 +1,99 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' provider_class = Puppet::Type.type(:zfs).provider(:solaris) describe provider_class do before do @resource = stub("resource", :name => "myzfs") @resource.stubs(:[]).with(:name).returns "myzfs" @resource.stubs(:[]).returns "shouldvalue" @provider = provider_class.new(@resource) end it "should have a create method" do @provider.should respond_to(:create) end it "should have a destroy method" do @provider.should respond_to(:destroy) end it "should have an exists? method" do @provider.should respond_to(:exists?) end describe "when calling add_properties" do it "should add -o and the key=value for each properties with a value" do @resource.stubs(:[]).with(:quota).returns "" @resource.stubs(:[]).with(:refquota).returns "" @resource.stubs(:[]).with(:mountpoint).returns "/foo" properties = @provider.add_properties properties.include?("-o").should == true properties.include?("mountpoint=/foo").should == true properties.detect { |a| a.include?("quota") }.should == nil end end describe "when calling create" do it "should call add_properties" do @provider.stubs(:zfs) @provider.expects(:add_properties).returns([]) @provider.create end it "should call zfs with create, properties and this zfs" do @provider.stubs(:add_properties).returns(%w{a b}) @provider.expects(:zfs).with(:create, "a", "b", @resource[:name]) @provider.create end end describe "when calling destroy" do it "should call zfs with :destroy and this zfs" do @provider.expects(:zfs).with(:destroy, @resource[:name]) @provider.destroy end end describe "when calling exist?" do it "should call zfs with :list" do #return stuff because we have to slice and dice it @provider.expects(:zfs).with(:list).returns("NAME USED AVAIL REFER MOUNTPOINT\nmyzfs 100K 27.4M /myzfs") @provider.exists? end it "should return true if returned values match the name" do @provider.stubs(:zfs).with(:list).returns("NAME USED AVAIL REFER MOUNTPOINT\n#{@resource[:name]} 100K 27.4M /myzfs") @provider.exists?.should == true end it "should return false if returned values don't match the name" do @provider.stubs(:zfs).with(:list).returns("no soup for you") @provider.exists?.should == false end end [:mountpoint, :recordsize, :aclmode, :aclinherit, :primarycache, :secondarycache, :compression, :copies, :quota, :reservation, :sharenfs, :snapdir].each do |prop| describe "when getting the #{prop} value" do it "should call zfs with :get, #{prop} and this zfs" do @provider.expects(:zfs).with(:get, "-H", "-o", "value", prop, @resource[:name]).returns("value\n") @provider.send(prop) end it "should get the third value of the second line from the output" do @provider.stubs(:zfs).with(:get, "-H", "-o", "value", prop, @resource[:name]).returns("value\n") @provider.send(prop).should == "value" end end describe "when setting the #{prop} value" do it "should call zfs with :set, #{prop}=value and this zfs" do @provider.expects(:zfs).with(:set, "#{prop}=value", @resource[:name]) @provider.send("#{prop}=".intern, "value") end end end end diff --git a/spec/unit/provider/zone/solaris_spec.rb b/spec/unit/provider/zone/solaris_spec.rb index 669a26b4f..17ec8f68f 100755 --- a/spec/unit/provider/zone/solaris_spec.rb +++ b/spec/unit/provider/zone/solaris_spec.rb @@ -1,55 +1,54 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' provider_class = Puppet::Type.type(:zone).provider(:solaris) describe provider_class do before do @resource = stub("resource", :name => "mypool") @resource.stubs(:[]).returns "shouldvalue" @provider = provider_class.new(@resource) end describe "when calling configure" do it "should add the create args to the create str" do @resource.stubs(:properties).returns([]) @resource.stubs(:[]).with(:create_args).returns("create_args") @provider.expects(:setconfig).with("create -b create_args\nset zonepath=shouldvalue\ncommit\n") @provider.configure end end describe "when installing" do it "should call zoneadm" do @provider.expects(:zoneadm) @provider.install end describe "when cloning" do before { @resource.stubs(:[]).with(:clone).returns(:clone_argument) } it "sohuld clone with the resource's clone attribute" do @provider.expects(:zoneadm).with(:clone, :clone_argument) @provider.install end end describe "when not cloning" do before { @resource.stubs(:[]).with(:clone).returns(nil)} it "should just install if there are no install args" do @resource.stubs(:[]).with(:install_args).returns(nil) @provider.expects(:zoneadm).with(:install) @provider.install end it "should add the install args to the command if they exist" do @resource.stubs(:[]).with(:install_args).returns("install args") @provider.expects(:zoneadm).with(:install, ["install", "args"]) @provider.install end end end end diff --git a/spec/unit/provider/zpool/solaris_spec.rb b/spec/unit/provider/zpool/solaris_spec.rb index 0ab0b25fa..7e3048a7a 100755 --- a/spec/unit/provider/zpool/solaris_spec.rb +++ b/spec/unit/provider/zpool/solaris_spec.rb @@ -1,209 +1,208 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' provider_class = Puppet::Type.type(:zpool).provider(:solaris) describe provider_class do before do @resource = stub("resource", :name => "mypool") @resource.stubs(:[]).returns "shouldvalue" @provider = provider_class.new(@resource) end describe "when getting the instance" do it "should call process_zpool_data with the result of get_pool_data only once" do @provider.stubs(:get_pool_data).returns(["foo", "disk"]) @provider.expects(:process_zpool_data).with(["foo", "disk"]).returns("stuff").once @provider.current_pool @provider.current_pool end end describe "when calling flush" do it "should need to reload the pool" do @provider.stubs(:get_pool_data) @provider.expects(:process_zpool_data).returns("stuff").times(2) @provider.current_pool @provider.flush @provider.current_pool end end describe "when procesing zpool data" do before do @zpool_data = ["foo", "disk"] end describe "when there is no data" do it "should return a hash with ensure=>:absent" do @provider.process_zpool_data([])[:ensure].should == :absent end end describe "when there is a spare" do it "should add the spare disk to the hash" do @zpool_data += ["spares", "spare_disk"] @provider.process_zpool_data(@zpool_data)[:spare].should == ["spare_disk"] end end describe "when there are two spares" do it "should add the spare disk to the hash as a single string" do @zpool_data += ["spares", "spare_disk", "spare_disk2"] @provider.process_zpool_data(@zpool_data)[:spare].should == ["spare_disk spare_disk2"] end end describe "when there is a log" do it "should add the log disk to the hash" do @zpool_data += ["logs", "log_disk"] @provider.process_zpool_data(@zpool_data)[:log].should == ["log_disk"] end end describe "when there are two logs" do it "should add the log disks to the hash as a single string" do @zpool_data += ["spares", "spare_disk", "spare_disk2"] @provider.process_zpool_data(@zpool_data)[:spare].should == ["spare_disk spare_disk2"] end end describe "when the vdev is a single mirror" do it "should call create_multi_array with mirror" do @zpool_data = ["mirrorpool", "mirror", "disk1", "disk2"] @provider.process_zpool_data(@zpool_data)[:mirror].should == ["disk1 disk2"] end end describe "when the vdev is a single mirror on solaris 10u9 or later" do it "should call create_multi_array with mirror" do @zpool_data = ["mirrorpool", "mirror-0", "disk1", "disk2"] @provider.process_zpool_data(@zpool_data)[:mirror].should == ["disk1 disk2"] end end describe "when the vdev is a double mirror" do it "should call create_multi_array with mirror" do @zpool_data = ["mirrorpool", "mirror", "disk1", "disk2", "mirror", "disk3", "disk4"] @provider.process_zpool_data(@zpool_data)[:mirror].should == ["disk1 disk2", "disk3 disk4"] end end describe "when the vdev is a double mirror on solaris 10u9 or later" do it "should call create_multi_array with mirror" do @zpool_data = ["mirrorpool", "mirror-0", "disk1", "disk2", "mirror-1", "disk3", "disk4"] @provider.process_zpool_data(@zpool_data)[:mirror].should == ["disk1 disk2", "disk3 disk4"] end end describe "when the vdev is a raidz1" do it "should call create_multi_array with raidz1" do @zpool_data = ["mirrorpool", "raidz1", "disk1", "disk2"] @provider.process_zpool_data(@zpool_data)[:raidz].should == ["disk1 disk2"] end end describe "when the vdev is a raidz1 on solaris 10u9 or later" do it "should call create_multi_array with raidz1" do @zpool_data = ["mirrorpool", "raidz1-0", "disk1", "disk2"] @provider.process_zpool_data(@zpool_data)[:raidz].should == ["disk1 disk2"] end end describe "when the vdev is a raidz2" do it "should call create_multi_array with raidz2 and set the raid_parity" do @zpool_data = ["mirrorpool", "raidz2", "disk1", "disk2"] pool = @provider.process_zpool_data(@zpool_data) pool[:raidz].should == ["disk1 disk2"] pool[:raid_parity].should == "raidz2" end end describe "when the vdev is a raidz2 on solaris 10u9 or later" do it "should call create_multi_array with raidz2 and set the raid_parity" do @zpool_data = ["mirrorpool", "raidz2-0", "disk1", "disk2"] pool = @provider.process_zpool_data(@zpool_data) pool[:raidz].should == ["disk1 disk2"] pool[:raid_parity].should == "raidz2" end end end describe "when calling the getters and setters" do [:disk, :mirror, :raidz, :log, :spare].each do |field| describe "when calling #{field}" do it "should get the #{field} value from the current_pool hash" do pool_hash = mock "pool hash" pool_hash.expects(:[]).with(field) @provider.stubs(:current_pool).returns(pool_hash) @provider.send(field) end end describe "when setting the #{field}" do it "should warn the #{field} values were not in sync" do Puppet.expects(:warning).with("NO CHANGES BEING MADE: zpool #{field} does not match, should be 'shouldvalue' currently is 'currentvalue'") @provider.stubs(:current_pool).returns(Hash.new("currentvalue")) @provider.send((field.to_s + "=").intern, "shouldvalue") end end end end describe "when calling create" do before do @resource.stubs(:[]).with(:pool).returns("mypool") @provider.stubs(:zpool) end it "should call build_vdevs" do @provider.expects(:build_vdevs).returns([]) @provider.create end it "should call build_named with 'spares' and 'log" do @provider.expects(:build_named).with("spare").returns([]) @provider.expects(:build_named).with("log").returns([]) @provider.create end it "should call zpool with arguments from build_vdevs and build_named" do @provider.expects(:zpool).with(:create, 'mypool', 'shouldvalue', 'spare', 'shouldvalue', 'log', 'shouldvalue') @provider.create end end describe "when calling delete" do it "should call zpool with destroy and the pool name" do @resource.stubs(:[]).with(:pool).returns("poolname") @provider.expects(:zpool).with(:destroy, "poolname") @provider.delete end end describe "when calling exists?" do before do @current_pool = Hash.new(:absent) @provider.stubs(:get_pool_data).returns([]) @provider.stubs(:process_zpool_data).returns(@current_pool) end it "should get the current pool" do @provider.expects(:process_zpool_data).returns(@current_pool) @provider.exists? end it "should return false if the current_pool is absent" do #the before sets it up @provider.exists?.should == false end it "should return true if the current_pool has values" do @current_pool[:pool] = "mypool" @provider.exists?.should == true end end end diff --git a/spec/unit/provider_spec.rb b/spec/unit/provider_spec.rb index 23d8ae2af..4eb5e12de 100755 --- a/spec/unit/provider_spec.rb +++ b/spec/unit/provider_spec.rb @@ -1,31 +1,30 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe Puppet::Provider do it "should have a specifity class method" do Puppet::Provider.should respond_to(:specificity) end it "should consider two defaults to be higher specificity than one default" do one = Class.new(Puppet::Provider) one.initvars one.defaultfor :operatingsystem => "solaris" two = Class.new(Puppet::Provider) two.initvars two.defaultfor :operatingsystem => "solaris", :operatingsystemrelease => "5.10" two.specificity.should > one.specificity end it "should consider a subclass more specific than its parent class" do one = Class.new(Puppet::Provider) one.initvars two = Class.new(one) two.initvars two.specificity.should > one.specificity end end diff --git a/spec/unit/puppet_spec.rb b/spec/unit/puppet_spec.rb index e0eb49bad..50d3a4718 100755 --- a/spec/unit/puppet_spec.rb +++ b/spec/unit/puppet_spec.rb @@ -1,12 +1,12 @@ -#!/usr/bin/env ruby" +#!/usr/bin/env rspec" require 'spec_helper' require 'puppet' describe Puppet do Puppet::Util::Log.eachlevel do |level| it "should have a method for sending '#{level}' logs" do Puppet.should respond_to(level) end end end diff --git a/spec/unit/rails/host_spec.rb b/spec/unit/rails/host_spec.rb index 07399a361..df0b2fa1d 100755 --- a/spec/unit/rails/host_spec.rb +++ b/spec/unit/rails/host_spec.rb @@ -1,161 +1,160 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe "Puppet::Rails::Host", :if => Puppet.features.rails? do def column(name, type) ActiveRecord::ConnectionAdapters::Column.new(name, nil, type, false) end before do require 'puppet/rails/host' # Stub this so we don't need access to the DB. Puppet::Rails::Host.stubs(:columns).returns([column("name", "string"), column("environment", "string"), column("ip", "string")]) @node = Puppet::Node.new("foo") @node.environment = "production" @node.ipaddress = "127.0.0.1" @host = stub 'host', :environment= => nil, :ip= => nil end describe "when converting a Puppet::Node instance into a Rails instance" do it "should modify any existing instance in the database" do Puppet::Rails::Host.expects(:find_by_name).with("foo").returns @host Puppet::Rails::Host.from_puppet(@node) end it "should create a new instance in the database if none can be found" do Puppet::Rails::Host.expects(:find_by_name).with("foo").returns nil Puppet::Rails::Host.expects(:new).with(:name => "foo").returns @host Puppet::Rails::Host.from_puppet(@node) end it "should copy the environment from the Puppet instance" do Puppet::Rails::Host.expects(:find_by_name).with("foo").returns @host @node.environment = "production" @host.expects(:environment=).with {|x| x.name.to_s == 'production' } Puppet::Rails::Host.from_puppet(@node) end it "should copy the ipaddress from the Puppet instance" do Puppet::Rails::Host.expects(:find_by_name).with("foo").returns @host @node.ipaddress = "192.168.0.1" @host.expects(:ip=).with "192.168.0.1" Puppet::Rails::Host.from_puppet(@node) end it "should not save the Rails instance" do Puppet::Rails::Host.expects(:find_by_name).with("foo").returns @host @host.expects(:save).never Puppet::Rails::Host.from_puppet(@node) end end describe "when converting a Puppet::Rails::Host instance into a Puppet::Node instance" do before do @host = Puppet::Rails::Host.new(:name => "foo", :environment => "production", :ip => "127.0.0.1") @node = Puppet::Node.new("foo") Puppet::Node.stubs(:new).with("foo").returns @node end it "should create a new instance with the correct name" do Puppet::Node.expects(:new).with("foo").returns @node @host.to_puppet end it "should copy the environment from the Rails instance" do @host.environment = "prod" @node.expects(:environment=).with "prod" @host.to_puppet end it "should copy the ipaddress from the Rails instance" do @host.ip = "192.168.0.1" @node.expects(:ipaddress=).with "192.168.0.1" @host.to_puppet end end describe "when merging catalog resources and database resources" do before :each do Puppet.settings.stubs(:[]).with(:thin_storeconfigs).returns(false) @resource1 = stub_everything 'res1' @resource2 = stub_everything 'res2' @resources = [ @resource1, @resource2 ] @dbresource1 = stub_everything 'dbres1' @dbresource2 = stub_everything 'dbres2' @dbresources = { 1 => @dbresource1, 2 => @dbresource2 } @host = Puppet::Rails::Host.new(:name => "foo", :environment => "production", :ip => "127.0.0.1") @host.stubs(:find_resources).returns(@dbresources) @host.stubs(:find_resources_parameters_tags) @host.stubs(:compare_to_catalog) @host.stubs(:id).returns(1) end it "should find all database resources" do @host.expects(:find_resources) @host.merge_resources(@resources) end it "should find all paramaters and tags for those database resources" do @host.expects(:find_resources_parameters_tags).with(@dbresources) @host.merge_resources(@resources) end it "should compare all database resources to catalog" do @host.expects(:compare_to_catalog).with(@dbresources, @resources) @host.merge_resources(@resources) end it "should compare only exported resources in thin_storeconfigs mode" do Puppet.settings.stubs(:[]).with(:thin_storeconfigs).returns(true) @resource1.stubs(:exported?).returns(true) @host.expects(:compare_to_catalog).with(@dbresources, [ @resource1 ]) @host.merge_resources(@resources) end end describe "when searching the database for host resources" do before :each do Puppet.settings.stubs(:[]).with(:thin_storeconfigs).returns(false) @resource1 = stub_everything 'res1', :id => 1 @resource2 = stub_everything 'res2', :id => 2 @resources = [ @resource1, @resource2 ] @dbresources = stub 'resources' @dbresources.stubs(:find).returns(@resources) @host = Puppet::Rails::Host.new(:name => "foo", :environment => "production", :ip => "127.0.0.1") @host.stubs(:resources).returns(@dbresources) end it "should return a hash keyed by id of all resources" do @host.find_resources.should == { 1 => @resource1, 2 => @resource2 } end it "should return a hash keyed by id of only exported resources in thin_storeconfigs mode" do Puppet.settings.stubs(:[]).with(:thin_storeconfigs).returns(true) @dbresources.expects(:find).with { |*h| h[1][:conditions] == { :exported => true } }.returns([]) @host.find_resources end end end diff --git a/spec/unit/rails/param_value_spec.rb b/spec/unit/rails/param_value_spec.rb index 6aff12b51..7f0086252 100755 --- a/spec/unit/rails/param_value_spec.rb +++ b/spec/unit/rails/param_value_spec.rb @@ -1,48 +1,47 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/rails' describe "Puppet::Rails::ParamValue", :if => Puppet.features.rails? do def column(name, type) ActiveRecord::ConnectionAdapters::Column.new(name, nil, type, false) end before do require 'puppet/rails/param_value' name = stub 'param_name', :name => "foo" # Stub this so we don't need access to the DB. Puppet::Rails::ParamValue.stubs(:columns).returns([column("value", "string")]) Puppet::Rails::ParamName.stubs(:find_or_create_by_name).returns(name) end describe "when creating initial parameter values" do it "should return an array of hashes" do Puppet::Rails::ParamValue.from_parser_param(:myparam, %w{a b})[0].should be_instance_of(Hash) end it "should return hashes for each value with the parameter name set as the ParamName instance" do name = stub 'param_name', :name => "foo" Puppet::Rails::ParamName.expects(:find_or_create_by_name).returns(name) result = Puppet::Rails::ParamValue.from_parser_param(:myparam, "a")[0] result[:value].should == "a" result[:param_name].should == name end it "should return an array of hashes even when only one parameter is provided" do Puppet::Rails::ParamValue.from_parser_param(:myparam, "a")[0].should be_instance_of(Hash) end it "should convert all arguments into strings" do Puppet::Rails::ParamValue.from_parser_param(:myparam, 50)[0][:value].should == "50" end it "should not convert Resource References into strings" do ref = Puppet::Resource.new(:file, "/file") Puppet::Rails::ParamValue.from_parser_param(:myparam, ref)[0][:value].should == ref end end end diff --git a/spec/unit/rails/resource_spec.rb b/spec/unit/rails/resource_spec.rb index 9791f49cb..22e5267f4 100755 --- a/spec/unit/rails/resource_spec.rb +++ b/spec/unit/rails/resource_spec.rb @@ -1,122 +1,121 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/rails' describe "Puppet::Rails::Resource", :if => Puppet.features.rails? do def column(name, type) ActiveRecord::ConnectionAdapters::Column.new(name, nil, type, false) end before do require 'puppet/rails/resource' # Stub this so we don't need access to the DB. Puppet::Rails::Resource.stubs(:columns).returns([column("title", "string"), column("restype", "string"), column("exported", "boolean")]) end describe "when creating initial resource arguments" do it "should set the restype to the resource's type" do Puppet::Rails::Resource.rails_resource_initial_args(Puppet::Resource.new(:file, "/file"))[:restype].should == "File" end it "should set the title to the resource's title" do Puppet::Rails::Resource.rails_resource_initial_args(Puppet::Resource.new(:file, "/file"))[:title].should == "/file" end it "should set the line to the resource's line if one is available" do resource = Puppet::Resource.new(:file, "/file") resource.line = 50 Puppet::Rails::Resource.rails_resource_initial_args(resource)[:line].should == 50 end it "should set 'exported' to true of the resource is exported" do resource = Puppet::Resource.new(:file, "/file") resource.exported = true Puppet::Rails::Resource.rails_resource_initial_args(resource)[:exported].should be_true end it "should set 'exported' to false of the resource is not exported" do resource = Puppet::Resource.new(:file, "/file") resource.exported = false Puppet::Rails::Resource.rails_resource_initial_args(resource)[:exported].should be_false resource = Puppet::Resource.new(:file, "/file") resource.exported = nil Puppet::Rails::Resource.rails_resource_initial_args(resource)[:exported].should be_false end end describe "when merging in a parser resource" do before do @parser = mock 'parser resource' @resource = Puppet::Rails::Resource.new [:merge_attributes, :merge_parameters, :merge_tags, :save].each { |m| @resource.stubs(m) } end it "should merge the attributes" do @resource.expects(:merge_attributes).with(@parser) @resource.merge_parser_resource(@parser) end it "should merge the parameters" do @resource.expects(:merge_parameters).with(@parser) @resource.merge_parser_resource(@parser) end it "should merge the tags" do @resource.expects(:merge_tags).with(@parser) @resource.merge_parser_resource(@parser) end it "should save itself" do @resource.expects(:save) @resource.merge_parser_resource(@parser) end end describe "merge_parameters" do it "should replace values that have changed" do @resource = Puppet::Rails::Resource.new @resource.params_list = [{"name" => "replace", "value" => 1, "id" => 100 }] Puppet::Rails::ParamValue.expects(:delete).with([100]) param_values = stub "param_values" param_values.expects(:build).with({:value=>nil, :param_name=>nil, :line=>{"replace"=>2}}) @resource.stubs(:param_values).returns(param_values) Puppet::Rails::ParamName.stubs(:accumulate_by_name) merge_resource = stub "merge_resource" merge_resource.expects(:line).returns({ "replace" => 2 }) merge_resource.stubs(:each).yields([["replace", 2]]) @resource.merge_parameters(merge_resource) end end describe "#to_resource" do it "should instantiate a Puppet::Parser::Resource" do scope = stub "scope", :source => nil, :environment => nil, :namespaces => nil @resource = Puppet::Rails::Resource.new @resource.stubs(:attributes).returns({ "restype" => 'notify', "title" => 'hello' }) @resource.stubs(:param_names).returns([]) @resource.to_resource(scope).should be_a(Puppet::Parser::Resource) end end end diff --git a/spec/unit/rails_spec.rb b/spec/unit/rails_spec.rb index eba85afc7..fe7fd8e29 100755 --- a/spec/unit/rails_spec.rb +++ b/spec/unit/rails_spec.rb @@ -1,314 +1,313 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/rails' describe Puppet::Rails, "when initializing any connection", :if => Puppet.features.rails? do before do Puppet.settings.stubs(:use) @logger = mock 'logger' @logger.stub_everything Logger.stubs(:new).returns(@logger) ActiveRecord::Base.stubs(:logger).returns(@logger) ActiveRecord::Base.stubs(:connected?).returns(false) end it "should use settings" do Puppet.settings.expects(:use).with(:main, :rails, :master) Puppet::Rails.connect end it "should set up a logger with the appropriate Rails log file" do logger = mock 'logger' Logger.expects(:new).with(Puppet[:railslog]).returns(logger) ActiveRecord::Base.expects(:logger=).with(logger) Puppet::Rails.connect end it "should set the log level to whatever the value is in the settings" do Puppet.settings.stubs(:use) Puppet.settings.stubs(:value).with(:rails_loglevel).returns("debug") Puppet.settings.stubs(:value).with(:railslog).returns("/my/file") logger = mock 'logger' Logger.stubs(:new).returns(logger) ActiveRecord::Base.stubs(:logger).returns(logger) logger.expects(:level=).with(Logger::DEBUG) ActiveRecord::Base.stubs(:allow_concurrency=) ActiveRecord::Base.stubs(:verify_active_connections!) ActiveRecord::Base.stubs(:establish_connection) Puppet::Rails.stubs(:database_arguments).returns({}) Puppet::Rails.connect end describe "ActiveRecord Version" do it "should set ActiveRecord::Base.allow_concurrency if ActiveRecord is 2.1" do Puppet::Util.stubs(:activerecord_version).returns(2.1) ActiveRecord::Base.expects(:allow_concurrency=).with(true) Puppet::Rails.connect end it "should not set ActiveRecord::Base.allow_concurrency if ActiveRecord is >= 2.2" do Puppet::Util.stubs(:activerecord_version).returns(2.2) ActiveRecord::Base.expects(:allow_concurrency=).never Puppet::Rails.connect end end it "should call ActiveRecord::Base.verify_active_connections!" do ActiveRecord::Base.expects(:verify_active_connections!) Puppet::Rails.connect end it "should call ActiveRecord::Base.establish_connection with database_arguments" do Puppet::Rails.expects(:database_arguments).returns({}) ActiveRecord::Base.expects(:establish_connection) Puppet::Rails.connect end end describe Puppet::Rails, "when initializing a sqlite3 connection", :if => Puppet.features.rails? do it "should provide the adapter, log_level, and database arguments" do Puppet.settings.expects(:value).with(:dbadapter).returns("sqlite3") Puppet.settings.expects(:value).with(:rails_loglevel).returns("testlevel") Puppet.settings.expects(:value).with(:dblocation).returns("testlocation") Puppet::Rails.database_arguments.should == { :adapter => "sqlite3", :log_level => "testlevel", :database => "testlocation" } end end describe Puppet::Rails, "when initializing a mysql connection", :if => Puppet.features.rails? do it "should provide the adapter, log_level, and host, port, username, password, database, and reconnect arguments" do Puppet.settings.stubs(:value).with(:dbadapter).returns("mysql") Puppet.settings.stubs(:value).with(:rails_loglevel).returns("testlevel") Puppet.settings.stubs(:value).with(:dbserver).returns("testserver") Puppet.settings.stubs(:value).with(:dbport).returns("") Puppet.settings.stubs(:value).with(:dbuser).returns("testuser") Puppet.settings.stubs(:value).with(:dbpassword).returns("testpassword") Puppet.settings.stubs(:value).with(:dbconnections).returns((pool_size = 45).to_s) Puppet.settings.stubs(:value).with(:dbname).returns("testname") Puppet.settings.stubs(:value).with(:dbsocket).returns("") Puppet::Rails.database_arguments.should == { :adapter => "mysql", :log_level => "testlevel", :host => "testserver", :username => "testuser", :password => "testpassword", :pool => pool_size, :database => "testname", :reconnect => true } end it "should provide the adapter, log_level, and host, port, username, password, database, socket, connections, and reconnect arguments" do Puppet.settings.stubs(:value).with(:dbadapter).returns("mysql") Puppet.settings.stubs(:value).with(:rails_loglevel).returns("testlevel") Puppet.settings.stubs(:value).with(:dbserver).returns("testserver") Puppet.settings.stubs(:value).with(:dbport).returns("9999") Puppet.settings.stubs(:value).with(:dbuser).returns("testuser") Puppet.settings.stubs(:value).with(:dbpassword).returns("testpassword") Puppet.settings.stubs(:value).with(:dbconnections).returns((pool_size = 12).to_s) Puppet.settings.stubs(:value).with(:dbname).returns("testname") Puppet.settings.stubs(:value).with(:dbsocket).returns("testsocket") Puppet::Rails.database_arguments.should == { :adapter => "mysql", :log_level => "testlevel", :host => "testserver", :port => "9999", :username => "testuser", :password => "testpassword", :pool => pool_size, :database => "testname", :socket => "testsocket", :reconnect => true } end it "should provide the adapter, log_level, and host, port, username, password, database, socket, and connections arguments" do Puppet.settings.stubs(:value).with(:dbadapter).returns("mysql") Puppet.settings.stubs(:value).with(:rails_loglevel).returns("testlevel") Puppet.settings.stubs(:value).with(:dbserver).returns("testserver") Puppet.settings.stubs(:value).with(:dbport).returns("9999") Puppet.settings.stubs(:value).with(:dbuser).returns("testuser") Puppet.settings.stubs(:value).with(:dbpassword).returns("testpassword") Puppet.settings.stubs(:value).with(:dbconnections).returns((pool_size = 23).to_s) Puppet.settings.stubs(:value).with(:dbname).returns("testname") Puppet.settings.stubs(:value).with(:dbsocket).returns("testsocket") Puppet::Rails.database_arguments.should == { :adapter => "mysql", :log_level => "testlevel", :host => "testserver", :port => "9999", :username => "testuser", :password => "testpassword", :pool => pool_size, :database => "testname", :socket => "testsocket", :reconnect => true } end it "should not provide the pool if dbconnections is 0, '0', or ''" do Puppet.settings.stubs(:value).with(:dbadapter).returns("mysql") Puppet.settings.stubs(:value).with(:rails_loglevel).returns("testlevel") Puppet.settings.stubs(:value).with(:dbserver).returns("testserver") Puppet.settings.stubs(:value).with(:dbport).returns("9999") Puppet.settings.stubs(:value).with(:dbuser).returns("testuser") Puppet.settings.stubs(:value).with(:dbpassword).returns("testpassword") Puppet.settings.stubs(:value).with(:dbname).returns("testname") Puppet.settings.stubs(:value).with(:dbsocket).returns("testsocket") Puppet.settings.stubs(:value).with(:dbconnections).returns(0) Puppet::Rails.database_arguments.should_not be_include(:pool) Puppet.settings.stubs(:value).with(:dbconnections).returns('0') Puppet::Rails.database_arguments.should_not be_include(:pool) Puppet.settings.stubs(:value).with(:dbconnections).returns('') Puppet::Rails.database_arguments.should_not be_include(:pool) end end describe Puppet::Rails, "when initializing a postgresql connection", :if => Puppet.features.rails? do it "should provide the adapter, log_level, and host, port, username, password, connections, and database arguments" do Puppet.settings.stubs(:value).with(:dbadapter).returns("postgresql") Puppet.settings.stubs(:value).with(:rails_loglevel).returns("testlevel") Puppet.settings.stubs(:value).with(:dbserver).returns("testserver") Puppet.settings.stubs(:value).with(:dbport).returns("9999") Puppet.settings.stubs(:value).with(:dbuser).returns("testuser") Puppet.settings.stubs(:value).with(:dbpassword).returns("testpassword") Puppet.settings.stubs(:value).with(:dbconnections).returns((pool_size = 200).to_s) Puppet.settings.stubs(:value).with(:dbname).returns("testname") Puppet.settings.stubs(:value).with(:dbsocket).returns("") Puppet::Rails.database_arguments.should == { :adapter => "postgresql", :log_level => "testlevel", :host => "testserver", :port => "9999", :username => "testuser", :password => "testpassword", :pool => pool_size, :database => "testname", :reconnect => true } end it "should provide the adapter, log_level, and host, port, username, password, database, connections, and socket arguments" do Puppet.settings.stubs(:value).with(:dbadapter).returns("postgresql") Puppet.settings.stubs(:value).with(:rails_loglevel).returns("testlevel") Puppet.settings.stubs(:value).with(:dbserver).returns("testserver") Puppet.settings.stubs(:value).with(:dbport).returns("9999") Puppet.settings.stubs(:value).with(:dbuser).returns("testuser") Puppet.settings.stubs(:value).with(:dbpassword).returns("testpassword") Puppet.settings.stubs(:value).with(:dbconnections).returns((pool_size = 122).to_s) Puppet.settings.stubs(:value).with(:dbname).returns("testname") Puppet.settings.stubs(:value).with(:dbsocket).returns("testsocket") Puppet::Rails.database_arguments.should == { :adapter => "postgresql", :log_level => "testlevel", :host => "testserver", :port => "9999", :username => "testuser", :password => "testpassword", :pool => pool_size, :database => "testname", :socket => "testsocket", :reconnect => true } end it "should not provide the pool if dbconnections is 0, '0', or ''" do Puppet.settings.stubs(:value).with(:dbadapter).returns("mysql") Puppet.settings.stubs(:value).with(:rails_loglevel).returns("testlevel") Puppet.settings.stubs(:value).with(:dbserver).returns("testserver") Puppet.settings.stubs(:value).with(:dbport).returns("9999") Puppet.settings.stubs(:value).with(:dbuser).returns("testuser") Puppet.settings.stubs(:value).with(:dbpassword).returns("testpassword") Puppet.settings.stubs(:value).with(:dbname).returns("testname") Puppet.settings.stubs(:value).with(:dbsocket).returns("testsocket") Puppet.settings.stubs(:value).with(:dbconnections).returns(0) Puppet::Rails.database_arguments.should_not be_include(:pool) Puppet.settings.stubs(:value).with(:dbconnections).returns('0') Puppet::Rails.database_arguments.should_not be_include(:pool) Puppet.settings.stubs(:value).with(:dbconnections).returns('') Puppet::Rails.database_arguments.should_not be_include(:pool) end end describe Puppet::Rails, "when initializing an Oracle connection", :if => Puppet.features.rails? do it "should provide the adapter, log_level, and username, password, and database arguments" do Puppet.settings.stubs(:value).with(:dbadapter).returns("oracle_enhanced") Puppet.settings.stubs(:value).with(:rails_loglevel).returns("testlevel") Puppet.settings.stubs(:value).with(:dbuser).returns("testuser") Puppet.settings.stubs(:value).with(:dbpassword).returns("testpassword") Puppet.settings.stubs(:value).with(:dbconnections).returns((pool_size = 123).to_s) Puppet.settings.stubs(:value).with(:dbname).returns("testname") Puppet::Rails.database_arguments.should == { :adapter => "oracle_enhanced", :log_level => "testlevel", :username => "testuser", :password => "testpassword", :pool => pool_size, :database => "testname" } end it "should provide the adapter, log_level, and host, username, password, database and socket arguments" do Puppet.settings.stubs(:value).with(:dbadapter).returns("oracle_enhanced") Puppet.settings.stubs(:value).with(:rails_loglevel).returns("testlevel") Puppet.settings.stubs(:value).with(:dbuser).returns("testuser") Puppet.settings.stubs(:value).with(:dbpassword).returns("testpassword") Puppet.settings.stubs(:value).with(:dbconnections).returns((pool_size = 124).to_s) Puppet.settings.stubs(:value).with(:dbname).returns("testname") Puppet::Rails.database_arguments.should == { :adapter => "oracle_enhanced", :log_level => "testlevel", :username => "testuser", :password => "testpassword", :pool => pool_size, :database => "testname" } end it "should not provide the pool if dbconnections is 0, '0', or ''" do Puppet.settings.stubs(:value).with(:dbadapter).returns("mysql") Puppet.settings.stubs(:value).with(:rails_loglevel).returns("testlevel") Puppet.settings.stubs(:value).with(:dbserver).returns("testserver") Puppet.settings.stubs(:value).with(:dbport).returns("9999") Puppet.settings.stubs(:value).with(:dbuser).returns("testuser") Puppet.settings.stubs(:value).with(:dbpassword).returns("testpassword") Puppet.settings.stubs(:value).with(:dbname).returns("testname") Puppet.settings.stubs(:value).with(:dbsocket).returns("testsocket") Puppet.settings.stubs(:value).with(:dbconnections).returns(0) Puppet::Rails.database_arguments.should_not be_include(:pool) Puppet.settings.stubs(:value).with(:dbconnections).returns('0') Puppet::Rails.database_arguments.should_not be_include(:pool) Puppet.settings.stubs(:value).with(:dbconnections).returns('') Puppet::Rails.database_arguments.should_not be_include(:pool) end end diff --git a/spec/unit/relationship_spec.rb b/spec/unit/relationship_spec.rb index 349be7c1a..a7e787b46 100755 --- a/spec/unit/relationship_spec.rb +++ b/spec/unit/relationship_spec.rb @@ -1,232 +1,232 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Created by Luke Kanies on 2007-11-1. # Copyright (c) 2006. All rights reserved. require 'spec_helper' require 'puppet/relationship' describe Puppet::Relationship do before do @edge = Puppet::Relationship.new(:a, :b) end it "should have a :source attribute" do @edge.should respond_to(:source) end it "should have a :target attribute" do @edge.should respond_to(:target) end it "should have a :callback attribute" do @edge.callback = :foo @edge.callback.should == :foo end it "should have an :event attribute" do @edge.event = :NONE @edge.event.should == :NONE end it "should require a callback if a non-NONE event is specified" do proc { @edge.event = :something }.should raise_error(ArgumentError) end it "should have a :label attribute" do @edge.should respond_to(:label) end it "should provide a :ref method that describes the edge" do @edge = Puppet::Relationship.new("a", "b") @edge.ref.should == "a => b" end it "should be able to produce a label as a hash with its event and callback" do @edge.callback = :foo @edge.event = :bar @edge.label.should == {:callback => :foo, :event => :bar} end it "should work if nil options are provided" do lambda { Puppet::Relationship.new("a", "b", nil) }.should_not raise_error end end describe Puppet::Relationship, " when initializing" do before do @edge = Puppet::Relationship.new(:a, :b) end it "should use the first argument as the source" do @edge.source.should == :a end it "should use the second argument as the target" do @edge.target.should == :b end it "should set the rest of the arguments as the event and callback" do @edge = Puppet::Relationship.new(:a, :b, :callback => :foo, :event => :bar) @edge.callback.should == :foo @edge.event.should == :bar end it "should accept events specified as strings" do @edge = Puppet::Relationship.new(:a, :b, "event" => :NONE) @edge.event.should == :NONE end it "should accept callbacks specified as strings" do @edge = Puppet::Relationship.new(:a, :b, "callback" => :foo) @edge.callback.should == :foo end end describe Puppet::Relationship, " when matching edges with no specified event" do before do @edge = Puppet::Relationship.new(:a, :b) end it "should not match :NONE" do @edge.should_not be_match(:NONE) end it "should not match :ALL_EVENTS" do @edge.should_not be_match(:NONE) end it "should not match any other events" do @edge.should_not be_match(:whatever) end end describe Puppet::Relationship, " when matching edges with :NONE as the event" do before do @edge = Puppet::Relationship.new(:a, :b, :event => :NONE) end it "should not match :NONE" do @edge.should_not be_match(:NONE) end it "should not match :ALL_EVENTS" do @edge.should_not be_match(:ALL_EVENTS) end it "should not match other events" do @edge.should_not be_match(:yayness) end end describe Puppet::Relationship, " when matching edges with :ALL as the event" do before do @edge = Puppet::Relationship.new(:a, :b, :event => :ALL_EVENTS, :callback => :whatever) end it "should not match :NONE" do @edge.should_not be_match(:NONE) end it "should match :ALL_EVENTS" do @edge.should be_match(:ALLEVENTS) end it "should match all other events" do @edge.should be_match(:foo) end end describe Puppet::Relationship, " when matching edges with a non-standard event" do before do @edge = Puppet::Relationship.new(:a, :b, :event => :random, :callback => :whatever) end it "should not match :NONE" do @edge.should_not be_match(:NONE) end it "should not match :ALL_EVENTS" do @edge.should_not be_match(:ALL_EVENTS) end it "should match events with the same name" do @edge.should be_match(:random) end end describe Puppet::Relationship, "when converting to pson", :if => Puppet.features.pson? do before do @edge = Puppet::Relationship.new(:a, :b, :event => :random, :callback => :whatever) end it "should store the stringified source as the source in the data" do PSON.parse(@edge.to_pson)["source"].should == "a" end it "should store the stringified target as the target in the data" do PSON.parse(@edge.to_pson)['target'].should == "b" end it "should store the psonified event as the event in the data" do PSON.parse(@edge.to_pson)["event"].should == "random" end it "should not store an event when none is set" do @edge.event = nil PSON.parse(@edge.to_pson)["event"].should be_nil end it "should store the psonified callback as the callback in the data" do @edge.callback = "whatever" PSON.parse(@edge.to_pson)["callback"].should == "whatever" end it "should not store a callback when none is set in the edge" do @edge.callback = nil PSON.parse(@edge.to_pson)["callback"].should be_nil end end describe Puppet::Relationship, "when converting from pson", :if => Puppet.features.pson? do before do @event = "random" @callback = "whatever" @data = { "source" => "mysource", "target" => "mytarget", "event" => @event, "callback" => @callback } @pson = { "type" => "Puppet::Relationship", "data" => @data } end def pson_result_should Puppet::Relationship.expects(:new).with { |*args| yield args } end it "should be extended with the PSON utility module" do Puppet::Relationship.singleton_class.ancestors.should be_include(Puppet::Util::Pson) end # LAK:NOTE For all of these tests, we convert back to the edge so we can # trap the actual data structure then. it "should pass the source in as the first argument" do Puppet::Relationship.from_pson("source" => "mysource", "target" => "mytarget").source.should == "mysource" end it "should pass the target in as the second argument" do Puppet::Relationship.from_pson("source" => "mysource", "target" => "mytarget").target.should == "mytarget" end it "should pass the event as an argument if it's provided" do Puppet::Relationship.from_pson("source" => "mysource", "target" => "mytarget", "event" => "myevent", "callback" => "eh").event.should == "myevent" end it "should pass the callback as an argument if it's provided" do Puppet::Relationship.from_pson("source" => "mysource", "target" => "mytarget", "callback" => "mycallback").callback.should == "mycallback" end end diff --git a/spec/unit/reports/http_spec.rb b/spec/unit/reports/http_spec.rb index acf0c045c..d7c37bfdd 100755 --- a/spec/unit/reports/http_spec.rb +++ b/spec/unit/reports/http_spec.rb @@ -1,56 +1,55 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/reports' # FakeHTTP fakes the behavior of Net::HTTP#request and acts as a sensor for an # otherwise difficult to trace method call. # class FakeHTTP REQUESTS = {} def self.request(req) REQUESTS[req.path] = req end end processor = Puppet::Reports.report(:http) describe processor do before { Net::HTTP.any_instance.stubs(:start).yields(FakeHTTP) } subject { Puppet::Transaction::Report.new("apply").extend(processor) } it { should respond_to(:process) } it "should use the reporturl setting's host and port" do uri = URI.parse(Puppet[:reporturl]) Net::HTTP.expects(:new).with(uri.host, uri.port).returns(stub_everything('http')) subject.process end describe "request" do before { subject.process } describe "path" do it "should use the path specified by the 'reporturl' setting" do reports_request.path.should == URI.parse(Puppet[:reporturl]).path end end describe "body" do it "should be the report as YAML" do reports_request.body.should == subject.to_yaml end end describe "content type" do it "should be 'application/x-yaml'" do reports_request.content_type.should == "application/x-yaml" end end end private def reports_request; FakeHTTP::REQUESTS[URI.parse(Puppet[:reporturl]).path] end end diff --git a/spec/unit/reports/rrdgraph_spec.rb b/spec/unit/reports/rrdgraph_spec.rb index 1443b53e0..3c2704a7a 100755 --- a/spec/unit/reports/rrdgraph_spec.rb +++ b/spec/unit/reports/rrdgraph_spec.rb @@ -1,31 +1,30 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/reports' processor = Puppet::Reports.report(:rrdgraph) describe processor do include PuppetSpec::Files before do Puppet[:rrddir] = tmpdir('rrdgraph') Puppet.settings.use :master end after do FileUtils.rm_rf(Puppet[:rrddir]) end it "should not error on 0.25.x report format" do report = YAML.load_file(File.join(PuppetSpec::FIXTURE_DIR, 'yaml/report0.25.x.yaml')).extend processor report.expects(:mkhtml) lambda{ report.process }.should_not raise_error end it "should not error on 2.6.x report format" do report = YAML.load_file(File.join(PuppetSpec::FIXTURE_DIR, 'yaml/report2.6.x.yaml')).extend processor report.expects(:mkhtml) lambda{ report.process }.should_not raise_error end end diff --git a/spec/unit/reports/store_spec.rb b/spec/unit/reports/store_spec.rb index 659940aa1..73a7e353f 100755 --- a/spec/unit/reports/store_spec.rb +++ b/spec/unit/reports/store_spec.rb @@ -1,31 +1,30 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/reports' require 'time' processor = Puppet::Reports.report(:store) describe processor do describe "#process" do include PuppetSpec::Files before :each do Puppet[:reportdir] = tmpdir('reports') << '/reports' @report = YAML.load_file(File.join(PuppetSpec::FIXTURE_DIR, 'yaml/report2.6.x.yaml')).extend processor end it "should create a report directory for the client if one doesn't exist" do @report.process File.should be_directory(File.join(Puppet[:reportdir], @report.host)) end it "should write the report to the file in YAML" do Time.stubs(:now).returns(Time.parse("2011-01-06 12:00:00 UTC")) @report.process File.read(File.join(Puppet[:reportdir], @report.host, "201101061200.yaml")).should == @report.to_yaml end end end diff --git a/spec/unit/reports/tagmail_spec.rb b/spec/unit/reports/tagmail_spec.rb index 9d67e7acb..a53d11978 100755 --- a/spec/unit/reports/tagmail_spec.rb +++ b/spec/unit/reports/tagmail_spec.rb @@ -1,92 +1,91 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/reports' tagmail = Puppet::Reports.report(:tagmail) describe tagmail do before do @processor = Puppet::Transaction::Report.new("apply") @processor.extend(Puppet::Reports.report(:tagmail)) end passers = my_fixture "tagmail_passers.conf" File.readlines(passers).each do |line| it "should be able to parse '#{line.inspect}'" do @processor.parse(line) end end failers = my_fixture "tagmail_failers.conf" File.readlines(failers).each do |line| it "should not be able to parse '#{line.inspect}'" do lambda { @processor.parse(line) }.should raise_error(ArgumentError) end end { "tag: abuse@domain.com" => [%w{abuse@domain.com}, %w{tag}, []], "tag.localhost: abuse@domain.com" => [%w{abuse@domain.com}, %w{tag.localhost}, []], "tag, other: abuse@domain.com" => [%w{abuse@domain.com}, %w{tag other}, []], "tag-other: abuse@domain.com" => [%w{abuse@domain.com}, %w{tag-other}, []], "tag, !other: abuse@domain.com" => [%w{abuse@domain.com}, %w{tag}, %w{other}], "tag, !other, one, !two: abuse@domain.com" => [%w{abuse@domain.com}, %w{tag one}, %w{other two}], "tag: abuse@domain.com, other@domain.com" => [%w{abuse@domain.com other@domain.com}, %w{tag}, []] }.each do |line, results| it "should parse '#{line}' as #{results.inspect}" do @processor.parse(line).shift.should == results end end describe "when matching logs" do before do @processor << Puppet::Util::Log.new(:level => :notice, :message => "first", :tags => %w{one}) @processor << Puppet::Util::Log.new(:level => :notice, :message => "second", :tags => %w{one two}) @processor << Puppet::Util::Log.new(:level => :notice, :message => "third", :tags => %w{one two three}) end def match(pos = [], neg = []) pos = Array(pos) neg = Array(neg) result = @processor.match([[%w{abuse@domain.com}, pos, neg]]) actual_result = result.shift if actual_result actual_result[1] else nil end end it "should match all messages when provided the 'all' tag as a positive matcher" do results = match("all") %w{first second third}.each do |str| results.should be_include(str) end end it "should remove messages that match a negated tag" do match("all", "three").should_not be_include("third") end it "should find any messages tagged with a provided tag" do results = match("two") results.should be_include("second") results.should be_include("third") results.should_not be_include("first") end it "should allow negation of specific tags from a specific tag list" do results = match("two", "three") results.should be_include("second") results.should_not be_include("third") end it "should allow a tag to negate all matches" do results = match([], "one") results.should be_nil end end end diff --git a/spec/unit/reports_spec.rb b/spec/unit/reports_spec.rb index 52608aeb3..a4b2e04a9 100755 --- a/spec/unit/reports_spec.rb +++ b/spec/unit/reports_spec.rb @@ -1,61 +1,60 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/reports' describe Puppet::Reports do it "should instance-load report types" do Puppet::Reports.instance_loader(:report).should be_instance_of(Puppet::Util::Autoload) end it "should have a method for registering report types" do Puppet::Reports.should respond_to(:register_report) end it "should have a method for retrieving report types by name" do Puppet::Reports.should respond_to(:report) end it "should provide a method for returning documentation for all reports" do Puppet::Reports.expects(:loaded_instances).with(:report).returns([:one, :two]) one = mock 'one', :doc => "onedoc" two = mock 'two', :doc => "twodoc" Puppet::Reports.expects(:report).with(:one).returns(one) Puppet::Reports.expects(:report).with(:two).returns(two) doc = Puppet::Reports.reportdocs doc.include?("onedoc").should be_true doc.include?("twodoc").should be_true end end describe Puppet::Reports, " when loading report types" do it "should use the instance loader to retrieve report types" do Puppet::Reports.expects(:loaded_instance).with(:report, :myreporttype) Puppet::Reports.report(:myreporttype) end end describe Puppet::Reports, " when registering report types" do it "should evaluate the supplied block as code for a module" do Puppet::Reports.expects(:genmodule).returns(Module.new) Puppet::Reports.register_report(:testing) { } end it "should extend the report type with the Puppet::Util::Docs module" do mod = stub 'module', :define_method => true Puppet::Reports.expects(:genmodule).with { |name, options, block| options[:extend] == Puppet::Util::Docs }.returns(mod) Puppet::Reports.register_report(:testing) { } end it "should define a :report_name method in the module that returns the name of the report" do mod = mock 'module' mod.expects(:define_method).with(:report_name) Puppet::Reports.expects(:genmodule).returns(mod) Puppet::Reports.register_report(:testing) { } end end diff --git a/spec/unit/resource/catalog_spec.rb b/spec/unit/resource/catalog_spec.rb index 59073c351..ae65aa91a 100755 --- a/spec/unit/resource/catalog_spec.rb +++ b/spec/unit/resource/catalog_spec.rb @@ -1,1062 +1,1061 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe Puppet::Resource::Catalog, "when compiling" do before do @basepath = Puppet.features.posix? ? "/somepath" : "C:/somepath" # stub this to not try to create state.yaml Puppet::Util::Storage.stubs(:store) end it "should be an Expirer" do Puppet::Resource::Catalog.ancestors.should be_include(Puppet::Util::Cacher::Expirer) end it "should always be expired if it's not applying" do @catalog = Puppet::Resource::Catalog.new("host") @catalog.expects(:applying?).returns false @catalog.should be_dependent_data_expired(Time.now) end it "should not be expired if it's applying and the timestamp is late enough" do @catalog = Puppet::Resource::Catalog.new("host") @catalog.expire @catalog.expects(:applying?).returns true @catalog.should_not be_dependent_data_expired(Time.now) end it "should be able to write its list of classes to the class file" do @catalog = Puppet::Resource::Catalog.new("host") @catalog.add_class "foo", "bar" Puppet.settings.expects(:value).with(:classfile).returns "/class/file" fh = mock 'filehandle' File.expects(:open).with("/class/file", "w").yields fh fh.expects(:puts).with "foo\nbar" @catalog.write_class_file end it "should have a client_version attribute" do @catalog = Puppet::Resource::Catalog.new("host") @catalog.client_version = 5 @catalog.client_version.should == 5 end it "should have a server_version attribute" do @catalog = Puppet::Resource::Catalog.new("host") @catalog.server_version = 5 @catalog.server_version.should == 5 end describe "when compiling" do it "should accept tags" do config = Puppet::Resource::Catalog.new("mynode") config.tag("one") config.tags.should == %w{one} end it "should accept multiple tags at once" do config = Puppet::Resource::Catalog.new("mynode") config.tag("one", "two") config.tags.should == %w{one two} end it "should convert all tags to strings" do config = Puppet::Resource::Catalog.new("mynode") config.tag("one", :two) config.tags.should == %w{one two} end it "should tag with both the qualified name and the split name" do config = Puppet::Resource::Catalog.new("mynode") config.tag("one::two") config.tags.include?("one").should be_true config.tags.include?("one::two").should be_true end it "should accept classes" do config = Puppet::Resource::Catalog.new("mynode") config.add_class("one") config.classes.should == %w{one} config.add_class("two", "three") config.classes.should == %w{one two three} end it "should tag itself with passed class names" do config = Puppet::Resource::Catalog.new("mynode") config.add_class("one") config.tags.should == %w{one} end end describe "when extracting transobjects" do def mkscope @node = Puppet::Node.new("mynode") @compiler = Puppet::Parser::Compiler.new(@node) # XXX This is ridiculous. @compiler.send(:evaluate_main) @scope = @compiler.topscope end def mkresource(type, name) Puppet::Parser::Resource.new(type, name, :source => @source, :scope => @scope) end it "should fail if no 'main' stage can be found" do lambda { Puppet::Resource::Catalog.new("mynode").extract }.should raise_error(Puppet::DevError) end it "should warn if any non-main stages are present" do config = Puppet::Resource::Catalog.new("mynode") @scope = mkscope @source = mock 'source' main = mkresource("stage", "main") config.add_resource(main) other = mkresource("stage", "other") config.add_resource(other) Puppet.expects(:warning) config.extract end it "should always create a TransBucket for the 'main' stage" do config = Puppet::Resource::Catalog.new("mynode") @scope = mkscope @source = mock 'source' main = mkresource("stage", "main") config.add_resource(main) result = config.extract result.type.should == "Stage" result.name.should == "main" end # Now try it with a more complicated graph -- a three tier graph, each tier it "should transform arbitrarily deep graphs into isomorphic trees" do config = Puppet::Resource::Catalog.new("mynode") @scope = mkscope @scope.stubs(:tags).returns([]) @source = mock 'source' # Create our scopes. top = mkresource "stage", "main" config.add_resource top topbucket = [] topbucket.expects(:classes=).with([]) top.expects(:to_trans).returns(topbucket) topres = mkresource "file", "/top" topres.expects(:to_trans).returns(:topres) config.add_edge top, topres middle = mkresource "class", "middle" middle.expects(:to_trans).returns([]) config.add_edge top, middle midres = mkresource "file", "/mid" midres.expects(:to_trans).returns(:midres) config.add_edge middle, midres bottom = mkresource "class", "bottom" bottom.expects(:to_trans).returns([]) config.add_edge middle, bottom botres = mkresource "file", "/bot" botres.expects(:to_trans).returns(:botres) config.add_edge bottom, botres toparray = config.extract # This is annoying; it should look like: # [[[:botres], :midres], :topres] # but we can't guarantee sort order. toparray.include?(:topres).should be_true midarray = toparray.find { |t| t.is_a?(Array) } midarray.include?(:midres).should be_true botarray = midarray.find { |t| t.is_a?(Array) } botarray.include?(:botres).should be_true end end describe " when converting to a Puppet::Resource catalog" do before do @original = Puppet::Resource::Catalog.new("mynode") @original.tag(*%w{one two three}) @original.add_class *%w{four five six} @top = Puppet::TransObject.new 'top', "class" @topobject = Puppet::TransObject.new '/topobject', "file" @middle = Puppet::TransObject.new 'middle', "class" @middleobject = Puppet::TransObject.new '/middleobject', "file" @bottom = Puppet::TransObject.new 'bottom', "class" @bottomobject = Puppet::TransObject.new '/bottomobject', "file" @resources = [@top, @topobject, @middle, @middleobject, @bottom, @bottomobject] @original.add_resource(*@resources) @original.add_edge(@top, @topobject) @original.add_edge(@top, @middle) @original.add_edge(@middle, @middleobject) @original.add_edge(@middle, @bottom) @original.add_edge(@bottom, @bottomobject) @catalog = @original.to_resource end it "should copy over the version" do @original.version = "foo" @original.to_resource.version.should == "foo" end it "should convert parser resources to plain resources" do resource = Puppet::Parser::Resource.new(:file, "foo", :scope => stub("scope", :environment => nil, :namespaces => nil), :source => stub("source")) catalog = Puppet::Resource::Catalog.new("whev") catalog.add_resource(resource) new = catalog.to_resource new.resource(:file, "foo").class.should == Puppet::Resource end it "should add all resources as Puppet::Resource instances" do @resources.each { |resource| @catalog.resource(resource.ref).should be_instance_of(Puppet::Resource) } end it "should copy the tag list to the new catalog" do @catalog.tags.sort.should == @original.tags.sort end it "should copy the class list to the new catalog" do @catalog.classes.should == @original.classes end it "should duplicate the original edges" do @original.edges.each do |edge| @catalog.edge?(@catalog.resource(edge.source.ref), @catalog.resource(edge.target.ref)).should be_true end end it "should set itself as the catalog for each converted resource" do @catalog.vertices.each { |v| v.catalog.object_id.should equal(@catalog.object_id) } end end describe "when converting to a RAL catalog" do before do @original = Puppet::Resource::Catalog.new("mynode") @original.tag(*%w{one two three}) @original.add_class *%w{four five six} @top = Puppet::Resource.new :class, 'top' @topobject = Puppet::Resource.new :file, @basepath+'/topobject' @middle = Puppet::Resource.new :class, 'middle' @middleobject = Puppet::Resource.new :file, @basepath+'/middleobject' @bottom = Puppet::Resource.new :class, 'bottom' @bottomobject = Puppet::Resource.new :file, @basepath+'/bottomobject' @resources = [@top, @topobject, @middle, @middleobject, @bottom, @bottomobject] @original.add_resource(*@resources) @original.add_edge(@top, @topobject) @original.add_edge(@top, @middle) @original.add_edge(@middle, @middleobject) @original.add_edge(@middle, @bottom) @original.add_edge(@bottom, @bottomobject) @catalog = @original.to_ral end it "should add all resources as RAL instances" do @resources.each { |resource| @catalog.resource(resource.ref).should be_instance_of(Puppet::Type) } end it "should copy the tag list to the new catalog" do @catalog.tags.sort.should == @original.tags.sort end it "should copy the class list to the new catalog" do @catalog.classes.should == @original.classes end it "should duplicate the original edges" do @original.edges.each do |edge| @catalog.edge?(@catalog.resource(edge.source.ref), @catalog.resource(edge.target.ref)).should be_true end end it "should set itself as the catalog for each converted resource" do @catalog.vertices.each { |v| v.catalog.object_id.should equal(@catalog.object_id) } end # This tests #931. it "should not lose track of resources whose names vary" do changer = Puppet::TransObject.new 'changer', 'test' config = Puppet::Resource::Catalog.new('test') config.add_resource(changer) config.add_resource(@top) config.add_edge(@top, changer) resource = stub 'resource', :name => "changer2", :title => "changer2", :ref => "Test[changer2]", :catalog= => nil, :remove => nil #changer is going to get duplicated as part of a fix for aliases 1094 changer.expects(:dup).returns(changer) changer.expects(:to_ral).returns(resource) newconfig = nil proc { @catalog = config.to_ral }.should_not raise_error @catalog.resource("Test[changer2]").should equal(resource) end after do # Remove all resource instances. @catalog.clear(true) end end describe "when filtering" do before :each do @original = Puppet::Resource::Catalog.new("mynode") @original.tag(*%w{one two three}) @original.add_class *%w{four five six} @r1 = stub_everything 'r1', :ref => "File[/a]" @r1.stubs(:respond_to?).with(:ref).returns(true) @r1.stubs(:dup).returns(@r1) @r1.stubs(:is_a?).returns(Puppet::Resource).returns(true) @r2 = stub_everything 'r2', :ref => "File[/b]" @r2.stubs(:respond_to?).with(:ref).returns(true) @r2.stubs(:dup).returns(@r2) @r2.stubs(:is_a?).returns(Puppet::Resource).returns(true) @resources = [@r1,@r2] @original.add_resource(@r1,@r2) end it "should transform the catalog to a resource catalog" do @original.expects(:to_catalog).with { |h,b| h == :to_resource } @original.filter end it "should scan each catalog resource in turn and apply filtering block" do @resources.each { |r| r.expects(:test?) } @original.filter do |r| r.test? end end it "should filter out resources which produce true when the filter block is evaluated" do @original.filter do |r| r == @r1 end.resource("File[/a]").should be_nil end it "should not consider edges against resources that were filtered out" do @original.add_edge(@r1,@r2) @original.filter do |r| r == @r1 end.edge?(@r1,@r2).should_not be end end describe "when functioning as a resource container" do before do @catalog = Puppet::Resource::Catalog.new("host") @one = Puppet::Type.type(:notify).new :name => "one" @two = Puppet::Type.type(:notify).new :name => "two" @dupe = Puppet::Type.type(:notify).new :name => "one" end it "should provide a method to add one or more resources" do @catalog.add_resource @one, @two @catalog.resource(@one.ref).should equal(@one) @catalog.resource(@two.ref).should equal(@two) end it "should add resources to the relationship graph if it exists" do relgraph = @catalog.relationship_graph @catalog.add_resource @one relgraph.should be_vertex(@one) end it "should set itself as the resource's catalog if it is not a relationship graph" do @one.expects(:catalog=).with(@catalog) @catalog.add_resource @one end it "should make all vertices available by resource reference" do @catalog.add_resource(@one) @catalog.resource(@one.ref).should equal(@one) @catalog.vertices.find { |r| r.ref == @one.ref }.should equal(@one) end it "should canonize how resources are referred to during retrieval when both type and title are provided" do @catalog.add_resource(@one) @catalog.resource("notify", "one").should equal(@one) end it "should canonize how resources are referred to during retrieval when just the title is provided" do @catalog.add_resource(@one) @catalog.resource("notify[one]", nil).should equal(@one) end it "should not allow two resources with the same resource reference" do @catalog.add_resource(@one) proc { @catalog.add_resource(@dupe) }.should raise_error(Puppet::Resource::Catalog::DuplicateResourceError) end it "should not store objects that do not respond to :ref" do proc { @catalog.add_resource("thing") }.should raise_error(ArgumentError) end it "should remove all resources when asked" do @catalog.add_resource @one @catalog.add_resource @two @one.expects :remove @two.expects :remove @catalog.clear(true) end it "should support a mechanism for finishing resources" do @one.expects :finish @two.expects :finish @catalog.add_resource @one @catalog.add_resource @two @catalog.finalize end it "should make default resources when finalizing" do @catalog.expects(:make_default_resources) @catalog.finalize end it "should add default resources to the catalog upon creation" do @catalog.make_default_resources @catalog.resource(:schedule, "daily").should_not be_nil end it "should optionally support an initialization block and should finalize after such blocks" do @one.expects :finish @two.expects :finish config = Puppet::Resource::Catalog.new("host") do |conf| conf.add_resource @one conf.add_resource @two end end it "should inform the resource that it is the resource's catalog" do @one.expects(:catalog=).with(@catalog) @catalog.add_resource @one end it "should be able to find resources by reference" do @catalog.add_resource @one @catalog.resource(@one.ref).should equal(@one) end it "should be able to find resources by reference or by type/title tuple" do @catalog.add_resource @one @catalog.resource("notify", "one").should equal(@one) end it "should have a mechanism for removing resources" do @catalog.add_resource @one @one.expects :remove @catalog.remove_resource(@one) @catalog.resource(@one.ref).should be_nil @catalog.vertex?(@one).should be_false end it "should have a method for creating aliases for resources" do @catalog.add_resource @one @catalog.alias(@one, "other") @catalog.resource("notify", "other").should equal(@one) end it "should ignore conflicting aliases that point to the aliased resource" do @catalog.alias(@one, "other") lambda { @catalog.alias(@one, "other") }.should_not raise_error end it "should create aliases for resources isomorphic resources whose names do not match their titles" do resource = Puppet::Type::File.new(:title => "testing", :path => @basepath+"/something") @catalog.add_resource(resource) @catalog.resource(:file, @basepath+"/something").should equal(resource) end it "should not create aliases for resources non-isomorphic resources whose names do not match their titles" do resource = Puppet::Type.type(:exec).new(:title => "testing", :command => "echo", :path => %w{/bin /usr/bin /usr/local/bin}) @catalog.add_resource(resource) # Yay, I've already got a 'should' method @catalog.resource(:exec, "echo").object_id.should == nil.object_id end # This test is the same as the previous, but the behaviour should be explicit. it "should alias using the class name from the resource reference, not the resource class name" do @catalog.add_resource @one @catalog.alias(@one, "other") @catalog.resource("notify", "other").should equal(@one) end it "should ignore conflicting aliases that point to the aliased resource" do @catalog.alias(@one, "other") lambda { @catalog.alias(@one, "other") }.should_not raise_error end it "should fail to add an alias if the aliased name already exists" do @catalog.add_resource @one proc { @catalog.alias @two, "one" }.should raise_error(ArgumentError) end it "should not fail when a resource has duplicate aliases created" do @catalog.add_resource @one proc { @catalog.alias @one, "one" }.should_not raise_error end it "should not create aliases that point back to the resource" do @catalog.alias(@one, "one") @catalog.resource(:notify, "one").should be_nil end it "should be able to look resources up by their aliases" do @catalog.add_resource @one @catalog.alias @one, "two" @catalog.resource(:notify, "two").should equal(@one) end it "should remove resource aliases when the target resource is removed" do @catalog.add_resource @one @catalog.alias(@one, "other") @one.expects :remove @catalog.remove_resource(@one) @catalog.resource("notify", "other").should be_nil end it "should add an alias for the namevar when the title and name differ on isomorphic resource types" do resource = Puppet::Type.type(:file).new :path => @basepath+"/something", :title => "other", :content => "blah" resource.expects(:isomorphic?).returns(true) @catalog.add_resource(resource) @catalog.resource(:file, "other").should equal(resource) @catalog.resource(:file, @basepath+"/something").ref.should == resource.ref end it "should not add an alias for the namevar when the title and name differ on non-isomorphic resource types" do resource = Puppet::Type.type(:file).new :path => @basepath+"/something", :title => "other", :content => "blah" resource.expects(:isomorphic?).returns(false) @catalog.add_resource(resource) @catalog.resource(:file, resource.title).should equal(resource) # We can't use .should here, because the resources respond to that method. raise "Aliased non-isomorphic resource" if @catalog.resource(:file, resource.name) end it "should provide a method to create additional resources that also registers the resource" do args = {:name => "/yay", :ensure => :file} resource = stub 'file', :ref => "File[/yay]", :catalog= => @catalog, :title => "/yay", :[] => "/yay" Puppet::Type.type(:file).expects(:new).with(args).returns(resource) @catalog.create_resource :file, args @catalog.resource("File[/yay]").should equal(resource) end end describe "when applying" do before :each do @catalog = Puppet::Resource::Catalog.new("host") @transaction = mock 'transaction' Puppet::Transaction.stubs(:new).returns(@transaction) @transaction.stubs(:evaluate) @transaction.stubs(:add_times) Puppet.settings.stubs(:use) end it "should create and evaluate a transaction" do @transaction.expects(:evaluate) @catalog.apply end it "should provide the catalog retrieval time to the transaction" do @catalog.retrieval_duration = 5 @transaction.expects(:add_times).with(:config_retrieval => 5) @catalog.apply end it "should use a retrieval time of 0 if none is set in the catalog" do @catalog.retrieval_duration = nil @transaction.expects(:add_times).with(:config_retrieval => 0) @catalog.apply end it "should return the transaction" do @catalog.apply.should equal(@transaction) end it "should yield the transaction if a block is provided" do @catalog.apply do |trans| trans.should equal(@transaction) end end it "should default to being a host catalog" do @catalog.host_config.should be_true end it "should be able to be set to a non-host_config" do @catalog.host_config = false @catalog.host_config.should be_false end it "should pass supplied tags on to the transaction" do @transaction.expects(:tags=).with(%w{one two}) @catalog.apply(:tags => %w{one two}) end it "should set ignoreschedules on the transaction if specified in apply()" do @transaction.expects(:ignoreschedules=).with(true) @catalog.apply(:ignoreschedules => true) end it "should expire cached data in the resources both before and after the transaction" do @catalog.expects(:expire).times(2) @catalog.apply end describe "host catalogs" do # super() doesn't work in the setup method for some reason before do @catalog.host_config = true Puppet::Util::Storage.stubs(:store) end it "should initialize the state database before applying a catalog" do Puppet::Util::Storage.expects(:load) # Short-circuit the apply, so we know we're loading before the transaction Puppet::Transaction.expects(:new).raises ArgumentError proc { @catalog.apply }.should raise_error(ArgumentError) end it "should sync the state database after applying" do Puppet::Util::Storage.expects(:store) @transaction.stubs :any_failed? => false @catalog.apply end after { Puppet.settings.clear } end describe "non-host catalogs" do before do @catalog.host_config = false end it "should never send reports" do Puppet[:report] = true Puppet[:summarize] = true @catalog.apply end it "should never modify the state database" do Puppet::Util::Storage.expects(:load).never Puppet::Util::Storage.expects(:store).never @catalog.apply end after { Puppet.settings.clear } end end describe "when creating a relationship graph" do before do Puppet::Type.type(:component) @catalog = Puppet::Resource::Catalog.new("host") @compone = Puppet::Type::Component.new :name => "one" @comptwo = Puppet::Type::Component.new :name => "two", :require => "Class[one]" @file = Puppet::Type.type(:file) @one = @file.new :path => @basepath+"/one" @two = @file.new :path => @basepath+"/two" @sub = @file.new :path => @basepath+"/two/subdir" @catalog.add_edge @compone, @one @catalog.add_edge @comptwo, @two @three = @file.new :path => @basepath+"/three" @four = @file.new :path => @basepath+"/four", :require => "File[#{@basepath}/three]" @five = @file.new :path => @basepath+"/five" @catalog.add_resource @compone, @comptwo, @one, @two, @three, @four, @five, @sub @relationships = @catalog.relationship_graph end it "should be able to create a relationship graph" do @relationships.should be_instance_of(Puppet::SimpleGraph) end it "should not have any components" do @relationships.vertices.find { |r| r.instance_of?(Puppet::Type::Component) }.should be_nil end it "should have all non-component resources from the catalog" do # The failures print out too much info, so i just do a class comparison @relationships.vertex?(@five).should be_true end it "should have all resource relationships set as edges" do @relationships.edge?(@three, @four).should be_true end it "should copy component relationships to all contained resources" do @relationships.path_between(@one, @two).should be end it "should add automatic relationships to the relationship graph" do @relationships.edge?(@two, @sub).should be_true end it "should get removed when the catalog is cleaned up" do @relationships.expects(:clear) @catalog.clear @catalog.instance_variable_get("@relationship_graph").should be_nil end it "should write :relationships and :expanded_relationships graph files if the catalog is a host catalog" do @catalog.clear graph = Puppet::SimpleGraph.new Puppet::SimpleGraph.expects(:new).returns graph graph.expects(:write_graph).with(:relationships) graph.expects(:write_graph).with(:expanded_relationships) @catalog.host_config = true @catalog.relationship_graph end it "should not write graph files if the catalog is not a host catalog" do @catalog.clear graph = Puppet::SimpleGraph.new Puppet::SimpleGraph.expects(:new).returns graph graph.expects(:write_graph).never @catalog.host_config = false @catalog.relationship_graph end it "should create a new relationship graph after clearing the old one" do @relationships.expects(:clear) @catalog.clear @catalog.relationship_graph.should be_instance_of(Puppet::SimpleGraph) end it "should remove removed resources from the relationship graph if it exists" do @catalog.remove_resource(@one) @catalog.relationship_graph.vertex?(@one).should be_false end end describe "when writing dot files" do before do @catalog = Puppet::Resource::Catalog.new("host") @name = :test @file = File.join(Puppet[:graphdir], @name.to_s + ".dot") end it "should only write when it is a host catalog" do File.expects(:open).with(@file).never @catalog.host_config = false Puppet[:graph] = true @catalog.write_graph(@name) end after do Puppet.settings.clear end end describe "when indirecting" do before do @real_indirection = Puppet::Resource::Catalog.indirection @indirection = stub 'indirection', :name => :catalog Puppet::Util::Cacher.expire end it "should use the value of the 'catalog_terminus' setting to determine its terminus class" do # Puppet only checks the terminus setting the first time you ask # so this returns the object to the clean state # at the expense of making this test less pure Puppet::Resource::Catalog.indirection.reset_terminus_class Puppet.settings[:catalog_terminus] = "rest" Puppet::Resource::Catalog.indirection.terminus_class.should == :rest end it "should allow the terminus class to be set manually" do Puppet::Resource::Catalog.indirection.terminus_class = :rest Puppet::Resource::Catalog.indirection.terminus_class.should == :rest end after do Puppet::Util::Cacher.expire @real_indirection.reset_terminus_class end end describe "when converting to yaml" do before do @catalog = Puppet::Resource::Catalog.new("me") @catalog.add_edge("one", "two") end it "should be able to be dumped to yaml" do YAML.dump(@catalog).should be_instance_of(String) end end describe "when converting from yaml" do before do @catalog = Puppet::Resource::Catalog.new("me") @catalog.add_edge("one", "two") text = YAML.dump(@catalog) @newcatalog = YAML.load(text) end it "should get converted back to a catalog" do @newcatalog.should be_instance_of(Puppet::Resource::Catalog) end it "should have all vertices" do @newcatalog.vertex?("one").should be_true @newcatalog.vertex?("two").should be_true end it "should have all edges" do @newcatalog.edge?("one", "two").should be_true end end end describe Puppet::Resource::Catalog, "when converting to pson", :if => Puppet.features.pson? do before do @catalog = Puppet::Resource::Catalog.new("myhost") end def pson_output_should @catalog.class.expects(:pson_create).with { |hash| yield hash }.returns(:something) end # LAK:NOTE For all of these tests, we convert back to the resource so we can # trap the actual data structure then. it "should set its document_type to 'Catalog'" do pson_output_should { |hash| hash['document_type'] == "Catalog" } PSON.parse @catalog.to_pson end it "should set its data as a hash" do pson_output_should { |hash| hash['data'].is_a?(Hash) } PSON.parse @catalog.to_pson end [:name, :version, :tags, :classes].each do |param| it "should set its #{param} to the #{param} of the resource" do @catalog.send(param.to_s + "=", "testing") unless @catalog.send(param) pson_output_should { |hash| hash['data'][param.to_s] == @catalog.send(param) } PSON.parse @catalog.to_pson end end it "should convert its resources to a PSON-encoded array and store it as the 'resources' data" do one = stub 'one', :to_pson_data_hash => "one_resource", :ref => "Foo[one]" two = stub 'two', :to_pson_data_hash => "two_resource", :ref => "Foo[two]" @catalog.add_resource(one) @catalog.add_resource(two) # TODO this should really guarantee sort order PSON.parse(@catalog.to_pson,:create_additions => false)['data']['resources'].sort.should == ["one_resource", "two_resource"].sort end it "should convert its edges to a PSON-encoded array and store it as the 'edges' data" do one = stub 'one', :to_pson_data_hash => "one_resource", :ref => 'Foo[one]' two = stub 'two', :to_pson_data_hash => "two_resource", :ref => 'Foo[two]' three = stub 'three', :to_pson_data_hash => "three_resource", :ref => 'Foo[three]' @catalog.add_edge(one, two) @catalog.add_edge(two, three) @catalog.edges_between(one, two )[0].expects(:to_pson_data_hash).returns "one_two_pson" @catalog.edges_between(two, three)[0].expects(:to_pson_data_hash).returns "two_three_pson" PSON.parse(@catalog.to_pson,:create_additions => false)['data']['edges'].sort.should == %w{one_two_pson two_three_pson}.sort end end describe Puppet::Resource::Catalog, "when converting from pson", :if => Puppet.features.pson? do def pson_result_should Puppet::Resource::Catalog.expects(:new).with { |hash| yield hash } end before do @data = { 'name' => "myhost" } @pson = { 'document_type' => 'Puppet::Resource::Catalog', 'data' => @data, 'metadata' => {} } @catalog = Puppet::Resource::Catalog.new("myhost") Puppet::Resource::Catalog.stubs(:new).returns @catalog end it "should be extended with the PSON utility module" do Puppet::Resource::Catalog.singleton_class.ancestors.should be_include(Puppet::Util::Pson) end it "should create it with the provided name" do Puppet::Resource::Catalog.expects(:new).with('myhost').returns @catalog PSON.parse @pson.to_pson end it "should set the provided version on the catalog if one is set" do @data['version'] = 50 PSON.parse @pson.to_pson @catalog.version.should == @data['version'] end it "should set any provided tags on the catalog" do @data['tags'] = %w{one two} PSON.parse @pson.to_pson @catalog.tags.should == @data['tags'] end it "should set any provided classes on the catalog" do @data['classes'] = %w{one two} PSON.parse @pson.to_pson @catalog.classes.should == @data['classes'] end it 'should convert the resources list into resources and add each of them' do @data['resources'] = [Puppet::Resource.new(:file, "/foo"), Puppet::Resource.new(:file, "/bar")] @catalog.expects(:add_resource).times(2).with { |res| res.type == "File" } PSON.parse @pson.to_pson end it 'should convert resources even if they do not include "type" information' do @data['resources'] = [Puppet::Resource.new(:file, "/foo")] @data['resources'][0].expects(:to_pson).returns '{"title":"/foo","tags":["file"],"type":"File"}' @catalog.expects(:add_resource).with { |res| res.type == "File" } PSON.parse @pson.to_pson end it 'should convert the edges list into edges and add each of them' do one = Puppet::Relationship.new("osource", "otarget", :event => "one", :callback => "refresh") two = Puppet::Relationship.new("tsource", "ttarget", :event => "two", :callback => "refresh") @data['edges'] = [one, two] @catalog.stubs(:resource).returns("eh") @catalog.expects(:add_edge).with { |edge| edge.event == "one" } @catalog.expects(:add_edge).with { |edge| edge.event == "two" } PSON.parse @pson.to_pson end it "should be able to convert relationships that do not include 'type' information" do one = Puppet::Relationship.new("osource", "otarget", :event => "one", :callback => "refresh") one.expects(:to_pson).returns "{\"event\":\"one\",\"callback\":\"refresh\",\"source\":\"osource\",\"target\":\"otarget\"}" @data['edges'] = [one] @catalog.stubs(:resource).returns("eh") @catalog.expects(:add_edge).with { |edge| edge.event == "one" } PSON.parse @pson.to_pson end it "should set the source and target for each edge to the actual resource" do edge = Puppet::Relationship.new("source", "target") @data['edges'] = [edge] @catalog.expects(:resource).with("source").returns("source_resource") @catalog.expects(:resource).with("target").returns("target_resource") @catalog.expects(:add_edge).with { |edge| edge.source == "source_resource" and edge.target == "target_resource" } PSON.parse @pson.to_pson end it "should fail if the source resource cannot be found" do edge = Puppet::Relationship.new("source", "target") @data['edges'] = [edge] @catalog.expects(:resource).with("source").returns(nil) @catalog.stubs(:resource).with("target").returns("target_resource") lambda { PSON.parse @pson.to_pson }.should raise_error(ArgumentError) end it "should fail if the target resource cannot be found" do edge = Puppet::Relationship.new("source", "target") @data['edges'] = [edge] @catalog.stubs(:resource).with("source").returns("source_resource") @catalog.expects(:resource).with("target").returns(nil) lambda { PSON.parse @pson.to_pson }.should raise_error(ArgumentError) end describe "#title_key_for_ref" do it "should parse a resource ref string into a pair" do @catalog.title_key_for_ref("Title[name]").should == ["Title", "name"] end it "should parse a resource ref string into a pair, even if there's a newline inside the name" do @catalog.title_key_for_ref("Title[na\nme]").should == ["Title", "na\nme"] end end end diff --git a/spec/unit/resource/status_spec.rb b/spec/unit/resource/status_spec.rb index d9bb2755d..bb88518c0 100755 --- a/spec/unit/resource/status_spec.rb +++ b/spec/unit/resource/status_spec.rb @@ -1,153 +1,152 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/resource/status' describe Puppet::Resource::Status do before do @resource = Puppet::Type.type(:file).new :path => "/my/file" @status = Puppet::Resource::Status.new(@resource) end it "should compute type and title correctly" do @status.resource_type.should == "File" @status.title.should == "/my/file" end [:node, :file, :line, :current_values, :status, :evaluation_time].each do |attr| it "should support #{attr}" do @status.send(attr.to_s + "=", "foo") @status.send(attr).should == "foo" end end [:skipped, :failed, :restarted, :failed_to_restart, :changed, :out_of_sync, :scheduled].each do |attr| it "should support #{attr}" do @status.send(attr.to_s + "=", "foo") @status.send(attr).should == "foo" end it "should have a boolean method for determining whehter it was #{attr}" do @status.send(attr.to_s + "=", "foo") @status.should send("be_#{attr}") end end it "should accept a resource at initialization" do Puppet::Resource::Status.new(@resource).resource.should_not be_nil end it "should set its source description to the resource's path" do @resource.expects(:path).returns "/my/path" Puppet::Resource::Status.new(@resource).source_description.should == "/my/path" end [:file, :line].each do |attr| it "should copy the resource's #{attr}" do @resource.expects(attr).returns "foo" Puppet::Resource::Status.new(@resource).send(attr).should == "foo" end end it "should copy the resource's tags" do @resource.expects(:tags).returns %w{foo bar} Puppet::Resource::Status.new(@resource).tags.should == %w{foo bar} end it "should always convert the resource to a string" do @resource.expects(:to_s).returns "foo" Puppet::Resource::Status.new(@resource).resource.should == "foo" end it "should support tags" do Puppet::Resource::Status.ancestors.should include(Puppet::Util::Tagging) end it "should create a timestamp at its creation time" do @status.time.should be_instance_of(Time) end describe "when sending logs" do before do Puppet::Util::Log.stubs(:new) end it "should set the tags to the event tags" do Puppet::Util::Log.expects(:new).with { |args| args[:tags] == %w{one two} } @status.stubs(:tags).returns %w{one two} @status.send_log :notice, "my message" end [:file, :line].each do |attr| it "should pass the #{attr}" do Puppet::Util::Log.expects(:new).with { |args| args[attr] == "my val" } @status.send(attr.to_s + "=", "my val") @status.send_log :notice, "my message" end end it "should use the source description as the source" do Puppet::Util::Log.expects(:new).with { |args| args[:source] == "my source" } @status.stubs(:source_description).returns "my source" @status.send_log :notice, "my message" end end it "should support adding events" do event = Puppet::Transaction::Event.new(:name => :foobar) @status.add_event(event) @status.events.should == [event] end it "should use '<<' to add events" do event = Puppet::Transaction::Event.new(:name => :foobar) (@status << event).should equal(@status) @status.events.should == [event] end it "should count the number of successful events and set changed" do 3.times{ @status << Puppet::Transaction::Event.new(:status => 'success') } @status.change_count.should == 3 @status.changed.should == true @status.out_of_sync.should == true end it "should not start with any changes" do @status.change_count.should == 0 @status.changed.should == false @status.out_of_sync.should == false end it "should not treat failure, audit, or noop events as changed" do ['failure', 'audit', 'noop'].each do |s| @status << Puppet::Transaction::Event.new(:status => s) end @status.change_count.should == 0 @status.changed.should == false end it "should not treat audit events as out of sync" do @status << Puppet::Transaction::Event.new(:status => 'audit') @status.out_of_sync_count.should == 0 @status.out_of_sync.should == false end ['failure', 'noop', 'success'].each do |event_status| it "should treat #{event_status} events as out of sync" do 3.times do @status << Puppet::Transaction::Event.new(:status => event_status) end @status.out_of_sync_count.should == 3 @status.out_of_sync.should == true end end describe "When converting to YAML" do it "should include only documented attributes" do @status.file = "/foo.rb" @status.line = 27 @status.evaluation_time = 2.7 @status.tags = %w{one two} @status.to_yaml_properties.should == Puppet::Resource::Status::YAML_ATTRIBUTES.sort end end end diff --git a/spec/unit/resource/type_collection_helper_spec.rb b/spec/unit/resource/type_collection_helper_spec.rb index 9bfba008f..ad8d75271 100755 --- a/spec/unit/resource/type_collection_helper_spec.rb +++ b/spec/unit/resource/type_collection_helper_spec.rb @@ -1,25 +1,24 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/resource/type_collection_helper' class RTCHelperTester include Puppet::Resource::TypeCollectionHelper end describe Puppet::Resource::TypeCollectionHelper do before do @helper = RTCHelperTester.new end it "should use its current environment to retrieve the known resource type collection" do env = stub 'environment' @helper.expects(:environment).returns env rtc = stub 'known_resource_types' env.expects(:known_resource_types).returns rtc @helper.known_resource_types.should equal(rtc) end end diff --git a/spec/unit/resource/type_collection_spec.rb b/spec/unit/resource/type_collection_spec.rb index 914d9fbba..b5f0a0ec7 100755 --- a/spec/unit/resource/type_collection_spec.rb +++ b/spec/unit/resource/type_collection_spec.rb @@ -1,447 +1,446 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/resource/type_collection' require 'puppet/resource/type' describe Puppet::Resource::TypeCollection do before do @instance = Puppet::Resource::Type.new(:hostclass, "foo") @code = Puppet::Resource::TypeCollection.new("env") end it "should require an environment at initialization" do env = Puppet::Node::Environment.new("testing") Puppet::Resource::TypeCollection.new(env).environment.should equal(env) end it "should convert the environment into an environment instance if a string is provided" do env = Puppet::Node::Environment.new("testing") Puppet::Resource::TypeCollection.new("testing").environment.should equal(env) end it "should create a 'loader' at initialization" do Puppet::Resource::TypeCollection.new("testing").loader.should be_instance_of(Puppet::Parser::TypeLoader) end it "should be able to add a resource type" do Puppet::Resource::TypeCollection.new("env").should respond_to(:add) end it "should consider '<<' to be an alias to 'add' but should return self" do loader = Puppet::Resource::TypeCollection.new("env") loader.expects(:add).with "foo" loader.expects(:add).with "bar" loader << "foo" << "bar" end it "should set itself as the code collection for added resource types" do loader = Puppet::Resource::TypeCollection.new("env") node = Puppet::Resource::Type.new(:node, "foo") @code.add(node) @code.node("foo").should equal(node) node.resource_type_collection.should equal(@code) end it "should store node resource types as nodes" do node = Puppet::Resource::Type.new(:node, "foo") @code.add(node) @code.node("foo").should equal(node) end it "should store hostclasses as hostclasses" do klass = Puppet::Resource::Type.new(:hostclass, "foo") @code.add(klass) @code.hostclass("foo").should equal(klass) end it "should store definitions as definitions" do define = Puppet::Resource::Type.new(:definition, "foo") @code.add(define) @code.definition("foo").should equal(define) end it "should merge new classes with existing classes of the same name" do loader = Puppet::Resource::TypeCollection.new("env") first = Puppet::Resource::Type.new(:hostclass, "foo") second = Puppet::Resource::Type.new(:hostclass, "foo") loader.add first first.expects(:merge).with(second) loader.add(second) end it "should remove all nodes, classes, and definitions when cleared" do loader = Puppet::Resource::TypeCollection.new("env") loader.add Puppet::Resource::Type.new(:hostclass, "class") loader.add Puppet::Resource::Type.new(:definition, "define") loader.add Puppet::Resource::Type.new(:node, "node") loader.clear loader.hostclass("class").should be_nil loader.definition("define").should be_nil loader.node("node").should be_nil end describe "when resolving namespaces" do [ ['', '::foo', ['foo']], ['a', '::foo', ['foo']], ['a::b', '::foo', ['foo']], [['a::b'], '::foo', ['foo']], [['a::b', 'c'], '::foo', ['foo']], [['A::B', 'C'], '::Foo', ['foo']], ['', '', ['']], ['a', '', ['']], ['a::b', '', ['']], [['a::b'], '', ['']], [['a::b', 'c'], '', ['']], [['A::B', 'C'], '', ['']], ['', 'foo', ['foo']], ['a', 'foo', ['a::foo', 'foo']], ['a::b', 'foo', ['a::b::foo', 'a::foo', 'foo']], ['A::B', 'Foo', ['a::b::foo', 'a::foo', 'foo']], [['a::b'], 'foo', ['a::b::foo', 'a::foo', 'foo']], [['a', 'b'], 'foo', ['a::foo', 'foo', 'b::foo']], [['a::b', 'c::d'], 'foo', ['a::b::foo', 'a::foo', 'foo', 'c::d::foo', 'c::foo']], [['a::b', 'a::c'], 'foo', ['a::b::foo', 'a::foo', 'foo', 'a::c::foo']], ].each do |namespaces, name, expected_result| it "should resolve #{name.inspect} in namespaces #{namespaces.inspect} correctly" do @code.instance_eval { resolve_namespaces(namespaces, name) }.should == expected_result end end end describe "when looking up names" do before do @type = Puppet::Resource::Type.new(:hostclass, "ns::klass") end it "should support looking up with multiple namespaces" do @code.add @type @code.find_hostclass(%w{boo baz ns}, "klass").should equal(@type) end it "should not attempt to import anything when the type is already defined" do @code.add @type @code.loader.expects(:import).never @code.find_hostclass(%w{ns}, "klass").should equal(@type) end describe "that need to be loaded" do it "should use the loader to load the files" do @code.loader.expects(:try_load_fqname).with(:hostclass, "ns::klass") @code.loader.expects(:try_load_fqname).with(:hostclass, "klass") @code.find_hostclass(["ns"], "klass") end it "should downcase the name and downcase and array-fy the namespaces before passing to the loader" do @code.loader.expects(:try_load_fqname).with(:hostclass, "ns::klass") @code.loader.expects(:try_load_fqname).with(:hostclass, "klass") @code.find_hostclass("Ns", "Klass") end it "should use the class returned by the loader" do @code.loader.expects(:try_load_fqname).returns(:klass) @code.expects(:hostclass).with("ns::klass").returns(false) @code.find_hostclass("ns", "klass").should == :klass end it "should return nil if the name isn't found" do @code.stubs(:try_load_fqname).returns(nil) @code.find_hostclass("Ns", "Klass").should be_nil end it "already-loaded names at broader scopes should not shadow autoloaded names" do @code.add Puppet::Resource::Type.new(:hostclass, "bar") @code.loader.expects(:try_load_fqname).with(:hostclass, "foo::bar").returns(:foobar) @code.find_hostclass("foo", "bar").should == :foobar end end end %w{hostclass node definition}.each do |data| before do @instance = Puppet::Resource::Type.new(data, "foo") end it "should have a method for adding a #{data}" do Puppet::Resource::TypeCollection.new("env").should respond_to("add_#{data}") end it "should use the name of the instance to add it" do loader = Puppet::Resource::TypeCollection.new("env") loader.send("add_#{data}", @instance) loader.send(data, @instance.name).should equal(@instance) end unless data == "hostclass" it "should fail to add a #{data} when one already exists" do loader = Puppet::Resource::TypeCollection.new("env") loader.add @instance lambda { loader.add(@instance) }.should raise_error(Puppet::ParseError) end end it "should return the added #{data}" do loader = Puppet::Resource::TypeCollection.new("env") loader.add(@instance).should equal(@instance) end it "should be able to retrieve #{data} by name" do loader = Puppet::Resource::TypeCollection.new("env") instance = Puppet::Resource::Type.new(data, "bar") loader.add instance loader.send(data, "bar").should equal(instance) end it "should retrieve #{data} insensitive to case" do loader = Puppet::Resource::TypeCollection.new("env") instance = Puppet::Resource::Type.new(data, "Bar") loader.add instance loader.send(data, "bAr").should equal(instance) end it "should return nil when asked for a #{data} that has not been added" do Puppet::Resource::TypeCollection.new("env").send(data, "foo").should be_nil end it "should be able to retrieve all #{data}s" do plurals = { "hostclass" => "hostclasses", "node" => "nodes", "definition" => "definitions" } loader = Puppet::Resource::TypeCollection.new("env") instance = Puppet::Resource::Type.new(data, "foo") loader.add instance loader.send(plurals[data]).should == { "foo" => instance } end end describe "when finding a qualified instance" do it "should return any found instance if the instance name is fully qualified" do loader = Puppet::Resource::TypeCollection.new("env") instance = Puppet::Resource::Type.new(:hostclass, "foo::bar") loader.add instance loader.find_hostclass("namespace", "::foo::bar").should equal(instance) end it "should return nil if the instance name is fully qualified and no such instance exists" do loader = Puppet::Resource::TypeCollection.new("env") loader.find_hostclass("namespace", "::foo::bar").should be_nil end it "should be able to find classes in the base namespace" do loader = Puppet::Resource::TypeCollection.new("env") instance = Puppet::Resource::Type.new(:hostclass, "foo") loader.add instance loader.find_hostclass("", "foo").should equal(instance) end it "should return the partially qualified object if it exists in a provided namespace" do loader = Puppet::Resource::TypeCollection.new("env") instance = Puppet::Resource::Type.new(:hostclass, "foo::bar::baz") loader.add instance loader.find_hostclass("foo", "bar::baz").should equal(instance) end it "should be able to find partially qualified objects in any of the provided namespaces" do loader = Puppet::Resource::TypeCollection.new("env") instance = Puppet::Resource::Type.new(:hostclass, "foo::bar::baz") loader.add instance loader.find_hostclass(["nons", "foo", "otherns"], "bar::baz").should equal(instance) end it "should return the unqualified object if it exists in a provided namespace" do loader = Puppet::Resource::TypeCollection.new("env") instance = Puppet::Resource::Type.new(:hostclass, "foo::bar") loader.add instance loader.find_hostclass("foo", "bar").should equal(instance) end it "should return the unqualified object if it exists in the parent namespace" do loader = Puppet::Resource::TypeCollection.new("env") instance = Puppet::Resource::Type.new(:hostclass, "foo::bar") loader.add instance loader.find_hostclass("foo::bar::baz", "bar").should equal(instance) end it "should should return the partially qualified object if it exists in the parent namespace" do loader = Puppet::Resource::TypeCollection.new("env") instance = Puppet::Resource::Type.new(:hostclass, "foo::bar::baz") loader.add instance loader.find_hostclass("foo::bar", "bar::baz").should equal(instance) end it "should return the qualified object if it exists in the root namespace" do loader = Puppet::Resource::TypeCollection.new("env") instance = Puppet::Resource::Type.new(:hostclass, "foo::bar::baz") loader.add instance loader.find_hostclass("foo::bar", "foo::bar::baz").should equal(instance) end it "should return nil if the object cannot be found" do loader = Puppet::Resource::TypeCollection.new("env") instance = Puppet::Resource::Type.new(:hostclass, "foo::bar::baz") loader.add instance loader.find_hostclass("foo::bar", "eh").should be_nil end describe "when topscope has a class that has the same name as a local class" do before do @loader = Puppet::Resource::TypeCollection.new("env") [ "foo::bar", "bar" ].each do |name| @loader.add Puppet::Resource::Type.new(:hostclass, name) end end it "should favor the local class, if the name is unqualified" do @loader.find_hostclass("foo", "bar").name.should == 'foo::bar' end it "should only look in the topclass, if the name is qualified" do @loader.find_hostclass("foo", "::bar").name.should == 'bar' end end it "should not look in the local scope for classes when the name is qualified" do @loader = Puppet::Resource::TypeCollection.new("env") @loader.add Puppet::Resource::Type.new(:hostclass, "foo::bar") @loader.find_hostclass("foo", "::bar").should == nil end end it "should be able to find nodes" do node = Puppet::Resource::Type.new(:node, "bar") loader = Puppet::Resource::TypeCollection.new("env") loader.add(node) loader.find_node(stub("ignored"), "bar").should == node end it "should use the 'find_or_load' method to find hostclasses" do loader = Puppet::Resource::TypeCollection.new("env") loader.expects(:find_or_load).with("foo", "bar", :hostclass) loader.find_hostclass("foo", "bar") end it "should use the 'find_or_load' method to find definitions" do loader = Puppet::Resource::TypeCollection.new("env") loader.expects(:find_or_load).with("foo", "bar", :definition) loader.find_definition("foo", "bar") end it "should indicate whether any nodes are defined" do loader = Puppet::Resource::TypeCollection.new("env") loader.add_node(Puppet::Resource::Type.new(:node, "foo")) loader.should be_nodes end it "should indicate whether no nodes are defined" do Puppet::Resource::TypeCollection.new("env").should_not be_nodes end describe "when finding nodes" do before :each do @loader = Puppet::Resource::TypeCollection.new("env") end it "should return any node whose name exactly matches the provided node name" do node = Puppet::Resource::Type.new(:node, "foo") @loader << node @loader.node("foo").should equal(node) end it "should return the first regex node whose regex matches the provided node name" do node1 = Puppet::Resource::Type.new(:node, /\w/) node2 = Puppet::Resource::Type.new(:node, /\d/) @loader << node1 << node2 @loader.node("foo10").should equal(node1) end it "should preferentially return a node whose name is string-equal over returning a node whose regex matches a provided name" do node1 = Puppet::Resource::Type.new(:node, /\w/) node2 = Puppet::Resource::Type.new(:node, "foo") @loader << node1 << node2 @loader.node("foo").should equal(node2) end end describe "when managing files" do before do @loader = Puppet::Resource::TypeCollection.new("env") Puppet::Util::LoadedFile.stubs(:new).returns stub("watched_file") end it "should have a method for specifying a file should be watched" do @loader.should respond_to(:watch_file) end it "should have a method for determining if a file is being watched" do @loader.watch_file("/foo/bar") @loader.should be_watching_file("/foo/bar") end it "should use LoadedFile to watch files" do Puppet::Util::LoadedFile.expects(:new).with("/foo/bar").returns stub("watched_file") @loader.watch_file("/foo/bar") end it "should be considered stale if any files have changed" do file1 = stub 'file1', :changed? => false file2 = stub 'file2', :changed? => true Puppet::Util::LoadedFile.expects(:new).times(2).returns(file1).then.returns(file2) @loader.watch_file("/foo/bar") @loader.watch_file("/other/bar") @loader.should be_stale end it "should not be considered stable if no files have changed" do file1 = stub 'file1', :changed? => false file2 = stub 'file2', :changed? => false Puppet::Util::LoadedFile.expects(:new).times(2).returns(file1).then.returns(file2) @loader.watch_file("/foo/bar") @loader.watch_file("/other/bar") @loader.should_not be_stale end end describe "when determining the configuration version" do before do @code = Puppet::Resource::TypeCollection.new("env") end it "should default to the current time" do time = Time.now Time.stubs(:now).returns time @code.version.should == time.to_i end it "should use the output of the environment's config_version setting if one is provided" do @code.environment.stubs(:[]).with(:config_version).returns("/my/foo") Puppet::Util.expects(:execute).with(["/my/foo"]).returns "output\n" @code.version.should == "output" end it "should raise a puppet parser error if executing config_version fails" do @code.environment.stubs(:[]).with(:config_version).returns("test") Puppet::Util.expects(:execute).raises(Puppet::ExecutionFailure.new("msg")) lambda { @code.version }.should raise_error(Puppet::ParseError) end end end diff --git a/spec/unit/resource/type_spec.rb b/spec/unit/resource/type_spec.rb index 45c880440..352f767e4 100755 --- a/spec/unit/resource/type_spec.rb +++ b/spec/unit/resource/type_spec.rb @@ -1,769 +1,768 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/resource/type' describe Puppet::Resource::Type do it "should have a 'name' attribute" do Puppet::Resource::Type.new(:hostclass, "foo").name.should == "foo" end [:code, :doc, :line, :file, :resource_type_collection, :ruby_code].each do |attr| it "should have a '#{attr}' attribute" do type = Puppet::Resource::Type.new(:hostclass, "foo") type.send(attr.to_s + "=", "yay") type.send(attr).should == "yay" end end [:hostclass, :node, :definition].each do |type| it "should know when it is a #{type}" do Puppet::Resource::Type.new(type, "foo").send("#{type}?").should be_true end end it "should indirect 'resource_type'" do Puppet::Resource::Type.indirection.name.should == :resource_type end it "should default to 'parser' for its terminus class" do Puppet::Resource::Type.indirection.terminus_class.should == :parser end describe "when converting to json" do before do @type = Puppet::Resource::Type.new(:hostclass, "foo") end def from_json(json) Puppet::Resource::Type.from_pson(json) end def double_convert Puppet::Resource::Type.from_pson(PSON.parse(@type.to_pson)) end it "should include the name and type" do double_convert.name.should == @type.name double_convert.type.should == @type.type end it "should include any arguments" do @type.set_arguments("one" => nil, "two" => "foo") double_convert.arguments.should == {"one" => nil, "two" => "foo"} end it "should not include arguments if none are present" do @type.to_pson["arguments"].should be_nil end [:line, :doc, :file, :parent].each do |attr| it "should include #{attr} when set" do @type.send(attr.to_s + "=", "value") double_convert.send(attr).should == "value" end it "should not include #{attr} when not set" do @type.to_pson[attr.to_s].should be_nil end end it "should not include docs if they are empty" do @type.doc = "" @type.to_pson["doc"].should be_nil end end describe "when a node" do it "should allow a regex as its name" do lambda { Puppet::Resource::Type.new(:node, /foo/) }.should_not raise_error end it "should allow a AST::HostName instance as its name" do regex = Puppet::Parser::AST::Regex.new(:value => /foo/) name = Puppet::Parser::AST::HostName.new(:value => regex) lambda { Puppet::Resource::Type.new(:node, name) }.should_not raise_error end it "should match against the regexp in the AST::HostName when a HostName instance is provided" do regex = Puppet::Parser::AST::Regex.new(:value => /\w/) name = Puppet::Parser::AST::HostName.new(:value => regex) node = Puppet::Resource::Type.new(:node, name) node.match("foo").should be_true end it "should return the value of the hostname if provided a string-form AST::HostName instance as the name" do name = Puppet::Parser::AST::HostName.new(:value => "foo") node = Puppet::Resource::Type.new(:node, name) node.name.should == "foo" end describe "and the name is a regex" do it "should have a method that indicates that this is the case" do Puppet::Resource::Type.new(:node, /w/).should be_name_is_regex end it "should set its namespace to ''" do Puppet::Resource::Type.new(:node, /w/).namespace.should == "" end it "should return the regex converted to a string when asked for its name" do Puppet::Resource::Type.new(:node, /ww/).name.should == "ww" end it "should downcase the regex when returning the name as a string" do Puppet::Resource::Type.new(:node, /W/).name.should == "w" end it "should remove non-alpha characters when returning the name as a string" do Puppet::Resource::Type.new(:node, /w*w/).name.should_not include("*") end it "should remove leading dots when returning the name as a string" do Puppet::Resource::Type.new(:node, /.ww/).name.should_not =~ /^\./ end it "should have a method for matching its regex name against a provided name" do Puppet::Resource::Type.new(:node, /.ww/).should respond_to(:match) end it "should return true when its regex matches the provided name" do Puppet::Resource::Type.new(:node, /\w/).match("foo").should be_true end it "should return false when its regex does not match the provided name" do (!!Puppet::Resource::Type.new(:node, /\d/).match("foo")).should be_false end it "should return true when its name, as a string, is matched against an equal string" do Puppet::Resource::Type.new(:node, "foo").match("foo").should be_true end it "should return false when its name is matched against an unequal string" do Puppet::Resource::Type.new(:node, "foo").match("bar").should be_false end it "should match names insensitive to case" do Puppet::Resource::Type.new(:node, "fOo").match("foO").should be_true end end it "should return the name converted to a string when the name is not a regex" do pending "Need to define LoadedCode behaviour first" name = Puppet::Parser::AST::HostName.new(:value => "foo") Puppet::Resource::Type.new(:node, name).name.should == "foo" end it "should return the name converted to a string when the name is a regex" do pending "Need to define LoadedCode behaviour first" name = Puppet::Parser::AST::HostName.new(:value => /regex/) Puppet::Resource::Type.new(:node, name).name.should == /regex/.to_s end it "should mark any created scopes as a node scope" do pending "Need to define LoadedCode behaviour first" name = Puppet::Parser::AST::HostName.new(:value => /regex/) Puppet::Resource::Type.new(:node, name).name.should == /regex/.to_s end end describe "when initializing" do it "should require a resource super type" do Puppet::Resource::Type.new(:hostclass, "foo").type.should == :hostclass end it "should fail if provided an invalid resource super type" do lambda { Puppet::Resource::Type.new(:nope, "foo") }.should raise_error(ArgumentError) end it "should set its name to the downcased, stringified provided name" do Puppet::Resource::Type.new(:hostclass, "Foo::Bar".intern).name.should == "foo::bar" end it "should set its namespace to the downcased, stringified qualified name for classes" do Puppet::Resource::Type.new(:hostclass, "Foo::Bar::Baz".intern).namespace.should == "foo::bar::baz" end [:definition, :node].each do |type| it "should set its namespace to the downcased, stringified qualified portion of the name for #{type}s" do Puppet::Resource::Type.new(type, "Foo::Bar::Baz".intern).namespace.should == "foo::bar" end end %w{code line file doc}.each do |arg| it "should set #{arg} if provided" do type = Puppet::Resource::Type.new(:hostclass, "foo", arg.to_sym => "something") type.send(arg).should == "something" end end it "should set any provided arguments with the keys as symbols" do type = Puppet::Resource::Type.new(:hostclass, "foo", :arguments => {:foo => "bar", :baz => "biz"}) type.should be_valid_parameter("foo") type.should be_valid_parameter("baz") end it "should set any provided arguments with they keys as strings" do type = Puppet::Resource::Type.new(:hostclass, "foo", :arguments => {"foo" => "bar", "baz" => "biz"}) type.should be_valid_parameter(:foo) type.should be_valid_parameter(:baz) end it "should function if provided no arguments" do type = Puppet::Resource::Type.new(:hostclass, "foo") type.should_not be_valid_parameter(:foo) end end describe "when testing the validity of an attribute" do it "should return true if the parameter was typed at initialization" do Puppet::Resource::Type.new(:hostclass, "foo", :arguments => {"foo" => "bar"}).should be_valid_parameter("foo") end it "should return true if it is a metaparam" do Puppet::Resource::Type.new(:hostclass, "foo").should be_valid_parameter("require") end it "should return true if the parameter is named 'name'" do Puppet::Resource::Type.new(:hostclass, "foo").should be_valid_parameter("name") end it "should return false if it is not a metaparam and was not provided at initialization" do Puppet::Resource::Type.new(:hostclass, "foo").should_not be_valid_parameter("yayness") end end describe "when setting its parameters in the scope" do before do @scope = Puppet::Parser::Scope.new(:compiler => stub("compiler", :environment => Puppet::Node::Environment.new), :source => stub("source")) @resource = Puppet::Parser::Resource.new(:foo, "bar", :scope => @scope) @type = Puppet::Resource::Type.new(:hostclass, "foo") end ['module_name', 'name', 'title'].each do |variable| it "should allow #{variable} to be evaluated as param default" do @type.instance_eval { @module_name = "bar" } var = Puppet::Parser::AST::Variable.new({'value' => variable}) @type.set_arguments :foo => var @type.set_resource_parameters(@resource, @scope) @scope.lookupvar('foo').should == 'bar' end end # this test is to clarify a crazy edge case # if you specify these special names as params, the resource # will override the special variables it "resource should override defaults" do @type.set_arguments :name => nil @resource[:name] = 'foobar' var = Puppet::Parser::AST::Variable.new({'value' => 'name'}) @type.set_arguments :foo => var @type.set_resource_parameters(@resource, @scope) @scope.lookupvar('foo').should == 'foobar' end it "should set each of the resource's parameters as variables in the scope" do @type.set_arguments :foo => nil, :boo => nil @resource[:foo] = "bar" @resource[:boo] = "baz" @type.set_resource_parameters(@resource, @scope) @scope.lookupvar("foo").should == "bar" @scope.lookupvar("boo").should == "baz" end it "should set the variables as strings" do @type.set_arguments :foo => nil @resource[:foo] = "bar" @type.set_resource_parameters(@resource, @scope) @scope.lookupvar("foo").should == "bar" end it "should fail if any of the resource's parameters are not valid attributes" do @type.set_arguments :foo => nil @resource[:boo] = "baz" lambda { @type.set_resource_parameters(@resource, @scope) }.should raise_error(Puppet::ParseError) end it "should evaluate and set its default values as variables for parameters not provided by the resource" do @type.set_arguments :foo => stub("value", :safeevaluate => "something") @type.set_resource_parameters(@resource, @scope) @scope.lookupvar("foo").should == "something" end it "should set all default values as parameters in the resource" do @type.set_arguments :foo => stub("value", :safeevaluate => "something") @type.set_resource_parameters(@resource, @scope) @resource[:foo].should == "something" end it "should fail if the resource does not provide a value for a required argument" do @type.set_arguments :foo => nil @resource.expects(:to_hash).returns({}) lambda { @type.set_resource_parameters(@resource, @scope) }.should raise_error(Puppet::ParseError) end it "should set the resource's title as a variable if not otherwise provided" do @type.set_resource_parameters(@resource, @scope) @scope.lookupvar("title").should == "bar" end it "should set the resource's name as a variable if not otherwise provided" do @type.set_resource_parameters(@resource, @scope) @scope.lookupvar("name").should == "bar" end it "should set its module name in the scope if available" do @type.instance_eval { @module_name = "mymod" } @type.set_resource_parameters(@resource, @scope) @scope.lookupvar("module_name").should == "mymod" end it "should set its caller module name in the scope if available" do @scope.expects(:parent_module_name).returns "mycaller" @type.set_resource_parameters(@resource, @scope) @scope.lookupvar("caller_module_name").should == "mycaller" end end describe "when describing and managing parent classes" do before do @code = Puppet::Resource::TypeCollection.new("env") @parent = Puppet::Resource::Type.new(:hostclass, "bar") @code.add @parent @child = Puppet::Resource::Type.new(:hostclass, "foo", :parent => "bar") @code.add @child @env = stub "environment", :known_resource_types => @code @scope = stub "scope", :environment => @env, :namespaces => [""] end it "should be able to define a parent" do Puppet::Resource::Type.new(:hostclass, "foo", :parent => "bar") end it "should use the code collection to find the parent resource type" do @child.parent_type(@scope).should equal(@parent) end it "should be able to find parent nodes" do parent = Puppet::Resource::Type.new(:node, "bar") @code.add parent child = Puppet::Resource::Type.new(:node, "foo", :parent => "bar") @code.add child child.parent_type(@scope).should equal(parent) end it "should cache a reference to the parent type" do @code.stubs(:hostclass).with("foo::bar").returns nil @code.expects(:hostclass).with("bar").once.returns @parent @child.parent_type(@scope) @child.parent_type end it "should correctly state when it is another type's child" do @child.parent_type(@scope) @child.should be_child_of(@parent) end it "should be considered the child of a parent's parent" do @grandchild = Puppet::Resource::Type.new(:hostclass, "baz", :parent => "foo") @code.add @grandchild @child.parent_type(@scope) @grandchild.parent_type(@scope) @grandchild.should be_child_of(@parent) end it "should correctly state when it is not another type's child" do @notchild = Puppet::Resource::Type.new(:hostclass, "baz") @code.add @notchild @notchild.should_not be_child_of(@parent) end end describe "when evaluating its code" do before do @compiler = Puppet::Parser::Compiler.new(Puppet::Node.new("mynode")) @scope = Puppet::Parser::Scope.new :compiler => @compiler @resource = Puppet::Parser::Resource.new(:foo, "yay", :scope => @scope) # This is so the internal resource lookup works, yo. @compiler.catalog.add_resource @resource @known_resource_types = stub 'known_resource_types' @resource.stubs(:known_resource_types).returns @known_resource_types @type = Puppet::Resource::Type.new(:hostclass, "foo") end it "should add hostclass names to the classes list" do @type.evaluate_code(@resource) @compiler.catalog.classes.should be_include("foo") end it "should add node names to the classes list" do @type = Puppet::Resource::Type.new(:node, "foo") @type.evaluate_code(@resource) @compiler.catalog.classes.should be_include("foo") end it "should not add defined resource names to the classes list" do @type = Puppet::Resource::Type.new(:definition, "foo") @type.evaluate_code(@resource) @compiler.catalog.classes.should_not be_include("foo") end it "should set all of its parameters in a subscope" do subscope = stub 'subscope', :compiler => @compiler @scope.expects(:newscope).with(:source => @type, :dynamic => true, :namespace => 'foo', :resource => @resource).returns subscope @type.expects(:set_resource_parameters).with(@resource, subscope) @type.evaluate_code(@resource) end it "should not create a subscope for the :main class" do @resource.stubs(:title).returns(:main) @type.expects(:subscope).never @type.expects(:set_resource_parameters).with(@resource, @scope) @type.evaluate_code(@resource) end it "should store the class scope" do @type.evaluate_code(@resource) @scope.class_scope(@type).should be_instance_of(@scope.class) end it "should still create a scope but not store it if the type is a definition" do @type = Puppet::Resource::Type.new(:definition, "foo") @type.evaluate_code(@resource) @scope.class_scope(@type).should be_nil end it "should evaluate the AST code if any is provided" do code = stub 'code' @type.stubs(:code).returns code subscope = stub_everything("subscope", :compiler => @compiler) @scope.stubs(:newscope).returns subscope code.expects(:safeevaluate).with subscope @type.evaluate_code(@resource) end describe "and ruby code is provided" do it "should create a DSL Resource API and evaluate it" do @type.stubs(:ruby_code).returns(proc { "foo" }) @api = stub 'api' Puppet::DSL::ResourceAPI.expects(:new).with { |res, scope, code| code == @type.ruby_code }.returns @api @api.expects(:evaluate) @type.evaluate_code(@resource) end end it "should noop if there is no code" do @type.expects(:code).returns nil @type.evaluate_code(@resource) end describe "and it has a parent class" do before do @parent_type = Puppet::Resource::Type.new(:hostclass, "parent") @type.parent = "parent" @parent_resource = Puppet::Parser::Resource.new(:class, "parent", :scope => @scope) @compiler.add_resource @scope, @parent_resource @type.resource_type_collection = @scope.known_resource_types @type.resource_type_collection.add @parent_type end it "should evaluate the parent's resource" do @type.parent_type(@scope) @type.evaluate_code(@resource) @scope.class_scope(@parent_type).should_not be_nil end it "should not evaluate the parent's resource if it has already been evaluated" do @parent_resource.evaluate @type.parent_type(@scope) @parent_resource.expects(:evaluate).never @type.evaluate_code(@resource) end it "should use the parent's scope as its base scope" do @type.parent_type(@scope) @type.evaluate_code(@resource) @scope.class_scope(@type).parent.object_id.should == @scope.class_scope(@parent_type).object_id end end describe "and it has a parent node" do before do @type = Puppet::Resource::Type.new(:node, "foo") @parent_type = Puppet::Resource::Type.new(:node, "parent") @type.parent = "parent" @parent_resource = Puppet::Parser::Resource.new(:node, "parent", :scope => @scope) @compiler.add_resource @scope, @parent_resource @type.resource_type_collection = @scope.known_resource_types @type.resource_type_collection.add(@parent_type) end it "should evaluate the parent's resource" do @type.parent_type(@scope) @type.evaluate_code(@resource) @scope.class_scope(@parent_type).should_not be_nil end it "should not evaluate the parent's resource if it has already been evaluated" do @parent_resource.evaluate @type.parent_type(@scope) @parent_resource.expects(:evaluate).never @type.evaluate_code(@resource) end it "should use the parent's scope as its base scope" do @type.parent_type(@scope) @type.evaluate_code(@resource) @scope.class_scope(@type).parent.object_id.should == @scope.class_scope(@parent_type).object_id end end end describe "when creating a resource" do before do @node = Puppet::Node.new("foo", :environment => 'env') @compiler = Puppet::Parser::Compiler.new(@node) @scope = Puppet::Parser::Scope.new(:compiler => @compiler) @top = Puppet::Resource::Type.new :hostclass, "top" @middle = Puppet::Resource::Type.new :hostclass, "middle", :parent => "top" @code = Puppet::Resource::TypeCollection.new("env") @code.add @top @code.add @middle @node.environment.stubs(:known_resource_types).returns(@code) end it "should create a resource instance" do @top.ensure_in_catalog(@scope).should be_instance_of(Puppet::Parser::Resource) end it "should set its resource type to 'class' when it is a hostclass" do Puppet::Resource::Type.new(:hostclass, "top").ensure_in_catalog(@scope).type.should == "Class" end it "should set its resource type to 'node' when it is a node" do Puppet::Resource::Type.new(:node, "top").ensure_in_catalog(@scope).type.should == "Node" end it "should fail when it is a definition" do lambda { Puppet::Resource::Type.new(:definition, "top").ensure_in_catalog(@scope) }.should raise_error(ArgumentError) end it "should add the created resource to the scope's catalog" do @top.ensure_in_catalog(@scope) @compiler.catalog.resource(:class, "top").should be_instance_of(Puppet::Parser::Resource) end it "should add specified parameters to the resource" do @top.ensure_in_catalog(@scope, {'one'=>'1', 'two'=>'2'}) @compiler.catalog.resource(:class, "top")['one'].should == '1' @compiler.catalog.resource(:class, "top")['two'].should == '2' end it "should not require params for a param class" do @top.ensure_in_catalog(@scope, {}) @compiler.catalog.resource(:class, "top").should be_instance_of(Puppet::Parser::Resource) end it "should evaluate the parent class if one exists" do @middle.ensure_in_catalog(@scope) @compiler.catalog.resource(:class, "top").should be_instance_of(Puppet::Parser::Resource) end it "should evaluate the parent class if one exists" do @middle.ensure_in_catalog(@scope, {}) @compiler.catalog.resource(:class, "top").should be_instance_of(Puppet::Parser::Resource) end it "should fail if you try to create duplicate class resources" do othertop = Puppet::Parser::Resource.new(:class, 'top',:source => @source, :scope => @scope ) # add the same class resource to the catalog @compiler.catalog.add_resource(othertop) lambda { @top.ensure_in_catalog(@scope, {}) }.should raise_error(Puppet::Resource::Catalog::DuplicateResourceError) end it "should fail to evaluate if a parent class is defined but cannot be found" do othertop = Puppet::Resource::Type.new :hostclass, "something", :parent => "yay" @code.add othertop lambda { othertop.ensure_in_catalog(@scope) }.should raise_error(Puppet::ParseError) end it "should not create a new resource if one already exists" do @compiler.catalog.expects(:resource).with(:class, "top").returns("something") @compiler.catalog.expects(:add_resource).never @top.ensure_in_catalog(@scope) end it "should return the existing resource when not creating a new one" do @compiler.catalog.expects(:resource).with(:class, "top").returns("something") @compiler.catalog.expects(:add_resource).never @top.ensure_in_catalog(@scope).should == "something" end it "should not create a new parent resource if one already exists and it has a parent class" do @top.ensure_in_catalog(@scope) top_resource = @compiler.catalog.resource(:class, "top") @middle.ensure_in_catalog(@scope) @compiler.catalog.resource(:class, "top").should equal(top_resource) end # #795 - tag before evaluation. it "should tag the catalog with the resource tags when it is evaluated" do @middle.ensure_in_catalog(@scope) @compiler.catalog.should be_tagged("middle") end it "should tag the catalog with the parent class tags when it is evaluated" do @middle.ensure_in_catalog(@scope) @compiler.catalog.should be_tagged("top") end end describe "when merging code from another instance" do def code(str) Puppet::Parser::AST::Leaf.new :value => str end it "should fail unless it is a class" do lambda { Puppet::Resource::Type.new(:node, "bar").merge("foo") }.should raise_error(Puppet::Error) end it "should fail unless the source instance is a class" do dest = Puppet::Resource::Type.new(:hostclass, "bar") source = Puppet::Resource::Type.new(:node, "foo") lambda { dest.merge(source) }.should raise_error(Puppet::Error) end it "should fail if both classes have different parent classes" do code = Puppet::Resource::TypeCollection.new("env") {"a" => "b", "c" => "d"}.each do |parent, child| code.add Puppet::Resource::Type.new(:hostclass, parent) code.add Puppet::Resource::Type.new(:hostclass, child, :parent => parent) end lambda { code.hostclass("b").merge(code.hostclass("d")) }.should raise_error(Puppet::Error) end it "should fail if it's named 'main' and 'freeze_main' is enabled" do Puppet.settings[:freeze_main] = true code = Puppet::Resource::TypeCollection.new("env") code.add Puppet::Resource::Type.new(:hostclass, "") other = Puppet::Resource::Type.new(:hostclass, "") lambda { code.hostclass("").merge(other) }.should raise_error(Puppet::Error) end it "should copy the other class's parent if it has not parent" do dest = Puppet::Resource::Type.new(:hostclass, "bar") parent = Puppet::Resource::Type.new(:hostclass, "parent") source = Puppet::Resource::Type.new(:hostclass, "foo", :parent => "parent") dest.merge(source) dest.parent.should == "parent" end it "should copy the other class's documentation as its docs if it has no docs" do dest = Puppet::Resource::Type.new(:hostclass, "bar") source = Puppet::Resource::Type.new(:hostclass, "foo", :doc => "yayness") dest.merge(source) dest.doc.should == "yayness" end it "should append the other class's docs to its docs if it has any" do dest = Puppet::Resource::Type.new(:hostclass, "bar", :doc => "fooness") source = Puppet::Resource::Type.new(:hostclass, "foo", :doc => "yayness") dest.merge(source) dest.doc.should == "foonessyayness" end it "should turn its code into an ASTArray if necessary" do dest = Puppet::Resource::Type.new(:hostclass, "bar", :code => code("foo")) source = Puppet::Resource::Type.new(:hostclass, "foo", :code => code("bar")) dest.merge(source) dest.code.should be_instance_of(Puppet::Parser::AST::ASTArray) end it "should set the other class's code as its code if it has none" do dest = Puppet::Resource::Type.new(:hostclass, "bar") source = Puppet::Resource::Type.new(:hostclass, "foo", :code => code("bar")) dest.merge(source) dest.code.value.should == "bar" end it "should append the other class's code to its code if it has any" do dcode = Puppet::Parser::AST::ASTArray.new :children => [code("dest")] dest = Puppet::Resource::Type.new(:hostclass, "bar", :code => dcode) scode = Puppet::Parser::AST::ASTArray.new :children => [code("source")] source = Puppet::Resource::Type.new(:hostclass, "foo", :code => scode) dest.merge(source) dest.code.children.collect { |l| l.value }.should == %w{dest source} end end end diff --git a/spec/unit/resource_spec.rb b/spec/unit/resource_spec.rb index 1b1839981..79ea69e9c 100755 --- a/spec/unit/resource_spec.rb +++ b/spec/unit/resource_spec.rb @@ -1,812 +1,811 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/resource' describe Puppet::Resource do before do @basepath = Puppet.features.posix? ? "/somepath" : "C:/somepath" end [:catalog, :file, :line].each do |attr| it "should have an #{attr} attribute" do resource = Puppet::Resource.new("file", "/my/file") resource.should respond_to(attr) resource.should respond_to(attr.to_s + "=") end end it "should have a :title attribute" do Puppet::Resource.new(:user, "foo").title.should == "foo" end it "should require the type and title" do lambda { Puppet::Resource.new }.should raise_error(ArgumentError) end it "should canonize types to capitalized strings" do Puppet::Resource.new(:user, "foo").type.should == "User" end it "should canonize qualified types so all strings are capitalized" do Puppet::Resource.new("foo::bar", "foo").type.should == "Foo::Bar" end it "should tag itself with its type" do Puppet::Resource.new("file", "/f").should be_tagged("file") end it "should tag itself with its title if the title is a valid tag" do Puppet::Resource.new("user", "bar").should be_tagged("bar") end it "should not tag itself with its title if the title is a not valid tag" do Puppet::Resource.new("file", "/bar").should_not be_tagged("/bar") end it "should allow setting of attributes" do Puppet::Resource.new("file", "/bar", :file => "/foo").file.should == "/foo" Puppet::Resource.new("file", "/bar", :exported => true).should be_exported end it "should set its type to 'Class' and its title to the passed title if the passed type is :component and the title has no square brackets in it" do ref = Puppet::Resource.new(:component, "foo") ref.type.should == "Class" ref.title.should == "Foo" end it "should interpret the title as a reference and assign appropriately if the type is :component and the title contains square brackets" do ref = Puppet::Resource.new(:component, "foo::bar[yay]") ref.type.should == "Foo::Bar" ref.title.should == "yay" end it "should set the type to 'Class' if it is nil and the title contains no square brackets" do ref = Puppet::Resource.new(nil, "yay") ref.type.should == "Class" ref.title.should == "Yay" end it "should interpret the title as a reference and assign appropriately if the type is nil and the title contains square brackets" do ref = Puppet::Resource.new(nil, "foo::bar[yay]") ref.type.should == "Foo::Bar" ref.title.should == "yay" end it "should interpret the title as a reference and assign appropriately if the type is nil and the title contains nested square brackets" do ref = Puppet::Resource.new(nil, "foo::bar[baz[yay]]") ref.type.should == "Foo::Bar" ref.title.should =="baz[yay]" end it "should interpret the type as a reference and assign appropriately if the title is nil and the type contains square brackets" do ref = Puppet::Resource.new("foo::bar[baz]") ref.type.should == "Foo::Bar" ref.title.should =="baz" end it "should be able to extract its information from a Puppet::Type instance" do ral = Puppet::Type.type(:file).new :path => @basepath+"/foo" ref = Puppet::Resource.new(ral) ref.type.should == "File" ref.title.should == @basepath+"/foo" end it "should fail if the title is nil and the type is not a valid resource reference string" do lambda { Puppet::Resource.new("foo") }.should raise_error(ArgumentError) end it 'should fail if strict is set and type does not exist' do lambda { Puppet::Resource.new('foo', 'title', {:strict=>true}) }.should raise_error(ArgumentError, 'Invalid resource type foo') end it 'should fail if strict is set and class does not exist' do lambda { Puppet::Resource.new('Class', 'foo', {:strict=>true}) }.should raise_error(ArgumentError, 'Could not find declared class foo') end it "should fail if the title is a hash and the type is not a valid resource reference string" do lambda { Puppet::Resource.new({:type => "foo", :title => "bar"}) }.should raise_error(ArgumentError, 'Puppet::Resource.new does not take a hash as the first argument. Did you mean ("foo", "bar") ?' ) end it "should be able to produce a backward-compatible reference array" do Puppet::Resource.new("foobar", "/f").to_trans_ref.should == %w{Foobar /f} end it "should be taggable" do Puppet::Resource.ancestors.should be_include(Puppet::Util::Tagging) end it "should have an 'exported' attribute" do resource = Puppet::Resource.new("file", "/f") resource.exported = true resource.exported.should == true resource.should be_exported end it "should support an environment attribute" do Puppet::Resource.new("file", "/my/file", :environment => :foo).environment.name.should == :foo end describe "and munging its type and title" do describe "when modeling a builtin resource" do it "should be able to find the resource type" do Puppet::Resource.new("file", "/my/file").resource_type.should equal(Puppet::Type.type(:file)) end it "should set its type to the capitalized type name" do Puppet::Resource.new("file", "/my/file").type.should == "File" end end describe "when modeling a defined resource" do describe "that exists" do before do @type = Puppet::Resource::Type.new(:definition, "foo::bar") Puppet::Node::Environment.new.known_resource_types.add @type end it "should set its type to the capitalized type name" do Puppet::Resource.new("foo::bar", "/my/file").type.should == "Foo::Bar" end it "should be able to find the resource type" do Puppet::Resource.new("foo::bar", "/my/file").resource_type.should equal(@type) end it "should set its title to the provided title" do Puppet::Resource.new("foo::bar", "/my/file").title.should == "/my/file" end end describe "that does not exist" do it "should set its resource type to the capitalized resource type name" do Puppet::Resource.new("foo::bar", "/my/file").type.should == "Foo::Bar" end end end describe "when modeling a node" do # Life's easier with nodes, because they can't be qualified. it "should set its type to 'Node' and its title to the provided title" do node = Puppet::Resource.new("node", "foo") node.type.should == "Node" node.title.should == "foo" end end describe "when modeling a class" do it "should set its type to 'Class'" do Puppet::Resource.new("class", "foo").type.should == "Class" end describe "that exists" do before do @type = Puppet::Resource::Type.new(:hostclass, "foo::bar") Puppet::Node::Environment.new.known_resource_types.add @type end it "should set its title to the capitalized, fully qualified resource type" do Puppet::Resource.new("class", "foo::bar").title.should == "Foo::Bar" end it "should be able to find the resource type" do Puppet::Resource.new("class", "foo::bar").resource_type.should equal(@type) end end describe "that does not exist" do it "should set its type to 'Class' and its title to the capitalized provided name" do klass = Puppet::Resource.new("class", "foo::bar") klass.type.should == "Class" klass.title.should == "Foo::Bar" end end describe "and its name is set to the empty string" do it "should set its title to :main" do Puppet::Resource.new("class", "").title.should == :main end describe "and a class exists whose name is the empty string" do # this was a bit tough to track down it "should set its title to :main" do @type = Puppet::Resource::Type.new(:hostclass, "") Puppet::Node::Environment.new.known_resource_types.add @type Puppet::Resource.new("class", "").title.should == :main end end end describe "and its name is set to :main" do it "should set its title to :main" do Puppet::Resource.new("class", :main).title.should == :main end describe "and a class exists whose name is the empty string" do # this was a bit tough to track down it "should set its title to :main" do @type = Puppet::Resource::Type.new(:hostclass, "") Puppet::Node::Environment.new.known_resource_types.add @type Puppet::Resource.new("class", :main).title.should == :main end end end end end it "should return nil when looking up resource types that don't exist" do Puppet::Resource.new("foobar", "bar").resource_type.should be_nil end it "should not fail when an invalid parameter is used and strict mode is disabled" do type = Puppet::Resource::Type.new(:definition, "foobar") Puppet::Node::Environment.new.known_resource_types.add type resource = Puppet::Resource.new("foobar", "/my/file") resource[:yay] = true end it "should be considered equivalent to another resource if their type and title match and no parameters are set" do Puppet::Resource.new("file", "/f").should == Puppet::Resource.new("file", "/f") end it "should be considered equivalent to another resource if their type, title, and parameters are equal" do Puppet::Resource.new("file", "/f", :parameters => {:foo => "bar"}).should == Puppet::Resource.new("file", "/f", :parameters => {:foo => "bar"}) end it "should not be considered equivalent to another resource if their type and title match but parameters are different" do Puppet::Resource.new("file", "/f", :parameters => {:fee => "baz"}).should_not == Puppet::Resource.new("file", "/f", :parameters => {:foo => "bar"}) end it "should not be considered equivalent to a non-resource" do Puppet::Resource.new("file", "/f").should_not == "foo" end it "should not be considered equivalent to another resource if their types do not match" do Puppet::Resource.new("file", "/f").should_not == Puppet::Resource.new("exec", "/f") end it "should not be considered equivalent to another resource if their titles do not match" do Puppet::Resource.new("file", "/foo").should_not == Puppet::Resource.new("file", "/f") end describe "when referring to a resource with name canonicalization" do it "should canonicalize its own name" do res = Puppet::Resource.new("file", "/path/") res.uniqueness_key.should == ["/path"] res.ref.should == "File[/path/]" end end describe "when running in strict mode" do it "should be strict" do Puppet::Resource.new("file", "/path", :strict => true).should be_strict end it "should fail if invalid parameters are used" do lambda { Puppet::Resource.new("file", "/path", :strict => true, :parameters => {:nosuchparam => "bar"}) }.should raise_error end it "should fail if the resource type cannot be resolved" do lambda { Puppet::Resource.new("nosuchtype", "/path", :strict => true) }.should raise_error end end describe "when managing parameters" do before do @resource = Puppet::Resource.new("file", "/my/file") end it "should correctly detect when provided parameters are not valid for builtin types" do Puppet::Resource.new("file", "/my/file").should_not be_valid_parameter("foobar") end it "should correctly detect when provided parameters are valid for builtin types" do Puppet::Resource.new("file", "/my/file").should be_valid_parameter("mode") end it "should correctly detect when provided parameters are not valid for defined resource types" do type = Puppet::Resource::Type.new(:definition, "foobar") Puppet::Node::Environment.new.known_resource_types.add type Puppet::Resource.new("foobar", "/my/file").should_not be_valid_parameter("myparam") end it "should correctly detect when provided parameters are valid for defined resource types" do type = Puppet::Resource::Type.new(:definition, "foobar", :arguments => {"myparam" => nil}) Puppet::Node::Environment.new.known_resource_types.add type Puppet::Resource.new("foobar", "/my/file").should be_valid_parameter("myparam") end it "should allow setting and retrieving of parameters" do @resource[:foo] = "bar" @resource[:foo].should == "bar" end it "should allow setting of parameters at initialization" do Puppet::Resource.new("file", "/my/file", :parameters => {:foo => "bar"})[:foo].should == "bar" end it "should canonicalize retrieved parameter names to treat symbols and strings equivalently" do @resource[:foo] = "bar" @resource["foo"].should == "bar" end it "should canonicalize set parameter names to treat symbols and strings equivalently" do @resource["foo"] = "bar" @resource[:foo].should == "bar" end it "should set the namevar when asked to set the name" do resource = Puppet::Resource.new("user", "bob") Puppet::Type.type(:user).stubs(:key_attributes).returns [:myvar] resource[:name] = "bob" resource[:myvar].should == "bob" end it "should return the namevar when asked to return the name" do resource = Puppet::Resource.new("user", "bob") Puppet::Type.type(:user).stubs(:key_attributes).returns [:myvar] resource[:myvar] = "test" resource[:name].should == "test" end it "should be able to set the name for non-builtin types" do resource = Puppet::Resource.new(:foo, "bar") resource[:name] = "eh" lambda { resource[:name] = "eh" }.should_not raise_error end it "should be able to return the name for non-builtin types" do resource = Puppet::Resource.new(:foo, "bar") resource[:name] = "eh" resource[:name].should == "eh" end it "should be able to iterate over parameters" do @resource[:foo] = "bar" @resource[:fee] = "bare" params = {} @resource.each do |key, value| params[key] = value end params.should == {:foo => "bar", :fee => "bare"} end it "should include Enumerable" do @resource.class.ancestors.should be_include(Enumerable) end it "should have a method for testing whether a parameter is included" do @resource[:foo] = "bar" @resource.should be_has_key(:foo) @resource.should_not be_has_key(:eh) end it "should have a method for providing the list of parameters" do @resource[:foo] = "bar" @resource[:bar] = "foo" keys = @resource.keys keys.should be_include(:foo) keys.should be_include(:bar) end it "should have a method for providing the number of parameters" do @resource[:foo] = "bar" @resource.length.should == 1 end it "should have a method for deleting parameters" do @resource[:foo] = "bar" @resource.delete(:foo) @resource[:foo].should be_nil end it "should have a method for testing whether the parameter list is empty" do @resource.should be_empty @resource[:foo] = "bar" @resource.should_not be_empty end it "should be able to produce a hash of all existing parameters" do @resource[:foo] = "bar" @resource[:fee] = "yay" hash = @resource.to_hash hash[:foo].should == "bar" hash[:fee].should == "yay" end it "should not provide direct access to the internal parameters hash when producing a hash" do hash = @resource.to_hash hash[:foo] = "bar" @resource[:foo].should be_nil end it "should use the title as the namevar to the hash if no namevar is present" do resource = Puppet::Resource.new("user", "bob") Puppet::Type.type(:user).stubs(:key_attributes).returns [:myvar] resource.to_hash[:myvar].should == "bob" end it "should set :name to the title if :name is not present for non-builtin types" do krt = Puppet::Resource::TypeCollection.new("myenv") krt.add Puppet::Resource::Type.new(:definition, :foo) resource = Puppet::Resource.new :foo, "bar" resource.stubs(:known_resource_types).returns krt resource.to_hash[:name].should == "bar" end end describe "when serializing" do before do @resource = Puppet::Resource.new("file", "/my/file") @resource["one"] = "test" @resource["two"] = "other" end it "should be able to be dumped to yaml" do proc { YAML.dump(@resource) }.should_not raise_error end it "should produce an equivalent yaml object" do text = YAML.dump(@resource) newresource = YAML.load(text) newresource.title.should == @resource.title newresource.type.should == @resource.type %w{one two}.each do |param| newresource[param].should == @resource[param] end end end describe "when loading 0.25.x storedconfigs YAML" do before :each do @old_storedconfig_yaml = %q{--- !ruby/object:Puppet::Resource::Reference builtin_type: title: /tmp/bar type: File } end it "should deserialize a Puppet::Resource::Reference without exceptions" do lambda { YAML.load(@old_storedconfig_yaml) }.should_not raise_error end it "should deserialize as a Puppet::Resource::Reference as a Puppet::Resource" do YAML.load(@old_storedconfig_yaml).class.should == Puppet::Resource end it "should to_hash properly" do YAML.load(@old_storedconfig_yaml).to_hash.should == { :path => "/tmp/bar" } end end describe "when converting to a RAL resource" do it "should use the resource type's :new method to create the resource if the resource is of a builtin type" do resource = Puppet::Resource.new("file", @basepath+"/my/file") result = resource.to_ral result.should be_instance_of(Puppet::Type.type(:file)) result[:path].should == @basepath+"/my/file" end it "should convert to a component instance if the resource type is not of a builtin type" do resource = Puppet::Resource.new("foobar", "somename") result = resource.to_ral result.should be_instance_of(Puppet::Type.type(:component)) result.title.should == "Foobar[somename]" end end it "should be able to convert itself to Puppet code" do Puppet::Resource.new("one::two", "/my/file").should respond_to(:to_manifest) end describe "when converting to puppet code" do before do @resource = Puppet::Resource.new("one::two", "/my/file", :parameters => { :noop => true, :foo => %w{one two}, :ensure => 'present', } ) end it "should align, sort and add trailing commas to attributes with ensure first" do @resource.to_manifest.should == <<-HEREDOC.gsub(/^\s{8}/, '').gsub(/\n$/, '') one::two { '/my/file': ensure => 'present', foo => ['one', 'two'], noop => 'true', } HEREDOC end end it "should be able to convert itself to a TransObject instance" do Puppet::Resource.new("one::two", "/my/file").should respond_to(:to_trans) end describe "when converting to a TransObject" do describe "and the resource is not an instance of a builtin type" do before do @resource = Puppet::Resource.new("foo", "bar") end it "should return a simple TransBucket if it is not an instance of a builtin type" do bucket = @resource.to_trans bucket.should be_instance_of(Puppet::TransBucket) bucket.type.should == @resource.type bucket.name.should == @resource.title end it "should return a simple TransBucket if it is a stage" do @resource = Puppet::Resource.new("stage", "bar") bucket = @resource.to_trans bucket.should be_instance_of(Puppet::TransBucket) bucket.type.should == @resource.type bucket.name.should == @resource.title end it "should copy over the resource's file" do @resource.file = "/foo/bar" @resource.to_trans.file.should == "/foo/bar" end it "should copy over the resource's line" do @resource.line = 50 @resource.to_trans.line.should == 50 end end describe "and the resource is an instance of a builtin type" do before do @resource = Puppet::Resource.new("file", "bar") end it "should return a TransObject if it is an instance of a builtin resource type" do trans = @resource.to_trans trans.should be_instance_of(Puppet::TransObject) trans.type.should == "file" trans.name.should == @resource.title end it "should copy over the resource's file" do @resource.file = "/foo/bar" @resource.to_trans.file.should == "/foo/bar" end it "should copy over the resource's line" do @resource.line = 50 @resource.to_trans.line.should == 50 end # Only TransObjects support tags, annoyingly it "should copy over the resource's tags" do @resource.tag "foo" @resource.to_trans.tags.should == @resource.tags end it "should copy the resource's parameters into the transobject and convert the parameter name to a string" do @resource[:foo] = "bar" @resource.to_trans["foo"].should == "bar" end it "should be able to copy arrays of values" do @resource[:foo] = %w{yay fee} @resource.to_trans["foo"].should == %w{yay fee} end it "should reduce single-value arrays to just a value" do @resource[:foo] = %w{yay} @resource.to_trans["foo"].should == "yay" end it "should convert resource references into the backward-compatible form" do @resource[:foo] = Puppet::Resource.new(:file, "/f") @resource.to_trans["foo"].should == %w{File /f} end it "should convert resource references into the backward-compatible form even when within arrays" do @resource[:foo] = ["a", Puppet::Resource.new(:file, "/f")] @resource.to_trans["foo"].should == ["a", %w{File /f}] end end end describe "when converting to pson", :if => Puppet.features.pson? do def pson_output_should @resource.class.expects(:pson_create).with { |hash| yield hash } end it "should include the pson util module" do Puppet::Resource.singleton_class.ancestors.should be_include(Puppet::Util::Pson) end # LAK:NOTE For all of these tests, we convert back to the resource so we can # trap the actual data structure then. it "should set its type to the provided type" do Puppet::Resource.from_pson(PSON.parse(Puppet::Resource.new("File", "/foo").to_pson)).type.should == "File" end it "should set its title to the provided title" do Puppet::Resource.from_pson(PSON.parse(Puppet::Resource.new("File", "/foo").to_pson)).title.should == "/foo" end it "should include all tags from the resource" do resource = Puppet::Resource.new("File", "/foo") resource.tag("yay") Puppet::Resource.from_pson(PSON.parse(resource.to_pson)).tags.should == resource.tags end it "should include the file if one is set" do resource = Puppet::Resource.new("File", "/foo") resource.file = "/my/file" Puppet::Resource.from_pson(PSON.parse(resource.to_pson)).file.should == "/my/file" end it "should include the line if one is set" do resource = Puppet::Resource.new("File", "/foo") resource.line = 50 Puppet::Resource.from_pson(PSON.parse(resource.to_pson)).line.should == 50 end it "should include the 'exported' value if one is set" do resource = Puppet::Resource.new("File", "/foo") resource.exported = true Puppet::Resource.from_pson(PSON.parse(resource.to_pson)).exported.should be_true end it "should set 'exported' to false if no value is set" do resource = Puppet::Resource.new("File", "/foo") Puppet::Resource.from_pson(PSON.parse(resource.to_pson)).exported.should be_false end it "should set all of its parameters as the 'parameters' entry" do resource = Puppet::Resource.new("File", "/foo") resource[:foo] = %w{bar eh} resource[:fee] = %w{baz} result = Puppet::Resource.from_pson(PSON.parse(resource.to_pson)) result["foo"].should == %w{bar eh} result["fee"].should == %w{baz} end it "should serialize relationships as reference strings" do resource = Puppet::Resource.new("File", "/foo") resource[:requires] = Puppet::Resource.new("File", "/bar") result = Puppet::Resource.from_pson(PSON.parse(resource.to_pson)) result[:requires].should == "File[/bar]" end it "should serialize multiple relationships as arrays of reference strings" do resource = Puppet::Resource.new("File", "/foo") resource[:requires] = [Puppet::Resource.new("File", "/bar"), Puppet::Resource.new("File", "/baz")] result = Puppet::Resource.from_pson(PSON.parse(resource.to_pson)) result[:requires].should == [ "File[/bar]", "File[/baz]" ] end end describe "when converting from pson", :if => Puppet.features.pson? do def pson_result_should Puppet::Resource.expects(:new).with { |hash| yield hash } end before do @data = { 'type' => "file", 'title' => @basepath+"/yay", } end it "should set its type to the provided type" do Puppet::Resource.from_pson(@data).type.should == "File" end it "should set its title to the provided title" do Puppet::Resource.from_pson(@data).title.should == @basepath+"/yay" end it "should tag the resource with any provided tags" do @data['tags'] = %w{foo bar} resource = Puppet::Resource.from_pson(@data) resource.tags.should be_include("foo") resource.tags.should be_include("bar") end it "should set its file to the provided file" do @data['file'] = "/foo/bar" Puppet::Resource.from_pson(@data).file.should == "/foo/bar" end it "should set its line to the provided line" do @data['line'] = 50 Puppet::Resource.from_pson(@data).line.should == 50 end it "should 'exported' to true if set in the pson data" do @data['exported'] = true Puppet::Resource.from_pson(@data).exported.should be_true end it "should 'exported' to false if not set in the pson data" do Puppet::Resource.from_pson(@data).exported.should be_false end it "should fail if no title is provided" do @data.delete('title') lambda { Puppet::Resource.from_pson(@data) }.should raise_error(ArgumentError) end it "should fail if no type is provided" do @data.delete('type') lambda { Puppet::Resource.from_pson(@data) }.should raise_error(ArgumentError) end it "should set each of the provided parameters" do @data['parameters'] = {'foo' => %w{one two}, 'fee' => %w{three four}} resource = Puppet::Resource.from_pson(@data) resource['foo'].should == %w{one two} resource['fee'].should == %w{three four} end it "should convert single-value array parameters to normal values" do @data['parameters'] = {'foo' => %w{one}} resource = Puppet::Resource.from_pson(@data) resource['foo'].should == %w{one} end end describe "it should implement to_resource" do resource = Puppet::Resource.new("file", "/my/file") resource.to_resource.should == resource end describe "because it is an indirector model" do it "should include Puppet::Indirector" do Puppet::Resource.should be_is_a(Puppet::Indirector) end it "should have a default terminus" do Puppet::Resource.indirection.terminus_class.should == :ral end it "should have a name" do Puppet::Resource.new("file", "/my/file").name.should == "File//my/file" end end describe "when resolving resources with a catalog" do it "should resolve all resources using the catalog" do catalog = mock 'catalog' resource = Puppet::Resource.new("foo::bar", "yay") resource.catalog = catalog catalog.expects(:resource).with("Foo::Bar[yay]").returns(:myresource) resource.resolve.should == :myresource end end describe "when generating the uniqueness key" do it "should include all of the key_attributes in alphabetical order by attribute name" do Puppet::Type.type(:file).stubs(:key_attributes).returns [:myvar, :owner, :path] Puppet::Type.type(:file).stubs(:title_patterns).returns( [ [ /(.*)/, [ [:path, lambda{|x| x} ] ] ] ] ) res = Puppet::Resource.new("file", "/my/file", :parameters => {:owner => 'root', :content => 'hello'}) res.uniqueness_key.should == [ nil, 'root', '/my/file'] end end end diff --git a/spec/unit/run_spec.rb b/spec/unit/run_spec.rb index d9a5690cb..ea6ec74b1 100755 --- a/spec/unit/run_spec.rb +++ b/spec/unit/run_spec.rb @@ -1,137 +1,136 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/agent' require 'puppet/run' describe Puppet::Run do before do @runner = Puppet::Run.new end it "should indirect :run" do Puppet::Run.indirection.name.should == :run end it "should use a configurer agent as its agent" do agent = mock 'agent' Puppet::Agent.expects(:new).with(Puppet::Configurer).returns agent @runner.agent.should equal(agent) end it "should accept options at initialization" do lambda { Puppet::Run.new :background => true }.should_not raise_error end it "should default to running in the foreground" do Puppet::Run.new.should_not be_background end it "should default to its options being an empty hash" do Puppet::Run.new.options.should == {} end it "should accept :tags for the agent" do Puppet::Run.new(:tags => "foo").options[:tags].should == "foo" end it "should accept :ignoreschedules for the agent" do Puppet::Run.new(:ignoreschedules => true).options[:ignoreschedules].should be_true end it "should accept an option to configure it to run in the background" do Puppet::Run.new(:background => true).should be_background end it "should retain the background option" do Puppet::Run.new(:background => true).options[:background].should be_nil end it "should not accept arbitrary options" do lambda { Puppet::Run.new(:foo => true) }.should raise_error(ArgumentError) end describe "when asked to run" do before do @agent = stub 'agent', :run => nil, :running? => false @runner.stubs(:agent).returns @agent end it "should run its agent" do agent = stub 'agent2', :running? => false @runner.stubs(:agent).returns agent agent.expects(:run) @runner.run end it "should pass any of its options on to the agent" do @runner.stubs(:options).returns(:foo => :bar) @agent.expects(:run).with(:foo => :bar) @runner.run end it "should log its run using the provided options" do @runner.expects(:log_run) @runner.run end it "should set its status to 'already_running' if the agent is already running" do @agent.expects(:running?).returns true @runner.run @runner.status.should == "running" end it "should set its status to 'success' if the agent is run" do @agent.expects(:running?).returns false @runner.run @runner.status.should == "success" end it "should run the agent in a thread if asked to run it in the background" do Thread.expects(:new) @runner.expects(:background?).returns true @agent.expects(:run).never # because our thread didn't yield @runner.run end it "should run the agent directly if asked to run it in the foreground" do Thread.expects(:new).never @runner.expects(:background?).returns false @agent.expects(:run) @runner.run end end describe ".from_pson" do it "should accept a hash of options, and pass them with symbolified keys to new" do options = { "tags" => "whatever", "background" => true, } Puppet::Run.expects(:new).with( { :tags => "whatever", :background => true, }) Puppet::Run.from_pson(options) end end end diff --git a/spec/unit/simple_graph_spec.rb b/spec/unit/simple_graph_spec.rb index 38d37c2e2..c8fea3b58 100755 --- a/spec/unit/simple_graph_spec.rb +++ b/spec/unit/simple_graph_spec.rb @@ -1,904 +1,904 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Created by Luke Kanies on 2007-11-1. # Copyright (c) 2006. All rights reserved. require 'spec_helper' require 'puppet/simple_graph' describe Puppet::SimpleGraph do it "should return the number of its vertices as its length" do @graph = Puppet::SimpleGraph.new @graph.add_vertex("one") @graph.add_vertex("two") @graph.size.should == 2 end it "should consider itself a directed graph" do Puppet::SimpleGraph.new.directed?.should be_true end it "should provide a method for reversing the graph" do @graph = Puppet::SimpleGraph.new @graph.add_edge(:one, :two) @graph.reversal.edge?(:two, :one).should be_true end it "should be able to produce a dot graph" do @graph = Puppet::SimpleGraph.new @graph.add_edge(:one, :two) proc { @graph.to_dot_graph }.should_not raise_error end describe "when managing vertices" do before do @graph = Puppet::SimpleGraph.new end it "should provide a method to add a vertex" do @graph.add_vertex(:test) @graph.vertex?(:test).should be_true end it "should reset its reversed graph when vertices are added" do rev = @graph.reversal @graph.add_vertex(:test) @graph.reversal.should_not equal(rev) end it "should ignore already-present vertices when asked to add a vertex" do @graph.add_vertex(:test) proc { @graph.add_vertex(:test) }.should_not raise_error end it "should return true when asked if a vertex is present" do @graph.add_vertex(:test) @graph.vertex?(:test).should be_true end it "should return false when asked if a non-vertex is present" do @graph.vertex?(:test).should be_false end it "should return all set vertices when asked" do @graph.add_vertex(:one) @graph.add_vertex(:two) @graph.vertices.length.should == 2 @graph.vertices.should include(:one) @graph.vertices.should include(:two) end it "should remove a given vertex when asked" do @graph.add_vertex(:one) @graph.remove_vertex!(:one) @graph.vertex?(:one).should be_false end it "should do nothing when a non-vertex is asked to be removed" do proc { @graph.remove_vertex!(:one) }.should_not raise_error end end describe "when managing edges" do before do @graph = Puppet::SimpleGraph.new end it "should provide a method to test whether a given vertex pair is an edge" do @graph.should respond_to(:edge?) end it "should reset its reversed graph when edges are added" do rev = @graph.reversal @graph.add_edge(:one, :two) @graph.reversal.should_not equal(rev) end it "should provide a method to add an edge as an instance of the edge class" do edge = Puppet::Relationship.new(:one, :two) @graph.add_edge(edge) @graph.edge?(:one, :two).should be_true end it "should provide a method to add an edge by specifying the two vertices" do @graph.add_edge(:one, :two) @graph.edge?(:one, :two).should be_true end it "should provide a method to add an edge by specifying the two vertices and a label" do @graph.add_edge(:one, :two, :callback => :awesome) @graph.edge?(:one, :two).should be_true end describe "when retrieving edges between two nodes" do it "should handle the case of nodes not in the graph" do @graph.edges_between(:one, :two).should == [] end it "should handle the case of nodes with no edges between them" do @graph.add_vertex(:one) @graph.add_vertex(:two) @graph.edges_between(:one, :two).should == [] end it "should handle the case of nodes connected by a single edge" do edge = Puppet::Relationship.new(:one, :two) @graph.add_edge(edge) @graph.edges_between(:one, :two).length.should == 1 @graph.edges_between(:one, :two)[0].should equal(edge) end it "should handle the case of nodes connected by multiple edges" do edge1 = Puppet::Relationship.new(:one, :two, :callback => :foo) edge2 = Puppet::Relationship.new(:one, :two, :callback => :bar) @graph.add_edge(edge1) @graph.add_edge(edge2) Set.new(@graph.edges_between(:one, :two)).should == Set.new([edge1, edge2]) end end it "should add the edge source as a vertex if it is not already" do edge = Puppet::Relationship.new(:one, :two) @graph.add_edge(edge) @graph.vertex?(:one).should be_true end it "should add the edge target as a vertex if it is not already" do edge = Puppet::Relationship.new(:one, :two) @graph.add_edge(edge) @graph.vertex?(:two).should be_true end it "should return all edges as edge instances when asked" do one = Puppet::Relationship.new(:one, :two) two = Puppet::Relationship.new(:two, :three) @graph.add_edge(one) @graph.add_edge(two) edges = @graph.edges edges.should be_instance_of(Array) edges.length.should == 2 edges.should include(one) edges.should include(two) end it "should remove an edge when asked" do edge = Puppet::Relationship.new(:one, :two) @graph.add_edge(edge) @graph.remove_edge!(edge) @graph.edge?(edge.source, edge.target).should be_false end it "should remove all related edges when a vertex is removed" do one = Puppet::Relationship.new(:one, :two) two = Puppet::Relationship.new(:two, :three) @graph.add_edge(one) @graph.add_edge(two) @graph.remove_vertex!(:two) @graph.edge?(:one, :two).should be_false @graph.edge?(:two, :three).should be_false @graph.edges.length.should == 0 end end describe "when finding adjacent vertices" do before do @graph = Puppet::SimpleGraph.new @one_two = Puppet::Relationship.new(:one, :two) @two_three = Puppet::Relationship.new(:two, :three) @one_three = Puppet::Relationship.new(:one, :three) @graph.add_edge(@one_two) @graph.add_edge(@one_three) @graph.add_edge(@two_three) end it "should return adjacent vertices" do adj = @graph.adjacent(:one) adj.should be_include(:three) adj.should be_include(:two) end it "should default to finding :out vertices" do @graph.adjacent(:two).should == [:three] end it "should support selecting :in vertices" do @graph.adjacent(:two, :direction => :in).should == [:one] end it "should default to returning the matching vertices as an array of vertices" do @graph.adjacent(:two).should == [:three] end it "should support returning an array of matching edges" do @graph.adjacent(:two, :type => :edges).should == [@two_three] end # Bug #2111 it "should not consider a vertex adjacent just because it was asked about previously" do @graph = Puppet::SimpleGraph.new @graph.add_vertex("a") @graph.add_vertex("b") @graph.edge?("a", "b") @graph.adjacent("a").should == [] end end describe "when clearing" do before do @graph = Puppet::SimpleGraph.new one = Puppet::Relationship.new(:one, :two) two = Puppet::Relationship.new(:two, :three) @graph.add_edge(one) @graph.add_edge(two) @graph.clear end it "should remove all vertices" do @graph.vertices.should be_empty end it "should remove all edges" do @graph.edges.should be_empty end end describe "when reversing graphs" do before do @graph = Puppet::SimpleGraph.new end it "should provide a method for reversing the graph" do @graph.add_edge(:one, :two) @graph.reversal.edge?(:two, :one).should be_true end it "should add all vertices to the reversed graph" do @graph.add_edge(:one, :two) @graph.vertex?(:one).should be_true @graph.vertex?(:two).should be_true end it "should retain labels on edges" do @graph.add_edge(:one, :two, :callback => :awesome) edge = @graph.reversal.edges_between(:two, :one)[0] edge.label.should == {:callback => :awesome} end end describe "when reporting cycles in the graph" do before do @graph = Puppet::SimpleGraph.new end def add_edges(hash) hash.each do |a,b| @graph.add_edge(a, b) end end it "should fail on two-vertex loops" do add_edges :a => :b, :b => :a proc { @graph.report_cycles_in_graph }.should raise_error(Puppet::Error) end it "should fail on multi-vertex loops" do add_edges :a => :b, :b => :c, :c => :a proc { @graph.report_cycles_in_graph }.should raise_error(Puppet::Error) end it "should fail when a larger tree contains a small cycle" do add_edges :a => :b, :b => :a, :c => :a, :d => :c proc { @graph.report_cycles_in_graph }.should raise_error(Puppet::Error) end it "should succeed on trees with no cycles" do add_edges :a => :b, :b => :e, :c => :a, :d => :c proc { @graph.report_cycles_in_graph }.should_not raise_error end it "should produce the correct relationship text" do add_edges :a => :b, :b => :a # cycle detection starts from a or b randomly # so we need to check for either ordering in the error message want = %r{Found 1 dependency cycle:\n\((a => b => a|b => a => b)\)\nTry} expect { @graph.report_cycles_in_graph }.to raise_error(Puppet::Error, want) end it "cycle discovery should be the minimum cycle for a simple graph" do add_edges "a" => "b" add_edges "b" => "a" add_edges "b" => "c" cycles = nil expect { cycles = @graph.find_cycles_in_graph.sort }.should_not raise_error cycles.should be == [["a", "b"]] end it "cycle discovery should handle two distinct cycles" do add_edges "a" => "a1", "a1" => "a" add_edges "b" => "b1", "b1" => "b" cycles = nil expect { cycles = @graph.find_cycles_in_graph.sort }.should_not raise_error cycles.should be == [["a", "a1"], ["b", "b1"]] end it "cycle discovery should handle two cycles in a connected graph" do add_edges "a" => "b", "b" => "c", "c" => "d" add_edges "a" => "a1", "a1" => "a" add_edges "c" => "c1", "c1" => "c2", "c2" => "c3", "c3" => "c" cycles = nil expect { cycles = @graph.find_cycles_in_graph.sort }.should_not raise_error cycles.should be == [%w{a a1}, %w{c c1 c2 c3}] end it "cycle discovery should handle a complicated cycle" do add_edges "a" => "b", "b" => "c" add_edges "a" => "c" add_edges "c" => "c1", "c1" => "a" add_edges "c" => "c2", "c2" => "b" cycles = nil expect { cycles = @graph.find_cycles_in_graph.sort }.should_not raise_error cycles.should be == [%w{a b c c1 c2}] end it "cycle discovery should not fail with large data sets" do limit = 3000 (1..(limit - 1)).each do |n| add_edges n.to_s => (n+1).to_s end cycles = nil expect { cycles = @graph.find_cycles_in_graph.sort }.should_not raise_error cycles.should be == [] end it "path finding should work with a simple cycle" do add_edges "a" => "b", "b" => "c", "c" => "a" cycles = @graph.find_cycles_in_graph.sort paths = @graph.paths_in_cycle(cycles.first, 100) paths.should be == [%w{a b c a}] end it "path finding should work with two independent cycles" do add_edges "a" => "b1" add_edges "a" => "b2" add_edges "b1" => "a", "b2" => "a" cycles = @graph.find_cycles_in_graph.sort cycles.length.should be == 1 paths = @graph.paths_in_cycle(cycles.first, 100) paths.sort.should be == [%w{a b1 a}, %w{a b2 a}] end it "path finding should prefer shorter paths in cycles" do add_edges "a" => "b", "b" => "c", "c" => "a" add_edges "b" => "a" cycles = @graph.find_cycles_in_graph.sort cycles.length.should be == 1 paths = @graph.paths_in_cycle(cycles.first, 100) paths.should be == [%w{a b a}, %w{a b c a}] end it "path finding should respect the max_path value" do (1..20).each do |n| add_edges "a" => "b#{n}", "b#{n}" => "a" end cycles = @graph.find_cycles_in_graph.sort cycles.length.should be == 1 (1..20).each do |n| paths = @graph.paths_in_cycle(cycles.first, n) paths.length.should be == n end paths = @graph.paths_in_cycle(cycles.first, 21) paths.length.should be == 20 end end describe "when writing dot files" do before do @graph = Puppet::SimpleGraph.new @name = :test @file = File.join(Puppet[:graphdir], @name.to_s + ".dot") end it "should only write when graphing is enabled" do File.expects(:open).with(@file).never Puppet[:graph] = false @graph.write_graph(@name) end it "should write a dot file based on the passed name" do File.expects(:open).with(@file, "w").yields(stub("file", :puts => nil)) @graph.expects(:to_dot).with("name" => @name.to_s.capitalize) Puppet[:graph] = true @graph.write_graph(@name) end after do Puppet.settings.clear end end describe Puppet::SimpleGraph do before do @graph = Puppet::SimpleGraph.new end it "should correctly clear vertices and edges when asked" do @graph.add_edge("a", "b") @graph.add_vertex "c" @graph.clear @graph.vertices.should be_empty @graph.edges.should be_empty end end describe "when matching edges" do before do @graph = Puppet::SimpleGraph.new @event = Puppet::Transaction::Event.new(:name => :yay, :resource => "a") @none = Puppet::Transaction::Event.new(:name => :NONE, :resource => "a") @edges = {} @edges["a/b"] = Puppet::Relationship.new("a", "b", {:event => :yay, :callback => :refresh}) @edges["a/c"] = Puppet::Relationship.new("a", "c", {:event => :yay, :callback => :refresh}) @graph.add_edge(@edges["a/b"]) end it "should match edges whose source matches the source of the event" do @graph.matching_edges(@event).should == [@edges["a/b"]] end it "should match always match nothing when the event is :NONE" do @graph.matching_edges(@none).should be_empty end it "should match multiple edges" do @graph.add_edge(@edges["a/c"]) edges = @graph.matching_edges(@event) edges.should be_include(@edges["a/b"]) edges.should be_include(@edges["a/c"]) end end describe "when determining dependencies" do before do @graph = Puppet::SimpleGraph.new @graph.add_edge("a", "b") @graph.add_edge("a", "c") @graph.add_edge("b", "d") end it "should find all dependents when they are on multiple levels" do @graph.dependents("a").sort.should == %w{b c d}.sort end it "should find single dependents" do @graph.dependents("b").sort.should == %w{d}.sort end it "should return an empty array when there are no dependents" do @graph.dependents("c").sort.should == [].sort end it "should find all dependencies when they are on multiple levels" do @graph.dependencies("d").sort.should == %w{a b} end it "should find single dependencies" do @graph.dependencies("c").sort.should == %w{a} end it "should return an empty array when there are no dependencies" do @graph.dependencies("a").sort.should == [] end end require 'puppet/util/graph' class Container < Puppet::Type::Component include Puppet::Util::Graph include Enumerable attr_accessor :name def each @children.each do |c| yield c end end def initialize(name, ary) @name = name @children = ary end def push(*ary) ary.each { |c| @children.push(c)} end def to_s @name end end require "puppet/resource/catalog" describe "when splicing the graph" do def container_graph @one = Container.new("one", %w{a b}) @two = Container.new("two", ["c", "d"]) @three = Container.new("three", ["i", "j"]) @middle = Container.new("middle", ["e", "f", @two]) @top = Container.new("top", ["g", "h", @middle, @one, @three]) @empty = Container.new("empty", []) @whit = Puppet::Type.type(:whit) @stage = Puppet::Type.type(:stage).new(:name => "foo") @contgraph = @top.to_graph(Puppet::Resource::Catalog.new) # We have to add the container to the main graph, else it won't # be spliced in the dependency graph. @contgraph.add_vertex(@empty) end def containers @contgraph.vertices.select { |x| !x.is_a? String } end def contents_of(x) @contgraph.direct_dependents_of(x) end def dependency_graph @depgraph = Puppet::SimpleGraph.new @contgraph.vertices.each do |v| @depgraph.add_vertex(v) end # We have to specify a relationship to our empty container, else it # never makes it into the dep graph in the first place. @explicit_dependencies = {@one => @two, "f" => "c", "h" => @middle, "c" => @empty} @explicit_dependencies.each do |source, target| @depgraph.add_edge(source, target, :callback => :refresh) end end def splice @contgraph.splice!(@depgraph) end def whit_called(name) x = @depgraph.vertices.find { |v| v.is_a?(@whit) && v.name =~ /#{name}/ } x.should_not be_nil def x.to_s "Whit[#{name}]" end def x.inspect to_s end x end def admissible_sentinal_of(x) @depgraph.vertex?(x) ? x : whit_called("admissible_#{x.name}") end def completed_sentinal_of(x) @depgraph.vertex?(x) ? x : whit_called("completed_#{x.name}") end before do container_graph dependency_graph splice end # This is the real heart of splicing -- replacing all containers X in our # relationship graph with a pair of whits { admissible_X and completed_X } # such that that # # 0) completed_X depends on admissible_X # 1) contents of X each depend on admissible_X # 2) completed_X depends on each on the contents of X # 3) everything which depended on X depends on completed_X # 4) admissible_X depends on everything X depended on # 5) the containers and their edges must be removed # # Note that this requires attention to the possible case of containers # which contain or depend on other containers. # # Point by point: # 0) completed_X depends on admissible_X # it "every container's completed sentinal should depend on its admissible sentinal" do containers.each { |container| @depgraph.path_between(admissible_sentinal_of(container),completed_sentinal_of(container)).should be } end # 1) contents of X each depend on admissible_X # it "all contained objects should depend on their container's admissible sentinal" do containers.each { |container| contents_of(container).each { |leaf| @depgraph.should be_edge(admissible_sentinal_of(container),admissible_sentinal_of(leaf)) } } end # 2) completed_X depends on each on the contents of X # it "completed sentinals should depend on their container's contents" do containers.each { |container| contents_of(container).each { |leaf| @depgraph.should be_edge(completed_sentinal_of(leaf),completed_sentinal_of(container)) } } end # # 3) everything which depended on X depends on completed_X # # 4) admissible_X depends on everything X depended on # 5) the containers and their edges must be removed # it "should remove all Container objects from the dependency graph" do @depgraph.vertices.find_all { |v| v.is_a?(Container) }.should be_empty end it "should remove all Stage resources from the dependency graph" do @depgraph.vertices.find_all { |v| v.is_a?(Puppet::Type.type(:stage)) }.should be_empty end it "should no longer contain anything but the non-container objects" do @depgraph.vertices.find_all { |v| ! v.is_a?(String) and ! v.is_a?(@whit)}.should be_empty end it "should retain labels on non-containment edges" do @explicit_dependencies.each { |f,t| @depgraph.edges_between(completed_sentinal_of(f),admissible_sentinal_of(t))[0].label.should == {:callback => :refresh} } end it "should not add labels to edges that have none" do @depgraph.add_edge(@two, @three) splice @depgraph.path_between("c", "i").any? {|segment| segment.all? {|e| e.label == {} }}.should be end it "should copy labels over edges that have none" do @depgraph.add_edge("c", @three, {:callback => :refresh}) splice # And make sure the label got copied. @depgraph.path_between("c", "i").flatten.select {|e| e.label == {:callback => :refresh} }.should_not be_empty end it "should not replace a label with a nil label" do # Lastly, add some new label-less edges and make sure the label stays. @depgraph.add_edge(@middle, @three) @depgraph.add_edge("c", @three, {:callback => :refresh}) splice @depgraph.path_between("c","i").flatten.select {|e| e.label == {:callback => :refresh} }.should_not be_empty end it "should copy labels to all created edges" do @depgraph.add_edge(@middle, @three) @depgraph.add_edge("c", @three, {:callback => :refresh}) splice @three.each do |child| edge = Puppet::Relationship.new("c", child) (path = @depgraph.path_between(edge.source, edge.target)).should be path.should_not be_empty path.flatten.select {|e| e.label == {:callback => :refresh} }.should_not be_empty end end end it "should serialize to YAML using the old format by default" do Puppet::SimpleGraph.use_new_yaml_format.should == false end describe "(yaml tests)" do def empty_graph(graph) end def one_vertex_graph(graph) graph.add_vertex(:a) end def graph_without_edges(graph) [:a, :b, :c].each { |x| graph.add_vertex(x) } end def one_edge_graph(graph) graph.add_edge(:a, :b) end def many_edge_graph(graph) graph.add_edge(:a, :b) graph.add_edge(:a, :c) graph.add_edge(:b, :d) graph.add_edge(:c, :d) end def labeled_edge_graph(graph) graph.add_edge(:a, :b, :callback => :foo, :event => :bar) end def overlapping_edge_graph(graph) graph.add_edge(:a, :b, :callback => :foo, :event => :bar) graph.add_edge(:a, :b, :callback => :biz, :event => :baz) end def self.all_test_graphs [:empty_graph, :one_vertex_graph, :graph_without_edges, :one_edge_graph, :many_edge_graph, :labeled_edge_graph, :overlapping_edge_graph] end def object_ids(enumerable) # Return a sorted list of the object id's of the elements of an # enumerable. enumerable.collect { |x| x.object_id }.sort end def graph_to_yaml(graph, which_format) previous_use_new_yaml_format = Puppet::SimpleGraph.use_new_yaml_format Puppet::SimpleGraph.use_new_yaml_format = (which_format == :new) ZAML.dump(graph) ensure Puppet::SimpleGraph.use_new_yaml_format = previous_use_new_yaml_format end # Test serialization of graph to YAML. [:old, :new].each do |which_format| all_test_graphs.each do |graph_to_test| it "should be able to serialize #{graph_to_test} to YAML (#{which_format} format)" do graph = Puppet::SimpleGraph.new send(graph_to_test, graph) yaml_form = graph_to_yaml(graph, which_format) # Hack the YAML so that objects in the Puppet namespace get # changed to YAML::DomainType objects. This lets us inspect # the serialized objects easily without invoking any # yaml_initialize hooks. yaml_form.gsub!('!ruby/object:Puppet::', '!hack/object:Puppet::') serialized_object = YAML.load(yaml_form) # Check that the object contains instance variables @edges and # @vertices only. @reversal is also permitted, but we don't # check it, because it is going to be phased out. serialized_object.type_id.should == 'object:Puppet::SimpleGraph' serialized_object.value.keys.reject { |x| x == 'reversal' }.sort.should == ['edges', 'vertices'] # Check edges by forming a set of tuples (source, target, # callback, event) based on the graph and the YAML and make sure # they match. edges = serialized_object.value['edges'] edges.should be_a(Array) expected_edge_tuples = graph.edges.collect { |edge| [edge.source, edge.target, edge.callback, edge.event] } actual_edge_tuples = edges.collect do |edge| edge.type_id.should == 'object:Puppet::Relationship' %w{source target}.each { |x| edge.value.keys.should include(x) } edge.value.keys.each { |x| ['source', 'target', 'callback', 'event'].should include(x) } %w{source target callback event}.collect { |x| edge.value[x] } end Set.new(actual_edge_tuples).should == Set.new(expected_edge_tuples) actual_edge_tuples.length.should == expected_edge_tuples.length # Check vertices one by one. vertices = serialized_object.value['vertices'] if which_format == :old vertices.should be_a(Hash) Set.new(vertices.keys).should == Set.new(graph.vertices) vertices.each do |key, value| value.type_id.should == 'object:Puppet::SimpleGraph::VertexWrapper' value.value.keys.sort.should == %w{adjacencies vertex} value.value['vertex'].should equal(key) adjacencies = value.value['adjacencies'] adjacencies.should be_a(Hash) Set.new(adjacencies.keys).should == Set.new([:in, :out]) [:in, :out].each do |direction| adjacencies[direction].should be_a(Hash) expected_adjacent_vertices = Set.new(graph.adjacent(key, :direction => direction, :type => :vertices)) Set.new(adjacencies[direction].keys).should == expected_adjacent_vertices adjacencies[direction].each do |adj_key, adj_value| # Since we already checked edges, just check consistency # with edges. desired_source = direction == :in ? adj_key : key desired_target = direction == :in ? key : adj_key expected_edges = edges.select do |edge| edge.value['source'] == desired_source && edge.value['target'] == desired_target end adj_value.should be_a(Set) if object_ids(adj_value) != object_ids(expected_edges) raise "For vertex #{key.inspect}, direction #{direction.inspect}: expected adjacencies #{expected_edges.inspect} but got #{adj_value.inspect}" end end end end else vertices.should be_a(Array) Set.new(vertices).should == Set.new(graph.vertices) vertices.length.should == graph.vertices.length end end end # Test deserialization of graph from YAML. This presumes the # correctness of serialization to YAML, which has already been # tested. all_test_graphs.each do |graph_to_test| it "should be able to deserialize #{graph_to_test} from YAML (#{which_format} format)" do reference_graph = Puppet::SimpleGraph.new send(graph_to_test, reference_graph) yaml_form = graph_to_yaml(reference_graph, which_format) recovered_graph = YAML.load(yaml_form) # Test that the recovered vertices match the vertices in the # reference graph. expected_vertices = reference_graph.vertices.to_a recovered_vertices = recovered_graph.vertices.to_a Set.new(recovered_vertices).should == Set.new(expected_vertices) recovered_vertices.length.should == expected_vertices.length # Test that the recovered edges match the edges in the # reference graph. expected_edge_tuples = reference_graph.edges.collect do |edge| [edge.source, edge.target, edge.callback, edge.event] end recovered_edge_tuples = recovered_graph.edges.collect do |edge| [edge.source, edge.target, edge.callback, edge.event] end Set.new(recovered_edge_tuples).should == Set.new(expected_edge_tuples) recovered_edge_tuples.length.should == expected_edge_tuples.length # We ought to test that the recovered graph is self-consistent # too. But we're not going to bother with that yet because # the internal representation of the graph is about to change. end end it "should be able to serialize a graph where the vertices contain backreferences to the graph (#{which_format} format)" do reference_graph = Puppet::SimpleGraph.new vertex = Object.new vertex.instance_eval { @graph = reference_graph } reference_graph.add_edge(vertex, :other_vertex) yaml_form = graph_to_yaml(reference_graph, which_format) recovered_graph = YAML.load(yaml_form) recovered_graph.vertices.length.should == 2 recovered_vertex = recovered_graph.vertices.reject { |x| x.is_a?(Symbol) }[0] recovered_vertex.instance_eval { @graph }.should equal(recovered_graph) recovered_graph.edges.length.should == 1 recovered_edge = recovered_graph.edges[0] recovered_edge.source.should equal(recovered_vertex) recovered_edge.target.should == :other_vertex end end it "should serialize properly when used as a base class" do class Puppet::TestDerivedClass < Puppet::SimpleGraph attr_accessor :foo end derived = Puppet::TestDerivedClass.new derived.add_edge(:a, :b) derived.foo = 1234 recovered_derived = YAML.load(YAML.dump(derived)) recovered_derived.class.should equal(Puppet::TestDerivedClass) recovered_derived.edges.length.should == 1 recovered_derived.edges[0].source.should == :a recovered_derived.edges[0].target.should == :b recovered_derived.vertices.length.should == 2 recovered_derived.foo.should == 1234 end end end diff --git a/spec/unit/ssl/base_spec.rb b/spec/unit/ssl/base_spec.rb index 263a3b9be..125623b70 100755 --- a/spec/unit/ssl/base_spec.rb +++ b/spec/unit/ssl/base_spec.rb @@ -1,43 +1,42 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/ssl/certificate' class TestCertificate < Puppet::SSL::Base; end describe Puppet::SSL::Certificate do before :each do @base = TestCertificate.new("name") end describe "when fingerprinting content" do before :each do @cert = stub 'cert', :to_der => "DER" @base.stubs(:content).returns(@cert) OpenSSL::Digest.stubs(:constants).returns ["MD5", "DIGEST"] @digest = stub_everything OpenSSL::Digest.stubs(:const_get).returns @digest end it "should digest the certificate DER value and return a ':' seperated nibblet string" do @cert.expects(:to_der).returns("DER") @digest.expects(:hexdigest).with("DER").returns "digest" @base.fingerprint.should == "DI:GE:ST" end it "should raise an error if the digest algorithm is not defined" do OpenSSL::Digest.expects(:constants).returns [] lambda { @base.fingerprint }.should raise_error end it "should use the given digest algorithm" do OpenSSL::Digest.stubs(:const_get).with("DIGEST").returns @digest @digest.expects(:hexdigest).with("DER").returns "digest" @base.fingerprint(:digest).should == "DI:GE:ST" end end end diff --git a/spec/unit/ssl/certificate_authority/interface_spec.rb b/spec/unit/ssl/certificate_authority/interface_spec.rb index 3e3f261e0..9e858dd54 100755 --- a/spec/unit/ssl/certificate_authority/interface_spec.rb +++ b/spec/unit/ssl/certificate_authority/interface_spec.rb @@ -1,333 +1,332 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/ssl/certificate_authority' shared_examples_for "a normal interface method" do it "should call the method on the CA for each host specified if an array was provided" do @ca.expects(@method).with("host1") @ca.expects(@method).with("host2") @applier = Puppet::SSL::CertificateAuthority::Interface.new(@method, :to => %w{host1 host2}) @applier.apply(@ca) end it "should call the method on the CA for all existing certificates if :all was provided" do @ca.expects(:list).returns %w{host1 host2} @ca.expects(@method).with("host1") @ca.expects(@method).with("host2") @applier = Puppet::SSL::CertificateAuthority::Interface.new(@method, :to => :all) @applier.apply(@ca) end end describe Puppet::SSL::CertificateAuthority::Interface do before do @class = Puppet::SSL::CertificateAuthority::Interface end describe "when initializing" do it "should set its method using its settor" do @class.any_instance.expects(:method=).with(:generate) @class.new(:generate, :to => :all) end it "should set its subjects using the settor" do @class.any_instance.expects(:subjects=).with(:all) @class.new(:generate, :to => :all) end it "should set the digest if given" do interface = @class.new(:generate, :to => :all, :digest => :digest) interface.digest.should == :digest end it "should set the digest to md5 if none given" do interface = @class.new(:generate, :to => :all) interface.digest.should == :MD5 end end describe "when setting the method" do it "should set the method" do @class.new(:generate, :to => :all).method.should == :generate end it "should fail if the method isn't a member of the INTERFACE_METHODS array" do Puppet::SSL::CertificateAuthority::Interface::INTERFACE_METHODS.expects(:include?).with(:thing).returns false lambda { @class.new(:thing, :to => :all) }.should raise_error(ArgumentError) end end describe "when setting the subjects" do it "should set the subjects" do @class.new(:generate, :to => :all).subjects.should == :all end it "should fail if the subjects setting isn't :all or an array" do lambda { @class.new(:generate, "other") }.should raise_error(ArgumentError) end end it "should have a method for triggering the application" do @class.new(:generate, :to => :all).should respond_to(:apply) end describe "when applying" do before do # We use a real object here, because :verify can't be stubbed, apparently. @ca = Object.new end it "should raise InterfaceErrors" do @applier = @class.new(:revoke, :to => :all) @ca.expects(:list).raises Puppet::SSL::CertificateAuthority::Interface::InterfaceError lambda { @applier.apply(@ca) }.should raise_error(Puppet::SSL::CertificateAuthority::Interface::InterfaceError) end it "should log non-Interface failures rather than failing" do @applier = @class.new(:revoke, :to => :all) @ca.expects(:list).raises ArgumentError Puppet.expects(:err) lambda { @applier.apply(@ca) }.should_not raise_error end describe "with an empty array specified and the method is not list" do it "should fail" do @applier = @class.new(:sign, :to => []) lambda { @applier.apply(@ca) }.should raise_error(ArgumentError) end end describe ":generate" do it "should fail if :all was specified" do @applier = @class.new(:generate, :to => :all) lambda { @applier.apply(@ca) }.should raise_error(ArgumentError) end it "should call :generate on the CA for each host specified" do @applier = @class.new(:generate, :to => %w{host1 host2}) @ca.expects(:generate).with("host1") @ca.expects(:generate).with("host2") @applier.apply(@ca) end end describe ":verify" do before { @method = :verify } #it_should_behave_like "a normal interface method" it "should call the method on the CA for each host specified if an array was provided" do # LAK:NOTE Mocha apparently doesn't allow you to mock :verify, but I'm confident this works in real life. end it "should call the method on the CA for all existing certificates if :all was provided" do # LAK:NOTE Mocha apparently doesn't allow you to mock :verify, but I'm confident this works in real life. end end describe ":destroy" do before { @method = :destroy } it_should_behave_like "a normal interface method" end describe ":revoke" do before { @method = :revoke } it_should_behave_like "a normal interface method" end describe ":sign" do describe "and an array of names was provided" do before do @applier = @class.new(:sign, :to => %w{host1 host2}) end it "should sign the specified waiting certificate requests" do @ca.expects(:sign).with("host1") @ca.expects(:sign).with("host2") @applier.apply(@ca) end end describe "and :all was provided" do it "should sign all waiting certificate requests" do @ca.stubs(:waiting?).returns(%w{cert1 cert2}) @ca.expects(:sign).with("cert1") @ca.expects(:sign).with("cert2") @applier = @class.new(:sign, :to => :all) @applier.apply(@ca) end it "should fail if there are no waiting certificate requests" do @ca.stubs(:waiting?).returns([]) @applier = @class.new(:sign, :to => :all) lambda { @applier.apply(@ca) }.should raise_error(Puppet::SSL::CertificateAuthority::Interface::InterfaceError) end end end describe ":list" do describe "and an empty array was provided" do it "should print a string containing all certificate requests" do @ca.expects(:waiting?).returns %w{host1 host2} @ca.stubs(:verify) @applier = @class.new(:list, :to => []) @applier.expects(:puts).with "host1\nhost2" @applier.apply(@ca) end end describe "and :all was provided" do it "should print a string containing all certificate requests and certificates" do @ca.expects(:waiting?).returns %w{host1 host2} @ca.expects(:list).returns %w{host3 host4} @ca.stubs(:verify) @ca.stubs(:fingerprint).returns "fingerprint" @ca.expects(:verify).with("host3").raises(Puppet::SSL::CertificateAuthority::CertificateVerificationError.new(23), "certificate revoked") @applier = @class.new(:list, :to => :all) @applier.expects(:puts).with "host1 (fingerprint)" @applier.expects(:puts).with "host2 (fingerprint)" @applier.expects(:puts).with "- host3 (fingerprint) (certificate revoked)" @applier.expects(:puts).with "+ host4 (fingerprint)" @applier.apply(@ca) end end describe "and :signed was provided" do it "should print a string containing all signed certificate requests and certificates" do @ca.expects(:list).returns %w{host1 host2} @applier = @class.new(:list, :to => :signed) @applier.apply(@ca) end end describe "and an array of names was provided" do it "should print a string of all named hosts that have a waiting request" do @ca.expects(:waiting?).returns %w{host1 host2} @ca.expects(:list).returns %w{host3 host4} @ca.stubs(:fingerprint).returns "fingerprint" @ca.stubs(:verify) @applier = @class.new(:list, :to => %w{host1 host2 host3 host4}) @applier.expects(:puts).with "host1 (fingerprint)" @applier.expects(:puts).with "host2 (fingerprint)" @applier.expects(:puts).with "+ host3 (fingerprint)" @applier.expects(:puts).with "+ host4 (fingerprint)" @applier.apply(@ca) end end end describe ":print" do describe "and :all was provided" do it "should print all certificates" do @ca.expects(:list).returns %w{host1 host2} @applier = @class.new(:print, :to => :all) @ca.expects(:print).with("host1").returns "h1" @applier.expects(:puts).with "h1" @ca.expects(:print).with("host2").returns "h2" @applier.expects(:puts).with "h2" @applier.apply(@ca) end end describe "and an array of names was provided" do it "should print each named certificate if found" do @applier = @class.new(:print, :to => %w{host1 host2}) @ca.expects(:print).with("host1").returns "h1" @applier.expects(:puts).with "h1" @ca.expects(:print).with("host2").returns "h2" @applier.expects(:puts).with "h2" @applier.apply(@ca) end it "should log any named but not found certificates" do @applier = @class.new(:print, :to => %w{host1 host2}) @ca.expects(:print).with("host1").returns "h1" @applier.expects(:puts).with "h1" @ca.expects(:print).with("host2").returns nil Puppet.expects(:err).with { |msg| msg.include?("host2") } @applier.apply(@ca) end end end describe ":fingerprint" do it "should fingerprint with the set digest algorithm" do @applier = @class.new(:fingerprint, :to => %w{host1}, :digest => :digest) @ca.expects(:fingerprint).with("host1", :digest).returns "fingerprint1" @applier.expects(:puts).with "host1 fingerprint1" @applier.apply(@ca) end describe "and :all was provided" do it "should fingerprint all certificates (including waiting ones)" do @ca.expects(:list).returns %w{host1} @ca.expects(:waiting?).returns %w{host2} @applier = @class.new(:fingerprint, :to => :all) @ca.expects(:fingerprint).with("host1", :MD5).returns "fingerprint1" @applier.expects(:puts).with "host1 fingerprint1" @ca.expects(:fingerprint).with("host2", :MD5).returns "fingerprint2" @applier.expects(:puts).with "host2 fingerprint2" @applier.apply(@ca) end end describe "and an array of names was provided" do it "should print each named certificate if found" do @applier = @class.new(:fingerprint, :to => %w{host1 host2}) @ca.expects(:fingerprint).with("host1", :MD5).returns "fingerprint1" @applier.expects(:puts).with "host1 fingerprint1" @ca.expects(:fingerprint).with("host2", :MD5).returns "fingerprint2" @applier.expects(:puts).with "host2 fingerprint2" @applier.apply(@ca) end end end end end diff --git a/spec/unit/ssl/certificate_authority_spec.rb b/spec/unit/ssl/certificate_authority_spec.rb index 518b4be4d..3aedfdc25 100755 --- a/spec/unit/ssl/certificate_authority_spec.rb +++ b/spec/unit/ssl/certificate_authority_spec.rb @@ -1,773 +1,772 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/ssl/certificate_authority' describe Puppet::SSL::CertificateAuthority do after do Puppet::Util::Cacher.expire Puppet.settings.clearused end def stub_ca_host @key = mock 'key' @key.stubs(:content).returns "cakey" @cacert = mock 'certificate' @cacert.stubs(:content).returns "cacertificate" @host = stub 'ssl_host', :key => @key, :certificate => @cacert, :name => Puppet::SSL::Host.ca_name end it "should have a class method for returning a singleton instance" do Puppet::SSL::CertificateAuthority.should respond_to(:instance) end describe "when finding an existing instance" do describe "and the host is a CA host and the run_mode is master" do before do Puppet.settings.stubs(:value).with(:ca).returns true Puppet.run_mode.stubs(:master?).returns true @ca = mock('ca') Puppet::SSL::CertificateAuthority.stubs(:new).returns @ca end it "should return an instance" do Puppet::SSL::CertificateAuthority.instance.should equal(@ca) end it "should always return the same instance" do Puppet::SSL::CertificateAuthority.instance.should equal(Puppet::SSL::CertificateAuthority.instance) end end describe "and the host is not a CA host" do it "should return nil" do Puppet.settings.stubs(:value).with(:ca).returns false Puppet.run_mode.stubs(:master?).returns true ca = mock('ca') Puppet::SSL::CertificateAuthority.expects(:new).never Puppet::SSL::CertificateAuthority.instance.should be_nil end end describe "and the run_mode is not master" do it "should return nil" do Puppet.settings.stubs(:value).with(:ca).returns true Puppet.run_mode.stubs(:master?).returns false ca = mock('ca') Puppet::SSL::CertificateAuthority.expects(:new).never Puppet::SSL::CertificateAuthority.instance.should be_nil end end end describe "when initializing" do before do Puppet.settings.stubs(:use) Puppet.settings.stubs(:value).returns "ca_testing" Puppet::SSL::CertificateAuthority.any_instance.stubs(:setup) end it "should always set its name to the value of :certname" do Puppet.settings.expects(:value).with(:certname).returns "ca_testing" Puppet::SSL::CertificateAuthority.new.name.should == "ca_testing" end it "should create an SSL::Host instance whose name is the 'ca_name'" do Puppet::SSL::Host.expects(:ca_name).returns "caname" host = stub 'host' Puppet::SSL::Host.expects(:new).with("caname").returns host Puppet::SSL::CertificateAuthority.new end it "should use the :main, :ca, and :ssl settings sections" do Puppet.settings.expects(:use).with(:main, :ssl, :ca) Puppet::SSL::CertificateAuthority.new end it "should create an inventory instance" do Puppet::SSL::Inventory.expects(:new).returns "inventory" Puppet::SSL::CertificateAuthority.new.inventory.should == "inventory" end it "should make sure the CA is set up" do Puppet::SSL::CertificateAuthority.any_instance.expects(:setup) Puppet::SSL::CertificateAuthority.new end end describe "when setting itself up" do it "should generate the CA certificate if it does not have one" do Puppet.settings.stubs :use host = stub 'host' Puppet::SSL::Host.stubs(:new).returns host host.expects(:certificate).returns nil Puppet::SSL::CertificateAuthority.any_instance.expects(:generate_ca_certificate) Puppet::SSL::CertificateAuthority.new end end describe "when retrieving the certificate revocation list" do before do Puppet.settings.stubs(:use) Puppet.settings.stubs(:value).returns "ca_testing" Puppet.settings.stubs(:value).with(:cacrl).returns "/my/crl" cert = stub("certificate", :content => "real_cert") key = stub("key", :content => "real_key") @host = stub 'host', :certificate => cert, :name => "hostname", :key => key Puppet::SSL::CertificateAuthority.any_instance.stubs(:setup) @ca = Puppet::SSL::CertificateAuthority.new @ca.stubs(:host).returns @host end it "should return any found CRL instance" do crl = mock 'crl' Puppet::SSL::CertificateRevocationList.indirection.expects(:find).returns crl @ca.crl.should equal(crl) end it "should create, generate, and save a new CRL instance of no CRL can be found" do crl = Puppet::SSL::CertificateRevocationList.new("fakename") Puppet::SSL::CertificateRevocationList.indirection.expects(:find).returns nil Puppet::SSL::CertificateRevocationList.expects(:new).returns crl crl.expects(:generate).with(@ca.host.certificate.content, @ca.host.key.content) Puppet::SSL::CertificateRevocationList.indirection.expects(:save).with(crl) @ca.crl.should equal(crl) end end describe "when generating a self-signed CA certificate" do before do Puppet.settings.stubs(:use) Puppet.settings.stubs(:value).returns "ca_testing" Puppet::SSL::CertificateAuthority.any_instance.stubs(:setup) Puppet::SSL::CertificateAuthority.any_instance.stubs(:crl) @ca = Puppet::SSL::CertificateAuthority.new @host = stub 'host', :key => mock("key"), :name => "hostname", :certificate => mock('certificate') Puppet::SSL::CertificateRequest.any_instance.stubs(:generate) @ca.stubs(:host).returns @host end it "should create and store a password at :capass" do Puppet.settings.expects(:value).with(:capass).returns "/path/to/pass" FileTest.expects(:exist?).with("/path/to/pass").returns false fh = mock 'filehandle' Puppet.settings.expects(:write).with(:capass).yields fh fh.expects(:print).with { |s| s.length > 18 } @ca.stubs(:sign) @ca.generate_ca_certificate end it "should generate a key if one does not exist" do @ca.stubs :generate_password @ca.stubs :sign @ca.host.expects(:key).returns nil @ca.host.expects(:generate_key) @ca.generate_ca_certificate end it "should create and sign a self-signed cert using the CA name" do request = mock 'request' Puppet::SSL::CertificateRequest.expects(:new).with(@ca.host.name).returns request request.expects(:generate).with(@ca.host.key) @ca.expects(:sign).with(@host.name, :ca, request) @ca.stubs :generate_password @ca.generate_ca_certificate end it "should generate its CRL" do @ca.stubs :generate_password @ca.stubs :sign @ca.host.expects(:key).returns nil @ca.host.expects(:generate_key) @ca.expects(:crl) @ca.generate_ca_certificate end end describe "when signing" do before do Puppet.settings.stubs(:use) Puppet::SSL::CertificateAuthority.any_instance.stubs(:password?).returns true stub_ca_host Puppet::SSL::Host.expects(:new).with(Puppet::SSL::Host.ca_name).returns @host @ca = Puppet::SSL::CertificateAuthority.new @name = "myhost" @real_cert = stub 'realcert', :sign => nil @cert = Puppet::SSL::Certificate.new(@name) @cert.content = @real_cert Puppet::SSL::Certificate.stubs(:new).returns @cert @cert.stubs(:content=) Puppet::SSL::Certificate.indirection.stubs(:save) # Stub out the factory @factory = stub 'factory', :result => "my real cert" Puppet::SSL::CertificateFactory.stubs(:new).returns @factory @request = stub 'request', :content => "myrequest", :name => @name # And the inventory @inventory = stub 'inventory', :add => nil @ca.stubs(:inventory).returns @inventory Puppet::SSL::CertificateRequest.indirection.stubs(:destroy) end describe "and calculating the next certificate serial number" do before do @path = "/path/to/serial" Puppet.settings.stubs(:value).with(:serial).returns @path @filehandle = stub 'filehandle', :<< => @filehandle Puppet.settings.stubs(:readwritelock).with(:serial).yields @filehandle end it "should default to 0x1 for the first serial number" do @ca.next_serial.should == 0x1 end it "should return the current content of the serial file" do FileTest.stubs(:exist?).with(@path).returns true File.expects(:read).with(@path).returns "0002" @ca.next_serial.should == 2 end it "should write the next serial number to the serial file as hex" do @filehandle.expects(:<<).with("0002") @ca.next_serial end it "should lock the serial file while writing" do Puppet.settings.expects(:readwritelock).with(:serial) @ca.next_serial end end describe "its own certificate" do before do @serial = 10 @ca.stubs(:next_serial).returns @serial end it "should not look up a certificate request for the host" do Puppet::SSL::CertificateRequest.indirection.expects(:find).never @ca.sign(@name, :ca, @request) end it "should use a certificate type of :ca" do Puppet::SSL::CertificateFactory.expects(:new).with do |*args| args[0] == :ca end.returns @factory @ca.sign(@name, :ca, @request) end it "should pass the provided CSR as the CSR" do Puppet::SSL::CertificateFactory.expects(:new).with do |*args| args[1] == "myrequest" end.returns @factory @ca.sign(@name, :ca, @request) end it "should use the provided CSR's content as the issuer" do Puppet::SSL::CertificateFactory.expects(:new).with do |*args| args[2] == "myrequest" end.returns @factory @ca.sign(@name, :ca, @request) end it "should pass the next serial as the serial number" do Puppet::SSL::CertificateFactory.expects(:new).with do |*args| args[3] == @serial end.returns @factory @ca.sign(@name, :ca, @request) end it "should save the resulting certificate" do Puppet::SSL::Certificate.indirection.expects(:save).with(@cert) @ca.sign(@name, :ca, @request) end end describe "another host's certificate" do before do @serial = 10 @ca.stubs(:next_serial).returns @serial Puppet::SSL::CertificateRequest.indirection.stubs(:find).with(@name).returns @request Puppet::SSL::CertificateRequest.indirection.stubs :save end it "should use a certificate type of :server" do Puppet::SSL::CertificateFactory.expects(:new).with do |*args| args[0] == :server end.returns @factory @ca.sign(@name) end it "should use look up a CSR for the host in the :ca_file terminus" do Puppet::SSL::CertificateRequest.indirection.expects(:find).with(@name).returns @request @ca.sign(@name) end it "should fail if no CSR can be found for the host" do Puppet::SSL::CertificateRequest.indirection.expects(:find).with(@name).returns nil lambda { @ca.sign(@name) }.should raise_error(ArgumentError) end it "should use the CA certificate as the issuer" do Puppet::SSL::CertificateFactory.expects(:new).with do |*args| args[2] == @cacert.content end.returns @factory @ca.sign(@name) end it "should pass the next serial as the serial number" do Puppet::SSL::CertificateFactory.expects(:new).with do |*args| args[3] == @serial end.returns @factory @ca.sign(@name) end it "should sign the resulting certificate using its real key and a digest" do digest = mock 'digest' OpenSSL::Digest::SHA1.expects(:new).returns digest key = stub 'key', :content => "real_key" @ca.host.stubs(:key).returns key @cert.content.expects(:sign).with("real_key", digest) @ca.sign(@name) end it "should save the resulting certificate" do Puppet::SSL::Certificate.indirection.stubs(:save).with(@cert) @ca.sign(@name) end it "should remove the host's certificate request" do Puppet::SSL::CertificateRequest.indirection.expects(:destroy).with(@name) @ca.sign(@name) end end it "should create a certificate instance with the content set to the newly signed x509 certificate" do @serial = 10 @ca.stubs(:next_serial).returns @serial Puppet::SSL::CertificateRequest.indirection.stubs(:find).with(@name).returns @request Puppet::SSL::Certificate.indirection.stubs :save Puppet::SSL::Certificate.expects(:new).with(@name).returns @cert @ca.sign(@name) end it "should return the certificate instance" do @ca.stubs(:next_serial).returns @serial Puppet::SSL::CertificateRequest.indirection.stubs(:find).with(@name).returns @request Puppet::SSL::Certificate.indirection.stubs :save @ca.sign(@name).should equal(@cert) end it "should add the certificate to its inventory" do @ca.stubs(:next_serial).returns @serial @inventory.expects(:add).with(@cert) Puppet::SSL::CertificateRequest.indirection.stubs(:find).with(@name).returns @request Puppet::SSL::Certificate.indirection.stubs :save @ca.sign(@name) end it "should have a method for triggering autosigning of available CSRs" do @ca.should respond_to(:autosign) end describe "when autosigning certificates" do it "should do nothing if autosign is disabled" do Puppet.settings.expects(:value).with(:autosign).returns 'false' Puppet::SSL::CertificateRequest.indirection.expects(:search).never @ca.autosign end it "should do nothing if no autosign.conf exists" do Puppet.settings.expects(:value).with(:autosign).returns '/auto/sign' FileTest.expects(:exist?).with("/auto/sign").returns false Puppet::SSL::CertificateRequest.indirection.expects(:search).never @ca.autosign end describe "and autosign is enabled and the autosign.conf file exists" do before do Puppet.settings.stubs(:value).with(:autosign).returns '/auto/sign' FileTest.stubs(:exist?).with("/auto/sign").returns true File.stubs(:readlines).with("/auto/sign").returns ["one\n", "two\n"] Puppet::SSL::CertificateRequest.indirection.stubs(:search).returns [] @store = stub 'store', :allow => nil Puppet::Network::AuthStore.stubs(:new).returns @store end describe "when creating the AuthStore instance to verify autosigning" do it "should create an AuthStore with each line in the configuration file allowed to be autosigned" do Puppet::Network::AuthStore.expects(:new).returns @store @store.expects(:allow).with("one") @store.expects(:allow).with("two") @ca.autosign end it "should reparse the autosign configuration on each call" do Puppet::Network::AuthStore.expects(:new).times(2).returns @store @ca.autosign @ca.autosign end it "should ignore comments" do File.stubs(:readlines).with("/auto/sign").returns ["one\n", "#two\n"] @store.expects(:allow).with("one") @ca.autosign end it "should ignore blank lines" do File.stubs(:readlines).with("/auto/sign").returns ["one\n", "\n"] @store.expects(:allow).with("one") @ca.autosign end end it "should sign all CSRs whose hostname matches the autosign configuration" do csr1 = mock 'csr1' csr2 = mock 'csr2' Puppet::SSL::CertificateRequest.indirection.stubs(:search).returns [csr1, csr2] end it "should not sign CSRs whose hostname does not match the autosign configuration" do csr1 = mock 'csr1' csr2 = mock 'csr2' Puppet::SSL::CertificateRequest.indirection.stubs(:search).returns [csr1, csr2] end end end end describe "when managing certificate clients" do before do Puppet.settings.stubs(:use) Puppet::SSL::CertificateAuthority.any_instance.stubs(:password?).returns true stub_ca_host Puppet::SSL::Host.expects(:new).returns @host Puppet::SSL::CertificateAuthority.any_instance.stubs(:host).returns @host @cacert = mock 'certificate' @cacert.stubs(:content).returns "cacertificate" @ca = Puppet::SSL::CertificateAuthority.new end it "should have a method for acting on the SSL files" do @ca.should respond_to(:apply) end describe "when applying a method to a set of hosts" do it "should fail if no subjects have been specified" do lambda { @ca.apply(:generate) }.should raise_error(ArgumentError) end it "should create an Interface instance with the specified method and the options" do Puppet::SSL::CertificateAuthority::Interface.expects(:new).with(:generate, :to => :host).returns(stub('applier', :apply => nil)) @ca.apply(:generate, :to => :host) end it "should apply the Interface with itself as the argument" do applier = stub('applier') applier.expects(:apply).with(@ca) Puppet::SSL::CertificateAuthority::Interface.expects(:new).returns applier @ca.apply(:generate, :to => :ca_testing) end end it "should be able to list waiting certificate requests" do req1 = stub 'req1', :name => "one" req2 = stub 'req2', :name => "two" Puppet::SSL::CertificateRequest.indirection.expects(:search).with("*").returns [req1, req2] @ca.waiting?.should == %w{one two} end it "should delegate removing hosts to the Host class" do Puppet::SSL::Host.expects(:destroy).with("myhost") @ca.destroy("myhost") end it "should be able to verify certificates" do @ca.should respond_to(:verify) end it "should list certificates as the sorted list of all existing signed certificates" do cert1 = stub 'cert1', :name => "cert1" cert2 = stub 'cert2', :name => "cert2" Puppet::SSL::Certificate.indirection.expects(:search).with("*").returns [cert1, cert2] @ca.list.should == %w{cert1 cert2} end describe "and printing certificates" do it "should return nil if the certificate cannot be found" do Puppet::SSL::Certificate.indirection.expects(:find).with("myhost").returns nil @ca.print("myhost").should be_nil end it "should print certificates by calling :to_text on the host's certificate" do cert1 = stub 'cert1', :name => "cert1", :to_text => "mytext" Puppet::SSL::Certificate.indirection.expects(:find).with("myhost").returns cert1 @ca.print("myhost").should == "mytext" end end describe "and fingerprinting certificates" do before :each do @cert = stub 'cert', :name => "cert", :fingerprint => "DIGEST" Puppet::SSL::Certificate.indirection.stubs(:find).with("myhost").returns @cert Puppet::SSL::CertificateRequest.indirection.stubs(:find).with("myhost") end it "should raise an error if the certificate or CSR cannot be found" do Puppet::SSL::Certificate.indirection.expects(:find).with("myhost").returns nil Puppet::SSL::CertificateRequest.indirection.expects(:find).with("myhost").returns nil lambda { @ca.fingerprint("myhost") }.should raise_error end it "should try to find a CSR if no certificate can be found" do Puppet::SSL::Certificate.indirection.expects(:find).with("myhost").returns nil Puppet::SSL::CertificateRequest.indirection.expects(:find).with("myhost").returns @cert @cert.expects(:fingerprint) @ca.fingerprint("myhost") end it "should delegate to the certificate fingerprinting" do @cert.expects(:fingerprint) @ca.fingerprint("myhost") end it "should propagate the digest algorithm to the certificate fingerprinting system" do @cert.expects(:fingerprint).with(:digest) @ca.fingerprint("myhost", :digest) end end describe "and verifying certificates" do before do @store = stub 'store', :verify => true, :add_file => nil, :purpose= => nil, :add_crl => true, :flags= => nil OpenSSL::X509::Store.stubs(:new).returns @store Puppet.settings.stubs(:value).returns "crtstuff" @cert = stub 'cert', :content => "mycert" Puppet::SSL::Certificate.indirection.stubs(:find).returns @cert @crl = stub('crl', :content => "mycrl") @ca.stubs(:crl).returns @crl end it "should fail if the host's certificate cannot be found" do Puppet::SSL::Certificate.indirection.expects(:find).with("me").returns(nil) lambda { @ca.verify("me") }.should raise_error(ArgumentError) end it "should create an SSL Store to verify" do OpenSSL::X509::Store.expects(:new).returns @store @ca.verify("me") end it "should add the CA Certificate to the store" do Puppet.settings.stubs(:value).with(:cacert).returns "/ca/cert" @store.expects(:add_file).with "/ca/cert" @ca.verify("me") end it "should add the CRL to the store if the crl is enabled" do @store.expects(:add_crl).with "mycrl" @ca.verify("me") end it "should set the store purpose to OpenSSL::X509::PURPOSE_SSL_CLIENT" do Puppet.settings.stubs(:value).with(:cacert).returns "/ca/cert" @store.expects(:add_file).with "/ca/cert" @ca.verify("me") end it "should set the store flags to check the crl" do @store.expects(:flags=).with OpenSSL::X509::V_FLAG_CRL_CHECK_ALL|OpenSSL::X509::V_FLAG_CRL_CHECK @ca.verify("me") end it "should use the store to verify the certificate" do @cert.expects(:content).returns "mycert" @store.expects(:verify).with("mycert").returns true @ca.verify("me") end it "should fail if the verification returns false" do @cert.expects(:content).returns "mycert" @store.expects(:verify).with("mycert").returns false lambda { @ca.verify("me") }.should raise_error end end describe "and revoking certificates" do before do @crl = mock 'crl' @ca.stubs(:crl).returns @crl @ca.stubs(:next_serial).returns 10 @real_cert = stub 'real_cert', :serial => 15 @cert = stub 'cert', :content => @real_cert Puppet::SSL::Certificate.indirection.stubs(:find).returns @cert end it "should fail if the certificate revocation list is disabled" do @ca.stubs(:crl).returns false lambda { @ca.revoke('ca_testing') }.should raise_error(ArgumentError) end it "should delegate the revocation to its CRL" do @ca.crl.expects(:revoke) @ca.revoke('host') end it "should get the serial number from the local certificate if it exists" do @ca.crl.expects(:revoke).with { |serial, key| serial == 15 } Puppet::SSL::Certificate.indirection.expects(:find).with("host").returns @cert @ca.revoke('host') end it "should get the serial number from inventory if no local certificate exists" do real_cert = stub 'real_cert', :serial => 15 cert = stub 'cert', :content => real_cert Puppet::SSL::Certificate.indirection.expects(:find).with("host").returns nil @ca.inventory.expects(:serial).with("host").returns 16 @ca.crl.expects(:revoke).with { |serial, key| serial == 16 } @ca.revoke('host') end end it "should be able to generate a complete new SSL host" do @ca.should respond_to(:generate) end describe "and generating certificates" do before do @host = stub 'host', :generate_certificate_request => nil Puppet::SSL::Host.stubs(:new).returns @host Puppet::SSL::Certificate.indirection.stubs(:find).returns nil @ca.stubs(:sign) end it "should fail if a certificate already exists for the host" do Puppet::SSL::Certificate.indirection.expects(:find).with("him").returns "something" lambda { @ca.generate("him") }.should raise_error(ArgumentError) end it "should create a new Host instance with the correct name" do Puppet::SSL::Host.expects(:new).with("him").returns @host @ca.generate("him") end it "should use the Host to generate the certificate request" do @host.expects :generate_certificate_request @ca.generate("him") end it "should sign the generated request" do @ca.expects(:sign).with("him") @ca.generate("him") end end end end diff --git a/spec/unit/ssl/certificate_factory_spec.rb b/spec/unit/ssl/certificate_factory_spec.rb index 7f305f768..f34dafe43 100755 --- a/spec/unit/ssl/certificate_factory_spec.rb +++ b/spec/unit/ssl/certificate_factory_spec.rb @@ -1,107 +1,106 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/ssl/certificate_factory' describe Puppet::SSL::CertificateFactory do before do @cert_type = mock 'cert_type' @name = mock 'name' @csr = stub 'csr', :subject => @name @issuer = mock 'issuer' @serial = mock 'serial' @factory = Puppet::SSL::CertificateFactory.new(@cert_type, @csr, @issuer, @serial) end describe "when initializing" do it "should set its :cert_type to its first argument" do @factory.cert_type.should equal(@cert_type) end it "should set its :csr to its second argument" do @factory.csr.should equal(@csr) end it "should set its :issuer to its third argument" do @factory.issuer.should equal(@issuer) end it "should set its :serial to its fourth argument" do @factory.serial.should equal(@serial) end it "should set its name to the subject of the csr" do @factory.name.should equal(@name) end end describe "when generating the certificate" do before do @cert = mock 'cert' @cert.stub_everything @factory.stubs :build_extensions @factory.stubs :set_ttl @issuer_name = mock 'issuer_name' @issuer.stubs(:subject).returns @issuer_name @public_key = mock 'public_key' @csr.stubs(:public_key).returns @public_key OpenSSL::X509::Certificate.stubs(:new).returns @cert end it "should return a new X509 certificate" do OpenSSL::X509::Certificate.expects(:new).returns @cert @factory.result.should equal(@cert) end it "should set the certificate's version to 2" do @cert.expects(:version=).with 2 @factory.result end it "should set the certificate's subject to the CSR's subject" do @cert.expects(:subject=).with @name @factory.result end it "should set the certificate's issuer to the Issuer's subject" do @cert.expects(:issuer=).with @issuer_name @factory.result end it "should set the certificate's public key to the CSR's public key" do @cert.expects(:public_key=).with @public_key @factory.result end it "should set the certificate's serial number to the provided serial number" do @cert.expects(:serial=).with @serial @factory.result end it "should build extensions for the certificate" do @factory.expects(:build_extensions) @factory.result end it "should set the ttl of the certificate" do @factory.expects(:set_ttl) @factory.result end end describe "when building extensions" do it "should have tests" end describe "when setting the ttl" do it "should have tests" end end diff --git a/spec/unit/ssl/certificate_request_spec.rb b/spec/unit/ssl/certificate_request_spec.rb index 3a2e7f4d8..e45f0130b 100755 --- a/spec/unit/ssl/certificate_request_spec.rb +++ b/spec/unit/ssl/certificate_request_spec.rb @@ -1,217 +1,216 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/ssl/certificate_request' require 'puppet/ssl/key' describe Puppet::SSL::CertificateRequest do before do @class = Puppet::SSL::CertificateRequest end it "should be extended with the Indirector module" do @class.singleton_class.should be_include(Puppet::Indirector) end it "should indirect certificate_request" do @class.indirection.name.should == :certificate_request end it "should use any provided name as its name" do @class.new("myname").name.should == "myname" end it "should only support the text format" do @class.supported_formats.should == [:s] end describe "when converting from a string" do it "should create a CSR instance with its name set to the CSR subject and its content set to the extracted CSR" do csr = stub 'csr', :subject => "/CN=Foo.madstop.com" OpenSSL::X509::Request.expects(:new).with("my csr").returns(csr) mycsr = stub 'sslcsr' mycsr.expects(:content=).with(csr) @class.expects(:new).with("foo.madstop.com").returns mycsr @class.from_s("my csr") end end describe "when managing instances" do before do @request = @class.new("myname") end it "should have a name attribute" do @request.name.should == "myname" end it "should downcase its name" do @class.new("MyName").name.should == "myname" end it "should have a content attribute" do @request.should respond_to(:content) end it "should be able to read requests from disk" do path = "/my/path" File.expects(:read).with(path).returns("my request") request = mock 'request' OpenSSL::X509::Request.expects(:new).with("my request").returns(request) @request.read(path).should equal(request) @request.content.should equal(request) end it "should return an empty string when converted to a string with no request" do @request.to_s.should == "" end it "should convert the request to pem format when converted to a string" do request = mock 'request', :to_pem => "pem" @request.content = request @request.to_s.should == "pem" end it "should have a :to_text method that it delegates to the actual key" do real_request = mock 'request' real_request.expects(:to_text).returns "requesttext" @request.content = real_request @request.to_text.should == "requesttext" end end describe "when generating" do before do @instance = @class.new("myname") key = Puppet::SSL::Key.new("myname") @key = key.generate @request = OpenSSL::X509::Request.new OpenSSL::X509::Request.expects(:new).returns(@request) @request.stubs(:verify).returns(true) end it "should use the content of the provided key if the key is a Puppet::SSL::Key instance" do key = Puppet::SSL::Key.new("test") key.expects(:content).returns @key @request.expects(:sign).with{ |key, digest| key == @key } @instance.generate(key) end it "should log that it is creating a new certificate request" do Puppet.expects(:info).twice @instance.generate(@key) end it "should set the subject to [CN, name]" do subject = mock 'subject' OpenSSL::X509::Name.expects(:new).with([["CN", @instance.name]]).returns(subject) @request.expects(:subject=).with(subject) @instance.generate(@key) end it "should set the CN to the CSR name when the CSR is not for a CA" do subject = mock 'subject' OpenSSL::X509::Name.expects(:new).with { |subject| subject[0][1] == @instance.name }.returns(subject) @request.expects(:subject=).with(subject) @instance.generate(@key) end it "should set the CN to the :ca_name setting when the CSR is for a CA" do subject = mock 'subject' Puppet.settings.expects(:value).with(:ca_name).returns "mycertname" OpenSSL::X509::Name.expects(:new).with { |subject| subject[0][1] == "mycertname" }.returns(subject) @request.expects(:subject=).with(subject) Puppet::SSL::CertificateRequest.new(Puppet::SSL::CA_NAME).generate(@key) end it "should set the version to 0" do @request.expects(:version=).with(0) @instance.generate(@key) end it "should set the public key to the provided key's public key" do # Yay, the private key extracts a new key each time. pubkey = @key.public_key @key.stubs(:public_key).returns pubkey @request.expects(:public_key=).with(@key.public_key) @instance.generate(@key) end it "should sign the csr with the provided key and a digest" do digest = mock 'digest' OpenSSL::Digest::MD5.expects(:new).returns(digest) @request.expects(:sign).with(@key, digest) @instance.generate(@key) end it "should verify the generated request using the public key" do # Stupid keys don't have a competent == method. @request.expects(:verify).with { |public_key| public_key.to_s == @key.public_key.to_s }.returns true @instance.generate(@key) end it "should fail if verification fails" do @request.expects(:verify).returns false lambda { @instance.generate(@key) }.should raise_error(Puppet::Error) end it "should fingerprint the request" do @instance.expects(:fingerprint) @instance.generate(@key) end it "should display the fingerprint" do Puppet.stubs(:info) @instance.stubs(:fingerprint).returns("FINGERPRINT") Puppet.expects(:info).with { |s| s =~ /FINGERPRINT/ } @instance.generate(@key) end it "should return the generated request" do @instance.generate(@key).should equal(@request) end it "should set its content to the generated request" do @instance.generate(@key) @instance.content.should equal(@request) end end describe "when a CSR is saved" do describe "and a CA is available" do it "should save the CSR and trigger autosigning" do ca = mock 'ca', :autosign Puppet::SSL::CertificateAuthority.expects(:instance).returns ca csr = Puppet::SSL::CertificateRequest.new("me") terminus = mock 'terminus' Puppet::SSL::CertificateRequest.indirection.expects(:prepare).returns(terminus) terminus.expects(:save).with { |request| request.instance == csr && request.key == "me" } Puppet::SSL::CertificateRequest.indirection.save(csr) end end describe "and a CA is not available" do it "should save the CSR" do Puppet::SSL::CertificateAuthority.expects(:instance).returns nil csr = Puppet::SSL::CertificateRequest.new("me") terminus = mock 'terminus' Puppet::SSL::CertificateRequest.indirection.expects(:prepare).returns(terminus) terminus.expects(:save).with { |request| request.instance == csr && request.key == "me" } Puppet::SSL::CertificateRequest.indirection.save(csr) end end end end diff --git a/spec/unit/ssl/certificate_revocation_list_spec.rb b/spec/unit/ssl/certificate_revocation_list_spec.rb index e84208c5a..99058b353 100755 --- a/spec/unit/ssl/certificate_revocation_list_spec.rb +++ b/spec/unit/ssl/certificate_revocation_list_spec.rb @@ -1,168 +1,167 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/ssl/certificate_revocation_list' describe Puppet::SSL::CertificateRevocationList do before do @cert = stub 'cert', :subject => "mysubject" @key = stub 'key', :private? => true @class = Puppet::SSL::CertificateRevocationList end it "should only support the text format" do @class.supported_formats.should == [:s] end describe "when converting from a string" do it "should create a CRL instance with its name set to 'foo' and its content set to the extracted CRL" do crl = stub 'crl' OpenSSL::X509::CRL.expects(:new).returns(crl) mycrl = stub 'sslcrl' mycrl.expects(:content=).with(crl) @class.expects(:new).with("foo").returns mycrl @class.from_s("my crl").should == mycrl end end describe "when an instance" do before do @class.any_instance.stubs(:read_or_generate) @crl = @class.new("whatever") end it "should always use 'crl' for its name" do @crl.name.should == "crl" end it "should have a content attribute" do @crl.should respond_to(:content) end end describe "when generating the crl" do before do @real_crl = mock 'crl' @real_crl.stub_everything OpenSSL::X509::CRL.stubs(:new).returns(@real_crl) @class.any_instance.stubs(:read_or_generate) @crl = @class.new("crl") end it "should set its issuer to the subject of the passed certificate" do @real_crl.expects(:issuer=).with(@cert.subject) @crl.generate(@cert, @key) end it "should set its version to 1" do @real_crl.expects(:version=).with(1) @crl.generate(@cert, @key) end it "should create an instance of OpenSSL::X509::CRL" do OpenSSL::X509::CRL.expects(:new).returns(@real_crl) @crl.generate(@cert, @key) end # The next three tests aren't good, but at least they # specify the behaviour. it "should add an extension for the CRL number" do @real_crl.expects(:extensions=) @crl.generate(@cert, @key) end it "should set the last update time" do @real_crl.expects(:last_update=) @crl.generate(@cert, @key) end it "should set the next update time" do @real_crl.expects(:next_update=) @crl.generate(@cert, @key) end it "should sign the CRL" do @real_crl.expects(:sign).with { |key, digest| key == @key } @crl.generate(@cert, @key) end it "should set the content to the generated crl" do @crl.generate(@cert, @key) @crl.content.should equal(@real_crl) end it "should return the generated crl" do @crl.generate(@cert, @key).should equal(@real_crl) end end # This test suite isn't exactly complete, because the # SSL stuff is very complicated. It just hits the high points. describe "when revoking a certificate" do before do @class.wrapped_class.any_instance.stubs(:issuer=) @class.wrapped_class.any_instance.stubs(:sign) @crl = @class.new("crl") @crl.generate(@cert, @key) @crl.content.stubs(:sign) Puppet::SSL::CertificateRevocationList.indirection.stubs :save @key = mock 'key' end it "should require a serial number and the CA's private key" do lambda { @crl.revoke }.should raise_error(ArgumentError) end it "should default to OpenSSL::OCSP::REVOKED_STATUS_KEYCOMPROMISE as the revocation reason" do # This makes it a bit more of an integration test than we'd normally like, but that's life # with openssl. reason = OpenSSL::ASN1::Enumerated(OpenSSL::OCSP::REVOKED_STATUS_KEYCOMPROMISE) OpenSSL::ASN1.expects(:Enumerated).with(OpenSSL::OCSP::REVOKED_STATUS_KEYCOMPROMISE).returns reason @crl.revoke(1, @key) end it "should mark the CRL as updated" do time = Time.now Time.stubs(:now).returns time @crl.content.expects(:last_update=).with(time) @crl.revoke(1, @key) end it "should mark the CRL valid for five years" do time = Time.now Time.stubs(:now).returns time @crl.content.expects(:next_update=).with(time + (5 * 365*24*60*60)) @crl.revoke(1, @key) end it "should sign the CRL with the CA's private key and a digest instance" do @crl.content.expects(:sign).with { |key, digest| key == @key and digest.is_a?(OpenSSL::Digest::SHA1) } @crl.revoke(1, @key) end it "should save the CRL" do Puppet::SSL::CertificateRevocationList.indirection.expects(:save).with(@crl, nil) @crl.revoke(1, @key) end end end diff --git a/spec/unit/ssl/certificate_spec.rb b/spec/unit/ssl/certificate_spec.rb index afee70999..0b635f2bc 100755 --- a/spec/unit/ssl/certificate_spec.rb +++ b/spec/unit/ssl/certificate_spec.rb @@ -1,124 +1,123 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/ssl/certificate' describe Puppet::SSL::Certificate do before do @class = Puppet::SSL::Certificate end after do @class.instance_variable_set("@ca_location", nil) end it "should be extended with the Indirector module" do @class.singleton_class.should be_include(Puppet::Indirector) end it "should indirect certificate" do @class.indirection.name.should == :certificate end it "should only support the text format" do @class.supported_formats.should == [:s] end describe "when converting from a string" do it "should create a certificate instance with its name set to the certificate subject and its content set to the extracted certificate" do cert = stub 'certificate', :subject => "/CN=Foo.madstop.com" OpenSSL::X509::Certificate.expects(:new).with("my certificate").returns(cert) mycert = stub 'sslcert' mycert.expects(:content=).with(cert) @class.expects(:new).with("foo.madstop.com").returns mycert @class.from_s("my certificate") end it "should create multiple certificate instances when asked" do cert1 = stub 'cert1' @class.expects(:from_s).with("cert1").returns cert1 cert2 = stub 'cert2' @class.expects(:from_s).with("cert2").returns cert2 @class.from_multiple_s("cert1\n---\ncert2").should == [cert1, cert2] end end describe "when converting to a string" do before do @certificate = @class.new("myname") end it "should return an empty string when it has no certificate" do @certificate.to_s.should == "" end it "should convert the certificate to pem format" do certificate = mock 'certificate', :to_pem => "pem" @certificate.content = certificate @certificate.to_s.should == "pem" end it "should be able to convert multiple instances to a string" do cert2 = @class.new("foo") @certificate.expects(:to_s).returns "cert1" cert2.expects(:to_s).returns "cert2" @class.to_multiple_s([@certificate, cert2]).should == "cert1\n---\ncert2" end end describe "when managing instances" do before do @certificate = @class.new("myname") end it "should have a name attribute" do @certificate.name.should == "myname" end it "should convert its name to a string and downcase it" do @class.new(:MyName).name.should == "myname" end it "should have a content attribute" do @certificate.should respond_to(:content) end it "should return a nil expiration if there is no actual certificate" do @certificate.stubs(:content).returns nil @certificate.expiration.should be_nil end it "should use the expiration of the certificate as its expiration date" do cert = stub 'cert' @certificate.stubs(:content).returns cert cert.expects(:not_after).returns "sometime" @certificate.expiration.should == "sometime" end it "should be able to read certificates from disk" do path = "/my/path" File.expects(:read).with(path).returns("my certificate") certificate = mock 'certificate' OpenSSL::X509::Certificate.expects(:new).with("my certificate").returns(certificate) @certificate.read(path).should equal(certificate) @certificate.content.should equal(certificate) end it "should have a :to_text method that it delegates to the actual key" do real_certificate = mock 'certificate' real_certificate.expects(:to_text).returns "certificatetext" @certificate.content = real_certificate @certificate.to_text.should == "certificatetext" end end end diff --git a/spec/unit/ssl/host_spec.rb b/spec/unit/ssl/host_spec.rb index be53f5f8f..2624c2234 100755 --- a/spec/unit/ssl/host_spec.rb +++ b/spec/unit/ssl/host_spec.rb @@ -1,796 +1,795 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/ssl/host' require 'puppet/sslcertificates' require 'puppet/sslcertificates/ca' describe Puppet::SSL::Host do before do Puppet::SSL::Host.indirection.terminus_class = :file @host = Puppet::SSL::Host.new("myname") end after do # Cleaned out any cached localhost instance. Puppet::Util::Cacher.expire Puppet::SSL::Host.ca_location = :none end it "should use any provided name as its name" do @host.name.should == "myname" end it "should retrieve its public key from its private key" do realkey = mock 'realkey' key = stub 'key', :content => realkey Puppet::SSL::Key.indirection.stubs(:find).returns(key) pubkey = mock 'public_key' realkey.expects(:public_key).returns pubkey @host.public_key.should equal(pubkey) end it "should default to being a non-ca host" do @host.ca?.should be_false end it "should be a ca host if its name matches the CA_NAME" do Puppet::SSL::Host.stubs(:ca_name).returns "yayca" Puppet::SSL::Host.new("yayca").should be_ca end it "should have a method for determining the CA location" do Puppet::SSL::Host.should respond_to(:ca_location) end it "should have a method for specifying the CA location" do Puppet::SSL::Host.should respond_to(:ca_location=) end it "should have a method for retrieving the default ssl host" do Puppet::SSL::Host.should respond_to(:ca_location=) end it "should have a method for producing an instance to manage the local host's keys" do Puppet::SSL::Host.should respond_to(:localhost) end it "should generate the certificate for the localhost instance if no certificate is available" do host = stub 'host', :key => nil Puppet::SSL::Host.expects(:new).returns host host.expects(:certificate).returns nil host.expects(:generate) Puppet::SSL::Host.localhost.should equal(host) end it "should always read the key for the localhost instance in from disk" do host = stub 'host', :certificate => "eh" Puppet::SSL::Host.expects(:new).returns host host.expects(:key) Puppet::SSL::Host.localhost end it "should cache the localhost instance" do host = stub 'host', :certificate => "eh", :key => 'foo' Puppet::SSL::Host.expects(:new).once.returns host Puppet::SSL::Host.localhost.should == Puppet::SSL::Host.localhost end it "should be able to expire the cached instance" do one = stub 'host1', :certificate => "eh", :key => 'foo' two = stub 'host2', :certificate => "eh", :key => 'foo' Puppet::SSL::Host.expects(:new).times(2).returns(one).then.returns(two) Puppet::SSL::Host.localhost.should equal(one) Puppet::Util::Cacher.expire Puppet::SSL::Host.localhost.should equal(two) end it "should be able to verify its certificate matches its key" do Puppet::SSL::Host.new("foo").should respond_to(:certificate_matches_key?) end it "should consider the certificate invalid if it cannot find a key" do host = Puppet::SSL::Host.new("foo") host.expects(:key).returns nil host.should_not be_certificate_matches_key end it "should consider the certificate invalid if it cannot find a certificate" do host = Puppet::SSL::Host.new("foo") host.expects(:key).returns mock("key") host.expects(:certificate).returns nil host.should_not be_certificate_matches_key end it "should consider the certificate invalid if the SSL certificate's key verification fails" do host = Puppet::SSL::Host.new("foo") key = mock 'key', :content => "private_key" sslcert = mock 'sslcert' certificate = mock 'cert', :content => sslcert host.stubs(:key).returns key host.stubs(:certificate).returns certificate sslcert.expects(:check_private_key).with("private_key").returns false host.should_not be_certificate_matches_key end it "should consider the certificate valid if the SSL certificate's key verification succeeds" do host = Puppet::SSL::Host.new("foo") key = mock 'key', :content => "private_key" sslcert = mock 'sslcert' certificate = mock 'cert', :content => sslcert host.stubs(:key).returns key host.stubs(:certificate).returns certificate sslcert.expects(:check_private_key).with("private_key").returns true host.should be_certificate_matches_key end describe "when specifying the CA location" do it "should support the location ':local'" do lambda { Puppet::SSL::Host.ca_location = :local }.should_not raise_error end it "should support the location ':remote'" do lambda { Puppet::SSL::Host.ca_location = :remote }.should_not raise_error end it "should support the location ':none'" do lambda { Puppet::SSL::Host.ca_location = :none }.should_not raise_error end it "should support the location ':only'" do lambda { Puppet::SSL::Host.ca_location = :only }.should_not raise_error end it "should not support other modes" do lambda { Puppet::SSL::Host.ca_location = :whatever }.should raise_error(ArgumentError) end describe "as 'local'" do before do Puppet::SSL::Host.ca_location = :local end it "should set the cache class for Certificate, CertificateRevocationList, and CertificateRequest as :file" do Puppet::SSL::Certificate.indirection.cache_class.should == :file Puppet::SSL::CertificateRequest.indirection.cache_class.should == :file Puppet::SSL::CertificateRevocationList.indirection.cache_class.should == :file end it "should set the terminus class for Key and Host as :file" do Puppet::SSL::Key.indirection.terminus_class.should == :file Puppet::SSL::Host.indirection.terminus_class.should == :file end it "should set the terminus class for Certificate, CertificateRevocationList, and CertificateRequest as :ca" do Puppet::SSL::Certificate.indirection.terminus_class.should == :ca Puppet::SSL::CertificateRequest.indirection.terminus_class.should == :ca Puppet::SSL::CertificateRevocationList.indirection.terminus_class.should == :ca end end describe "as 'remote'" do before do Puppet::SSL::Host.ca_location = :remote end it "should set the cache class for Certificate, CertificateRevocationList, and CertificateRequest as :file" do Puppet::SSL::Certificate.indirection.cache_class.should == :file Puppet::SSL::CertificateRequest.indirection.cache_class.should == :file Puppet::SSL::CertificateRevocationList.indirection.cache_class.should == :file end it "should set the terminus class for Key as :file" do Puppet::SSL::Key.indirection.terminus_class.should == :file end it "should set the terminus class for Host, Certificate, CertificateRevocationList, and CertificateRequest as :rest" do Puppet::SSL::Host.indirection.terminus_class.should == :rest Puppet::SSL::Certificate.indirection.terminus_class.should == :rest Puppet::SSL::CertificateRequest.indirection.terminus_class.should == :rest Puppet::SSL::CertificateRevocationList.indirection.terminus_class.should == :rest end end describe "as 'only'" do before do Puppet::SSL::Host.ca_location = :only end it "should set the terminus class for Key, Certificate, CertificateRevocationList, and CertificateRequest as :ca" do Puppet::SSL::Key.indirection.terminus_class.should == :ca Puppet::SSL::Certificate.indirection.terminus_class.should == :ca Puppet::SSL::CertificateRequest.indirection.terminus_class.should == :ca Puppet::SSL::CertificateRevocationList.indirection.terminus_class.should == :ca end it "should set the cache class for Certificate, CertificateRevocationList, and CertificateRequest to nil" do Puppet::SSL::Certificate.indirection.cache_class.should be_nil Puppet::SSL::CertificateRequest.indirection.cache_class.should be_nil Puppet::SSL::CertificateRevocationList.indirection.cache_class.should be_nil end it "should set the terminus class for Host to :file" do Puppet::SSL::Host.indirection.terminus_class.should == :file end end describe "as 'none'" do before do Puppet::SSL::Host.ca_location = :none end it "should set the terminus class for Key, Certificate, CertificateRevocationList, and CertificateRequest as :file" do Puppet::SSL::Key.indirection.terminus_class.should == :file Puppet::SSL::Certificate.indirection.terminus_class.should == :file Puppet::SSL::CertificateRequest.indirection.terminus_class.should == :file Puppet::SSL::CertificateRevocationList.indirection.terminus_class.should == :file end it "should set the terminus class for Host to 'none'" do lambda { Puppet::SSL::Host.indirection.terminus_class }.should raise_error(Puppet::DevError) end end end it "should have a class method for destroying all files related to a given host" do Puppet::SSL::Host.should respond_to(:destroy) end describe "when destroying a host's SSL files" do before do Puppet::SSL::Key.indirection.stubs(:destroy).returns false Puppet::SSL::Certificate.indirection.stubs(:destroy).returns false Puppet::SSL::CertificateRequest.indirection.stubs(:destroy).returns false end it "should destroy its certificate, certificate request, and key" do Puppet::SSL::Key.indirection.expects(:destroy).with("myhost") Puppet::SSL::Certificate.indirection.expects(:destroy).with("myhost") Puppet::SSL::CertificateRequest.indirection.expects(:destroy).with("myhost") Puppet::SSL::Host.destroy("myhost") end it "should return true if any of the classes returned true" do Puppet::SSL::Certificate.indirection.expects(:destroy).with("myhost").returns true Puppet::SSL::Host.destroy("myhost").should be_true end it "should report that nothing was deleted if none of the classes returned true" do Puppet::SSL::Host.destroy("myhost").should == "Nothing was deleted" end end describe "when initializing" do it "should default its name to the :certname setting" do Puppet.settings.expects(:value).with(:certname).returns "myname" Puppet::SSL::Host.new.name.should == "myname" end it "should downcase a passed in name" do Puppet::SSL::Host.new("Host.Domain.Com").name.should == "host.domain.com" end it "should downcase the certname if it's used" do Puppet.settings.expects(:value).with(:certname).returns "Host.Domain.Com" Puppet::SSL::Host.new.name.should == "host.domain.com" end it "should indicate that it is a CA host if its name matches the ca_name constant" do Puppet::SSL::Host.stubs(:ca_name).returns "myca" Puppet::SSL::Host.new("myca").should be_ca end end describe "when managing its private key" do before do @realkey = "mykey" @key = Puppet::SSL::Key.new("mykey") @key.content = @realkey end it "should return nil if the key is not set and cannot be found" do Puppet::SSL::Key.indirection.expects(:find).with("myname").returns(nil) @host.key.should be_nil end it "should find the key in the Key class and return the Puppet instance" do Puppet::SSL::Key.indirection.expects(:find).with("myname").returns(@key) @host.key.should equal(@key) end it "should be able to generate and save a new key" do Puppet::SSL::Key.expects(:new).with("myname").returns(@key) @key.expects(:generate) Puppet::SSL::Key.indirection.expects(:save) @host.generate_key.should be_true @host.key.should equal(@key) end it "should not retain keys that could not be saved" do Puppet::SSL::Key.expects(:new).with("myname").returns(@key) @key.stubs(:generate) Puppet::SSL::Key.indirection.expects(:save).raises "eh" lambda { @host.generate_key }.should raise_error @host.key.should be_nil end it "should return any previously found key without requerying" do Puppet::SSL::Key.indirection.expects(:find).with("myname").returns(@key).once @host.key.should equal(@key) @host.key.should equal(@key) end end describe "when managing its certificate request" do before do @realrequest = "real request" @request = Puppet::SSL::CertificateRequest.new("myname") @request.content = @realrequest end it "should return nil if the key is not set and cannot be found" do Puppet::SSL::CertificateRequest.indirection.expects(:find).with("myname").returns(nil) @host.certificate_request.should be_nil end it "should find the request in the Key class and return it and return the Puppet SSL request" do Puppet::SSL::CertificateRequest.indirection.expects(:find).with("myname").returns @request @host.certificate_request.should equal(@request) end it "should generate a new key when generating the cert request if no key exists" do Puppet::SSL::CertificateRequest.expects(:new).with("myname").returns @request key = stub 'key', :public_key => mock("public_key"), :content => "mycontent" @host.expects(:key).times(2).returns(nil).then.returns(key) @host.expects(:generate_key).returns(key) @request.stubs(:generate) Puppet::SSL::CertificateRequest.indirection.stubs(:save) @host.generate_certificate_request end it "should be able to generate and save a new request using the private key" do Puppet::SSL::CertificateRequest.expects(:new).with("myname").returns @request key = stub 'key', :public_key => mock("public_key"), :content => "mycontent" @host.stubs(:key).returns(key) @request.expects(:generate).with("mycontent") Puppet::SSL::CertificateRequest.indirection.expects(:save).with(@request) @host.generate_certificate_request.should be_true @host.certificate_request.should equal(@request) end it "should return any previously found request without requerying" do Puppet::SSL::CertificateRequest.indirection.expects(:find).with("myname").returns(@request).once @host.certificate_request.should equal(@request) @host.certificate_request.should equal(@request) end it "should not keep its certificate request in memory if the request cannot be saved" do Puppet::SSL::CertificateRequest.expects(:new).with("myname").returns @request key = stub 'key', :public_key => mock("public_key"), :content => "mycontent" @host.stubs(:key).returns(key) @request.stubs(:generate) @request.stubs(:name).returns("myname") terminus = stub 'terminus' Puppet::SSL::CertificateRequest.indirection.expects(:prepare).returns(terminus) terminus.expects(:save).with { |req| req.instance == @request && req.key == "myname" }.raises "eh" lambda { @host.generate_certificate_request }.should raise_error @host.instance_eval { @certificate_request }.should be_nil end end describe "when managing its certificate" do before do @realcert = mock 'certificate' @cert = stub 'cert', :content => @realcert @host.stubs(:key).returns mock("key") @host.stubs(:certificate_matches_key?).returns true end it "should find the CA certificate if it does not have a certificate" do Puppet::SSL::Certificate.indirection.expects(:find).with(Puppet::SSL::CA_NAME).returns mock("cacert") Puppet::SSL::Certificate.indirection.stubs(:find).with("myname").returns @cert @host.certificate end it "should not find the CA certificate if it is the CA host" do @host.expects(:ca?).returns true Puppet::SSL::Certificate.indirection.stubs(:find) Puppet::SSL::Certificate.indirection.expects(:find).with(Puppet::SSL::CA_NAME).never @host.certificate end it "should return nil if it cannot find a CA certificate" do Puppet::SSL::Certificate.indirection.expects(:find).with(Puppet::SSL::CA_NAME).returns nil Puppet::SSL::Certificate.indirection.expects(:find).with("myname").never @host.certificate.should be_nil end it "should find the key if it does not have one" do Puppet::SSL::Certificate.indirection.stubs(:find) @host.expects(:key).returns mock("key") @host.certificate end it "should generate the key if one cannot be found" do Puppet::SSL::Certificate.indirection.stubs(:find) @host.expects(:key).returns nil @host.expects(:generate_key) @host.certificate end it "should find the certificate in the Certificate class and return the Puppet certificate instance" do Puppet::SSL::Certificate.indirection.expects(:find).with(Puppet::SSL::CA_NAME).returns mock("cacert") Puppet::SSL::Certificate.indirection.expects(:find).with("myname").returns @cert @host.certificate.should equal(@cert) end it "should fail if the found certificate does not match the private key" do @host.expects(:certificate_matches_key?).returns false Puppet::SSL::Certificate.indirection.stubs(:find).returns @cert lambda { @host.certificate }.should raise_error(Puppet::Error) end it "should return any previously found certificate" do Puppet::SSL::Certificate.indirection.expects(:find).with(Puppet::SSL::CA_NAME).returns mock("cacert") Puppet::SSL::Certificate.indirection.expects(:find).with("myname").returns(@cert).once @host.certificate.should equal(@cert) @host.certificate.should equal(@cert) end end it "should have a method for listing certificate hosts" do Puppet::SSL::Host.should respond_to(:search) end describe "when listing certificate hosts" do it "should default to listing all clients with any file types" do Puppet::SSL::Key.indirection.expects(:search).returns [] Puppet::SSL::Certificate.indirection.expects(:search).returns [] Puppet::SSL::CertificateRequest.indirection.expects(:search).returns [] Puppet::SSL::Host.search end it "should be able to list only clients with a key" do Puppet::SSL::Key.indirection.expects(:search).returns [] Puppet::SSL::Certificate.indirection.expects(:search).never Puppet::SSL::CertificateRequest.indirection.expects(:search).never Puppet::SSL::Host.search :for => Puppet::SSL::Key end it "should be able to list only clients with a certificate" do Puppet::SSL::Key.indirection.expects(:search).never Puppet::SSL::Certificate.indirection.expects(:search).returns [] Puppet::SSL::CertificateRequest.indirection.expects(:search).never Puppet::SSL::Host.search :for => Puppet::SSL::Certificate end it "should be able to list only clients with a certificate request" do Puppet::SSL::Key.indirection.expects(:search).never Puppet::SSL::Certificate.indirection.expects(:search).never Puppet::SSL::CertificateRequest.indirection.expects(:search).returns [] Puppet::SSL::Host.search :for => Puppet::SSL::CertificateRequest end it "should return a Host instance created with the name of each found instance" do key = stub 'key', :name => "key" cert = stub 'cert', :name => "cert" csr = stub 'csr', :name => "csr" Puppet::SSL::Key.indirection.expects(:search).returns [key] Puppet::SSL::Certificate.indirection.expects(:search).returns [cert] Puppet::SSL::CertificateRequest.indirection.expects(:search).returns [csr] returned = [] %w{key cert csr}.each do |name| result = mock(name) returned << result Puppet::SSL::Host.expects(:new).with(name).returns result end result = Puppet::SSL::Host.search returned.each do |r| result.should be_include(r) end end end it "should have a method for generating all necessary files" do Puppet::SSL::Host.new("me").should respond_to(:generate) end describe "when generating files" do before do @host = Puppet::SSL::Host.new("me") @host.stubs(:generate_key) @host.stubs(:generate_certificate_request) end it "should generate a key if one is not present" do @host.stubs(:key).returns nil @host.expects(:generate_key) @host.generate end it "should generate a certificate request if one is not present" do @host.expects(:certificate_request).returns nil @host.expects(:generate_certificate_request) @host.generate end describe "and it can create a certificate authority" do before do @ca = mock 'ca' Puppet::SSL::CertificateAuthority.stubs(:instance).returns @ca end it "should use the CA to sign its certificate request if it does not have a certificate" do @host.expects(:certificate).returns nil @ca.expects(:sign).with(@host.name) @host.generate end end describe "and it cannot create a certificate authority" do before do Puppet::SSL::CertificateAuthority.stubs(:instance).returns nil end it "should seek its certificate" do @host.expects(:certificate) @host.generate end end end it "should have a method for creating an SSL store" do Puppet::SSL::Host.new("me").should respond_to(:ssl_store) end it "should always return the same store" do host = Puppet::SSL::Host.new("foo") store = mock 'store' store.stub_everything OpenSSL::X509::Store.expects(:new).returns store host.ssl_store.should equal(host.ssl_store) end describe "when creating an SSL store" do before do @host = Puppet::SSL::Host.new("me") @store = mock 'store' @store.stub_everything OpenSSL::X509::Store.stubs(:new).returns @store Puppet.settings.stubs(:value).with(:localcacert).returns "ssl_host_testing" Puppet::SSL::CertificateRevocationList.indirection.stubs(:find).returns(nil) end it "should accept a purpose" do @store.expects(:purpose=).with "my special purpose" @host.ssl_store("my special purpose") end it "should default to OpenSSL::X509::PURPOSE_ANY as the purpose" do @store.expects(:purpose=).with OpenSSL::X509::PURPOSE_ANY @host.ssl_store end it "should add the local CA cert file" do Puppet.settings.stubs(:value).with(:localcacert).returns "/ca/cert/file" @store.expects(:add_file).with "/ca/cert/file" @host.ssl_store end describe "and a CRL is available" do before do @crl = stub 'crl', :content => "real_crl" Puppet::SSL::CertificateRevocationList.indirection.stubs(:find).returns @crl Puppet.settings.stubs(:value).with(:certificate_revocation).returns true end it "should add the CRL" do @store.expects(:add_crl).with "real_crl" @host.ssl_store end it "should set the flags to OpenSSL::X509::V_FLAG_CRL_CHECK_ALL|OpenSSL::X509::V_FLAG_CRL_CHECK" do @store.expects(:flags=).with OpenSSL::X509::V_FLAG_CRL_CHECK_ALL|OpenSSL::X509::V_FLAG_CRL_CHECK @host.ssl_store end end end describe "when waiting for a cert" do before do @host = Puppet::SSL::Host.new("me") end it "should generate its certificate request and attempt to read the certificate again if no certificate is found" do @host.expects(:certificate).times(2).returns(nil).then.returns "foo" @host.expects(:generate) @host.wait_for_cert(1) end it "should catch and log errors during CSR saving" do @host.expects(:certificate).times(2).returns(nil).then.returns "foo" @host.expects(:generate).raises(RuntimeError).then.returns nil @host.stubs(:sleep) @host.wait_for_cert(1) end it "should sleep and retry after failures saving the CSR if waitforcert is enabled" do @host.expects(:certificate).times(2).returns(nil).then.returns "foo" @host.expects(:generate).raises(RuntimeError).then.returns nil @host.expects(:sleep).with(1) @host.wait_for_cert(1) end it "should exit after failures saving the CSR of waitforcert is disabled" do @host.expects(:certificate).returns(nil) @host.expects(:generate).raises(RuntimeError) @host.expects(:puts) @host.expects(:exit).with(1).raises(SystemExit) lambda { @host.wait_for_cert(0) }.should raise_error(SystemExit) end it "should exit if the wait time is 0 and it can neither find nor retrieve a certificate" do @host.stubs(:certificate).returns nil @host.expects(:generate) @host.expects(:puts) @host.expects(:exit).with(1).raises(SystemExit) lambda { @host.wait_for_cert(0) }.should raise_error(SystemExit) end it "should sleep for the specified amount of time if no certificate is found after generating its certificate request" do @host.expects(:certificate).times(3).returns(nil).then.returns(nil).then.returns "foo" @host.expects(:generate) @host.expects(:sleep).with(1) @host.wait_for_cert(1) end it "should catch and log exceptions during certificate retrieval" do @host.expects(:certificate).times(3).returns(nil).then.raises(RuntimeError).then.returns("foo") @host.stubs(:generate) @host.stubs(:sleep) Puppet.expects(:err) @host.wait_for_cert(1) end end describe "when handling PSON" do include PuppetSpec::Files before do Puppet[:vardir] = tmpdir("ssl_test_vardir") Puppet[:ssldir] = tmpdir("ssl_test_ssldir") Puppet::SSLCertificates::CA.new.mkrootcert # localcacert is where each client stores the CA certificate # cacert is where the master stores the CA certificate # Since we need to play the role of both for testing we need them to be the same and exist Puppet[:cacert] = Puppet[:localcacert] @ca=Puppet::SSL::CertificateAuthority.new end describe "when converting to PSON" do it "should be able to identify a host with an unsigned certificate request" do host = Puppet::SSL::Host.new("bazinga") host.generate_certificate_request pson_hash = { "fingerprint" => host.certificate_request.fingerprint, "desired_state" => 'requested', "name" => host.name } result = PSON.parse(Puppet::SSL::Host.new(host.name).to_pson) result["fingerprint"].should == pson_hash["fingerprint"] result["name"].should == pson_hash["name"] result["state"].should == pson_hash["desired_state"] end it "should be able to identify a host with a signed certificate" do host = Puppet::SSL::Host.new("bazinga") host.generate_certificate_request @ca.sign(host.name) pson_hash = { "fingerprint" => Puppet::SSL::Certificate.indirection.find(host.name).fingerprint, "desired_state" => 'signed', "name" => host.name, } result = PSON.parse(Puppet::SSL::Host.new(host.name).to_pson) result["fingerprint"].should == pson_hash["fingerprint"] result["name"].should == pson_hash["name"] result["state"].should == pson_hash["desired_state"] end it "should be able to identify a host with a revoked certificate" do host = Puppet::SSL::Host.new("bazinga") host.generate_certificate_request @ca.sign(host.name) @ca.revoke(host.name) pson_hash = { "fingerprint" => Puppet::SSL::Certificate.indirection.find(host.name).fingerprint, "desired_state" => 'revoked', "name" => host.name, } result = PSON.parse(Puppet::SSL::Host.new(host.name).to_pson) result["fingerprint"].should == pson_hash["fingerprint"] result["name"].should == pson_hash["name"] result["state"].should == pson_hash["desired_state"] end end describe "when converting from PSON" do it "should return a Puppet::SSL::Host object with the specified desired state" do host = Puppet::SSL::Host.new("bazinga") host.desired_state="signed" pson_hash = { "name" => host.name, "desired_state" => host.desired_state, } generated_host = Puppet::SSL::Host.from_pson(pson_hash) generated_host.desired_state.should == host.desired_state generated_host.name.should == host.name end end end end diff --git a/spec/unit/ssl/inventory_spec.rb b/spec/unit/ssl/inventory_spec.rb index 613f420a9..d8606b1b4 100755 --- a/spec/unit/ssl/inventory_spec.rb +++ b/spec/unit/ssl/inventory_spec.rb @@ -1,180 +1,179 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/ssl/inventory' describe Puppet::SSL::Inventory do before do @class = Puppet::SSL::Inventory end it "should use the :certinventory setting for the path to the inventory file" do Puppet.settings.expects(:value).with(:cert_inventory).returns "/inven/tory" @class.any_instance.stubs(:rebuild) @class.new.path.should == "/inven/tory" end describe "when initializing" do it "should set its path to the inventory file" do Puppet.settings.stubs(:value).with(:cert_inventory).returns "/inven/tory" @class.new.path.should == "/inven/tory" end end describe "when managing an inventory" do before do Puppet.settings.stubs(:value).with(:cert_inventory).returns "/inven/tory" FileTest.stubs(:exist?).with("/inven/tory").returns true @inventory = @class.new @cert = mock 'cert' end describe "and creating the inventory file" do before do Puppet.settings.stubs(:write) FileTest.stubs(:exist?).with("/inven/tory").returns false Puppet::SSL::Certificate.indirection.stubs(:search).returns [] end it "should log that it is building a new inventory file" do Puppet.expects(:notice) @inventory.rebuild end it "should use the Settings to write to the file" do Puppet.settings.expects(:write).with(:cert_inventory) @inventory.rebuild end it "should add a header to the file" do fh = mock 'filehandle' Puppet.settings.stubs(:write).yields fh fh.expects(:print).with { |str| str =~ /^#/ } @inventory.rebuild end it "should add formatted information on all existing certificates" do cert1 = mock 'cert1' cert2 = mock 'cert2' Puppet::SSL::Certificate.indirection.expects(:search).with("*").returns [cert1, cert2] @class.any_instance.expects(:add).with(cert1) @class.any_instance.expects(:add).with(cert2) @inventory.rebuild end end describe "and adding a certificate" do it "should build the inventory file if one does not exist" do Puppet.settings.stubs(:value).with(:cert_inventory).returns "/inven/tory" Puppet.settings.stubs(:write) FileTest.expects(:exist?).with("/inven/tory").returns false @inventory.expects(:rebuild) @inventory.add(@cert) end it "should use the Settings to write to the file" do Puppet.settings.expects(:write).with(:cert_inventory, "a") @inventory.add(@cert) end it "should use the actual certificate if it was passed a Puppet certificate" do cert = Puppet::SSL::Certificate.new("mycert") cert.content = @cert fh = stub 'filehandle', :print => nil Puppet.settings.stubs(:write).yields fh @inventory.expects(:format).with(@cert) @inventory.add(@cert) end it "should add formatted certificate information to the end of the file" do fh = mock 'filehandle' Puppet.settings.stubs(:write).yields fh @inventory.expects(:format).with(@cert).returns "myformat" fh.expects(:print).with("myformat") @inventory.add(@cert) end end describe "and formatting a certificate" do before do @cert = stub 'cert', :not_before => Time.now, :not_after => Time.now, :subject => "mycert", :serial => 15 end it "should print the serial number as a 4 digit hex number in the first field" do @inventory.format(@cert).split[0].should == "0x000f" # 15 in hex end it "should print the not_before date in '%Y-%m-%dT%H:%M:%S%Z' format in the second field" do @cert.not_before.expects(:strftime).with('%Y-%m-%dT%H:%M:%S%Z').returns "before_time" @inventory.format(@cert).split[1].should == "before_time" end it "should print the not_after date in '%Y-%m-%dT%H:%M:%S%Z' format in the third field" do @cert.not_after.expects(:strftime).with('%Y-%m-%dT%H:%M:%S%Z').returns "after_time" @inventory.format(@cert).split[2].should == "after_time" end it "should print the subject in the fourth field" do @inventory.format(@cert).split[3].should == "mycert" end it "should add a carriage return" do @inventory.format(@cert).should =~ /\n$/ end it "should produce a line consisting of the serial number, start date, expiration date, and subject" do # Just make sure our serial and subject bracket the lines. @inventory.format(@cert).should =~ /^0x.+mycert$/ end end it "should be able to find a given host's serial number" do @inventory.should respond_to(:serial) end describe "and finding a serial number" do it "should return nil if the inventory file is missing" do FileTest.expects(:exist?).with("/inven/tory").returns false @inventory.serial(:whatever).should be_nil end it "should return the serial number from the line matching the provided name" do File.expects(:readlines).with("/inven/tory").returns ["0x00f blah blah /CN=me\n", "0x001 blah blah /CN=you\n"] @inventory.serial("me").should == 15 end it "should return the number as an integer" do File.expects(:readlines).with("/inven/tory").returns ["0x00f blah blah /CN=me\n", "0x001 blah blah /CN=you\n"] @inventory.serial("me").should == 15 end end end end diff --git a/spec/unit/ssl/key_spec.rb b/spec/unit/ssl/key_spec.rb index aabc92c6d..cddf9f8ea 100755 --- a/spec/unit/ssl/key_spec.rb +++ b/spec/unit/ssl/key_spec.rb @@ -1,198 +1,197 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/ssl/key' describe Puppet::SSL::Key do before do @class = Puppet::SSL::Key end it "should be extended with the Indirector module" do @class.singleton_class.should be_include(Puppet::Indirector) end it "should indirect key" do @class.indirection.name.should == :key end it "should default to the :file terminus" do @class.indirection.terminus_class.should == :file end it "should only support the text format" do @class.supported_formats.should == [:s] end it "should have a method for determining whether it's a CA key" do @class.new("test").should respond_to(:ca?) end it "should consider itself a ca key if its name matches the CA_NAME" do @class.new(Puppet::SSL::Host.ca_name).should be_ca end describe "when initializing" do it "should set its password file to the :capass if it's a CA key" do Puppet.settings.stubs(:value).returns "whatever" Puppet.settings.stubs(:value).with(:capass).returns "/ca/pass" key = Puppet::SSL::Key.new(Puppet::SSL::Host.ca_name) key.password_file.should == "/ca/pass" end it "should downcase its name" do @class.new("MyName").name.should == "myname" end it "should set its password file to the default password file if it is not the CA key" do Puppet.settings.stubs(:value).returns "whatever" Puppet.settings.stubs(:value).with(:passfile).returns "/normal/pass" key = Puppet::SSL::Key.new("notca") key.password_file.should == "/normal/pass" end end describe "when managing instances" do before do @key = @class.new("myname") end it "should have a name attribute" do @key.name.should == "myname" end it "should have a content attribute" do @key.should respond_to(:content) end it "should be able to read keys from disk" do path = "/my/path" File.expects(:read).with(path).returns("my key") key = mock 'key' OpenSSL::PKey::RSA.expects(:new).returns(key) @key.read(path).should equal(key) @key.content.should equal(key) end it "should not try to use the provided password file if the file does not exist" do FileTest.stubs(:exist?).returns false @key.password_file = "/path/to/password" path = "/my/path" File.stubs(:read).with(path).returns("my key") OpenSSL::PKey::RSA.expects(:new).with("my key", nil).returns(mock('key')) File.expects(:read).with("/path/to/password").never @key.read(path) end it "should read the key with the password retrieved from the password file if one is provided" do FileTest.stubs(:exist?).returns true @key.password_file = "/path/to/password" path = "/my/path" File.expects(:read).with(path).returns("my key") File.expects(:read).with("/path/to/password").returns("my password") key = mock 'key' OpenSSL::PKey::RSA.expects(:new).with("my key", "my password").returns(key) @key.read(path).should equal(key) @key.content.should equal(key) end it "should return an empty string when converted to a string with no key" do @key.to_s.should == "" end it "should convert the key to pem format when converted to a string" do key = mock 'key', :to_pem => "pem" @key.content = key @key.to_s.should == "pem" end it "should have a :to_text method that it delegates to the actual key" do real_key = mock 'key' real_key.expects(:to_text).returns "keytext" @key.content = real_key @key.to_text.should == "keytext" end end describe "when generating the private key" do before do @instance = @class.new("test") @key = mock 'key' end it "should create an instance of OpenSSL::PKey::RSA" do OpenSSL::PKey::RSA.expects(:new).returns(@key) @instance.generate end it "should create the private key with the keylength specified in the settings" do Puppet.settings.expects(:value).with(:keylength).returns("50") OpenSSL::PKey::RSA.expects(:new).with(50).returns(@key) @instance.generate end it "should set the content to the generated key" do OpenSSL::PKey::RSA.stubs(:new).returns(@key) @instance.generate @instance.content.should equal(@key) end it "should return the generated key" do OpenSSL::PKey::RSA.stubs(:new).returns(@key) @instance.generate.should equal(@key) end it "should return the key in pem format" do @instance.generate @instance.content.expects(:to_pem).returns "my normal key" @instance.to_s.should == "my normal key" end describe "with a password file set" do it "should return a nil password if the password file does not exist" do FileTest.expects(:exist?).with("/path/to/pass").returns false File.expects(:read).with("/path/to/pass").never @instance.password_file = "/path/to/pass" @instance.password.should be_nil end it "should return the contents of the password file as its password" do FileTest.expects(:exist?).with("/path/to/pass").returns true File.expects(:read).with("/path/to/pass").returns "my password" @instance.password_file = "/path/to/pass" @instance.password.should == "my password" end it "should export the private key to text using the password" do Puppet.settings.stubs(:value).with(:keylength).returns("50") @instance.password_file = "/path/to/pass" @instance.stubs(:password).returns "my password" OpenSSL::PKey::RSA.expects(:new).returns(@key) @instance.generate cipher = mock 'cipher' OpenSSL::Cipher::DES.expects(:new).with(:EDE3, :CBC).returns cipher @key.expects(:export).with(cipher, "my password").returns "my encrypted key" @instance.to_s.should == "my encrypted key" end end end end diff --git a/spec/unit/sslcertificates/ca_spec.rb b/spec/unit/sslcertificates/ca_spec.rb index 46cdbd0e9..eea246ba1 100755 --- a/spec/unit/sslcertificates/ca_spec.rb +++ b/spec/unit/sslcertificates/ca_spec.rb @@ -1,110 +1,110 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec require 'spec_helper' require 'puppet' require 'puppet/sslcertificates' require 'puppet/sslcertificates/ca' describe Puppet::SSLCertificates::CA do before :all do @hosts = %w{host.domain.com Other.Testing.Com} end before :each do Puppet::Util::SUIDManager.stubs(:asuser).yields file = Tempfile.new("ca_testing") @dir = file.path file.delete Puppet.settings[:confdir] = @dir Puppet.settings[:vardir] = @dir @ca = Puppet::SSLCertificates::CA.new end after :each do system("rm -rf #{@dir}") end describe 'when cleaning' do it 'should remove associated files' do dirs = [:csrdir, :signeddir, :publickeydir, :privatekeydir, :certdir] @hosts.each do |host| files = [] dirs.each do |dir| dir = Puppet[dir] # Case insensitivity is handled through downcasing file = File.join(dir, host.downcase + '.pem') File.open(file, "w") do |f| f.puts "testing" end files << file end lambda { @ca.clean(host) }.should_not raise_error files.reject {|f| ! File.exists?(f)}.should be_empty end end end describe 'when mapping hosts to files' do it 'should correctly return the certfile' do @hosts.each do |host| value = nil lambda { value = @ca.host2certfile host }.should_not raise_error File.join(Puppet[:signeddir], host.downcase + '.pem').should == value end end it 'should correctly return the csrfile' do @hosts.each do |host| value = nil lambda { value = @ca.host2csrfile host }.should_not raise_error File.join(Puppet[:csrdir], host.downcase + '.pem').should == value end end end describe 'when listing' do it 'should find all csr' do list = [] # Make some fake CSRs @hosts.each do |host| file = File.join(Puppet[:csrdir], host.downcase + '.pem') File.open(file, 'w') { |f| f.puts "yay" } list << host.downcase end @ca.list.sort.should == list.sort end end describe 'when creating a root certificate' do before :each do lambda { @ca.mkrootcert }.should_not raise_exception end it 'should store the public key' do File.exists?(Puppet[:capub]).should be_true end it 'should prepend "Puppet CA: " to the fqdn as the ca_name by default' do host_mock_fact = mock() host_mock_fact.expects(:value).returns('myhost') domain_mock_fact = mock() domain_mock_fact.expects(:value).returns('puppetlabs.lan') Facter.stubs(:[]).with('hostname').returns(host_mock_fact) Facter.stubs(:[]).with('domain').returns(domain_mock_fact) @ca.mkrootcert.name.should == 'Puppet CA: myhost.puppetlabs.lan' end end end diff --git a/spec/unit/status_spec.rb b/spec/unit/status_spec.rb index 4e8f551bc..820807638 100755 --- a/spec/unit/status_spec.rb +++ b/spec/unit/status_spec.rb @@ -1,31 +1,30 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe Puppet::Status do it "should implement find" do Puppet::Status.indirection.find( :default ).should be_is_a(Puppet::Status) Puppet::Status.indirection.find( :default ).status["is_alive"].should == true end it "should default to is_alive is true" do Puppet::Status.new.status["is_alive"].should == true end it "should return a pson hash" do Puppet::Status.new.status.to_pson.should == '{"is_alive":true}' end it "should accept a hash from pson" do status = Puppet::Status.new( { "is_alive" => false } ) status.status.should == { "is_alive" => false } end it "should have a name" do Puppet::Status.new.name end it "should allow a name to be set" do Puppet::Status.new.name = "status" end end diff --git a/spec/unit/transaction/event_manager_spec.rb b/spec/unit/transaction/event_manager_spec.rb index 378948ebc..d127d0391 100755 --- a/spec/unit/transaction/event_manager_spec.rb +++ b/spec/unit/transaction/event_manager_spec.rb @@ -1,260 +1,259 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/transaction/event_manager' describe Puppet::Transaction::EventManager do describe "at initialization" do it "should require a transaction" do Puppet::Transaction::EventManager.new("trans").transaction.should == "trans" end end it "should delegate its relationship graph to the transaction" do transaction = stub 'transaction' manager = Puppet::Transaction::EventManager.new(transaction) transaction.expects(:relationship_graph).returns "mygraph" manager.relationship_graph.should == "mygraph" end describe "when queueing events" do before do @manager = Puppet::Transaction::EventManager.new(@transaction) @resource = Puppet::Type.type(:file).new :path => "/my/file" @graph = stub 'graph', :matching_edges => [], :resource => @resource @manager.stubs(:relationship_graph).returns @graph @event = Puppet::Transaction::Event.new(:name => :foo, :resource => @resource) end it "should store all of the events in its event list" do @event2 = Puppet::Transaction::Event.new(:name => :bar, :resource => @resource) @manager.queue_events(@resource, [@event, @event2]) @manager.events.should include(@event) @manager.events.should include(@event2) end it "should queue events for the target and callback of any matching edges" do edge1 = stub("edge1", :callback => :c1, :source => stub("s1"), :target => stub("t1", :c1 => nil)) edge2 = stub("edge2", :callback => :c2, :source => stub("s2"), :target => stub("t2", :c2 => nil)) @graph.expects(:matching_edges).with { |event, resource| event == @event }.returns [edge1, edge2] @manager.expects(:queue_events_for_resource).with(@resource, edge1.target, edge1.callback, [@event]) @manager.expects(:queue_events_for_resource).with(@resource, edge2.target, edge2.callback, [@event]) @manager.queue_events(@resource, [@event]) end it "should queue events for the changed resource if the resource is self-refreshing and not being deleted" do @graph.stubs(:matching_edges).returns [] @resource.expects(:self_refresh?).returns true @resource.expects(:deleting?).returns false @manager.expects(:queue_events_for_resource).with(@resource, @resource, :refresh, [@event]) @manager.queue_events(@resource, [@event]) end it "should not queue events for the changed resource if the resource is not self-refreshing" do @graph.stubs(:matching_edges).returns [] @resource.expects(:self_refresh?).returns false @resource.stubs(:deleting?).returns false @manager.expects(:queue_events_for_resource).never @manager.queue_events(@resource, [@event]) end it "should not queue events for the changed resource if the resource is being deleted" do @graph.stubs(:matching_edges).returns [] @resource.expects(:self_refresh?).returns true @resource.expects(:deleting?).returns true @manager.expects(:queue_events_for_resource).never @manager.queue_events(@resource, [@event]) end it "should ignore edges that don't have a callback" do edge1 = stub("edge1", :callback => :nil, :source => stub("s1"), :target => stub("t1", :c1 => nil)) @graph.expects(:matching_edges).returns [edge1] @manager.expects(:queue_events_for_resource).never @manager.queue_events(@resource, [@event]) end it "should ignore targets that don't respond to the callback" do edge1 = stub("edge1", :callback => :c1, :source => stub("s1"), :target => stub("t1")) @graph.expects(:matching_edges).returns [edge1] @manager.expects(:queue_events_for_resource).never @manager.queue_events(@resource, [@event]) end end describe "when queueing events for a resource" do before do @transaction = stub 'transaction' @manager = Puppet::Transaction::EventManager.new(@transaction) end it "should do nothing if no events are queued" do @manager.queued_events(stub("target")) { |callback, events| raise "should never reach this" } end it "should yield the callback and events for each callback" do target = stub("target") 2.times do |i| @manager.queue_events_for_resource(stub("source", :info => nil), target, "callback#{i}", ["event#{i}"]) end @manager.queued_events(target) { |callback, events| } end it "should use the source to log that it's scheduling a refresh of the target" do target = stub("target") source = stub 'source' source.expects(:info) @manager.queue_events_for_resource(source, target, "callback", ["event"]) @manager.queued_events(target) { |callback, events| } end end describe "when processing events for a given resource" do before do @transaction = Puppet::Transaction.new(Puppet::Resource::Catalog.new) @manager = Puppet::Transaction::EventManager.new(@transaction) @manager.stubs(:queue_events) @resource = Puppet::Type.type(:file).new :path => "/my/file" @event = Puppet::Transaction::Event.new(:name => :event, :resource => @resource) end it "should call the required callback once for each set of associated events" do @manager.expects(:queued_events).with(@resource).multiple_yields([:callback1, [@event]], [:callback2, [@event]]) @resource.expects(:callback1) @resource.expects(:callback2) @manager.process_events(@resource) end it "should set the 'restarted' state on the resource status" do @manager.expects(:queued_events).with(@resource).yields(:callback1, [@event]) @resource.stubs(:callback1) @manager.process_events(@resource) @transaction.resource_status(@resource).should be_restarted end it "should queue a 'restarted' event generated by the resource" do @manager.expects(:queued_events).with(@resource).yields(:callback1, [@event]) @resource.stubs(:callback1) @resource.expects(:event).with(:name => :restarted, :status => "success").returns "myevent" @manager.expects(:queue_events).with(@resource, ["myevent"]) @manager.process_events(@resource) end it "should log that it restarted" do @manager.expects(:queued_events).with(@resource).yields(:callback1, [@event]) @resource.stubs(:callback1) @resource.expects(:notice).with { |msg| msg.include?("Triggered 'callback1'") } @manager.process_events(@resource) end describe "and the events include a noop event and at least one non-noop event" do before do @event.stubs(:status).returns "noop" @event2 = Puppet::Transaction::Event.new(:name => :event, :resource => @resource) @event2.status = "success" @manager.expects(:queued_events).with(@resource).yields(:callback1, [@event, @event2]) end it "should call the callback" do @resource.expects(:callback1) @manager.process_events(@resource) end end describe "and the events are all noop events" do before do @event.stubs(:status).returns "noop" @resource.stubs(:event).returns(Puppet::Transaction::Event.new) @manager.expects(:queued_events).with(@resource).yields(:callback1, [@event]) end it "should log" do @resource.expects(:notice).with { |msg| msg.include?("Would have triggered 'callback1'") } @manager.process_events(@resource) end it "should not call the callback" do @resource.expects(:callback1).never @manager.process_events(@resource) end it "should queue a new noop event generated from the resource" do event = Puppet::Transaction::Event.new @resource.expects(:event).with(:status => "noop", :name => :noop_restart).returns event @manager.expects(:queue_events).with(@resource, [event]) @manager.process_events(@resource) end end describe "and the callback fails" do before do @resource.expects(:callback1).raises "a failure" @resource.stubs(:err) @manager.expects(:queued_events).yields(:callback1, [@event]) end it "should log but not fail" do @resource.expects(:err) lambda { @manager.process_events(@resource) }.should_not raise_error end it "should set the 'failed_restarts' state on the resource status" do @manager.process_events(@resource) @transaction.resource_status(@resource).should be_failed_to_restart end it "should not queue a 'restarted' event" do @manager.expects(:queue_events).never @manager.process_events(@resource) end it "should set the 'restarted' state on the resource status" do @manager.process_events(@resource) @transaction.resource_status(@resource).should_not be_restarted end end end end diff --git a/spec/unit/transaction/event_spec.rb b/spec/unit/transaction/event_spec.rb index 115c30dc0..1227802a7 100755 --- a/spec/unit/transaction/event_spec.rb +++ b/spec/unit/transaction/event_spec.rb @@ -1,127 +1,126 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/transaction/event' describe Puppet::Transaction::Event do [:previous_value, :desired_value, :property, :resource, :name, :message, :file, :line, :tags, :audited].each do |attr| it "should support #{attr}" do event = Puppet::Transaction::Event.new event.send(attr.to_s + "=", "foo") event.send(attr).should == "foo" end end it "should always convert the property to a string" do Puppet::Transaction::Event.new(:property => :foo).property.should == "foo" end it "should always convert the resource to a string" do Puppet::Transaction::Event.new(:resource => :foo).resource.should == "foo" end it "should produce the message when converted to a string" do event = Puppet::Transaction::Event.new event.expects(:message).returns "my message" event.to_s.should == "my message" end it "should support 'status'" do event = Puppet::Transaction::Event.new event.status = "success" event.status.should == "success" end it "should fail if the status is not to 'audit', 'noop', 'success', or 'failure" do event = Puppet::Transaction::Event.new lambda { event.status = "foo" }.should raise_error(ArgumentError) end it "should support tags" do Puppet::Transaction::Event.ancestors.should include(Puppet::Util::Tagging) end it "should create a timestamp at its creation time" do Puppet::Transaction::Event.new.time.should be_instance_of(Time) end describe "audit property" do it "should default to false" do Puppet::Transaction::Event.new.audited.should == false end end describe "when sending logs" do before do Puppet::Util::Log.stubs(:new) end it "should set the level to the resources's log level if the event status is 'success' and a resource is available" do resource = stub 'resource' resource.expects(:[]).with(:loglevel).returns :myloglevel Puppet::Util::Log.expects(:create).with { |args| args[:level] == :myloglevel } Puppet::Transaction::Event.new(:status => "success", :resource => resource).send_log end it "should set the level to 'notice' if the event status is 'success' and no resource is available" do Puppet::Util::Log.expects(:new).with { |args| args[:level] == :notice } Puppet::Transaction::Event.new(:status => "success").send_log end it "should set the level to 'notice' if the event status is 'noop'" do Puppet::Util::Log.expects(:new).with { |args| args[:level] == :notice } Puppet::Transaction::Event.new(:status => "noop").send_log end it "should set the level to 'err' if the event status is 'failure'" do Puppet::Util::Log.expects(:new).with { |args| args[:level] == :err } Puppet::Transaction::Event.new(:status => "failure").send_log end it "should set the 'message' to the event log" do Puppet::Util::Log.expects(:new).with { |args| args[:message] == "my message" } Puppet::Transaction::Event.new(:message => "my message").send_log end it "should set the tags to the event tags" do Puppet::Util::Log.expects(:new).with { |args| args[:tags] == %w{one two} } Puppet::Transaction::Event.new(:tags => %w{one two}).send_log end [:file, :line].each do |attr| it "should pass the #{attr}" do Puppet::Util::Log.expects(:new).with { |args| args[attr] == "my val" } Puppet::Transaction::Event.new(attr => "my val").send_log end end it "should use the source description as the source if one is set" do Puppet::Util::Log.expects(:new).with { |args| args[:source] == "/my/param" } Puppet::Transaction::Event.new(:source_description => "/my/param", :resource => "Foo[bar]", :property => "foo").send_log end it "should use the property as the source if one is available and no source description is set" do Puppet::Util::Log.expects(:new).with { |args| args[:source] == "foo" } Puppet::Transaction::Event.new(:resource => "Foo[bar]", :property => "foo").send_log end it "should use the property as the source if one is available and no property or source description is set" do Puppet::Util::Log.expects(:new).with { |args| args[:source] == "Foo[bar]" } Puppet::Transaction::Event.new(:resource => "Foo[bar]").send_log end end describe "When converting to YAML" do it "should include only documented attributes" do resource = Puppet::Type.type(:file).new(:title => "/tmp/foo") event = Puppet::Transaction::Event.new(:source_description => "/my/param", :resource => resource, :file => "/foo.rb", :line => 27, :tags => %w{one two}, :desired_value => 7, :historical_value => 'Brazil', :message => "Help I'm trapped in a spec test", :name => :mode_changed, :previous_value => 6, :property => :mode, :status => 'success') event.to_yaml_properties.should == Puppet::Transaction::Event::YAML_ATTRIBUTES.sort end end end diff --git a/spec/unit/transaction/report_spec.rb b/spec/unit/transaction/report_spec.rb index 07ac62415..191a30eb7 100755 --- a/spec/unit/transaction/report_spec.rb +++ b/spec/unit/transaction/report_spec.rb @@ -1,313 +1,312 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/transaction/report' describe Puppet::Transaction::Report do include PuppetSpec::Files before do Puppet::Util::Storage.stubs(:store) end it "should set its host name to the certname" do Puppet.settings.expects(:value).with(:certname).returns "myhost" Puppet::Transaction::Report.new("apply").host.should == "myhost" end it "should return its host name as its name" do r = Puppet::Transaction::Report.new("apply") r.name.should == r.host end it "should create an initialization timestamp" do Time.expects(:now).returns "mytime" Puppet::Transaction::Report.new("apply").time.should == "mytime" end it "should take a 'kind' as an argument" do Puppet::Transaction::Report.new("inspect").kind.should == "inspect" end it "should take a 'configuration_version' as an argument" do Puppet::Transaction::Report.new("inspect", "some configuration version").configuration_version.should == "some configuration version" end it "should be able to set configuration_version" do report = Puppet::Transaction::Report.new("inspect") report.configuration_version = "some version" report.configuration_version.should == "some version" end it "should not include whits" do Puppet::FileBucket::File.indirection.stubs(:save) filename = tmpfile('whit_test') file = Puppet::Type.type(:file).new(:path => filename) catalog = Puppet::Resource::Catalog.new catalog.add_resource(file) report = Puppet::Transaction::Report.new("apply") catalog.apply(:report => report) report.finalize_report report.resource_statuses.values.any? {|res| res.resource_type =~ /whit/i}.should be_false report.metrics['time'].values.any? {|metric| metric.first =~ /whit/i}.should be_false end describe "when accepting logs" do before do @report = Puppet::Transaction::Report.new("apply") end it "should add new logs to the log list" do @report << "log" @report.logs[-1].should == "log" end it "should return self" do r = @report << "log" r.should equal(@report) end end describe "when accepting resource statuses" do before do @report = Puppet::Transaction::Report.new("apply") end it "should add each status to its status list" do status = stub 'status', :resource => "foo" @report.add_resource_status status @report.resource_statuses["foo"].should equal(status) end end describe "when using the indirector" do it "should redirect :save to the indirection" do Facter.stubs(:value).returns("eh") @indirection = stub 'indirection', :name => :report Puppet::Transaction::Report.stubs(:indirection).returns(@indirection) report = Puppet::Transaction::Report.new("apply") @indirection.expects(:save) Puppet::Transaction::Report.indirection.save(report) end it "should default to the 'processor' terminus" do Puppet::Transaction::Report.indirection.terminus_class.should == :processor end it "should delegate its name attribute to its host method" do report = Puppet::Transaction::Report.new("apply") report.expects(:host).returns "me" report.name.should == "me" end after do Puppet::Util::Cacher.expire end end describe "when computing exit status" do it "should produce 2 if changes are present" do report = Puppet::Transaction::Report.new("apply") report.add_metric("changes", {"total" => 1}) report.add_metric("resources", {"failed" => 0}) report.exit_status.should == 2 end it "should produce 4 if failures are present" do report = Puppet::Transaction::Report.new("apply") report.add_metric("changes", {"total" => 0}) report.add_metric("resources", {"failed" => 1}) report.exit_status.should == 4 end it "should produce 6 if both changes and failures are present" do report = Puppet::Transaction::Report.new("apply") report.add_metric("changes", {"total" => 1}) report.add_metric("resources", {"failed" => 1}) report.exit_status.should == 6 end end describe "before finalizing the report" do it "should have a status of 'failed'" do report = Puppet::Transaction::Report.new("apply") report.status.should == 'failed' end end describe "when finalizing the report" do before do @report = Puppet::Transaction::Report.new("apply") end def metric(name, value) if metric = @report.metrics[name.to_s] metric[value] else nil end end def add_statuses(count, type = :file) count.times do |i| status = Puppet::Resource::Status.new(Puppet::Type.type(type).new(:title => "/my/path#{i}")) yield status if block_given? @report.add_resource_status status end end [:time, :resources, :changes, :events].each do |type| it "should add #{type} metrics" do @report.finalize_report @report.metrics[type.to_s].should be_instance_of(Puppet::Transaction::Metric) end end describe "for resources" do it "should provide the total number of resources" do add_statuses(3) @report.finalize_report metric(:resources, "total").should == 3 end Puppet::Resource::Status::STATES.each do |state| it "should provide the number of #{state} resources as determined by the status objects" do add_statuses(3) { |status| status.send(state.to_s + "=", true) } @report.finalize_report metric(:resources, state.to_s).should == 3 end end it "should mark the report as 'failed' if there are failing resources" do add_statuses(1) { |status| status.failed = true } @report.finalize_report @report.status.should == 'failed' end end describe "for changes" do it "should provide the number of changes from the resource statuses and mark the report as 'changed'" do add_statuses(3) { |status| 3.times { status << Puppet::Transaction::Event.new(:status => 'success') } } @report.finalize_report metric(:changes, "total").should == 9 @report.status.should == 'changed' end it "should provide a total even if there are no changes, and mark the report as 'unchanged'" do @report.finalize_report metric(:changes, "total").should == 0 @report.status.should == 'unchanged' end end describe "for times" do it "should provide the total amount of time for each resource type" do add_statuses(3, :file) do |status| status.evaluation_time = 1 end add_statuses(3, :exec) do |status| status.evaluation_time = 2 end add_statuses(3, :mount) do |status| status.evaluation_time = 3 end @report.finalize_report metric(:time, "file").should == 3 metric(:time, "exec").should == 6 metric(:time, "mount").should == 9 end it "should add any provided times from external sources" do @report.add_times :foobar, 50 @report.finalize_report metric(:time, "foobar").should == 50 end it "should have a total time" do add_statuses(3, :file) do |status| status.evaluation_time = 1.25 end @report.add_times :config_retrieval, 0.5 @report.finalize_report metric(:time, "total").should == 4.25 end end describe "for events" do it "should provide the total number of events" do add_statuses(3) do |status| 3.times { |i| status.add_event(Puppet::Transaction::Event.new :status => 'success') } end @report.finalize_report metric(:events, "total").should == 9 end it "should provide the total even if there are no events" do @report.finalize_report metric(:events, "total").should == 0 end Puppet::Transaction::Event::EVENT_STATUSES.each do |status_name| it "should provide the number of #{status_name} events" do add_statuses(3) do |status| 3.times do |i| event = Puppet::Transaction::Event.new event.status = status_name status.add_event(event) end end @report.finalize_report metric(:events, status_name).should == 9 end end end end describe "when producing a summary" do before do resource = Puppet::Type.type(:notify).new(:name => "testing") catalog = Puppet::Resource::Catalog.new catalog.add_resource resource trans = catalog.apply @report = trans.report @report.finalize_report end %w{changes time resources events}.each do |main| it "should include the key #{main} in the raw summary hash" do @report.raw_summary.should be_key main end end it "should include the last run time in the raw summary hash" do Time.stubs(:now).returns(Time.utc(2010,11,10,12,0,24)) @report.raw_summary["time"]["last_run"].should == 1289390424 end %w{Changes Total Resources Time Events}.each do |main| it "should include information on #{main} in the textual summary" do @report.summary.should be_include(main) end end end describe "when outputting yaml" do it "should not include @external_times" do report = Puppet::Transaction::Report.new('apply') report.add_times('config_retrieval', 1.0) report.to_yaml_properties.should_not include('@external_times') end end end diff --git a/spec/unit/transaction/resource_harness_spec.rb b/spec/unit/transaction/resource_harness_spec.rb index d7b873c6b..20a42d27b 100755 --- a/spec/unit/transaction/resource_harness_spec.rb +++ b/spec/unit/transaction/resource_harness_spec.rb @@ -1,481 +1,480 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/transaction/resource_harness' describe Puppet::Transaction::ResourceHarness do include PuppetSpec::Files before do @transaction = Puppet::Transaction.new(Puppet::Resource::Catalog.new) @resource = Puppet::Type.type(:file).new :path => "/my/file" @harness = Puppet::Transaction::ResourceHarness.new(@transaction) @current_state = Puppet::Resource.new(:file, "/my/file") @resource.stubs(:retrieve).returns @current_state @status = Puppet::Resource::Status.new(@resource) Puppet::Resource::Status.stubs(:new).returns @status end it "should accept a transaction at initialization" do harness = Puppet::Transaction::ResourceHarness.new(@transaction) harness.transaction.should equal(@transaction) end it "should delegate to the transaction for its relationship graph" do @transaction.expects(:relationship_graph).returns "relgraph" Puppet::Transaction::ResourceHarness.new(@transaction).relationship_graph.should == "relgraph" end describe "when evaluating a resource" do it "should create and return a resource status instance for the resource" do @harness.evaluate(@resource).should be_instance_of(Puppet::Resource::Status) end it "should fail if no status can be created" do Puppet::Resource::Status.expects(:new).raises ArgumentError lambda { @harness.evaluate(@resource) }.should raise_error end it "should retrieve the current state of the resource" do @resource.expects(:retrieve).returns @current_state @harness.evaluate(@resource) end it "should mark the resource as failed and return if the current state cannot be retrieved" do @resource.expects(:retrieve).raises ArgumentError @harness.evaluate(@resource).should be_failed end it "should store the resource's evaluation time in the resource status" do @harness.evaluate(@resource).evaluation_time.should be_instance_of(Float) end end def events_to_hash(events) events.map do |event| hash = {} event.instance_variables.each do |varname| hash[varname] = event.instance_variable_get(varname.to_sym) end hash end end def make_stub_provider stubProvider = Class.new(Puppet::Type) stubProvider.instance_eval do initvars newparam(:name) do desc "The name var" isnamevar end newproperty(:foo) do desc "A property that can be changed successfully" def sync end def retrieve :absent end def insync?(reference_value) false end end newproperty(:bar) do desc "A property that raises an exception when you try to change it" def sync raise ZeroDivisionError.new('bar') end def retrieve :absent end def insync?(reference_value) false end end end stubProvider end describe "when an error occurs" do before :each do stub_provider = make_stub_provider resource = stub_provider.new :name => 'name', :foo => 1, :bar => 2 resource.expects(:err).never @status = @harness.evaluate(resource) end it "should record previous successful events" do @status.events[0].property.should == 'foo' @status.events[0].status.should == 'success' end it "should record a failure event" do @status.events[1].property.should == 'bar' @status.events[1].status.should == 'failure' end end describe "when auditing" do it "should not call insync? on parameters that are merely audited" do stub_provider = make_stub_provider resource = stub_provider.new :name => 'name', :audit => ['foo'] resource.property(:foo).expects(:insync?).never status = @harness.evaluate(resource) status.events.each do |event| event.status.should != 'failure' end end it "should be able to audit a file's group" do # see bug #5710 test_file = tmpfile('foo') File.open(test_file, 'w').close resource = Puppet::Type.type(:file).new :path => test_file, :audit => ['group'], :backup => false resource.expects(:err).never # make sure no exceptions get swallowed status = @harness.evaluate(resource) status.events.each do |event| event.status.should != 'failure' end end end describe "when applying changes" do [false, true].each do |noop_mode|; describe (noop_mode ? "in noop mode" : "in normal mode") do [nil, '750'].each do |machine_state|; describe (machine_state ? "with a file initially present" : "with no file initially present") do [nil, '750', '755'].each do |yaml_mode| [nil, :file, :absent].each do |yaml_ensure|; describe "with mode=#{yaml_mode.inspect} and ensure=#{yaml_ensure.inspect} stored in state.yml" do [false, true].each do |auditing_ensure| [false, true].each do |auditing_mode| auditing = [] auditing.push(:mode) if auditing_mode auditing.push(:ensure) if auditing_ensure [nil, :file, :absent].each do |ensure_property| # what we set "ensure" to in the manifest [nil, '750', '755'].each do |mode_property| # what we set "mode" to in the manifest manifest_settings = {} manifest_settings[:audit] = auditing if !auditing.empty? manifest_settings[:ensure] = ensure_property if ensure_property manifest_settings[:mode] = mode_property if mode_property describe "with manifest settings #{manifest_settings.inspect}" do; it "should behave properly" do # Set up preconditions test_file = tmpfile('foo') if machine_state File.open(test_file, 'w', machine_state.to_i(8)).close end Puppet[:noop] = noop_mode params = { :path => test_file, :backup => false } params.merge!(manifest_settings) resource = Puppet::Type.type(:file).new params @harness.cache(resource, :mode, yaml_mode) if yaml_mode @harness.cache(resource, :ensure, yaml_ensure) if yaml_ensure fake_time = Time.utc(2011, 'jan', 3, 12, 24, 0) Time.stubs(:now).returns(fake_time) # So that Puppet::Resource::Status objects will compare properly resource.expects(:err).never # make sure no exceptions get swallowed status = @harness.evaluate(resource) # do the thing # check that the state of the machine has been properly updated expected_logs = [] expected_status_events = [] if auditing_mode @harness.cached(resource, :mode).should == (machine_state || :absent) else @harness.cached(resource, :mode).should == yaml_mode end if auditing_ensure @harness.cached(resource, :ensure).should == (machine_state ? :file : :absent) else @harness.cached(resource, :ensure).should == yaml_ensure end if ensure_property == :file file_would_be_there_if_not_noop = true elsif ensure_property == nil file_would_be_there_if_not_noop = machine_state != nil else # ensure_property == :absent file_would_be_there_if_not_noop = false end file_should_be_there = noop_mode ? machine_state != nil : file_would_be_there_if_not_noop File.exists?(test_file).should == file_should_be_there if file_should_be_there if noop_mode expected_file_mode = machine_state else expected_file_mode = mode_property || machine_state end if !expected_file_mode # we didn't specify a mode and the file was created, so mode comes from umode else file_mode = File.stat(test_file).mode & 0777 file_mode.should == expected_file_mode.to_i(8) end end # Test log output for the "mode" parameter previously_recorded_mode_already_logged = false mode_status_msg = nil if machine_state && file_would_be_there_if_not_noop && mode_property && machine_state != mode_property if noop_mode what_happened = "current_value #{machine_state}, should be #{mode_property} (noop)" expected_status = 'noop' else what_happened = "mode changed '#{machine_state}' to '#{mode_property}'" expected_status = 'success' end if auditing_mode && yaml_mode && yaml_mode != machine_state previously_recorded_mode_already_logged = true mode_status_msg = "#{what_happened} (previously recorded value was #{yaml_mode})" else mode_status_msg = what_happened end expected_logs << "notice: /#{resource}/mode: #{mode_status_msg}" end if @harness.cached(resource, :mode) && @harness.cached(resource, :mode) != yaml_mode if yaml_mode unless previously_recorded_mode_already_logged mode_status_msg = "audit change: previously recorded value #{yaml_mode} has been changed to #{@harness.cached(resource, :mode)}" expected_logs << "notice: /#{resource}/mode: #{mode_status_msg}" expected_status = 'audit' end else expected_logs << "notice: /#{resource}/mode: audit change: newly-recorded value #{@harness.cached(resource, :mode)}" end end if mode_status_msg expected_status_events << Puppet::Transaction::Event.new( :source_description => "/#{resource}/mode", :resource => resource, :file => nil, :line => nil, :tags => %w{file}, :desired_value => mode_property, :historical_value => yaml_mode, :message => mode_status_msg, :name => :mode_changed, :previous_value => machine_state || :absent, :property => :mode, :status => expected_status, :audited => auditing_mode) end # Test log output for the "ensure" parameter previously_recorded_ensure_already_logged = false ensure_status_msg = nil if file_would_be_there_if_not_noop != (machine_state != nil) if noop_mode what_happened = "current_value #{machine_state ? 'file' : 'absent'}, should be #{file_would_be_there_if_not_noop ? 'file' : 'absent'} (noop)" expected_status = 'noop' else what_happened = file_would_be_there_if_not_noop ? 'created' : 'removed' expected_status = 'success' end if auditing_ensure && yaml_ensure && yaml_ensure != (machine_state ? :file : :absent) previously_recorded_ensure_already_logged = true ensure_status_msg = "#{what_happened} (previously recorded value was #{yaml_ensure})" else ensure_status_msg = "#{what_happened}" end expected_logs << "notice: /#{resource}/ensure: #{ensure_status_msg}" end if @harness.cached(resource, :ensure) && @harness.cached(resource, :ensure) != yaml_ensure if yaml_ensure unless previously_recorded_ensure_already_logged ensure_status_msg = "audit change: previously recorded value #{yaml_ensure} has been changed to #{@harness.cached(resource, :ensure)}" expected_logs << "notice: /#{resource}/ensure: #{ensure_status_msg}" expected_status = 'audit' end else expected_logs << "notice: /#{resource}/ensure: audit change: newly-recorded value #{@harness.cached(resource, :ensure)}" end end if ensure_status_msg if ensure_property == :file ensure_event_name = :file_created elsif ensure_property == nil ensure_event_name = :file_changed else # ensure_property == :absent ensure_event_name = :file_removed end expected_status_events << Puppet::Transaction::Event.new( :source_description => "/#{resource}/ensure", :resource => resource, :file => nil, :line => nil, :tags => %w{file}, :desired_value => ensure_property, :historical_value => yaml_ensure, :message => ensure_status_msg, :name => ensure_event_name, :previous_value => machine_state ? :file : :absent, :property => :ensure, :status => expected_status, :audited => auditing_ensure) end # Actually check the logs. @logs.map {|l| "#{l.level}: #{l.source}: #{l.message}"}.should =~ expected_logs # All the log messages should show up as events except the "newly-recorded" ones. expected_event_logs = @logs.reject {|l| l.message =~ /newly-recorded/ } status.events.map {|e| e.message}.should =~ expected_event_logs.map {|l| l.message } events_to_hash(status.events).should =~ events_to_hash(expected_status_events) # Check change count - this is the number of changes that actually occurred. expected_change_count = 0 if (machine_state != nil) != file_should_be_there expected_change_count = 1 elsif machine_state != nil if expected_file_mode != machine_state expected_change_count = 1 end end status.change_count.should == expected_change_count # Check out of sync count - this is the number # of changes that would have occurred in # non-noop mode. expected_out_of_sync_count = 0 if (machine_state != nil) != file_would_be_there_if_not_noop expected_out_of_sync_count = 1 elsif machine_state != nil if mode_property != nil && mode_property != machine_state expected_out_of_sync_count = 1 end end if !noop_mode expected_out_of_sync_count.should == expected_change_count end status.out_of_sync_count.should == expected_out_of_sync_count # Check legacy summary fields status.changed.should == (expected_change_count != 0) status.out_of_sync.should == (expected_out_of_sync_count != 0) # Check the :synced field on state.yml synced_should_be_set = !noop_mode && status.changed (@harness.cached(resource, :synced) != nil).should == synced_should_be_set end; end end end end end end; end end end; end end; end it "should not apply changes if allow_changes?() returns false" do test_file = tmpfile('foo') resource = Puppet::Type.type(:file).new :path => test_file, :backup => false, :ensure => :file resource.expects(:err).never # make sure no exceptions get swallowed @harness.expects(:allow_changes?).with(resource).returns false status = @harness.evaluate(resource) File.exists?(test_file).should == false end end describe "when determining whether the resource can be changed" do before do @resource.stubs(:purging?).returns true @resource.stubs(:deleting?).returns true end it "should be true if the resource is not being purged" do @resource.expects(:purging?).returns false @harness.should be_allow_changes(@resource) end it "should be true if the resource is not being deleted" do @resource.expects(:deleting?).returns false @harness.should be_allow_changes(@resource) end it "should be true if the resource has no dependents" do @harness.relationship_graph.expects(:dependents).with(@resource).returns [] @harness.should be_allow_changes(@resource) end it "should be true if all dependents are being deleted" do dep = stub 'dependent', :deleting? => true @harness.relationship_graph.expects(:dependents).with(@resource).returns [dep] @resource.expects(:purging?).returns true @harness.should be_allow_changes(@resource) end it "should be false if the resource's dependents are not being deleted" do dep = stub 'dependent', :deleting? => false, :ref => "myres" @resource.expects(:warning) @harness.relationship_graph.expects(:dependents).with(@resource).returns [dep] @harness.should_not be_allow_changes(@resource) end end describe "when finding the schedule" do before do @catalog = Puppet::Resource::Catalog.new @resource.catalog = @catalog end it "should warn and return nil if the resource has no catalog" do @resource.catalog = nil @resource.expects(:warning) @harness.schedule(@resource).should be_nil end it "should return nil if the resource specifies no schedule" do @harness.schedule(@resource).should be_nil end it "should fail if the named schedule cannot be found" do @resource[:schedule] = "whatever" @resource.expects(:fail) @harness.schedule(@resource) end it "should return the named schedule if it exists" do sched = Puppet::Type.type(:schedule).new(:name => "sched") @catalog.add_resource(sched) @resource[:schedule] = "sched" @harness.schedule(@resource).to_s.should == sched.to_s end end describe "when determining if a resource is scheduled" do before do @catalog = Puppet::Resource::Catalog.new @resource.catalog = @catalog @status = Puppet::Resource::Status.new(@resource) end it "should return true if 'ignoreschedules' is set" do Puppet[:ignoreschedules] = true @resource[:schedule] = "meh" @harness.should be_scheduled(@status, @resource) end it "should return true if the resource has no schedule set" do @harness.should be_scheduled(@status, @resource) end it "should return the result of matching the schedule with the cached 'checked' time if a schedule is set" do t = Time.now @harness.expects(:cached).with(@resource, :checked).returns(t) sched = Puppet::Type.type(:schedule).new(:name => "sched") @catalog.add_resource(sched) @resource[:schedule] = "sched" sched.expects(:match?).with(t.to_i).returns "feh" @harness.scheduled?(@status, @resource).should == "feh" end end it "should be able to cache data in the Storage module" do data = {} Puppet::Util::Storage.expects(:cache).with(@resource).returns data @harness.cache(@resource, :foo, "something") data[:foo].should == "something" end it "should be able to retrieve data from the cache" do data = {:foo => "other"} Puppet::Util::Storage.expects(:cache).with(@resource).returns data @harness.cached(@resource, :foo).should == "other" end end diff --git a/spec/unit/transaction_spec.rb b/spec/unit/transaction_spec.rb index baeab14af..4157e58ac 100755 --- a/spec/unit/transaction_spec.rb +++ b/spec/unit/transaction_spec.rb @@ -1,441 +1,440 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/transaction' def without_warnings flag = $VERBOSE $VERBOSE = nil yield $VERBOSE = flag end describe Puppet::Transaction do before do @basepath = Puppet.features.posix? ? "/what/ever" : "C:/tmp" @transaction = Puppet::Transaction.new(Puppet::Resource::Catalog.new) end it "should delegate its event list to the event manager" do @transaction = Puppet::Transaction.new(Puppet::Resource::Catalog.new) @transaction.event_manager.expects(:events).returns %w{my events} @transaction.events.should == %w{my events} end it "should delegate adding times to its report" do @transaction = Puppet::Transaction.new(Puppet::Resource::Catalog.new) @transaction.report.expects(:add_times).with(:foo, 10) @transaction.report.expects(:add_times).with(:bar, 20) @transaction.add_times :foo => 10, :bar => 20 end it "should be able to accept resource status instances" do resource = Puppet::Type.type(:notify).new :title => "foobar" status = Puppet::Resource::Status.new(resource) @transaction.add_resource_status(status) @transaction.resource_status(resource).should equal(status) end it "should be able to look resource status up by resource reference" do resource = Puppet::Type.type(:notify).new :title => "foobar" status = Puppet::Resource::Status.new(resource) @transaction.add_resource_status(status) @transaction.resource_status(resource.to_s).should equal(status) end # This will basically only ever be used during testing. it "should automatically create resource statuses if asked for a non-existent status" do resource = Puppet::Type.type(:notify).new :title => "foobar" @transaction.resource_status(resource).should be_instance_of(Puppet::Resource::Status) end it "should add provided resource statuses to its report" do resource = Puppet::Type.type(:notify).new :title => "foobar" status = Puppet::Resource::Status.new(resource) @transaction.add_resource_status(status) @transaction.report.resource_statuses[resource.to_s].should equal(status) end it "should consider a resource to be failed if a status instance exists for that resource and indicates it is failed" do resource = Puppet::Type.type(:notify).new :name => "yayness" status = Puppet::Resource::Status.new(resource) status.failed = "some message" @transaction.add_resource_status(status) @transaction.should be_failed(resource) end it "should not consider a resource to be failed if a status instance exists for that resource but indicates it is not failed" do resource = Puppet::Type.type(:notify).new :name => "yayness" status = Puppet::Resource::Status.new(resource) @transaction.add_resource_status(status) @transaction.should_not be_failed(resource) end it "should consider there to be failed resources if any statuses are marked failed" do resource = Puppet::Type.type(:notify).new :name => "yayness" status = Puppet::Resource::Status.new(resource) status.failed = "some message" @transaction.add_resource_status(status) @transaction.should be_any_failed end it "should not consider there to be failed resources if no statuses are marked failed" do resource = Puppet::Type.type(:notify).new :name => "yayness" status = Puppet::Resource::Status.new(resource) @transaction.add_resource_status(status) @transaction.should_not be_any_failed end it "should be possible to replace the report object" do report = Puppet::Transaction::Report.new("apply") @transaction.report = report @transaction.report.should == report end it "should consider a resource to have failed dependencies if any of its dependencies are failed" describe "when initializing" do it "should create an event manager" do @transaction = Puppet::Transaction.new(Puppet::Resource::Catalog.new) @transaction.event_manager.should be_instance_of(Puppet::Transaction::EventManager) @transaction.event_manager.transaction.should equal(@transaction) end it "should create a resource harness" do @transaction = Puppet::Transaction.new(Puppet::Resource::Catalog.new) @transaction.resource_harness.should be_instance_of(Puppet::Transaction::ResourceHarness) @transaction.resource_harness.transaction.should equal(@transaction) end end describe "when evaluating a resource" do before do @transaction = Puppet::Transaction.new(Puppet::Resource::Catalog.new) @transaction.stubs(:skip?).returns false @resource = Puppet::Type.type(:file).new :path => @basepath end it "should check whether the resource should be skipped" do @transaction.expects(:skip?).with(@resource).returns false @transaction.eval_resource(@resource) end it "should process events" do @transaction.event_manager.expects(:process_events).with(@resource) @transaction.eval_resource(@resource) end describe "and the resource should be skipped" do before do @transaction.expects(:skip?).with(@resource).returns true end it "should mark the resource's status as skipped" do @transaction.eval_resource(@resource) @transaction.resource_status(@resource).should be_skipped end end end describe "when applying a resource" do before do @resource = Puppet::Type.type(:file).new :path => @basepath @status = Puppet::Resource::Status.new(@resource) @transaction = Puppet::Transaction.new(Puppet::Resource::Catalog.new) @transaction.event_manager.stubs(:queue_events) @transaction.resource_harness.stubs(:evaluate).returns(@status) end it "should use its resource harness to apply the resource" do @transaction.resource_harness.expects(:evaluate).with(@resource) @transaction.apply(@resource) end it "should add the resulting resource status to its status list" do @transaction.apply(@resource) @transaction.resource_status(@resource).should be_instance_of(Puppet::Resource::Status) end it "should queue any events added to the resource status" do @status.expects(:events).returns %w{a b} @transaction.event_manager.expects(:queue_events).with(@resource, ["a", "b"]) @transaction.apply(@resource) end it "should log and skip any resources that cannot be applied" do @transaction.resource_harness.expects(:evaluate).raises ArgumentError @resource.expects(:err) @transaction.apply(@resource) @transaction.report.resource_statuses[@resource.to_s].should be_nil end end describe "when generating resources" do it "should call 'generate' on all created resources" do first = Puppet::Type.type(:notify).new(:name => "first") second = Puppet::Type.type(:notify).new(:name => "second") third = Puppet::Type.type(:notify).new(:name => "third") @catalog = Puppet::Resource::Catalog.new @transaction = Puppet::Transaction.new(@catalog) first.expects(:generate).returns [second] second.expects(:generate).returns [third] third.expects(:generate) @transaction.generate_additional_resources(first) end it "should finish all resources" do generator = stub 'generator', :depthfirst? => true, :tags => [] resource = stub 'resource', :tag => nil @catalog = Puppet::Resource::Catalog.new @transaction = Puppet::Transaction.new(@catalog) generator.expects(:generate).returns [resource] @catalog.expects(:add_resource).yields(resource) resource.expects(:finish) @transaction.generate_additional_resources(generator) end it "should skip generated resources that conflict with existing resources" do generator = mock 'generator', :tags => [] resource = stub 'resource', :tag => nil @catalog = Puppet::Resource::Catalog.new @transaction = Puppet::Transaction.new(@catalog) generator.expects(:generate).returns [resource] @catalog.expects(:add_resource).raises(Puppet::Resource::Catalog::DuplicateResourceError.new("foo")) resource.expects(:finish).never resource.expects(:info) # log that it's skipped @transaction.generate_additional_resources(generator) end it "should copy all tags to the newly generated resources" do child = stub 'child' generator = stub 'resource', :tags => ["one", "two"] @catalog = Puppet::Resource::Catalog.new @transaction = Puppet::Transaction.new(@catalog) generator.stubs(:generate).returns [child] @catalog.stubs(:add_resource) child.expects(:tag).with("one", "two") child.expects(:finish) generator.expects(:depthfirst?) @transaction.generate_additional_resources(generator) end end describe "when skipping a resource" do before :each do @resource = Puppet::Type.type(:notify).new :name => "foo" @catalog = Puppet::Resource::Catalog.new @resource.catalog = @catalog @transaction = Puppet::Transaction.new(@catalog) end it "should skip resource with missing tags" do @transaction.stubs(:missing_tags?).returns(true) @transaction.should be_skip(@resource) end it "should skip unscheduled resources" do @transaction.stubs(:scheduled?).returns(false) @transaction.should be_skip(@resource) end it "should skip resources with failed dependencies" do @transaction.stubs(:failed_dependencies?).returns(true) @transaction.should be_skip(@resource) end it "should skip virtual resource" do @resource.stubs(:virtual?).returns true @transaction.should be_skip(@resource) end end describe "when determining if tags are missing" do before :each do @resource = Puppet::Type.type(:notify).new :name => "foo" @catalog = Puppet::Resource::Catalog.new @resource.catalog = @catalog @transaction = Puppet::Transaction.new(@catalog) @transaction.stubs(:ignore_tags?).returns false end it "should not be missing tags if tags are being ignored" do @transaction.expects(:ignore_tags?).returns true @resource.expects(:tagged?).never @transaction.should_not be_missing_tags(@resource) end it "should not be missing tags if the transaction tags are empty" do @transaction.tags = [] @resource.expects(:tagged?).never @transaction.should_not be_missing_tags(@resource) end it "should otherwise let the resource determine if it is missing tags" do tags = ['one', 'two'] @transaction.tags = tags @resource.expects(:tagged?).with(*tags).returns(false) @transaction.should be_missing_tags(@resource) end end describe "when determining if a resource should be scheduled" do before :each do @resource = Puppet::Type.type(:notify).new :name => "foo" @catalog = Puppet::Resource::Catalog.new @resource.catalog = @catalog @transaction = Puppet::Transaction.new(@catalog) end it "should always schedule resources if 'ignoreschedules' is set" do @transaction.ignoreschedules = true @transaction.resource_harness.expects(:scheduled?).never @transaction.should be_scheduled(@resource) end it "should let the resource harness determine whether the resource should be scheduled" do @transaction.resource_harness.expects(:scheduled?).with(@transaction.resource_status(@resource), @resource).returns "feh" @transaction.scheduled?(@resource).should == "feh" end end describe "when prefetching" do it "should match resources by name, not title" do @catalog = Puppet::Resource::Catalog.new @transaction = Puppet::Transaction.new(@catalog) # Have both a title and name resource = Puppet::Type.type(:sshkey).create :title => "foo", :name => "bar", :type => :dsa, :key => "eh" @catalog.add_resource resource resource.provider.class.expects(:prefetch).with("bar" => resource) @transaction.prefetch end end it "should return all resources for which the resource status indicates the resource has changed when determinig changed resources" do @catalog = Puppet::Resource::Catalog.new @transaction = Puppet::Transaction.new(@catalog) names = [] 2.times do |i| name = File.join(@basepath, "file#{i}") resource = Puppet::Type.type(:file).new :path => name names << resource.to_s @catalog.add_resource resource @transaction.add_resource_status Puppet::Resource::Status.new(resource) end @transaction.resource_status(names[0]).changed = true @transaction.changed?.should == [@catalog.resource(names[0])] end describe 'when checking application run state' do before do without_warnings { Puppet::Application = Class.new(Puppet::Application) } @catalog = Puppet::Resource::Catalog.new @transaction = Puppet::Transaction.new(@catalog) end after do without_warnings { Puppet::Application = Puppet::Application.superclass } end it 'should return true for :stop_processing? if Puppet::Application.stop_requested? is true' do Puppet::Application.stubs(:stop_requested?).returns(true) @transaction.stop_processing?.should be_true end it 'should return false for :stop_processing? if Puppet::Application.stop_requested? is false' do Puppet::Application.stubs(:stop_requested?).returns(false) @transaction.stop_processing?.should be_false end describe 'within an evaluate call' do before do @resource = Puppet::Type.type(:notify).new :title => "foobar" @catalog.add_resource @resource @transaction.stubs(:prepare) end it 'should stop processing if :stop_processing? is true' do @transaction.stubs(:stop_processing?).returns(true) @transaction.expects(:eval_resource).never @transaction.evaluate end it 'should continue processing if :stop_processing? is false' do @transaction.stubs(:stop_processing?).returns(false) @transaction.expects(:eval_resource).returns(nil) @transaction.evaluate end end end end describe Puppet::Transaction, " when determining tags" do before do @config = Puppet::Resource::Catalog.new @transaction = Puppet::Transaction.new(@config) end it "should default to the tags specified in the :tags setting" do Puppet.expects(:[]).with(:tags).returns("one") @transaction.tags.should == %w{one} end it "should split tags based on ','" do Puppet.expects(:[]).with(:tags).returns("one,two") @transaction.tags.should == %w{one two} end it "should use any tags set after creation" do Puppet.expects(:[]).with(:tags).never @transaction.tags = %w{one two} @transaction.tags.should == %w{one two} end it "should always convert assigned tags to an array" do @transaction.tags = "one::two" @transaction.tags.should == %w{one::two} end it "should accept a comma-delimited string" do @transaction.tags = "one, two" @transaction.tags.should == %w{one two} end it "should accept an empty string" do @transaction.tags = "" @transaction.tags.should == [] end end diff --git a/spec/unit/transportable_spec.rb b/spec/unit/transportable_spec.rb old mode 100644 new mode 100755 diff --git a/spec/unit/type/augeas_spec.rb b/spec/unit/type/augeas_spec.rb index 896c66587..c8dc207f9 100755 --- a/spec/unit/type/augeas_spec.rb +++ b/spec/unit/type/augeas_spec.rb @@ -1,120 +1,119 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' augeas = Puppet::Type.type(:augeas) describe augeas do describe "when augeas is present", :if => Puppet.features.augeas? do it "should have a default provider inheriting from Puppet::Provider" do augeas.defaultprovider.ancestors.should be_include(Puppet::Provider) end it "should have a valid provider" do augeas.new(:name => "foo").provider.class.ancestors.should be_include(Puppet::Provider) end end describe "basic structure" do it "should be able to create a instance" do provider_class = Puppet::Type::Augeas.provider(Puppet::Type::Augeas.providers[0]) Puppet::Type::Augeas.expects(:defaultprovider).returns provider_class augeas.new(:name => "bar").should_not be_nil end it "should have an parse_commands feature" do augeas.provider_feature(:parse_commands).should_not be_nil end it "should have an need_to_run? feature" do augeas.provider_feature(:need_to_run?).should_not be_nil end it "should have an execute_changes feature" do augeas.provider_feature(:execute_changes).should_not be_nil end properties = [:returns] params = [:name, :context, :onlyif, :changes, :root, :load_path, :type_check] properties.each do |property| it "should have a #{property} property" do augeas.attrclass(property).ancestors.should be_include(Puppet::Property) end it "should have documentation for its #{property} property" do augeas.attrclass(property).doc.should be_instance_of(String) end end params.each do |param| it "should have a #{param} parameter" do augeas.attrclass(param).ancestors.should be_include(Puppet::Parameter) end it "should have documentation for its #{param} parameter" do augeas.attrclass(param).doc.should be_instance_of(String) end end end describe "default values" do before do provider_class = augeas.provider(augeas.providers[0]) augeas.expects(:defaultprovider).returns provider_class end it "should be blank for context" do augeas.new(:name => :context)[:context].should == "" end it "should be blank for onlyif" do augeas.new(:name => :onlyif)[:onlyif].should == "" end it "should be blank for load_path" do augeas.new(:name => :load_path)[:load_path].should == "" end it "should be / for root" do augeas.new(:name => :root)[:root].should == "/" end it "should be false for type_check" do augeas.new(:name => :type_check)[:type_check].should == :false end end describe "provider interaction" do it "should return 0 if it does not need to run" do provider = stub("provider", :need_to_run? => false) resource = stub('resource', :resource => nil, :provider => provider, :line => nil, :file => nil) changes = augeas.attrclass(:returns).new(:resource => resource) changes.retrieve.should == 0 end it "should return :need_to_run if it needs to run" do provider = stub("provider", :need_to_run? => true) resource = stub('resource', :resource => nil, :provider => provider, :line => nil, :file => nil) changes = augeas.attrclass(:returns).new(:resource => resource) changes.retrieve.should == :need_to_run end end describe "loading specific files" do it "should require lens when incl is used" do lambda { augeas.new(:name => :no_lens, :incl => "/etc/hosts")}.should raise_error(Puppet::Error) end it "should require incl when lens is used" do lambda { augeas.new(:name => :no_incl, :lens => "Hosts.lns") }.should raise_error(Puppet::Error) end it "should set the context when a specific file is used" do fake_provider = stub_everything "fake_provider" augeas.stubs(:defaultprovider).returns fake_provider augeas.new(:name => :no_incl, :lens => "Hosts.lns", :incl => "/etc/hosts")[:context].should == "/files/etc/hosts" end end end diff --git a/spec/unit/type/component_spec.rb b/spec/unit/type/component_spec.rb index 193d82fcc..9d6d71926 100755 --- a/spec/unit/type/component_spec.rb +++ b/spec/unit/type/component_spec.rb @@ -1,63 +1,62 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' component = Puppet::Type.type(:component) describe component do it "should have a :name attribute" do component.attrclass(:name).should_not be_nil end it "should use Class as its type when a normal string is provided as the title" do component.new(:name => "bar").ref.should == "Class[Bar]" end it "should always produce a resource reference string as its title" do component.new(:name => "bar").title.should == "Class[Bar]" end it "should have a reference string equivalent to its title" do comp = component.new(:name => "Foo[bar]") comp.title.should == comp.ref end it "should alias itself to its reference if it has a catalog and the catalog does not already have a resource with the same reference" do catalog = mock 'catalog' catalog.expects(:resource).with("Foo[bar]").returns nil catalog.expects(:alias).with { |resource, name| resource.is_a?(component) and name == "Foo[bar]" } component.new(:name => "Foo[bar]", :catalog => catalog) end it "should not fail when provided an invalid value" do comp = component.new(:name => "Foo[bar]") lambda { comp[:yayness] = "ey" }.should_not raise_error end it "should return previously provided invalid values" do comp = component.new(:name => "Foo[bar]") comp[:yayness] = "eh" comp[:yayness].should == "eh" end it "should correctly support metaparameters" do comp = component.new(:name => "Foo[bar]", :require => "Foo[bar]") comp.parameter(:require).should be_instance_of(component.attrclass(:require)) end describe "when building up the path" do it "should produce the class name if the component models a class" do component.new(:name => "Class[foo]").pathbuilder.must == ["Foo"] end it "should produce an empty string if the component models the 'main' class" do component.new(:name => "Class[main]").pathbuilder.must == [""] end it "should produce a resource reference if the component does not model a class" do component.new(:name => "Foo[bar]").pathbuilder.must == ["Foo[bar]"] end end end diff --git a/spec/unit/type/computer_spec.rb b/spec/unit/type/computer_spec.rb index 9bce5106c..1e15d7a4f 100755 --- a/spec/unit/type/computer_spec.rb +++ b/spec/unit/type/computer_spec.rb @@ -1,81 +1,80 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' computer = Puppet::Type.type(:computer) describe Puppet::Type.type(:computer), " when checking computer objects" do before do provider_class = Puppet::Type::Computer.provider(Puppet::Type::Computer.providers[0]) Puppet::Type::Computer.expects(:defaultprovider).returns provider_class @resource = Puppet::Type::Computer.new( :name => "puppetcomputertest", :en_address => "aa:bb:cc:dd:ee:ff", :ip_address => "1.2.3.4") @properties = {} @ensure = Puppet::Type::Computer.attrclass(:ensure).new(:resource => @resource) end it "should be able to create a instance" do provider_class = Puppet::Type::Computer.provider(Puppet::Type::Computer.providers[0]) Puppet::Type::Computer.expects(:defaultprovider).returns provider_class computer.new(:name => "bar").should_not be_nil end properties = [:en_address, :ip_address] params = [:name] properties.each do |property| it "should have a #{property} property" do computer.attrclass(property).ancestors.should be_include(Puppet::Property) end it "should have documentation for its #{property} property" do computer.attrclass(property).doc.should be_instance_of(String) end it "should accept :absent as a value" do prop = computer.attrclass(property).new(:resource => @resource) prop.should = :absent prop.should.must == :absent end end params.each do |param| it "should have a #{param} parameter" do computer.attrclass(param).ancestors.should be_include(Puppet::Parameter) end it "should have documentation for its #{param} parameter" do computer.attrclass(param).doc.should be_instance_of(String) end end describe "default values" do before do provider_class = computer.provider(computer.providers[0]) computer.expects(:defaultprovider).returns provider_class end it "should be nil for en_address" do computer.new(:name => :en_address)[:en_address].should == nil end it "should be nil for ip_address" do computer.new(:name => :ip_address)[:ip_address].should == nil end end describe "when managing the ensure property" do it "should support a :present value" do lambda { @ensure.should = :present }.should_not raise_error end it "should support an :absent value" do lambda { @ensure.should = :absent }.should_not raise_error end end end diff --git a/spec/unit/type/cron_spec.rb b/spec/unit/type/cron_spec.rb index e98529c60..7bf92eb02 100755 --- a/spec/unit/type/cron_spec.rb +++ b/spec/unit/type/cron_spec.rb @@ -1,491 +1,490 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe Puppet::Type.type(:cron) do before do @class = Puppet::Type.type(:cron) # Init a fake provider @provider_class = stub 'provider_class', :ancestors => [], :name => 'fake', :suitable? => true, :supports_parameter? => true @class.stubs(:defaultprovider).returns @provider_class @class.stubs(:provider).returns @provider_class @provider = stub 'provider', :class => @provider_class, :clean => nil @provider.stubs(:is_a?).returns false @provider_class.stubs(:new).returns @provider @cron = @class.new( :name => "foo" ) end it "should have :name be its namevar" do @class.key_attributes.should == [:name] end describe "when validating attributes" do [:name, :provider].each do |param| it "should have a #{param} parameter" do @class.attrtype(param).should == :param end end [:command, :special, :minute, :hour, :weekday, :month, :monthday, :environment, :user, :target].each do |property| it "should have a #{property} property" do @class.attrtype(property).should == :property end end [:command, :minute, :hour, :weekday, :month, :monthday].each do |cronparam| it "should have #{cronparam} of type CronParam" do @class.attrclass(cronparam).ancestors.should include CronParam end end end describe "when validating attribute" do describe "ensure" do it "should support present as a value for ensure" do proc { @class.new(:name => 'foo', :ensure => :present) }.should_not raise_error end it "should support absent as a value for ensure" do proc { @class.new(:name => 'foo', :ensure => :present) }.should_not raise_error end end describe "minute" do it "should support absent" do proc { @class.new(:name => 'foo', :minute => 'absent') }.should_not raise_error end it "should support *" do proc { @class.new(:name => 'foo', :minute => '*') }.should_not raise_error end it "should translate absent to :absent" do @class.new(:name => 'foo', :minute => 'absent')[:minute].should == :absent end it "should translate * to :absent" do @class.new(:name => 'foo', :minute => '*')[:minute].should == :absent end it "should support valid single values" do proc { @class.new(:name => 'foo', :minute => '0') }.should_not raise_error proc { @class.new(:name => 'foo', :minute => '1') }.should_not raise_error proc { @class.new(:name => 'foo', :minute => '59') }.should_not raise_error end it "should not support non numeric characters" do proc { @class.new(:name => 'foo', :minute => 'z59') }.should raise_error(Puppet::Error) proc { @class.new(:name => 'foo', :minute => '5z9') }.should raise_error(Puppet::Error) proc { @class.new(:name => 'foo', :minute => '59z') }.should raise_error(Puppet::Error) end it "should not support single values out of range" do proc { @class.new(:name => 'foo', :minute => '-1') }.should raise_error(Puppet::Error) proc { @class.new(:name => 'foo', :minute => '60') }.should raise_error(Puppet::Error) proc { @class.new(:name => 'foo', :minute => '61') }.should raise_error(Puppet::Error) proc { @class.new(:name => 'foo', :minute => '120') }.should raise_error(Puppet::Error) end it "should support valid multiple values" do proc { @class.new(:name => 'foo', :minute => ['0','1','59'] ) }.should_not raise_error proc { @class.new(:name => 'foo', :minute => ['40','30','20'] ) }.should_not raise_error proc { @class.new(:name => 'foo', :minute => ['10','30','20'] ) }.should_not raise_error end it "should not support multiple values if at least one is invalid" do # one invalid proc { @class.new(:name => 'foo', :minute => ['0','1','60'] ) }.should raise_error(Puppet::Error) proc { @class.new(:name => 'foo', :minute => ['0','120','59'] ) }.should raise_error(Puppet::Error) proc { @class.new(:name => 'foo', :minute => ['-1','1','59'] ) }.should raise_error(Puppet::Error) # two invalid proc { @class.new(:name => 'foo', :minute => ['0','61','62'] ) }.should raise_error(Puppet::Error) # all invalid proc { @class.new(:name => 'foo', :minute => ['-1','61','62'] ) }.should raise_error(Puppet::Error) end it "should support valid step syntax" do proc { @class.new(:name => 'foo', :minute => '*/2' ) }.should_not raise_error proc { @class.new(:name => 'foo', :minute => '10-16/2' ) }.should_not raise_error end it "should not support invalid steps" do proc { @class.new(:name => 'foo', :minute => '*/A' ) }.should raise_error(Puppet::Error) proc { @class.new(:name => 'foo', :minute => '*/2A' ) }.should raise_error(Puppet::Error) # As it turns out cron does not complaining about steps that exceed the valid range # proc { @class.new(:name => 'foo', :minute => '*/120' ) }.should raise_error(Puppet::Error) end end describe "hour" do it "should support absent" do proc { @class.new(:name => 'foo', :hour => 'absent') }.should_not raise_error end it "should support *" do proc { @class.new(:name => 'foo', :hour => '*') }.should_not raise_error end it "should translate absent to :absent" do @class.new(:name => 'foo', :hour => 'absent')[:hour].should == :absent end it "should translate * to :absent" do @class.new(:name => 'foo', :hour => '*')[:hour].should == :absent end it "should support valid single values" do proc { @class.new(:name => 'foo', :hour => '0') }.should_not raise_error proc { @class.new(:name => 'foo', :hour => '11') }.should_not raise_error proc { @class.new(:name => 'foo', :hour => '12') }.should_not raise_error proc { @class.new(:name => 'foo', :hour => '13') }.should_not raise_error proc { @class.new(:name => 'foo', :hour => '23') }.should_not raise_error end it "should not support non numeric characters" do proc { @class.new(:name => 'foo', :hour => 'z15') }.should raise_error(Puppet::Error) proc { @class.new(:name => 'foo', :hour => '1z5') }.should raise_error(Puppet::Error) proc { @class.new(:name => 'foo', :hour => '15z') }.should raise_error(Puppet::Error) end it "should not support single values out of range" do proc { @class.new(:name => 'foo', :hour => '-1') }.should raise_error(Puppet::Error) proc { @class.new(:name => 'foo', :hour => '24') }.should raise_error(Puppet::Error) proc { @class.new(:name => 'foo', :hour => '120') }.should raise_error(Puppet::Error) end it "should support valid multiple values" do proc { @class.new(:name => 'foo', :hour => ['0','1','23'] ) }.should_not raise_error proc { @class.new(:name => 'foo', :hour => ['5','16','14'] ) }.should_not raise_error proc { @class.new(:name => 'foo', :hour => ['16','13','9'] ) }.should_not raise_error end it "should not support multiple values if at least one is invalid" do # one invalid proc { @class.new(:name => 'foo', :hour => ['0','1','24'] ) }.should raise_error(Puppet::Error) proc { @class.new(:name => 'foo', :hour => ['0','-1','5'] ) }.should raise_error(Puppet::Error) proc { @class.new(:name => 'foo', :hour => ['-1','1','23'] ) }.should raise_error(Puppet::Error) # two invalid proc { @class.new(:name => 'foo', :hour => ['0','25','26'] ) }.should raise_error(Puppet::Error) # all invalid proc { @class.new(:name => 'foo', :hour => ['-1','24','120'] ) }.should raise_error(Puppet::Error) end it "should support valid step syntax" do proc { @class.new(:name => 'foo', :hour => '*/2' ) }.should_not raise_error proc { @class.new(:name => 'foo', :hour => '10-18/4' ) }.should_not raise_error end it "should not support invalid steps" do proc { @class.new(:name => 'foo', :hour => '*/A' ) }.should raise_error(Puppet::Error) proc { @class.new(:name => 'foo', :hour => '*/2A' ) }.should raise_error(Puppet::Error) # As it turns out cron does not complaining about steps that exceed the valid range # proc { @class.new(:name => 'foo', :hour => '*/26' ) }.should raise_error(Puppet::Error) end end describe "weekday" do it "should support absent" do proc { @class.new(:name => 'foo', :weekday => 'absent') }.should_not raise_error end it "should support *" do proc { @class.new(:name => 'foo', :weekday => '*') }.should_not raise_error end it "should translate absent to :absent" do @class.new(:name => 'foo', :weekday => 'absent')[:weekday].should == :absent end it "should translate * to :absent" do @class.new(:name => 'foo', :weekday => '*')[:weekday].should == :absent end it "should support valid numeric weekdays" do proc { @class.new(:name => 'foo', :weekday => '0') }.should_not raise_error proc { @class.new(:name => 'foo', :weekday => '1') }.should_not raise_error proc { @class.new(:name => 'foo', :weekday => '6') }.should_not raise_error # According to http://www.manpagez.com/man/5/crontab 7 is also valid (Sunday) proc { @class.new(:name => 'foo', :weekday => '7') }.should_not raise_error end it "should support valid weekdays as words (3 character version)" do proc { @class.new(:name => 'foo', :weekday => 'Monday') }.should_not raise_error proc { @class.new(:name => 'foo', :weekday => 'Tuesday') }.should_not raise_error proc { @class.new(:name => 'foo', :weekday => 'Wednesday') }.should_not raise_error proc { @class.new(:name => 'foo', :weekday => 'Thursday') }.should_not raise_error proc { @class.new(:name => 'foo', :weekday => 'Friday') }.should_not raise_error proc { @class.new(:name => 'foo', :weekday => 'Saturday') }.should_not raise_error proc { @class.new(:name => 'foo', :weekday => 'Sunday') }.should_not raise_error end it "should support valid weekdays as words (3 character version)" do proc { @class.new(:name => 'foo', :weekday => 'Mon') }.should_not raise_error proc { @class.new(:name => 'foo', :weekday => 'Tue') }.should_not raise_error proc { @class.new(:name => 'foo', :weekday => 'Wed') }.should_not raise_error proc { @class.new(:name => 'foo', :weekday => 'Thu') }.should_not raise_error proc { @class.new(:name => 'foo', :weekday => 'Fri') }.should_not raise_error proc { @class.new(:name => 'foo', :weekday => 'Sat') }.should_not raise_error proc { @class.new(:name => 'foo', :weekday => 'Sun') }.should_not raise_error end it "should not support numeric values out of range" do proc { @class.new(:name => 'foo', :weekday => '-1') }.should raise_error(Puppet::Error) proc { @class.new(:name => 'foo', :weekday => '8') }.should raise_error(Puppet::Error) end it "should not support invalid weekday names" do proc { @class.new(:name => 'foo', :weekday => 'Sar') }.should raise_error(Puppet::Error) end it "should support valid multiple values" do proc { @class.new(:name => 'foo', :weekday => ['0','1','6'] ) }.should_not raise_error proc { @class.new(:name => 'foo', :weekday => ['Mon','Wed','Friday'] ) }.should_not raise_error end it "should not support multiple values if at least one is invalid" do # one invalid proc { @class.new(:name => 'foo', :weekday => ['0','1','8'] ) }.should raise_error(Puppet::Error) proc { @class.new(:name => 'foo', :weekday => ['Mon','Fii','Sat'] ) }.should raise_error(Puppet::Error) # two invalid proc { @class.new(:name => 'foo', :weekday => ['Mos','Fii','Sat'] ) }.should raise_error(Puppet::Error) # all invalid proc { @class.new(:name => 'foo', :weekday => ['Mos','Fii','Saa'] ) }.should raise_error(Puppet::Error) proc { @class.new(:name => 'foo', :weekday => ['-1','8','11'] ) }.should raise_error(Puppet::Error) end it "should support valid step syntax" do proc { @class.new(:name => 'foo', :weekday => '*/2' ) }.should_not raise_error proc { @class.new(:name => 'foo', :weekday => '0-4/2' ) }.should_not raise_error end it "should not support invalid steps" do proc { @class.new(:name => 'foo', :weekday => '*/A' ) }.should raise_error(Puppet::Error) proc { @class.new(:name => 'foo', :weekday => '*/2A' ) }.should raise_error(Puppet::Error) # As it turns out cron does not complaining about steps that exceed the valid range # proc { @class.new(:name => 'foo', :weekday => '*/9' ) }.should raise_error(Puppet::Error) end end describe "month" do it "should support absent" do proc { @class.new(:name => 'foo', :month => 'absent') }.should_not raise_error end it "should support *" do proc { @class.new(:name => 'foo', :month => '*') }.should_not raise_error end it "should translate absent to :absent" do @class.new(:name => 'foo', :month => 'absent')[:month].should == :absent end it "should translate * to :absent" do @class.new(:name => 'foo', :month => '*')[:month].should == :absent end it "should support valid numeric values" do proc { @class.new(:name => 'foo', :month => '1') }.should_not raise_error proc { @class.new(:name => 'foo', :month => '12') }.should_not raise_error end it "should support valid months as words" do proc { @class.new(:name => 'foo', :month => 'January') }.should_not raise_error proc { @class.new(:name => 'foo', :month => 'February') }.should_not raise_error proc { @class.new(:name => 'foo', :month => 'March') }.should_not raise_error proc { @class.new(:name => 'foo', :month => 'April') }.should_not raise_error proc { @class.new(:name => 'foo', :month => 'May') }.should_not raise_error proc { @class.new(:name => 'foo', :month => 'June') }.should_not raise_error proc { @class.new(:name => 'foo', :month => 'July') }.should_not raise_error proc { @class.new(:name => 'foo', :month => 'August') }.should_not raise_error proc { @class.new(:name => 'foo', :month => 'September') }.should_not raise_error proc { @class.new(:name => 'foo', :month => 'October') }.should_not raise_error proc { @class.new(:name => 'foo', :month => 'November') }.should_not raise_error proc { @class.new(:name => 'foo', :month => 'December') }.should_not raise_error end it "should support valid months as words (3 character short version)" do proc { @class.new(:name => 'foo', :month => 'Jan') }.should_not raise_error proc { @class.new(:name => 'foo', :month => 'Feb') }.should_not raise_error proc { @class.new(:name => 'foo', :month => 'Mar') }.should_not raise_error proc { @class.new(:name => 'foo', :month => 'Apr') }.should_not raise_error proc { @class.new(:name => 'foo', :month => 'May') }.should_not raise_error proc { @class.new(:name => 'foo', :month => 'Jun') }.should_not raise_error proc { @class.new(:name => 'foo', :month => 'Jul') }.should_not raise_error proc { @class.new(:name => 'foo', :month => 'Aug') }.should_not raise_error proc { @class.new(:name => 'foo', :month => 'Sep') }.should_not raise_error proc { @class.new(:name => 'foo', :month => 'Oct') }.should_not raise_error proc { @class.new(:name => 'foo', :month => 'Nov') }.should_not raise_error proc { @class.new(:name => 'foo', :month => 'Dec') }.should_not raise_error end it "should not support numeric values out of range" do proc { @class.new(:name => 'foo', :month => '-1') }.should raise_error(Puppet::Error) proc { @class.new(:name => 'foo', :month => '0') }.should raise_error(Puppet::Error) proc { @class.new(:name => 'foo', :month => '13') }.should raise_error(Puppet::Error) end it "should not support words that are not valid months" do proc { @class.new(:name => 'foo', :month => 'Jal') }.should raise_error(Puppet::Error) end it "should not support single values out of range" do proc { @class.new(:name => 'foo', :month => '-1') }.should raise_error(Puppet::Error) proc { @class.new(:name => 'foo', :month => '60') }.should raise_error(Puppet::Error) proc { @class.new(:name => 'foo', :month => '61') }.should raise_error(Puppet::Error) proc { @class.new(:name => 'foo', :month => '120') }.should raise_error(Puppet::Error) end it "should support valid multiple values" do proc { @class.new(:name => 'foo', :month => ['1','9','12'] ) }.should_not raise_error proc { @class.new(:name => 'foo', :month => ['Jan','March','Jul'] ) }.should_not raise_error end it "should not support multiple values if at least one is invalid" do # one invalid proc { @class.new(:name => 'foo', :month => ['0','1','12'] ) }.should raise_error(Puppet::Error) proc { @class.new(:name => 'foo', :month => ['1','13','10'] ) }.should raise_error(Puppet::Error) proc { @class.new(:name => 'foo', :month => ['Jan','Feb','Jxx'] ) }.should raise_error(Puppet::Error) # two invalid proc { @class.new(:name => 'foo', :month => ['Jan','Fex','Jux'] ) }.should raise_error(Puppet::Error) # all invalid proc { @class.new(:name => 'foo', :month => ['-1','0','13'] ) }.should raise_error(Puppet::Error) proc { @class.new(:name => 'foo', :month => ['Jax','Fex','Aux'] ) }.should raise_error(Puppet::Error) end it "should support valid step syntax" do proc { @class.new(:name => 'foo', :month => '*/2' ) }.should_not raise_error proc { @class.new(:name => 'foo', :month => '1-12/3' ) }.should_not raise_error end it "should not support invalid steps" do proc { @class.new(:name => 'foo', :month => '*/A' ) }.should raise_error(Puppet::Error) proc { @class.new(:name => 'foo', :month => '*/2A' ) }.should raise_error(Puppet::Error) # As it turns out cron does not complaining about steps that exceed the valid range # proc { @class.new(:name => 'foo', :month => '*/13' ) }.should raise_error(Puppet::Error) end end describe "monthday" do it "should support absent" do proc { @class.new(:name => 'foo', :monthday => 'absent') }.should_not raise_error end it "should support *" do proc { @class.new(:name => 'foo', :monthday => '*') }.should_not raise_error end it "should translate absent to :absent" do @class.new(:name => 'foo', :monthday => 'absent')[:monthday].should == :absent end it "should translate * to :absent" do @class.new(:name => 'foo', :monthday => '*')[:monthday].should == :absent end it "should support valid single values" do proc { @class.new(:name => 'foo', :monthday => '1') }.should_not raise_error proc { @class.new(:name => 'foo', :monthday => '30') }.should_not raise_error proc { @class.new(:name => 'foo', :monthday => '31') }.should_not raise_error end it "should not support non numeric characters" do proc { @class.new(:name => 'foo', :monthday => 'z23') }.should raise_error(Puppet::Error) proc { @class.new(:name => 'foo', :monthday => '2z3') }.should raise_error(Puppet::Error) proc { @class.new(:name => 'foo', :monthday => '23z') }.should raise_error(Puppet::Error) end it "should not support single values out of range" do proc { @class.new(:name => 'foo', :monthday => '-1') }.should raise_error(Puppet::Error) proc { @class.new(:name => 'foo', :monthday => '0') }.should raise_error(Puppet::Error) proc { @class.new(:name => 'foo', :monthday => '32') }.should raise_error(Puppet::Error) end it "should support valid multiple values" do proc { @class.new(:name => 'foo', :monthday => ['1','23','31'] ) }.should_not raise_error proc { @class.new(:name => 'foo', :monthday => ['31','23','1'] ) }.should_not raise_error proc { @class.new(:name => 'foo', :monthday => ['1','31','23'] ) }.should_not raise_error end it "should not support multiple values if at least one is invalid" do # one invalid proc { @class.new(:name => 'foo', :monthday => ['1','23','32'] ) }.should raise_error(Puppet::Error) proc { @class.new(:name => 'foo', :monthday => ['-1','12','23'] ) }.should raise_error(Puppet::Error) proc { @class.new(:name => 'foo', :monthday => ['13','32','30'] ) }.should raise_error(Puppet::Error) # two invalid proc { @class.new(:name => 'foo', :monthday => ['-1','0','23'] ) }.should raise_error(Puppet::Error) # all invalid proc { @class.new(:name => 'foo', :monthday => ['-1','0','32'] ) }.should raise_error(Puppet::Error) end it "should support valid step syntax" do proc { @class.new(:name => 'foo', :monthday => '*/2' ) }.should_not raise_error proc { @class.new(:name => 'foo', :monthday => '10-16/2' ) }.should_not raise_error end it "should not support invalid steps" do proc { @class.new(:name => 'foo', :monthday => '*/A' ) }.should raise_error(Puppet::Error) proc { @class.new(:name => 'foo', :monthday => '*/2A' ) }.should raise_error(Puppet::Error) # As it turns out cron does not complaining about steps that exceed the valid range # proc { @class.new(:name => 'foo', :monthday => '*/32' ) }.should raise_error(Puppet::Error) end end describe "environment" do it "it should accept an :environment that looks like a path" do lambda do @cron[:environment] = 'PATH=/bin:/usr/bin:/usr/sbin' end.should_not raise_error end it "should not accept environment variables that do not contain '='" do lambda do @cron[:environment] = "INVALID" end.should raise_error(Puppet::Error) end it "should accept empty environment variables that do not contain '='" do lambda do @cron[:environment] = "MAILTO=" end.should_not raise_error(Puppet::Error) end it "should accept 'absent'" do lambda do @cron[:environment] = 'absent' end.should_not raise_error(Puppet::Error) end end end it "should require a command when adding an entry" do entry = @class.new(:name => "test_entry", :ensure => :present) expect { entry.value(:command) }.should raise_error(/No command/) end it "should not require a command when removing an entry" do entry = @class.new(:name => "test_entry", :ensure => :absent) entry.value(:command).should == nil end end diff --git a/spec/unit/type/exec_spec.rb b/spec/unit/type/exec_spec.rb index 42c79e737..47d1b8523 100755 --- a/spec/unit/type/exec_spec.rb +++ b/spec/unit/type/exec_spec.rb @@ -1,660 +1,659 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe Puppet::Type.type(:exec) do def exec_tester(command, exitstatus = 0, rest = {}) @user_name = 'some_user_name' @group_name = 'some_group_name' Puppet.features.stubs(:root?).returns(true) output = rest.delete(:output) || '' tries = rest[:tries] || 1 args = { :name => command, :path => @example_path, :user => @user_name, :group => @group_name, :logoutput => false, :loglevel => :err, :returns => 0 }.merge(rest) exec = Puppet::Type.type(:exec).new(args) status = stub "process", :exitstatus => exitstatus Puppet::Util::SUIDManager.expects(:run_and_capture).times(tries). with([command], @user_name, @group_name).returns([output, status]) return exec end before do @command = Puppet.features.posix? ? '/bin/true whatever' : '"C:/Program Files/something.exe" whatever' end describe "when not stubbing the provider" do before do @executable = Puppet.features.posix? ? '/bin/true' : 'C:/Program Files/something.exe' File.stubs(:exists?).returns false File.stubs(:exists?).with(@executable).returns true File.stubs(:exists?).with('/bin/false').returns true @example_path = Puppet.features.posix? ? %w{/usr/bin /bin} : [ "C:/Program Files/something/bin", "C:/Ruby/bin" ] File.stubs(:exists?).with(File.join(@example_path[0],"true")).returns true File.stubs(:exists?).with(File.join(@example_path[0],"false")).returns true end it "should return :executed_command as its event" do resource = Puppet::Type.type(:exec).new :command => @command resource.parameter(:returns).event.name.should == :executed_command end describe "when execing" do it "should use the 'run_and_capture' method to exec" do exec_tester("true").refresh.should == :executed_command end it "should report a failure" do proc { exec_tester('false', 1).refresh }. should raise_error(Puppet::Error, /^false returned 1 instead of/) end it "should not report a failure if the exit status is specified in a returns array" do proc { exec_tester("false", 1, :returns => [0, 1]).refresh }.should_not raise_error end it "should report a failure if the exit status is not specified in a returns array" do proc { exec_tester('false', 1, :returns => [0, 100]).refresh }. should raise_error(Puppet::Error, /^false returned 1 instead of/) end it "should log the output on success" do output = "output1\noutput2\n" exec_tester('false', 0, :output => output, :logoutput => true).refresh output.split("\n").each do |line| log = @logs.shift log.level.should == :err log.message.should == line end end it "should log the output on failure" do output = "output1\noutput2\n" proc { exec_tester('false', 1, :output => output, :logoutput => true).refresh }. should raise_error(Puppet::Error) output.split("\n").each do |line| log = @logs.shift log.level.should == :err log.message.should == line end end end describe "when logoutput=>on_failure is set" do it "should log the output on failure" do output = "output1\noutput2\n" proc { exec_tester('false', 1, :output => output, :logoutput => :on_failure).refresh }. should raise_error(Puppet::Error, /^false returned 1 instead of/) output.split("\n").each do |line| log = @logs.shift log.level.should == :err log.message.should == line end end it "should log the output on failure when returns is specified as an array" do output = "output1\noutput2\n" proc { exec_tester('false', 1, :output => output, :returns => [0, 100], :logoutput => :on_failure).refresh }.should raise_error(Puppet::Error, /^false returned 1 instead of/) output.split("\n").each do |line| log = @logs.shift log.level.should == :err log.message.should == line end end it "shouldn't log the output on success" do exec_tester('true', 0, :output => "a\nb\nc\n", :logoutput => :on_failure).refresh @logs.should == [] end end it "shouldn't log the output on success when non-zero exit status is in a returns array" do exec_tester("true", 100, :output => "a\n", :logoutput => :on_failure, :returns => [1, 100]).refresh @logs.should == [] end describe " when multiple tries are set," do it "should repeat the command attempt 'tries' times on failure and produce an error" do tries = 5 resource = exec_tester("false", 1, :tries => tries, :try_sleep => 0) proc { resource.refresh }.should raise_error(Puppet::Error) end end end it "should be able to autorequire files mentioned in the command" do catalog = Puppet::Resource::Catalog.new tmp = Puppet::Type.type(:file).new(:name => "/bin/foo") catalog.add_resource tmp execer = Puppet::Type.type(:exec).new(:name => "/bin/foo") catalog.add_resource execer catalog.relationship_graph.dependencies(execer).should == [tmp] end describe "when handling the path parameter" do expect = %w{one two three four} { "an array" => expect, "a colon separated list" => "one:two:three:four", "a semi-colon separated list" => "one;two;three;four", "both array and colon lists" => ["one", "two:three", "four"], "both array and semi-colon lists" => ["one", "two;three", "four"], "colon and semi-colon lists" => ["one:two", "three;four"] }.each do |test, input| it "should accept #{test}" do type = Puppet::Type.type(:exec).new(:name => @command, :path => input) type[:path].should == expect end end end describe "when setting user" do it "should fail if we are not root" do Puppet.features.stubs(:root?).returns(false) expect { Puppet::Type.type(:exec).new(:name => @command, :user => 'input') }. should raise_error Puppet::Error, /Parameter user failed/ end ['one', 2, 'root', 4294967295, 4294967296].each do |value| it "should accept '#{value}' as user if we are root" do Puppet.features.stubs(:root?).returns(true) type = Puppet::Type.type(:exec).new(:name => @command, :user => value) type[:user].should == value end end end describe "when setting group" do shared_examples_for "exec[:group]" do ['one', 2, 'wheel', 4294967295, 4294967296].each do |value| it "should accept '#{value}' without error or judgement" do type = Puppet::Type.type(:exec).new(:name => @command, :group => value) type[:group].should == value end end end describe "when running as root" do before :each do Puppet.features.stubs(:root?).returns(true) end it_behaves_like "exec[:group]" end describe "when not running as root" do before :each do Puppet.features.stubs(:root?).returns(false) end it_behaves_like "exec[:group]" end end describe "when setting cwd" do it_should_behave_like "all path parameters", :cwd, :array => false do def instance(path) Puppet::Type.type(:exec).new(:name => '/bin/true', :cwd => path) end end end shared_examples_for "all exec command parameters" do |param| { "relative" => "example", "absolute" => "/bin/example" }.sort.each do |name, command| describe "if command is #{name}" do before :each do @param = param end def test(command, valid) if @param == :name then instance = Puppet::Type.type(:exec).new() else instance = Puppet::Type.type(:exec).new(:name => "/bin/true") end if valid then instance.provider.expects(:validatecmd).returns(true) else instance.provider.expects(:validatecmd).raises(Puppet::Error, "from a stub") end instance[@param] = command end it "should work if the provider calls the command valid" do expect { test(command, true) }.should_not raise_error end it "should fail if the provider calls the command invalid" do expect { test(command, false) }. should raise_error Puppet::Error, /Parameter #{@param} failed: from a stub/ end end end end shared_examples_for "all exec command parameters that take arrays" do |param| describe "when given an array of inputs" do before :each do @test = Puppet::Type.type(:exec).new(:name => "/bin/true") end it "should accept the array when all commands return valid" do input = %w{one two three} @test.provider.expects(:validatecmd).times(input.length).returns(true) @test[param] = input @test[param].should == input end it "should reject the array when any commands return invalid" do input = %w{one two three} @test.provider.expects(:validatecmd).with(input.first).returns(false) input[1..-1].each do |cmd| @test.provider.expects(:validatecmd).with(cmd).returns(true) end @test[param] = input @test[param].should == input end it "should reject the array when all commands return invalid" do input = %w{one two three} @test.provider.expects(:validatecmd).times(input.length).returns(false) @test[param] = input @test[param].should == input end end end describe "when setting refresh" do it_should_behave_like "all exec command parameters", :refresh end describe "for simple parameters" do before :each do @exec = Puppet::Type.type(:exec).new(:name => '/bin/true') end describe "when setting environment" do { "single values" => "foo=bar", "multiple values" => ["foo=bar", "baz=quux"], }.each do |name, data| it "should accept #{name}" do @exec[:environment] = data @exec[:environment].should == data end end { "single values" => "foo", "only values" => ["foo", "bar"], "any values" => ["foo=bar", "baz"] }.each do |name, data| it "should reject #{name} without assignment" do expect { @exec[:environment] = data }. should raise_error Puppet::Error, /Invalid environment setting/ end end end describe "when setting timeout" do [0, 0.1, 1, 10, 4294967295].each do |valid| it "should accept '#{valid}' as valid" do @exec[:timeout] = valid @exec[:timeout].should == valid end it "should accept '#{valid}' in an array as valid" do @exec[:timeout] = [valid] @exec[:timeout].should == valid end end ['1/2', '', 'foo', '5foo'].each do |invalid| it "should reject '#{invalid}' as invalid" do expect { @exec[:timeout] = invalid }. should raise_error Puppet::Error, /The timeout must be a number/ end it "should reject '#{invalid}' in an array as invalid" do expect { @exec[:timeout] = [invalid] }. should raise_error Puppet::Error, /The timeout must be a number/ end end it "should fail if timeout is exceeded" do File.stubs(:exists?).with('/bin/sleep').returns(true) File.stubs(:exists?).with('sleep').returns(false) sleep_exec = Puppet::Type.type(:exec).new(:name => 'sleep 1', :path => ['/bin'], :timeout => '0.2') lambda { sleep_exec.refresh }.should raise_error Puppet::Error, "Command exceeded timeout" end it "should convert timeout to a float" do resource = Puppet::Type.type(:exec).new :command => "/bin/false", :timeout => "12" resource[:timeout].should be_a(Float) resource[:timeout].should == 12.0 end it "should munge negative timeouts to 0.0" do resource = Puppet::Type.type(:exec).new :command => "/bin/false", :timeout => "-12.0" resource.parameter(:timeout).value.should be_a(Float) resource.parameter(:timeout).value.should == 0.0 end end describe "when setting tries" do [1, 10, 4294967295].each do |valid| it "should accept '#{valid}' as valid" do @exec[:tries] = valid @exec[:tries].should == valid end if "REVISIT: too much test log spam" == "a good thing" then it "should accept '#{valid}' in an array as valid" do pending "inconsistent, but this is not supporting arrays, unlike timeout" @exec[:tries] = [valid] @exec[:tries].should == valid end end end [-3.5, -1, 0, 0.2, '1/2', '1_000_000', '+12', '', 'foo'].each do |invalid| it "should reject '#{invalid}' as invalid" do expect { @exec[:tries] = invalid }. should raise_error Puppet::Error, /Tries must be an integer/ end if "REVISIT: too much test log spam" == "a good thing" then it "should reject '#{invalid}' in an array as invalid" do pending "inconsistent, but this is not supporting arrays, unlike timeout" expect { @exec[:tries] = [invalid] }. should raise_error Puppet::Error, /Tries must be an integer/ end end end end describe "when setting try_sleep" do [0, 0.2, 1, 10, 4294967295].each do |valid| it "should accept '#{valid}' as valid" do @exec[:try_sleep] = valid @exec[:try_sleep].should == valid end if "REVISIT: too much test log spam" == "a good thing" then it "should accept '#{valid}' in an array as valid" do pending "inconsistent, but this is not supporting arrays, unlike timeout" @exec[:try_sleep] = [valid] @exec[:try_sleep].should == valid end end end { -3.5 => "cannot be a negative number", -1 => "cannot be a negative number", '1/2' => 'must be a number', '1_000_000' => 'must be a number', '+12' => 'must be a number', '' => 'must be a number', 'foo' => 'must be a number', }.each do |invalid, error| it "should reject '#{invalid}' as invalid" do expect { @exec[:try_sleep] = invalid }. should raise_error Puppet::Error, /try_sleep #{error}/ end if "REVISIT: too much test log spam" == "a good thing" then it "should reject '#{invalid}' in an array as invalid" do pending "inconsistent, but this is not supporting arrays, unlike timeout" expect { @exec[:try_sleep] = [invalid] }. should raise_error Puppet::Error, /try_sleep #{error}/ end end end end describe "when setting refreshonly" do [:true, :false].each do |value| it "should accept '#{value}'" do @exec[:refreshonly] = value @exec[:refreshonly].should == value end end [1, 0, "1", "0", "yes", "y", "no", "n"].each do |value| it "should reject '#{value}'" do expect { @exec[:refreshonly] = value }. should raise_error(Puppet::Error, /Invalid value #{value.inspect}\. Valid values are true, false/ ) end end end describe "when setting creates" do it_should_behave_like "all path parameters", :creates, :array => true do def instance(path) Puppet::Type.type(:exec).new(:name => '/bin/true', :creates => path) end end end end describe "when setting unless" do it_should_behave_like "all exec command parameters", :unless it_should_behave_like "all exec command parameters that take arrays", :unless end describe "when setting onlyif" do it_should_behave_like "all exec command parameters", :onlyif it_should_behave_like "all exec command parameters that take arrays", :onlyif end describe "#check" do before :each do @test = Puppet::Type.type(:exec).new(:name => "/bin/true") end describe ":refreshonly" do { :true => false, :false => true }.each do |input, result| it "should return '#{result}' when given '#{input}'" do @test[:refreshonly] = input @test.check_all_attributes.should == result end end end describe ":creates" do before :all do @exist = "/" @unexist = "/this/path/should/never/exist" while FileTest.exist?(@unexist) do @unexist += "/foo" end end context "with a single item" do it "should run when the item does not exist" do @test[:creates] = @unexist @test.check_all_attributes.should == true end it "should not run when the item exists" do @test[:creates] = @exist @test.check_all_attributes.should == false end end context "with an array with one item" do it "should run when the item does not exist" do @test[:creates] = [@unexist] @test.check_all_attributes.should == true end it "should not run when the item exists" do @test[:creates] = [@exist] @test.check_all_attributes.should == false end end context "with an array with multiple items" do it "should run when all items do not exist" do @test[:creates] = [@unexist] * 3 @test.check_all_attributes.should == true end it "should not run when one item exists" do @test[:creates] = [@unexist, @exist, @unexist] @test.check_all_attributes.should == false end it "should not run when all items exist" do @test[:creates] = [@exist] * 3 end end end { :onlyif => { :pass => false, :fail => true }, :unless => { :pass => true, :fail => false }, }.each do |param, sense| describe ":#{param}" do before :each do @pass = "/magic/pass" @fail = "/magic/fail" @pass_status = stub('status', :exitstatus => sense[:pass] ? 0 : 1) @fail_status = stub('status', :exitstatus => sense[:fail] ? 0 : 1) @test.provider.stubs(:checkexe).returns(true) [true, false].each do |check| @test.provider.stubs(:run).with(@pass, check). returns(['test output', @pass_status]) @test.provider.stubs(:run).with(@fail, check). returns(['test output', @fail_status]) end end context "with a single item" do it "should run if the command exits non-zero" do @test[param] = @fail @test.check_all_attributes.should == true end it "should not run if the command exits zero" do @test[param] = @pass @test.check_all_attributes.should == false end end context "with an array with a single item" do it "should run if the command exits non-zero" do @test[param] = [@fail] @test.check_all_attributes.should == true end it "should not run if the command exits zero" do @test[param] = [@pass] @test.check_all_attributes.should == false end end context "with an array with multiple items" do it "should run if all the commands exits non-zero" do @test[param] = [@fail] * 3 @test.check_all_attributes.should == true end it "should not run if one command exits zero" do @test[param] = [@pass, @fail, @pass] @test.check_all_attributes.should == false end it "should not run if all command exits zero" do @test[param] = [@pass] * 3 @test.check_all_attributes.should == false end end end end end describe "#retrieve" do before :each do @exec_resource = Puppet::Type.type(:exec).new(:name => "/bogus/cmd") end it "should return :notrun when check_all_attributes returns true" do @exec_resource.stubs(:check_all_attributes).returns true @exec_resource.retrieve[:returns].should == :notrun end it "should return default exit code 0 when check_all_attributes returns false" do @exec_resource.stubs(:check_all_attributes).returns false @exec_resource.retrieve[:returns].should == ['0'] end it "should return the specified exit code when check_all_attributes returns false" do @exec_resource.stubs(:check_all_attributes).returns false @exec_resource[:returns] = 42 @exec_resource.retrieve[:returns].should == ["42"] end end describe "#output" do before :each do @exec_resource = Puppet::Type.type(:exec).new(:name => "/bogus/cmd") end it "should return the provider's run output" do provider = stub 'provider' status = stubs "process_status" status.stubs(:exitstatus).returns("0") provider.expects(:run).returns(["silly output", status]) @exec_resource.stubs(:provider).returns(provider) @exec_resource.refresh @exec_resource.output.should == 'silly output' end end describe "#refresh" do before :each do @exec_resource = Puppet::Type.type(:exec).new(:name => "/bogus/cmd") end it "should call provider run with the refresh parameter if it is set" do provider = stub 'provider' @exec_resource.stubs(:provider).returns(provider) @exec_resource.stubs(:[]).with(:refresh).returns('/myother/bogus/cmd') provider.expects(:run).with('/myother/bogus/cmd') @exec_resource.refresh end it "should call provider run with the specified command if the refresh parameter is not set" do provider = stub 'provider' status = stubs "process_status" status.stubs(:exitstatus).returns("0") provider.expects(:run).with('/bogus/cmd').returns(["silly output", status]) @exec_resource.stubs(:provider).returns(provider) @exec_resource.refresh end it "should not run the provider if check_all_attributes is false" do @exec_resource.stubs(:check_all_attributes).returns false provider = stub 'provider' provider.expects(:run).never @exec_resource.stubs(:provider).returns(provider) @exec_resource.refresh end end end diff --git a/spec/unit/type/file/checksum_spec.rb b/spec/unit/type/file/checksum_spec.rb index d4b0382ce..b47f617cc 100755 --- a/spec/unit/type/file/checksum_spec.rb +++ b/spec/unit/type/file/checksum_spec.rb @@ -1,73 +1,72 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' checksum = Puppet::Type.type(:file).attrclass(:checksum) describe checksum do before do @resource = Puppet::Type.type(:file).new :path => "/foo/bar" @checksum = @resource.parameter(:checksum) end it "should be a parameter" do checksum.superclass.must == Puppet::Parameter end it "should use its current value when asked to sum content" do @checksum.value = :md5lite @checksum.expects(:md5lite).with("foobar").returns "yay" @checksum.sum("foobar") end it "should use :md5 to sum when no value is set" do @checksum.expects(:md5).with("foobar").returns "yay" @checksum.sum("foobar") end it "should return the summed contents with a checksum label" do sum = Digest::MD5.hexdigest("foobar") @resource[:checksum] = :md5 @checksum.sum("foobar").should == "{md5}#{sum}" end it "should use :md5 as its default type" do @checksum.default.should == :md5 end it "should use its current value when asked to sum a file's content" do @checksum.value = :md5lite @checksum.expects(:md5lite_file).with("/foo/bar").returns "yay" @checksum.sum_file("/foo/bar") end it "should use :md5 to sum a file when no value is set" do @checksum.expects(:md5_file).with("/foo/bar").returns "yay" @checksum.sum_file("/foo/bar") end it "should convert all sums to strings when summing files" do @checksum.value = :mtime @checksum.expects(:mtime_file).with("/foo/bar").returns Time.now lambda { @checksum.sum_file("/foo/bar") }.should_not raise_error end it "should return the summed contents of a file with a checksum label" do @resource[:checksum] = :md5 @checksum.expects(:md5_file).returns "mysum" @checksum.sum_file("/foo/bar").should == "{md5}mysum" end it "should return the summed contents of a stream with a checksum label" do @resource[:checksum] = :md5 @checksum.expects(:md5_stream).returns "mysum" @checksum.sum_stream.should == "{md5}mysum" end it "should yield the sum_stream block to the underlying checksum" do @resource[:checksum] = :md5 @checksum.expects(:md5_stream).yields("something").returns("mysum") @checksum.sum_stream do |sum| sum.should == "something" end end end diff --git a/spec/unit/type/file/content_spec.rb b/spec/unit/type/file/content_spec.rb index a63437768..7af5f9d83 100755 --- a/spec/unit/type/file/content_spec.rb +++ b/spec/unit/type/file/content_spec.rb @@ -1,436 +1,435 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' content = Puppet::Type.type(:file).attrclass(:content) describe content do include PuppetSpec::Files before do @filename = tmpfile('testfile') @resource = Puppet::Type.type(:file).new :path => @filename File.open(@filename, 'w') {|f| f.write "initial file content"} content.stubs(:standalone?).returns(false) end describe "when determining the checksum type" do it "should use the type specified in the source checksum if a source is set" do @resource[:source] = "/foo" @resource.parameter(:source).expects(:checksum).returns "{md5lite}eh" @content = content.new(:resource => @resource) @content.checksum_type.should == :md5lite end it "should use the type specified by the checksum parameter if no source is set" do @resource[:checksum] = :md5lite @content = content.new(:resource => @resource) @content.checksum_type.should == :md5lite end end describe "when determining the actual content to write" do it "should use the set content if available" do @content = content.new(:resource => @resource) @content.should = "ehness" @content.actual_content.should == "ehness" end it "should not use the content from the source if the source is set" do source = mock 'source' @resource.expects(:parameter).never.with(:source).returns source @content = content.new(:resource => @resource) @content.actual_content.should be_nil end end describe "when setting the desired content" do it "should make the actual content available via an attribute" do @content = content.new(:resource => @resource) @content.stubs(:checksum_type).returns "md5" @content.should = "this is some content" @content.actual_content.should == "this is some content" end it "should store the checksum as the desired content" do @content = content.new(:resource => @resource) digest = Digest::MD5.hexdigest("this is some content") @content.stubs(:checksum_type).returns "md5" @content.should = "this is some content" @content.should.must == "{md5}#{digest}" end it "should not checksum 'absent'" do @content = content.new(:resource => @resource) @content.should = :absent @content.should.must == :absent end it "should accept a checksum as the desired content" do @content = content.new(:resource => @resource) digest = Digest::MD5.hexdigest("this is some content") string = "{md5}#{digest}" @content.should = string @content.should.must == string end end describe "when retrieving the current content" do it "should return :absent if the file does not exist" do @content = content.new(:resource => @resource) @resource.expects(:stat).returns nil @content.retrieve.should == :absent end it "should not manage content on directories" do @content = content.new(:resource => @resource) stat = mock 'stat', :ftype => "directory" @resource.expects(:stat).returns stat @content.retrieve.should be_nil end it "should not manage content on links" do @content = content.new(:resource => @resource) stat = mock 'stat', :ftype => "link" @resource.expects(:stat).returns stat @content.retrieve.should be_nil end it "should always return the checksum as a string" do @content = content.new(:resource => @resource) @resource[:checksum] = :mtime stat = mock 'stat', :ftype => "file" @resource.expects(:stat).returns stat time = Time.now @resource.parameter(:checksum).expects(:mtime_file).with(@resource[:path]).returns time @content.retrieve.should == "{mtime}#{time}" end it "should return the checksum of the file if it exists and is a normal file" do @content = content.new(:resource => @resource) stat = mock 'stat', :ftype => "file" @resource.expects(:stat).returns stat @resource.parameter(:checksum).expects(:md5_file).with(@resource[:path]).returns "mysum" @content.retrieve.should == "{md5}mysum" end end describe "when testing whether the content is in sync" do before do @resource[:ensure] = :file @content = content.new(:resource => @resource) end it "should return true if the resource shouldn't be a regular file" do @resource.expects(:should_be_file?).returns false @content.should = "foo" @content.must be_safe_insync("whatever") end it "should return false if the current content is :absent" do @content.should = "foo" @content.should_not be_safe_insync(:absent) end it "should return false if the file should be a file but is not present" do @resource.expects(:should_be_file?).returns true @content.should = "foo" @content.should_not be_safe_insync(:absent) end describe "and the file exists" do before do @resource.stubs(:stat).returns mock("stat") end it "should return false if the current contents are different from the desired content" do @content.should = "some content" @content.should_not be_safe_insync("other content") end it "should return true if the sum for the current contents is the same as the sum for the desired content" do @content.should = "some content" @content.must be_safe_insync("{md5}" + Digest::MD5.hexdigest("some content")) end describe "and Puppet[:show_diff] is set" do before do Puppet[:show_diff] = true end it "should display a diff if the current contents are different from the desired content" do @content.should = "some content" @content.expects(:diff).returns("my diff").once @content.expects(:print).with("my diff").once @content.safe_insync?("other content") end it "should not display a diff if the sum for the current contents is the same as the sum for the desired content" do @content.should = "some content" @content.expects(:diff).never @content.safe_insync?("{md5}" + Digest::MD5.hexdigest("some content")) end end end describe "and :replace is false" do before do @resource.stubs(:replace?).returns false end it "should be insync if the file exists and the content is different" do @resource.stubs(:stat).returns mock('stat') @content.must be_safe_insync("whatever") end it "should be insync if the file exists and the content is right" do @resource.stubs(:stat).returns mock('stat') @content.must be_safe_insync("something") end it "should not be insync if the file does not exist" do @content.should = "foo" @content.should_not be_safe_insync(:absent) end end end describe "when changing the content" do before do @content = content.new(:resource => @resource) @content.should = "some content" @resource.stubs(:[]).with(:path).returns "/boo" @resource.stubs(:stat).returns "eh" end it "should use the file's :write method to write the content" do @resource.expects(:write).with(:content) @content.sync end it "should return :file_changed if the file already existed" do @resource.expects(:stat).returns "something" @resource.stubs(:write) @content.sync.should == :file_changed end it "should return :file_created if the file did not exist" do @resource.expects(:stat).returns nil @resource.stubs(:write) @content.sync.should == :file_created end end describe "when writing" do before do @content = content.new(:resource => @resource) end it "should attempt to read from the filebucket if no actual content nor source exists" do @fh = File.open(@filename, 'w') @content.should = "{md5}foo" @content.resource.bucket.class.any_instance.stubs(:getfile).returns "foo" @content.write(@fh) end describe "from actual content" do before(:each) do @content.stubs(:actual_content).returns("this is content") end it "should write to the given file handle" do @fh.expects(:print).with("this is content") @content.write(@fh) end it "should return the current checksum value" do @resource.parameter(:checksum).expects(:sum_stream).returns "checksum" @content.write(@fh).should == "checksum" end end describe "from a file bucket" do it "should fail if a file bucket cannot be retrieved" do @content.should = "{md5}foo" @content.resource.expects(:bucket).returns nil lambda { @content.write(@fh) }.should raise_error(Puppet::Error) end it "should fail if the file bucket cannot find any content" do @content.should = "{md5}foo" bucket = stub 'bucket' @content.resource.expects(:bucket).returns bucket bucket.expects(:getfile).with("foo").raises "foobar" lambda { @content.write(@fh) }.should raise_error(Puppet::Error) end it "should write the returned content to the file" do @content.should = "{md5}foo" bucket = stub 'bucket' @content.resource.expects(:bucket).returns bucket bucket.expects(:getfile).with("foo").returns "mycontent" @fh.expects(:print).with("mycontent") @content.write(@fh) end end describe "from local source" do before(:each) do @resource = Puppet::Type.type(:file).new :path => @filename, :backup => false @sourcename = tmpfile('source') @source_content = "source file content"*10000 @sourcefile = File.open(@sourcename, 'w') {|f| f.write @source_content} @content = @resource.newattr(:content) @source = @resource.newattr(:source) @source.stubs(:metadata).returns stub_everything('metadata', :source => @sourcename, :ftype => 'file') end it "should copy content from the source to the file" do @resource.write(@source) File.read(@filename).should == @source_content end it "should return the checksum computed" do File.open(@filename, 'w') do |file| @content.write(file).should == "{md5}#{Digest::MD5.hexdigest(@source_content)}" end end end describe "from remote source" do before(:each) do @resource = Puppet::Type.type(:file).new :path => @filename, :backup => false @response = stub_everything 'response', :code => "200" @source_content = "source file content"*10000 @response.stubs(:read_body).multiple_yields(*(["source file content"]*10000)) @conn = stub_everything 'connection' @conn.stubs(:request_get).yields(@response) Puppet::Network::HttpPool.stubs(:http_instance).returns @conn @content = @resource.newattr(:content) @sourcename = "puppet:///test/foo" @source = @resource.newattr(:source) @source.stubs(:metadata).returns stub_everything('metadata', :source => @sourcename, :ftype => 'file') end it "should write the contents to the file" do @resource.write(@source) File.read(@filename).should == @source_content end it "should not write anything if source is not found" do @response.stubs(:code).returns("404") lambda {@resource.write(@source)}.should raise_error(Net::HTTPError) { |e| e.message =~ /404/ } File.read(@filename).should == "initial file content" end it "should raise an HTTP error in case of server error" do @response.stubs(:code).returns("500") lambda { @content.write(@fh) }.should raise_error { |e| e.message.include? @source_content } end it "should return the checksum computed" do File.open(@filename, 'w') do |file| @content.write(file).should == "{md5}#{Digest::MD5.hexdigest(@source_content)}" end end end # These are testing the implementation rather than the desired behaviour; while that bites, there are a whole # pile of other methods in the File type that depend on intimate details of this implementation and vice-versa. # If these blow up, you are gonna have to review the callers to make sure they don't explode! --daniel 2011-02-01 describe "each_chunk_from should work" do before do @content = content.new(:resource => @resource) end it "when content is a string" do @content.each_chunk_from('i_am_a_string') { |chunk| chunk.should == 'i_am_a_string' } end # The following manifest is a case where source and content.should are both set # file { "/tmp/mydir" : # source => '/tmp/sourcedir', # recurse => true, # } it "when content checksum comes from source" do source_param = Puppet::Type.type(:file).attrclass(:source) source = source_param.new(:resource => @resource) @content.should = "{md5}123abcd" @content.expects(:chunk_file_from_source).returns('from_source') @content.each_chunk_from(source) { |chunk| chunk.should == 'from_source' } end it "when no content, source, but ensure present" do @resource[:ensure] = :present @content.each_chunk_from(nil) { |chunk| chunk.should == '' } end # you might do this if you were just auditing it "when no content, source, but ensure file" do @resource[:ensure] = :file @content.each_chunk_from(nil) { |chunk| chunk.should == '' } end it "when source_or_content is nil and content not a checksum" do @content.each_chunk_from(nil) { |chunk| chunk.should == '' } end # the content is munged so that if it's a checksum nil gets passed in it "when content is a checksum it should try to read from filebucket" do @content.should = "{md5}123abcd" @content.expects(:read_file_from_filebucket).once.returns('im_a_filebucket') @content.each_chunk_from(nil) { |chunk| chunk.should == 'im_a_filebucket' } end it "when running as puppet apply" do @content.class.expects(:standalone?).returns true source_or_content = stubs('source_or_content') source_or_content.expects(:content).once.returns :whoo @content.each_chunk_from(source_or_content) { |chunk| chunk.should == :whoo } end it "when running from source with a local file" do source_or_content = stubs('source_or_content') source_or_content.expects(:local?).returns true @content.expects(:chunk_file_from_disk).with(source_or_content).once.yields 'woot' @content.each_chunk_from(source_or_content) { |chunk| chunk.should == 'woot' } end it "when running from source with a remote file" do source_or_content = stubs('source_or_content') source_or_content.expects(:local?).returns false @content.expects(:chunk_file_from_source).with(source_or_content).once.yields 'woot' @content.each_chunk_from(source_or_content) { |chunk| chunk.should == 'woot' } end end end end diff --git a/spec/unit/type/file/ctime.rb b/spec/unit/type/file/ctime.rb index 72a10b568..1700d4928 100755 --- a/spec/unit/type/file/ctime.rb +++ b/spec/unit/type/file/ctime.rb @@ -1,35 +1,34 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe Puppet::Type.type(:file).attrclass(:ctime) do require 'puppet_spec/files' include PuppetSpec::Files before do @filename = tmpfile('ctime') @resource = Puppet::Type.type(:file).new({:name => @filename}) end it "should be able to audit the file's ctime" do File.open(@filename, "w"){ } @resource[:audit] = [:ctime] # this .to_resource audit behavior is magical :-( @resource.to_resource[:ctime].should == File.stat(@filename).ctime end it "should return absent if auditing an absent file" do @resource[:audit] = [:ctime] @resource.to_resource[:ctime].should == :absent end it "should prevent the user from trying to set the ctime" do lambda { @resource[:ctime] = Time.now.to_s }.should raise_error(Puppet::Error, /ctime is read-only/) end end diff --git a/spec/unit/type/file/ensure_spec.rb b/spec/unit/type/file/ensure_spec.rb index 5f51bdcc0..8555ef035 100755 --- a/spec/unit/type/file/ensure_spec.rb +++ b/spec/unit/type/file/ensure_spec.rb @@ -1,85 +1,84 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' property = Puppet::Type.type(:file).attrclass(:ensure) describe property do before do # Wow that's a messy interface to the resource. @resource = stub 'resource', :[] => nil, :[]= => nil, :property => nil, :newattr => nil, :parameter => nil, :replace? => true @resource.stubs(:[]).returns "foo" @resource.stubs(:[]).with(:path).returns "/my/file" @ensure = property.new :resource => @resource end it "should be a subclass of Ensure" do property.superclass.must == Puppet::Property::Ensure end describe "when retrieving the current state" do it "should return :absent if the file does not exist" do @ensure = property.new(:resource => @resource) @resource.expects(:stat).returns nil @ensure.retrieve.should == :absent end it "should return the current file type if the file exists" do @ensure = property.new(:resource => @resource) stat = mock 'stat', :ftype => "directory" @resource.expects(:stat).returns stat @ensure.retrieve.should == :directory end end describe "when testing whether :ensure is in sync" do before do @ensure = property.new(:resource => @resource) @stat = stub 'stat', :ftype => "file" end it "should always be in sync if replace is 'false' unless the file is missing" do @ensure.should = :file @resource.expects(:replace?).returns false @ensure.safe_insync?(:link).should be_true end it "should be in sync if :ensure is set to :absent and the file does not exist" do @ensure.should = :absent @ensure.must be_safe_insync(:absent) end it "should not be in sync if :ensure is set to :absent and the file exists" do @ensure.should = :absent @ensure.should_not be_safe_insync(:file) end it "should be in sync if a normal file exists and :ensure is set to :present" do @ensure.should = :present @ensure.must be_safe_insync(:file) end it "should be in sync if a directory exists and :ensure is set to :present" do @ensure.should = :present @ensure.must be_safe_insync(:directory) end it "should be in sync if a symlink exists and :ensure is set to :present" do @ensure.should = :present @ensure.must be_safe_insync(:link) end it "should not be in sync if :ensure is set to :file and a directory exists" do @ensure.should = :file @ensure.should_not be_safe_insync(:directory) end end end diff --git a/spec/unit/type/file/group_spec.rb b/spec/unit/type/file/group_spec.rb index 7aeb4f7eb..707a37cd6 100755 --- a/spec/unit/type/file/group_spec.rb +++ b/spec/unit/type/file/group_spec.rb @@ -1,123 +1,122 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' property = Puppet::Type.type(:file).attrclass(:group) describe property do before do @resource = stub 'resource', :line => "foo", :file => "bar" @resource.stubs(:[]).returns "foo" @resource.stubs(:[]).with(:path).returns "/my/file" @group = property.new :resource => @resource end it "should have a method for testing whether a group is valid" do @group.must respond_to(:validgroup?) end it "should return the found gid if a group is valid" do @group.expects(:gid).with("foo").returns 500 @group.validgroup?("foo").should == 500 end it "should return false if a group is not valid" do @group.expects(:gid).with("foo").returns nil @group.validgroup?("foo").should be_false end describe "when retrieving the current value" do it "should return :absent if the file cannot stat" do @resource.expects(:stat).returns nil @group.retrieve.should == :absent end it "should get the gid from the stat instance from the file" do stat = stub 'stat', :ftype => "foo" @resource.expects(:stat).returns stat stat.expects(:gid).returns 500 @group.retrieve.should == 500 end it "should warn and return :silly if the found value is higher than the maximum uid value" do Puppet.settings.expects(:value).with(:maximum_uid).returns 500 stat = stub 'stat', :ftype => "foo" @resource.expects(:stat).returns stat stat.expects(:gid).returns 1000 @group.expects(:warning) @group.retrieve.should == :silly end end describe "when determining if the file is in sync" do it "should directly compare the group values if the desired group is an integer" do @group.should = [10] @group.must be_safe_insync(10) end it "should treat numeric strings as integers" do @group.should = ["10"] @group.must be_safe_insync(10) end it "should convert the group name to an integer if the desired group is a string" do @group.expects(:gid).with("foo").returns 10 @group.should = %w{foo} @group.must be_safe_insync(10) end it "should not validate that groups exist when a group is specified as an integer" do @group.expects(:gid).never @group.validgroup?(10) end it "should fail if it cannot convert a group name to an integer" do @group.expects(:gid).with("foo").returns nil @group.should = %w{foo} lambda { @group.safe_insync?(10) }.should raise_error(Puppet::Error) end it "should return false if the groups are not equal" do @group.should = [10] @group.should_not be_safe_insync(20) end end describe "when changing the group" do before do @group.should = %w{one} @group.stubs(:gid).returns 500 end it "should chown the file if :links is set to :follow" do @resource.expects(:[]).with(:links).returns :follow File.expects(:chown) @group.sync end it "should lchown the file if :links is set to :manage" do @resource.expects(:[]).with(:links).returns :manage File.expects(:lchown) @group.sync end it "should use the first valid group in its 'should' list" do @group.should = %w{one two three} @group.expects(:validgroup?).with("one").returns nil @group.expects(:validgroup?).with("two").returns 500 @group.expects(:validgroup?).with("three").never File.expects(:chown).with(nil, 500, "/my/file") @group.sync end end end diff --git a/spec/unit/type/file/mtime.rb b/spec/unit/type/file/mtime.rb index f00692f5e..3222df095 100755 --- a/spec/unit/type/file/mtime.rb +++ b/spec/unit/type/file/mtime.rb @@ -1,35 +1,34 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe Puppet::Type.type(:file).attrclass(:mtime) do require 'puppet_spec/files' include PuppetSpec::Files before do @filename = tmpfile('mtime') @resource = Puppet::Type.type(:file).new({:name => @filename}) end it "should be able to audit the file's mtime" do File.open(@filename, "w"){ } @resource[:audit] = [:mtime] # this .to_resource audit behavior is magical :-( @resource.to_resource[:mtime].should == File.stat(@filename).mtime end it "should return absent if auditing an absent file" do @resource[:audit] = [:mtime] @resource.to_resource[:mtime].should == :absent end it "should prevent the user from trying to set the mtime" do lambda { @resource[:mtime] = Time.now.to_s }.should raise_error(Puppet::Error, /mtime is read-only/) end end diff --git a/spec/unit/type/file/owner_spec.rb b/spec/unit/type/file/owner_spec.rb index bf99a99e7..ed3bef1fe 100755 --- a/spec/unit/type/file/owner_spec.rb +++ b/spec/unit/type/file/owner_spec.rb @@ -1,150 +1,149 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' property = Puppet::Type.type(:file).attrclass(:owner) describe property do before do # FIXME: many of these tests exercise the provider rather than `owner` # and should be moved into provider tests. ~JW @provider = Puppet::Type.type(:file).provider(:posix).new @provider.stubs(:uid).with("one").returns(1) @resource = stub 'resource', :line => "foo", :file => "bar" @resource.stubs(:[]).returns "foo" @resource.stubs(:[]).with(:path).returns "/my/file" @resource.stubs(:provider).returns @provider @owner = property.new :resource => @resource end it "should have a method for testing whether an owner is valid" do @provider.must respond_to(:validuser?) end it "should return the found uid if an owner is valid" do @provider.expects(:uid).with("foo").returns 500 @provider.validuser?("foo").should == 500 end it "should return false if an owner is not valid" do @provider.expects(:uid).with("foo").returns nil @provider.validuser?("foo").should be_false end describe "when retrieving the current value" do it "should return :absent if the file cannot stat" do @resource.expects(:stat).returns nil @owner.retrieve.should == :absent end it "should get the uid from the stat instance from the file" do stat = stub 'stat', :ftype => "foo" @resource.expects(:stat).returns stat stat.expects(:uid).returns 500 @owner.retrieve.should == 500 end it "should warn and return :silly if the found value is higher than the maximum uid value" do Puppet.settings.expects(:value).with(:maximum_uid).returns 500 stat = stub 'stat', :ftype => "foo" @resource.expects(:stat).returns stat stat.expects(:uid).returns 1000 @provider.expects(:warning) @owner.retrieve.should == :silly end end describe "when determining if the file is in sync" do describe "and not running as root" do it "should warn once and return true" do Puppet.features.expects(:root?).returns false @provider.expects(:warnonce) @owner.should = [10] @owner.must be_safe_insync(20) end end before do Puppet.features.stubs(:root?).returns true end it "should be in sync if 'should' is not provided" do @owner.must be_safe_insync(10) end it "should directly compare the owner values if the desired owner is an integer" do @owner.should = [10] @owner.must be_safe_insync(10) end it "should treat numeric strings as integers" do @owner.should = ["10"] @owner.must be_safe_insync(10) end it "should convert the owner name to an integer if the desired owner is a string" do @provider.expects(:uid).with("foo").returns 10 @owner.should = %w{foo} @owner.must be_safe_insync(10) end it "should not validate that users exist when a user is specified as an integer" do @provider.expects(:uid).never @provider.validuser?(10) end it "should fail if it cannot convert an owner name to an integer" do @provider.expects(:uid).with("foo").returns nil @owner.should = %w{foo} lambda { @owner.safe_insync?(10) }.should raise_error(Puppet::Error) end it "should return false if the owners are not equal" do @owner.should = [10] @owner.should_not be_safe_insync(20) end end describe "when changing the owner" do before do @owner.should = %w{one} @owner.stubs(:path).returns "path" @owner.stubs(:uid).returns 500 end it "should chown the file if :links is set to :follow" do @resource.expects(:[]).with(:links).returns :follow File.expects(:chown) @owner.sync end it "should lchown the file if :links is set to :manage" do @resource.expects(:[]).with(:links).returns :manage File.expects(:lchown) @owner.sync end it "should use the first valid owner in its 'should' list" do @owner.should = %w{one two three} @provider.expects(:validuser?).with("one").returns nil @provider.expects(:validuser?).with("two").returns 500 @provider.expects(:validuser?).with("three").never File.expects(:chown).with(500, nil, "/my/file") @owner.sync end end end diff --git a/spec/unit/type/file/selinux_spec.rb b/spec/unit/type/file/selinux_spec.rb index 27a0e5863..2622948d0 100755 --- a/spec/unit/type/file/selinux_spec.rb +++ b/spec/unit/type/file/selinux_spec.rb @@ -1,88 +1,87 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' [:seluser, :selrole, :seltype, :selrange].each do |param| property = Puppet::Type.type(:file).attrclass(param) describe property do before do @resource = Puppet::Type.type(:file).new :path => "/my/file" @sel = property.new :resource => @resource end it "retrieve on #{param} should return :absent if the file isn't statable" do @resource.expects(:stat).returns nil @sel.retrieve.should == :absent end it "should retrieve nil for #{param} if there is no SELinux support" do stat = stub 'stat', :ftype => "foo" @resource.expects(:stat).returns stat @sel.expects(:get_selinux_current_context).with("/my/file").returns nil @sel.retrieve.should be_nil end it "should retrieve #{param} if a SELinux context is found with a range" do stat = stub 'stat', :ftype => "foo" @resource.expects(:stat).returns stat @sel.expects(:get_selinux_current_context).with("/my/file").returns "user_u:role_r:type_t:s0" expectedresult = case param when :seluser; "user_u" when :selrole; "role_r" when :seltype; "type_t" when :selrange; "s0" end @sel.retrieve.should == expectedresult end it "should retrieve #{param} if a SELinux context is found without a range" do stat = stub 'stat', :ftype => "foo" @resource.expects(:stat).returns stat @sel.expects(:get_selinux_current_context).with("/my/file").returns "user_u:role_r:type_t" expectedresult = case param when :seluser; "user_u" when :selrole; "role_r" when :seltype; "type_t" when :selrange; nil end @sel.retrieve.should == expectedresult end it "should handle no default gracefully" do @sel.expects(:get_selinux_default_context).with("/my/file").returns nil @sel.default.must be_nil end it "should be able to detect matchpathcon defaults" do @sel.stubs(:debug) @sel.expects(:get_selinux_default_context).with("/my/file").returns "user_u:role_r:type_t:s0" expectedresult = case param when :seluser; "user_u" when :selrole; "role_r" when :seltype; "type_t" when :selrange; "s0" end @sel.default.must == expectedresult end it "should return nil for defaults if selinux_ignore_defaults is true" do @resource[:selinux_ignore_defaults] = :true @sel.default.must be_nil end it "should be able to set a new context" do stat = stub 'stat', :ftype => "foo" @sel.should = %w{newone} @sel.expects(:set_selinux_context).with("/my/file", ["newone"], param) @sel.sync end it "should do nothing for safe_insync? if no SELinux support" do @sel.should = %{newcontext} @sel.expects(:selinux_support?).returns false @sel.safe_insync?("oldcontext").should == true end end end diff --git a/spec/unit/type/file/source_spec.rb b/spec/unit/type/file/source_spec.rb index 95a3618a2..e8683b712 100755 --- a/spec/unit/type/file/source_spec.rb +++ b/spec/unit/type/file/source_spec.rb @@ -1,272 +1,271 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' source = Puppet::Type.type(:file).attrclass(:source) describe Puppet::Type.type(:file).attrclass(:source) do before do # Wow that's a messy interface to the resource. @resource = stub 'resource', :[]= => nil, :property => nil, :catalog => stub("catalog", :dependent_data_expired? => false), :line => 0, :file => '' end it "should be a subclass of Parameter" do source.superclass.must == Puppet::Parameter end describe "when initializing" do it "should fail if the set values are not URLs" do s = source.new(:resource => @resource) URI.expects(:parse).with('foo').raises RuntimeError lambda { s.value = %w{foo} }.must raise_error(Puppet::Error) end it "should fail if the URI is not a local file, file URI, or puppet URI" do s = source.new(:resource => @resource) lambda { s.value = %w{http://foo/bar} }.must raise_error(Puppet::Error) end end it "should have a method for retrieving its metadata" do source.new(:resource => @resource).must respond_to(:metadata) end it "should have a method for setting its metadata" do source.new(:resource => @resource).must respond_to(:metadata=) end describe "when returning the metadata" do before do @metadata = stub 'metadata', :source= => nil end it "should return already-available metadata" do @source = source.new(:resource => @resource) @source.metadata = "foo" @source.metadata.should == "foo" end it "should return nil if no @should value is set and no metadata is available" do @source = source.new(:resource => @resource) @source.metadata.should be_nil end it "should collect its metadata using the Metadata class if it is not already set" do @source = source.new(:resource => @resource, :value => "/foo/bar") Puppet::FileServing::Metadata.indirection.expects(:find).with("/foo/bar").returns @metadata @source.metadata end it "should use the metadata from the first found source" do metadata = stub 'metadata', :source= => nil @source = source.new(:resource => @resource, :value => ["/foo/bar", "/fee/booz"]) Puppet::FileServing::Metadata.indirection.expects(:find).with("/foo/bar").returns nil Puppet::FileServing::Metadata.indirection.expects(:find).with("/fee/booz").returns metadata @source.metadata.should equal(metadata) end it "should store the found source as the metadata's source" do metadata = mock 'metadata' @source = source.new(:resource => @resource, :value => "/foo/bar") Puppet::FileServing::Metadata.indirection.expects(:find).with("/foo/bar").returns metadata metadata.expects(:source=).with("/foo/bar") @source.metadata end it "should fail intelligently if an exception is encountered while querying for metadata" do @source = source.new(:resource => @resource, :value => "/foo/bar") Puppet::FileServing::Metadata.indirection.expects(:find).with("/foo/bar").raises RuntimeError @source.expects(:fail).raises ArgumentError lambda { @source.metadata }.should raise_error(ArgumentError) end it "should fail if no specified sources can be found" do @source = source.new(:resource => @resource, :value => "/foo/bar") Puppet::FileServing::Metadata.indirection.expects(:find).with("/foo/bar").returns nil @source.expects(:fail).raises RuntimeError lambda { @source.metadata }.should raise_error(RuntimeError) end it "should expire the metadata appropriately" do expirer = stub 'expired', :dependent_data_expired? => true metadata = stub 'metadata', :source= => nil Puppet::FileServing::Metadata.indirection.expects(:find).with("/fee/booz").returns metadata @source = source.new(:resource => @resource, :value => ["/fee/booz"]) @source.metadata = "foo" @source.stubs(:expirer).returns expirer @source.metadata.should_not == "foo" end end it "should have a method for setting the desired values on the resource" do source.new(:resource => @resource).must respond_to(:copy_source_values) end describe "when copying the source values" do before do @resource = Puppet::Type.type(:file).new :path => "/foo/bar" @source = source.new(:resource => @resource) @metadata = stub 'metadata', :owner => 100, :group => 200, :mode => 123, :checksum => "{md5}asdfasdf", :ftype => "file" @source.stubs(:metadata).returns @metadata end it "should fail if there is no metadata" do @source.stubs(:metadata).returns nil @source.expects(:devfail).raises ArgumentError lambda { @source.copy_source_values }.should raise_error(ArgumentError) end it "should set :ensure to the file type" do @metadata.stubs(:ftype).returns "file" @source.copy_source_values @resource[:ensure].must == :file end it "should not set 'ensure' if it is already set to 'absent'" do @metadata.stubs(:ftype).returns "file" @resource[:ensure] = :absent @source.copy_source_values @resource[:ensure].must == :absent end describe "and the source is a file" do before do @metadata.stubs(:ftype).returns "file" end it "should copy the metadata's owner, group, checksum, and mode to the resource if they are not set on the resource" do Puppet.features.expects(:root?).returns true @source.copy_source_values @resource[:owner].must == 100 @resource[:group].must == 200 @resource[:mode].must == "173" # Metadata calls it checksum, we call it content. @resource[:content].must == @metadata.checksum end it "should not copy the metadata's owner to the resource if it is already set" do @resource[:owner] = 1 @resource[:group] = 2 @resource[:mode] = 3 @resource[:content] = "foobar" @source.copy_source_values @resource[:owner].must == 1 @resource[:group].must == 2 @resource[:mode].must == "3" @resource[:content].should_not == @metadata.checksum end describe "and puppet is not running as root" do it "should not try to set the owner" do Puppet.features.expects(:root?).returns false @source.copy_source_values @resource[:owner].should be_nil end end end describe "and the source is a link" do it "should set the target to the link destination" do @metadata.stubs(:ftype).returns "link" @resource.stubs(:[]) @resource.stubs(:[]=) @metadata.expects(:destination).returns "/path/to/symlink" @resource.expects(:[]=).with(:target, "/path/to/symlink") @source.copy_source_values end end end it "should have a local? method" do source.new(:resource => @resource).must be_respond_to(:local?) end context "when accessing source properties" do before(:each) do @source = source.new(:resource => @resource) @metadata = stub_everything @source.stubs(:metadata).returns(@metadata) end describe "for local sources" do before(:each) do @metadata.stubs(:ftype).returns "file" @metadata.stubs(:source).returns("file:///path/to/source") end it "should be local" do @source.must be_local end it "should be local if there is no scheme" do @metadata.stubs(:source).returns("/path/to/source") @source.must be_local end it "should be able to return the metadata source full path" do @source.full_path.should == "/path/to/source" end end describe "for remote sources" do before(:each) do @metadata.stubs(:ftype).returns "file" @metadata.stubs(:source).returns("puppet://server:8192/path/to/source") end it "should not be local" do @source.should_not be_local end it "should be able to return the metadata source full path" do @source.full_path.should == "/path/to/source" end it "should be able to return the source server" do @source.server.should == "server" end it "should be able to return the source port" do @source.port.should == 8192 end describe "which don't specify server or port" do before(:each) do @metadata.stubs(:source).returns("puppet:///path/to/source") end it "should return the default source server" do Puppet.settings.expects(:[]).with(:server).returns("myserver") @source.server.should == "myserver" end it "should return the default source port" do Puppet.settings.expects(:[]).with(:masterport).returns(1234) @source.port.should == 1234 end end end end end diff --git a/spec/unit/type/file/type.rb b/spec/unit/type/file/type.rb index 26ec3b5cd..7d4af0e16 100755 --- a/spec/unit/type/file/type.rb +++ b/spec/unit/type/file/type.rb @@ -1,20 +1,19 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe Puppet::Type.type(:file).attrclass(:type) do require 'puppet_spec/files' include PuppetSpec::Files before do @filename = tmpfile('type') @resource = Puppet::Type.type(:file).new({:name => @filename}) end it "should prevent the user from trying to set the type" do lambda { @resource[:type] = "fifo" }.should raise_error(Puppet::Error, /type is read-only/) end end diff --git a/spec/unit/type/file_spec.rb b/spec/unit/type/file_spec.rb index d0b60e01b..683c3654b 100755 --- a/spec/unit/type/file_spec.rb +++ b/spec/unit/type/file_spec.rb @@ -1,1185 +1,1184 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe Puppet::Type.type(:file) do before do Puppet.settings.stubs(:use) @real_posix = Puppet.features.posix? Puppet.features.stubs("posix?").returns(true) @path = Tempfile.new("puppetspec") pathname = @path.path @path.close!() @path = pathname @file = Puppet::Type::File.new(:name => @path) @catalog = Puppet::Resource::Catalog.new @file.catalog = @catalog end describe "when determining if recursion is enabled" do it "should default to recursion being disabled" do @file.should_not be_recurse end [true, "true", 10, "inf", "remote"].each do |value| it "should consider #{value} to enable recursion" do @file[:recurse] = value @file.must be_recurse end end [false, "false", 0].each do |value| it "should consider #{value} to disable recursion" do @file[:recurse] = value @file.should_not be_recurse end end end describe "#write" do it "should propagate failures encountered when renaming the temporary file" do File.stubs(:open) File.expects(:rename).raises ArgumentError file = Puppet::Type::File.new(:name => "/my/file", :backup => "puppet") file.stubs(:validate_checksum?).returns(false) property = stub('content_property', :actual_content => "something", :length => "something".length) file.stubs(:property).with(:content).returns(property) lambda { file.write(:content) }.should raise_error(Puppet::Error) end it "should delegate writing to the content property" do filehandle = stub_everything 'fh' File.stubs(:open).yields(filehandle) File.stubs(:rename) property = stub('content_property', :actual_content => "something", :length => "something".length) file = Puppet::Type::File.new(:name => "/my/file", :backup => "puppet") file.stubs(:validate_checksum?).returns(false) file.stubs(:property).with(:content).returns(property) property.expects(:write).with(filehandle) file.write(:content) end describe "when validating the checksum" do before { @file.stubs(:validate_checksum?).returns(true) } it "should fail if the checksum parameter and content checksums do not match" do checksum = stub('checksum_parameter', :sum => 'checksum_b', :sum_file => 'checksum_b') @file.stubs(:parameter).with(:checksum).returns(checksum) property = stub('content_property', :actual_content => "something", :length => "something".length, :write => 'checksum_a') @file.stubs(:property).with(:content).returns(property) lambda { @file.write :NOTUSED }.should raise_error(Puppet::Error) end end describe "when not validating the checksum" do before { @file.stubs(:validate_checksum?).returns(false) } it "should not fail if the checksum property and content checksums do not match" do checksum = stub('checksum_parameter', :sum => 'checksum_b') @file.stubs(:parameter).with(:checksum).returns(checksum) property = stub('content_property', :actual_content => "something", :length => "something".length, :write => 'checksum_a') @file.stubs(:property).with(:content).returns(property) lambda { @file.write :NOTUSED }.should_not raise_error(Puppet::Error) end end end it "should have a method for determining if the file is present" do @file.must respond_to(:exist?) end it "should be considered existent if it can be stat'ed" do @file.expects(:stat).returns mock('stat') @file.must be_exist end it "should be considered nonexistent if it can not be stat'ed" do @file.expects(:stat).returns nil @file.must_not be_exist end it "should have a method for determining if the file should be a normal file" do @file.must respond_to(:should_be_file?) end it "should be a file if :ensure is set to :file" do @file[:ensure] = :file @file.must be_should_be_file end it "should be a file if :ensure is set to :present and the file exists as a normal file" do @file.stubs(:stat).returns(mock('stat', :ftype => "file")) @file[:ensure] = :present @file.must be_should_be_file end it "should not be a file if :ensure is set to something other than :file" do @file[:ensure] = :directory @file.must_not be_should_be_file end it "should not be a file if :ensure is set to :present and the file exists but is not a normal file" do @file.stubs(:stat).returns(mock('stat', :ftype => "directory")) @file[:ensure] = :present @file.must_not be_should_be_file end it "should be a file if :ensure is not set and :content is" do @file[:content] = "foo" @file.must be_should_be_file end it "should be a file if neither :ensure nor :content is set but the file exists as a normal file" do @file.stubs(:stat).returns(mock("stat", :ftype => "file")) @file.must be_should_be_file end it "should not be a file if neither :ensure nor :content is set but the file exists but not as a normal file" do @file.stubs(:stat).returns(mock("stat", :ftype => "directory")) @file.must_not be_should_be_file end describe "when using POSIX filenames" do describe "on POSIX systems" do before do Puppet.features.stubs(:posix?).returns(true) Puppet.features.stubs(:microsoft_windows?).returns(false) end it "should autorequire its parent directory" do file = Puppet::Type::File.new(:path => "/foo/bar") dir = Puppet::Type::File.new(:path => "/foo") @catalog.add_resource file @catalog.add_resource dir reqs = file.autorequire reqs[0].source.must == dir reqs[0].target.must == file end it "should not autorequire its parent dir if its parent dir is itself" do file = Puppet::Type::File.new(:path => "/") @catalog.add_resource file file.autorequire.should be_empty end it "should remove trailing slashes" do file = Puppet::Type::File.new(:path => "/foo/bar/baz/") file[:path].should == "/foo/bar/baz" end it "should remove double slashes" do file = Puppet::Type::File.new(:path => "/foo/bar//baz") file[:path].should == "/foo/bar/baz" end it "should remove trailing double slashes" do file = Puppet::Type::File.new(:path => "/foo/bar/baz//") file[:path].should == "/foo/bar/baz" end it "should leave a single slash alone" do file = Puppet::Type::File.new(:path => "/") file[:path].should == "/" end it "should accept a double-slash at the start of the path" do expect { file = Puppet::Type::File.new(:path => "//tmp/xxx") # REVISIT: This should be wrong, later. See the next test. # --daniel 2011-01-31 file[:path].should == '/tmp/xxx' }.should_not raise_error end # REVISIT: This is pending, because I don't want to try and audit the # entire codebase to make sure we get this right. POSIX treats two (and # exactly two) '/' characters at the start of the path specially. # # See sections 3.2 and 4.11, which allow DomainOS to be all special like # and still have the POSIX branding and all. --daniel 2011-01-31 it "should preserve the double-slash at the start of the path" end describe "on Microsoft Windows systems" do before do Puppet.features.stubs(:posix?).returns(false) Puppet.features.stubs(:microsoft_windows?).returns(true) end it "should refuse to work" do lambda { Puppet::Type::File.new(:path => "/foo/bar") }.should raise_error(Puppet::Error) end end end describe "when using Microsoft Windows filenames", :if => Puppet.features.microsoft_windows? do describe "on Microsoft Windows systems" do before do Puppet.features.stubs(:posix?).returns(false) Puppet.features.stubs(:microsoft_windows?).returns(true) end it "should autorequire its parent directory" do file = Puppet::Type::File.new(:path => "X:/foo/bar") dir = Puppet::Type::File.new(:path => "X:/foo") @catalog.add_resource file @catalog.add_resource dir reqs = file.autorequire reqs[0].source.must == dir reqs[0].target.must == file end it "should not autorequire its parent dir if its parent dir is itself" do file = Puppet::Type::File.new(:path => "X:/") @catalog.add_resource file file.autorequire.should be_empty end it "should remove trailing slashes" do file = Puppet::Type::File.new(:path => "X:/foo/bar/baz/") file[:path].should == "X:/foo/bar/baz" end it "should remove double slashes" do file = Puppet::Type::File.new(:path => "X:/foo/bar//baz") file[:path].should == "X:/foo/bar/baz" end it "should remove trailing double slashes" do file = Puppet::Type::File.new(:path => "X:/foo/bar/baz//") file[:path].should == "X:/foo/bar/baz" end it "should leave a drive letter with a slash alone" do file = Puppet::Type::File.new(:path => "X:/") file[:path].should == "X:/" end it "should add a slash to a drive letter" do file = Puppet::Type::File.new(:path => "X:") file[:path].should == "X:/" end end describe "on POSIX systems" do before do Puppet.features.stubs(:posix?).returns(true) Puppet.features.stubs(:microsoft_windows?).returns(false) end it "should refuse to work" do lambda { Puppet::Type::File.new(:path => "X:/foo/bar") }.should raise_error(Puppet::Error) end end end describe "when using UNC filenames" do describe "on Microsoft Windows systems", :if => Puppet.features.microsoft_windows? do before do Puppet.features.stubs(:posix?).returns(false) Puppet.features.stubs(:microsoft_windows?).returns(true) end it "should autorequire its parent directory" do file = Puppet::Type::File.new(:path => "//server/foo/bar") dir = Puppet::Type::File.new(:path => "//server/foo") @catalog.add_resource file @catalog.add_resource dir reqs = file.autorequire reqs[0].source.must == dir reqs[0].target.must == file end it "should not autorequire its parent dir if its parent dir is itself" do file = Puppet::Type::File.new(:path => "//server/foo") @catalog.add_resource file puts file.autorequire file.autorequire.should be_empty end it "should remove trailing slashes" do file = Puppet::Type::File.new(:path => "//server/foo/bar/baz/") file[:path].should == "//server/foo/bar/baz" end it "should remove double slashes" do file = Puppet::Type::File.new(:path => "//server/foo/bar//baz") file[:path].should == "//server/foo/bar/baz" end it "should remove trailing double slashes" do file = Puppet::Type::File.new(:path => "//server/foo/bar/baz//") file[:path].should == "//server/foo/bar/baz" end it "should remove a trailing slash from a sharename" do file = Puppet::Type::File.new(:path => "//server/foo/") file[:path].should == "//server/foo" end it "should not modify a sharename" do file = Puppet::Type::File.new(:path => "//server/foo") file[:path].should == "//server/foo" end end describe "on POSIX systems" do before do Puppet.features.stubs(:posix?).returns(true) Puppet.features.stubs(:microsoft_windows?).returns(false) end it "should refuse to work" do lambda { Puppet::Type::File.new(:path => "X:/foo/bar") }.should raise_error(Puppet::Error) end end end describe "when initializing" do it "should set a desired 'ensure' value if none is set and 'content' is set" do file = Puppet::Type::File.new(:name => "/my/file", :content => "/foo/bar") file[:ensure].should == :file end it "should set a desired 'ensure' value if none is set and 'target' is set" do file = Puppet::Type::File.new(:name => "/my/file", :target => "/foo/bar") file[:ensure].should == :symlink end end describe "when validating attributes" do %w{path checksum backup recurse recurselimit source replace force ignore links purge sourceselect}.each do |attr| it "should have a '#{attr}' parameter" do Puppet::Type.type(:file).attrtype(attr.intern).should == :param end end %w{content target ensure owner group mode type}.each do |attr| it "should have a '#{attr}' property" do Puppet::Type.type(:file).attrtype(attr.intern).should == :property end end it "should have its 'path' attribute set as its namevar" do Puppet::Type.type(:file).key_attributes.should == [:path] end end describe "when managing links" do require 'tempfile' if @real_posix describe "on POSIX systems" do before do @basedir = tempfile Dir.mkdir(@basedir) @file = File.join(@basedir, "file") @link = File.join(@basedir, "link") File.open(@file, "w", 0644) { |f| f.puts "yayness"; f.flush } File.symlink(@file, @link) @resource = Puppet::Type.type(:file).new(:path => @link, :mode => "755") @catalog.add_resource @resource end after do remove_tmp_files end it "should default to managing the link" do @catalog.apply # I convert them to strings so they display correctly if there's an error. ("%o" % (File.stat(@file).mode & 007777)).should == "%o" % 0644 end it "should be able to follow links" do @resource[:links] = :follow @catalog.apply ("%o" % (File.stat(@file).mode & 007777)).should == "%o" % 0755 end end else # @real_posix # should recode tests using expectations instead of using the filesystem end describe "on Microsoft Windows systems" do before do Puppet.features.stubs(:posix?).returns(false) Puppet.features.stubs(:microsoft_windows?).returns(true) end it "should refuse to work with links" end end it "should be able to retrieve a stat instance for the file it is managing" do Puppet::Type.type(:file).new(:path => "/foo/bar", :source => "/bar/foo").should respond_to(:stat) end describe "when stat'ing its file" do before do @resource = Puppet::Type.type(:file).new(:path => "/foo/bar") @resource[:links] = :manage # so we always use :lstat end it "should use :stat if it is following links" do @resource[:links] = :follow File.expects(:stat) @resource.stat end it "should use :lstat if is it not following links" do @resource[:links] = :manage File.expects(:lstat) @resource.stat end it "should stat the path of the file" do File.expects(:lstat).with("/foo/bar") @resource.stat end # This only happens in testing. it "should return nil if the stat does not exist" do File.expects(:lstat).returns nil @resource.stat.should be_nil end it "should return nil if the file does not exist" do File.expects(:lstat).raises(Errno::ENOENT) @resource.stat.should be_nil end it "should return nil if the file cannot be stat'ed" do File.expects(:lstat).raises(Errno::EACCES) @resource.stat.should be_nil end it "should return the stat instance" do File.expects(:lstat).returns "mystat" @resource.stat.should == "mystat" end it "should cache the stat instance if it has a catalog and is applying" do stat = mock 'stat' File.expects(:lstat).returns stat catalog = Puppet::Resource::Catalog.new @resource.catalog = catalog catalog.stubs(:applying?).returns true @resource.stat.should equal(@resource.stat) end end describe "when flushing" do it "should flush all properties that respond to :flush" do @resource = Puppet::Type.type(:file).new(:path => "/foo/bar", :source => "/bar/foo") @resource.parameter(:source).expects(:flush) @resource.flush end it "should reset its stat reference" do @resource = Puppet::Type.type(:file).new(:path => "/foo/bar") File.expects(:lstat).times(2).returns("stat1").then.returns("stat2") @resource.stat.should == "stat1" @resource.flush @resource.stat.should == "stat2" end end it "should have a method for performing recursion" do @file.must respond_to(:perform_recursion) end describe "when executing a recursive search" do it "should use Metadata to do its recursion" do Puppet::FileServing::Metadata.indirection.expects(:search) @file.perform_recursion(@file[:path]) end it "should use the provided path as the key to the search" do Puppet::FileServing::Metadata.indirection.expects(:search).with { |key, options| key == "/foo" } @file.perform_recursion("/foo") end it "should return the results of the metadata search" do Puppet::FileServing::Metadata.indirection.expects(:search).returns "foobar" @file.perform_recursion(@file[:path]).should == "foobar" end it "should pass its recursion value to the search" do @file[:recurse] = true Puppet::FileServing::Metadata.indirection.expects(:search).with { |key, options| options[:recurse] == true } @file.perform_recursion(@file[:path]) end it "should pass true if recursion is remote" do @file[:recurse] = :remote Puppet::FileServing::Metadata.indirection.expects(:search).with { |key, options| options[:recurse] == true } @file.perform_recursion(@file[:path]) end it "should pass its recursion limit value to the search" do @file[:recurselimit] = 10 Puppet::FileServing::Metadata.indirection.expects(:search).with { |key, options| options[:recurselimit] == 10 } @file.perform_recursion(@file[:path]) end it "should configure the search to ignore or manage links" do @file[:links] = :manage Puppet::FileServing::Metadata.indirection.expects(:search).with { |key, options| options[:links] == :manage } @file.perform_recursion(@file[:path]) end it "should pass its 'ignore' setting to the search if it has one" do @file[:ignore] = %w{.svn CVS} Puppet::FileServing::Metadata.indirection.expects(:search).with { |key, options| options[:ignore] == %w{.svn CVS} } @file.perform_recursion(@file[:path]) end end it "should have a method for performing local recursion" do @file.must respond_to(:recurse_local) end describe "when doing local recursion" do before do @metadata = stub 'metadata', :relative_path => "my/file" end it "should pass its path to the :perform_recursion method" do @file.expects(:perform_recursion).with(@file[:path]).returns [@metadata] @file.stubs(:newchild) @file.recurse_local end it "should return an empty hash if the recursion returns nothing" do @file.expects(:perform_recursion).returns nil @file.recurse_local.should == {} end it "should create a new child resource with each generated metadata instance's relative path" do @file.expects(:perform_recursion).returns [@metadata] @file.expects(:newchild).with(@metadata.relative_path).returns "fiebar" @file.recurse_local end it "should not create a new child resource for the '.' directory" do @metadata.stubs(:relative_path).returns "." @file.expects(:perform_recursion).returns [@metadata] @file.expects(:newchild).never @file.recurse_local end it "should return a hash of the created resources with the relative paths as the hash keys" do @file.expects(:perform_recursion).returns [@metadata] @file.expects(:newchild).with("my/file").returns "fiebar" @file.recurse_local.should == {"my/file" => "fiebar"} end it "should set checksum_type to none if this file checksum is none" do @file[:checksum] = :none Puppet::FileServing::Metadata.indirection.expects(:search).with { |path,params| params[:checksum_type] == :none }.returns [@metadata] @file.expects(:newchild).with("my/file").returns "fiebar" @file.recurse_local end end it "should have a method for performing link recursion" do @file.must respond_to(:recurse_link) end describe "when doing link recursion" do before do @first = stub 'first', :relative_path => "first", :full_path => "/my/first", :ftype => "directory" @second = stub 'second', :relative_path => "second", :full_path => "/my/second", :ftype => "file" @resource = stub 'file', :[]= => nil end it "should pass its target to the :perform_recursion method" do @file[:target] = "mylinks" @file.expects(:perform_recursion).with("mylinks").returns [@first] @file.stubs(:newchild).returns @resource @file.recurse_link({}) end it "should ignore the recursively-found '.' file and configure the top-level file to create a directory" do @first.stubs(:relative_path).returns "." @file[:target] = "mylinks" @file.expects(:perform_recursion).with("mylinks").returns [@first] @file.stubs(:newchild).never @file.expects(:[]=).with(:ensure, :directory) @file.recurse_link({}) end it "should create a new child resource for each generated metadata instance's relative path that doesn't already exist in the children hash" do @file.expects(:perform_recursion).returns [@first, @second] @file.expects(:newchild).with(@first.relative_path).returns @resource @file.recurse_link("second" => @resource) end it "should not create a new child resource for paths that already exist in the children hash" do @file.expects(:perform_recursion).returns [@first] @file.expects(:newchild).never @file.recurse_link("first" => @resource) end it "should set the target to the full path of discovered file and set :ensure to :link if the file is not a directory" do file = stub 'file' file.expects(:[]=).with(:target, "/my/second") file.expects(:[]=).with(:ensure, :link) @file.stubs(:perform_recursion).returns [@first, @second] @file.recurse_link("first" => @resource, "second" => file) end it "should :ensure to :directory if the file is a directory" do file = stub 'file' file.expects(:[]=).with(:ensure, :directory) @file.stubs(:perform_recursion).returns [@first, @second] @file.recurse_link("first" => file, "second" => @resource) end it "should return a hash with both created and existing resources with the relative paths as the hash keys" do file = stub 'file', :[]= => nil @file.expects(:perform_recursion).returns [@first, @second] @file.stubs(:newchild).returns file @file.recurse_link("second" => @resource).should == {"second" => @resource, "first" => file} end end it "should have a method for performing remote recursion" do @file.must respond_to(:recurse_remote) end describe "when doing remote recursion" do before do @file[:source] = "puppet://foo/bar" @first = Puppet::FileServing::Metadata.new("/my", :relative_path => "first") @second = Puppet::FileServing::Metadata.new("/my", :relative_path => "second") @first.stubs(:ftype).returns "directory" @second.stubs(:ftype).returns "directory" @parameter = stub 'property', :metadata= => nil @resource = stub 'file', :[]= => nil, :parameter => @parameter end it "should pass its source to the :perform_recursion method" do data = Puppet::FileServing::Metadata.new("/whatever", :relative_path => "foobar") @file.expects(:perform_recursion).with("puppet://foo/bar").returns [data] @file.stubs(:newchild).returns @resource @file.recurse_remote({}) end it "should not recurse when the remote file is not a directory" do data = Puppet::FileServing::Metadata.new("/whatever", :relative_path => ".") data.stubs(:ftype).returns "file" @file.expects(:perform_recursion).with("puppet://foo/bar").returns [data] @file.expects(:newchild).never @file.recurse_remote({}) end it "should set the source of each returned file to the searched-for URI plus the found relative path" do @first.expects(:source=).with File.join("puppet://foo/bar", @first.relative_path) @file.expects(:perform_recursion).returns [@first] @file.stubs(:newchild).returns @resource @file.recurse_remote({}) end it "should create a new resource for any relative file paths that do not already have a resource" do @file.stubs(:perform_recursion).returns [@first] @file.expects(:newchild).with("first").returns @resource @file.recurse_remote({}).should == {"first" => @resource} end it "should not create a new resource for any relative file paths that do already have a resource" do @file.stubs(:perform_recursion).returns [@first] @file.expects(:newchild).never @file.recurse_remote("first" => @resource) end it "should set the source of each resource to the source of the metadata" do @file.stubs(:perform_recursion).returns [@first] @resource.stubs(:[]=) @resource.expects(:[]=).with(:source, File.join("puppet://foo/bar", @first.relative_path)) @file.recurse_remote("first" => @resource) end # LAK:FIXME This is a bug, but I can't think of a fix for it. Fortunately it's already # filed, and when it's fixed, we'll just fix the whole flow. it "should set the checksum type to :md5 if the remote file is a file" do @first.stubs(:ftype).returns "file" @file.stubs(:perform_recursion).returns [@first] @resource.stubs(:[]=) @resource.expects(:[]=).with(:checksum, :md5) @file.recurse_remote("first" => @resource) end it "should store the metadata in the source property for each resource so the source does not have to requery the metadata" do @file.stubs(:perform_recursion).returns [@first] @resource.expects(:parameter).with(:source).returns @parameter @parameter.expects(:metadata=).with(@first) @file.recurse_remote("first" => @resource) end it "should not create a new resource for the '.' file" do @first.stubs(:relative_path).returns "." @file.stubs(:perform_recursion).returns [@first] @file.expects(:newchild).never @file.recurse_remote({}) end it "should store the metadata in the main file's source property if the relative path is '.'" do @first.stubs(:relative_path).returns "." @file.stubs(:perform_recursion).returns [@first] @file.parameter(:source).expects(:metadata=).with @first @file.recurse_remote("first" => @resource) end describe "and multiple sources are provided" do describe "and :sourceselect is set to :first" do it "should create file instances for the results for the first source to return any values" do data = Puppet::FileServing::Metadata.new("/whatever", :relative_path => "foobar") @file[:source] = %w{/one /two /three /four} @file.expects(:perform_recursion).with("/one").returns nil @file.expects(:perform_recursion).with("/two").returns [] @file.expects(:perform_recursion).with("/three").returns [data] @file.expects(:perform_recursion).with("/four").never @file.expects(:newchild).with("foobar").returns @resource @file.recurse_remote({}) end end describe "and :sourceselect is set to :all" do before do @file[:sourceselect] = :all end it "should return every found file that is not in a previous source" do klass = Puppet::FileServing::Metadata @file[:source] = %w{/one /two /three /four} @file.stubs(:newchild).returns @resource one = [klass.new("/one", :relative_path => "a")] @file.expects(:perform_recursion).with("/one").returns one @file.expects(:newchild).with("a").returns @resource two = [klass.new("/two", :relative_path => "a"), klass.new("/two", :relative_path => "b")] @file.expects(:perform_recursion).with("/two").returns two @file.expects(:newchild).with("b").returns @resource three = [klass.new("/three", :relative_path => "a"), klass.new("/three", :relative_path => "c")] @file.expects(:perform_recursion).with("/three").returns three @file.expects(:newchild).with("c").returns @resource @file.expects(:perform_recursion).with("/four").returns [] @file.recurse_remote({}) end end end end describe "when specifying both source, and content properties" do before do @file[:source] = '/one' @file[:content] = 'file contents' end it "should raise an exception" do lambda {@file.validate }.should raise_error(/You cannot specify more than one of/) end end describe "when using source" do before do @file[:source] = '/one' end Puppet::Type::File::ParameterChecksum.value_collection.values.reject {|v| v == :none}.each do |checksum_type| describe "with checksum '#{checksum_type}'" do before do @file[:checksum] = checksum_type end it 'should validate' do lambda { @file.validate }.should_not raise_error end end end describe "with checksum 'none'" do before do @file[:checksum] = :none end it 'should raise an exception when validating' do lambda { @file.validate }.should raise_error(/You cannot specify source when using checksum 'none'/) end end end describe "when using content" do before do @file[:content] = 'file contents' end (Puppet::Type::File::ParameterChecksum.value_collection.values - SOURCE_ONLY_CHECKSUMS).each do |checksum_type| describe "with checksum '#{checksum_type}'" do before do @file[:checksum] = checksum_type end it 'should validate' do lambda { @file.validate }.should_not raise_error end end end SOURCE_ONLY_CHECKSUMS.each do |checksum_type| describe "with checksum '#{checksum_type}'" do it 'should raise an exception when validating' do @file[:checksum] = checksum_type lambda { @file.validate }.should raise_error(/You cannot specify content when using checksum '#{checksum_type}'/) end end end end describe "when returning resources with :eval_generate" do before do @graph = stub 'graph', :add_edge => nil @catalog.stubs(:relationship_graph).returns @graph @file.catalog = @catalog @file[:recurse] = true end it "should recurse if recursion is enabled" do resource = stub('resource', :[] => "resource") @file.expects(:recurse?).returns true @file.expects(:recurse).returns [resource] @file.eval_generate.should == [resource] end it "should not recurse if recursion is disabled" do @file.expects(:recurse?).returns false @file.expects(:recurse).never @file.eval_generate.should == [] end it "should return each resource found through recursion" do foo = stub 'foo', :[] => "/foo" bar = stub 'bar', :[] => "/bar" bar2 = stub 'bar2', :[] => "/bar" @file.expects(:recurse).returns [foo, bar] @file.eval_generate.should == [foo, bar] end end describe "when recursing" do before do @file[:recurse] = true @metadata = Puppet::FileServing::Metadata end describe "and a source is set" do before { @file[:source] = "/my/source" } it "should pass the already-discovered resources to recurse_remote" do @file.stubs(:recurse_local).returns(:foo => "bar") @file.expects(:recurse_remote).with(:foo => "bar").returns [] @file.recurse end end describe "and a target is set" do before { @file[:target] = "/link/target" } it "should use recurse_link" do @file.stubs(:recurse_local).returns(:foo => "bar") @file.expects(:recurse_link).with(:foo => "bar").returns [] @file.recurse end end it "should use recurse_local if recurse is not remote" do @file.expects(:recurse_local).returns({}) @file.recurse end it "should not use recurse_local if recurse remote" do @file[:recurse] = :remote @file.expects(:recurse_local).never @file.recurse end it "should return the generated resources as an array sorted by file path" do one = stub 'one', :[] => "/one" two = stub 'two', :[] => "/one/two" three = stub 'three', :[] => "/three" @file.expects(:recurse_local).returns(:one => one, :two => two, :three => three) @file.recurse.should == [one, two, three] end describe "and purging is enabled" do before do @file[:purge] = true end it "should configure each file to be removed" do local = stub 'local' local.stubs(:[]).with(:source).returns nil # Thus, a local file local.stubs(:[]).with(:path).returns "foo" @file.expects(:recurse_local).returns("local" => local) local.expects(:[]=).with(:ensure, :absent) @file.recurse end it "should not remove files that exist in the remote repository" do @file["source"] = "/my/file" @file.expects(:recurse_local).returns({}) remote = stub 'remote' remote.stubs(:[]).with(:source).returns "/whatever" # Thus, a remote file remote.stubs(:[]).with(:path).returns "foo" @file.expects(:recurse_remote).with { |hash| hash["remote"] = remote } remote.expects(:[]=).with(:ensure, :absent).never @file.recurse end end describe "and making a new child resource" do it "should not copy the parent resource's parent" do Puppet::Type.type(:file).expects(:new).with { |options| ! options.include?(:parent) } @file.newchild("my/path") end {:recurse => true, :target => "/foo/bar", :ensure => :present, :alias => "yay", :source => "/foo/bar"}.each do |param, value| it "should not pass on #{param} to the sub resource" do @file = Puppet::Type::File.new(:name => @path, param => value, :catalog => @catalog) @file.class.expects(:new).with { |params| params[param].nil? } @file.newchild("sub/file") end end it "should copy all of the parent resource's 'should' values that were set at initialization" do file = @file.class.new(:path => "/foo/bar", :owner => "root", :group => "wheel") @catalog.add_resource(file) file.class.expects(:new).with { |options| options[:owner] == "root" and options[:group] == "wheel" } file.newchild("my/path") end it "should not copy default values to the new child" do @file.class.expects(:new).with { |params| params[:backup].nil? } @file.newchild("my/path") end it "should not copy values to the child which were set by the source" do @file[:source] = "/foo/bar" metadata = stub 'metadata', :owner => "root", :group => "root", :mode => 0755, :ftype => "file", :checksum => "{md5}whatever" @file.parameter(:source).stubs(:metadata).returns metadata @file.parameter(:source).copy_source_values @file.class.expects(:new).with { |params| params[:group].nil? } @file.newchild("my/path") end end end describe "when setting the backup" do it "should default to 'puppet'" do Puppet::Type::File.new(:name => "/my/file")[:backup].should == "puppet" end it "should allow setting backup to 'false'" do (!Puppet::Type::File.new(:name => "/my/file", :backup => false)[:backup]).should be_true end it "should set the backup to '.puppet-bak' if it is set to true" do Puppet::Type::File.new(:name => "/my/file", :backup => true)[:backup].should == ".puppet-bak" end it "should support any other backup extension" do Puppet::Type::File.new(:name => "/my/file", :backup => ".bak")[:backup].should == ".bak" end it "should set the filebucket when backup is set to a string matching the name of a filebucket in the catalog" do catalog = Puppet::Resource::Catalog.new bucket_resource = Puppet::Type.type(:filebucket).new :name => "foo", :path => "/my/file/bucket" catalog.add_resource bucket_resource file = Puppet::Type::File.new(:name => "/my/file") catalog.add_resource file file[:backup] = "foo" file.bucket.should == bucket_resource.bucket end it "should find filebuckets added to the catalog after the file resource was created" do catalog = Puppet::Resource::Catalog.new file = Puppet::Type::File.new(:name => "/my/file", :backup => "foo") catalog.add_resource file bucket_resource = Puppet::Type.type(:filebucket).new :name => "foo", :path => "/my/file/bucket" catalog.add_resource bucket_resource file.bucket.should == bucket_resource.bucket end it "should have a nil filebucket if backup is false" do catalog = Puppet::Resource::Catalog.new bucket_resource = Puppet::Type.type(:filebucket).new :name => "foo", :path => "/my/file/bucket" catalog.add_resource bucket_resource file = Puppet::Type::File.new(:name => "/my/file", :backup => false) catalog.add_resource file file.bucket.should be_nil end it "should have a nil filebucket if backup is set to a string starting with '.'" do catalog = Puppet::Resource::Catalog.new bucket_resource = Puppet::Type.type(:filebucket).new :name => "foo", :path => "/my/file/bucket" catalog.add_resource bucket_resource file = Puppet::Type::File.new(:name => "/my/file", :backup => ".foo") catalog.add_resource file file.bucket.should be_nil end it "should fail if there's no catalog and backup is not false" do file = Puppet::Type::File.new(:name => "/my/file", :backup => "foo") lambda { file.bucket }.should raise_error(Puppet::Error) end it "should fail if a non-existent catalog is specified" do file = Puppet::Type::File.new(:name => "/my/file", :backup => "foo") catalog = Puppet::Resource::Catalog.new catalog.add_resource file lambda { file.bucket }.should raise_error(Puppet::Error) end it "should be able to use the default filebucket without a catalog" do file = Puppet::Type::File.new(:name => "/my/file", :backup => "puppet") file.bucket.should be_instance_of(Puppet::FileBucket::Dipper) end it "should look up the filebucket during finish()" do file = Puppet::Type::File.new(:name => "/my/file", :backup => ".foo") file.expects(:bucket) file.finish end end describe "when retrieving the current file state" do it "should copy the source values if the 'source' parameter is set" do file = Puppet::Type::File.new(:name => "/my/file", :source => "/foo/bar") file.parameter(:source).expects(:copy_source_values) file.retrieve end end describe ".title_patterns" do before do @type_class = Puppet::Type.type(:file) end it "should have a regexp that captures the entire string, except for a terminating slash" do patterns = @type_class.title_patterns string = "abc/\n\tdef/" patterns[0][0] =~ string $1.should == "abc/\n\tdef" end end describe "when auditing" do it "should not fail if creating a new file if group is not set" do File.exists?(@path).should == false file = Puppet::Type::File.new(:name => @path, :audit => "all", :content => "content") catalog = Puppet::Resource::Catalog.new catalog.add_resource(file) Puppet::Util::Storage.stubs(:store) # to prevent the catalog from trying to write state.yaml transaction = catalog.apply transaction.report.resource_statuses["File[#{@path}]"].failed.should == false File.exists?(@path).should == true end it "should not log errors if creating a new file with ensure present and no content" do File.exists?(@path).should == false file = Puppet::Type::File.new(:name => @path, :audit => "content", :ensure => "present") catalog = Puppet::Resource::Catalog.new catalog.add_resource(file) Puppet::Util::Storage.stubs(:store) # to prevent the catalog from trying to write state.yaml catalog.apply @logs.reject {|l| l.level == :notice }.should be_empty end end describe "when specifying both source and checksum" do it 'should use the specified checksum when source is first' do @file[:source] = '/foo' @file[:checksum] = :md5lite @file[:checksum].should be :md5lite end it 'should use the specified checksum when source is last' do @file[:checksum] = :md5lite @file[:source] = '/foo' @file[:checksum].should be :md5lite end end end diff --git a/spec/unit/type/filebucket_spec.rb b/spec/unit/type/filebucket_spec.rb index f13fb00a5..3c5311184 100755 --- a/spec/unit/type/filebucket_spec.rb +++ b/spec/unit/type/filebucket_spec.rb @@ -1,74 +1,73 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe Puppet::Type.type(:filebucket) do describe "when validating attributes" do %w{name server port path}.each do |attr| it "should have a '#{attr}' parameter" do Puppet::Type.type(:filebucket).attrtype(attr.intern).should == :param end end it "should have its 'name' attribute set as its namevar" do Puppet::Type.type(:filebucket).key_attributes.should == [:name] end end it "should use the clientbucketdir as the path by default path" do Puppet.settings[:clientbucketdir] = "/my/bucket" Puppet::Type.type(:filebucket).new(:name => "main")[:path].should == Puppet[:clientbucketdir] end it "should use the masterport as the path by default port" do Puppet.settings[:masterport] = 50 Puppet::Type.type(:filebucket).new(:name => "main")[:port].should == Puppet[:masterport] end it "should use the server as the path by default server" do Puppet.settings[:server] = "myserver" Puppet::Type.type(:filebucket).new(:name => "main")[:server].should == Puppet[:server] end it "be local by default" do bucket = Puppet::Type.type(:filebucket).new :name => "main" bucket.bucket.should be_local end it "not be local if path is false" do bucket = Puppet::Type.type(:filebucket).new :name => "main", :path => false bucket.bucket.should_not be_local end it "be local if both a path and a server are specified" do bucket = Puppet::Type.type(:filebucket).new :name => "main", :server => "puppet", :path => "/my/path" bucket.bucket.should be_local end describe "when creating the filebucket" do before do @bucket = stub 'bucket', :name= => nil end it "should use any provided path" do bucket = Puppet::Type.type(:filebucket).new :name => "main", :path => "/foo/bar" Puppet::FileBucket::Dipper.expects(:new).with(:Path => "/foo/bar").returns @bucket bucket.bucket end it "should use any provided server and port" do bucket = Puppet::Type.type(:filebucket).new :name => "main", :server => "myserv", :port => "myport", :path => false Puppet::FileBucket::Dipper.expects(:new).with(:Server => "myserv", :Port => "myport").returns @bucket bucket.bucket end it "should use the default server if the path is unset and no server is provided" do Puppet.settings[:server] = "myserv" bucket = Puppet::Type.type(:filebucket).new :name => "main", :path => false Puppet::FileBucket::Dipper.expects(:new).with { |args| args[:Server] == "myserv" }.returns @bucket bucket.bucket end end end diff --git a/spec/unit/type/group_spec.rb b/spec/unit/type/group_spec.rb index a16f35925..b32204aa6 100755 --- a/spec/unit/type/group_spec.rb +++ b/spec/unit/type/group_spec.rb @@ -1,57 +1,56 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe Puppet::Type.type(:group) do before do ENV["PATH"] += File::PATH_SEPARATOR + "/usr/sbin" unless ENV["PATH"].split(File::PATH_SEPARATOR).include?("/usr/sbin") @class = Puppet::Type.type(:group) end it "should have a default provider" do @class.defaultprovider.should_not be_nil end it "should have a default provider inheriting from Puppet::Provider" do @class.defaultprovider.ancestors.should be_include(Puppet::Provider) end describe "when validating attributes" do [:name, :allowdupe].each do |param| it "should have a #{param} parameter" do @class.attrtype(param).should == :param end end [:ensure, :gid].each do |param| it "should have a #{param} property" do @class.attrtype(param).should == :property end end it "should convert gids provided as strings into integers" do @class.new(:name => "foo", :gid => "15")[:gid].should == 15 end it "should accepts gids provided as integers" do @class.new(:name => "foo", :gid => 15)[:gid].should == 15 end end # #1407 - we need to declare the allowdupe param as boolean. it "should have a boolean method for determining if duplicates are allowed" do @class.new(:name => "foo").methods.should be_include("allowdupe?") end it "should call 'create' to create the group" do group = @class.new(:name => "foo", :ensure => :present) group.provider.expects(:create) group.parameter(:ensure).sync end it "should call 'delete' to remove the group" do group = @class.new(:name => "foo", :ensure => :absent) group.provider.expects(:delete) group.parameter(:ensure).sync end end diff --git a/spec/unit/type/host_spec.rb b/spec/unit/type/host_spec.rb index b0d5a16e3..602c428af 100755 --- a/spec/unit/type/host_spec.rb +++ b/spec/unit/type/host_spec.rb @@ -1,130 +1,129 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' host = Puppet::Type.type(:host) describe host do before do @class = host @catalog = Puppet::Resource::Catalog.new @provider = stub 'provider' @resource = stub 'resource', :resource => nil, :provider => @provider end it "should have :name be its namevar" do @class.key_attributes.should == [:name] end describe "when validating attributes" do [:name, :provider ].each do |param| it "should have a #{param} parameter" do @class.attrtype(param).should == :param end end [:ip, :target, :host_aliases, :comment, :ensure].each do |property| it "should have a #{property} property" do @class.attrtype(property).should == :property end end it "should have a list host_aliases" do @class.attrclass(:host_aliases).ancestors.should be_include(Puppet::Property::OrderedList) end end describe "when validating values" do it "should support present as a value for ensure" do proc { @class.new(:name => "foo", :ensure => :present) }.should_not raise_error end it "should support absent as a value for ensure" do proc { @class.new(:name => "foo", :ensure => :absent) }.should_not raise_error end it "should accept IPv4 addresses" do proc { @class.new(:name => "foo", :ip => '10.96.0.1') }.should_not raise_error end it "should accept long IPv6 addresses" do # Taken from wikipedia article about ipv6 proc { @class.new(:name => "foo", :ip => '2001:0db8:85a3:08d3:1319:8a2e:0370:7344') }.should_not raise_error end it "should accept one host_alias" do proc { @class.new(:name => "foo", :host_aliases => 'alias1') }.should_not raise_error end it "should accept multiple host_aliases" do proc { @class.new(:name => "foo", :host_aliases => [ 'alias1', 'alias2' ]) }.should_not raise_error end it "should accept shortened IPv6 addresses" do proc { @class.new(:name => "foo", :ip => '2001:db8:0:8d3:0:8a2e:70:7344') }.should_not raise_error proc { @class.new(:name => "foo", :ip => '::ffff:192.0.2.128') }.should_not raise_error proc { @class.new(:name => "foo", :ip => '::1') }.should_not raise_error end it "should not accept malformed IPv4 addresses like 192.168.0.300" do proc { @class.new(:name => "foo", :ip => '192.168.0.300') }.should raise_error end it "should not accept malformed IP addresses like 2001:0dg8:85a3:08d3:1319:8a2e:0370:7344" do proc { @class.new(:name => "foo", :ip => '2001:0dg8:85a3:08d3:1319:8a2e:0370:7344') }.should raise_error end it "should not accept spaces in resourcename" do proc { @class.new(:name => "foo bar") }.should raise_error end it "should not accept host_aliases with spaces" do proc { @class.new(:name => "foo", :host_aliases => [ 'well_formed', 'not wellformed' ]) }.should raise_error end it "should not accept empty host_aliases" do proc { @class.new(:name => "foo", :host_aliases => ['alias1','']) }.should raise_error end end describe "when syncing" do it "should send the first value to the provider for ip property" do @ip = @class.attrclass(:ip).new(:resource => @resource, :should => %w{192.168.0.1 192.168.0.2}) @provider.expects(:ip=).with '192.168.0.1' @ip.sync end it "should send the first value to the provider for comment property" do @comment = @class.attrclass(:comment).new(:resource => @resource, :should => %w{Bazinga Notme}) @provider.expects(:comment=).with 'Bazinga' @comment.sync end it "should send the joined array to the provider for host_alias" do @host_aliases = @class.attrclass(:host_aliases).new(:resource => @resource, :should => %w{foo bar}) @provider.expects(:host_aliases=).with 'foo bar' @host_aliases.sync end it "should also use the specified delimiter for joining" do @host_aliases = @class.attrclass(:host_aliases).new(:resource => @resource, :should => %w{foo bar}) @host_aliases.stubs(:delimiter).returns "\t" @provider.expects(:host_aliases=).with "foo\tbar" @host_aliases.sync end it "should care about the order of host_aliases" do @host_aliases = @class.attrclass(:host_aliases).new(:resource => @resource, :should => %w{foo bar}) @host_aliases.insync?(%w{foo bar}).should == true @host_aliases.insync?(%w{bar foo}).should == false end it "should not consider aliases to be in sync if should is a subset of current" do @host_aliases = @class.attrclass(:host_aliases).new(:resource => @resource, :should => %w{foo bar}) @host_aliases.insync?(%w{foo bar anotherone}).should == false end end end diff --git a/spec/unit/type/interface_spec.rb b/spec/unit/type/interface_spec.rb old mode 100644 new mode 100755 index 630e45aa9..68f4c765f --- a/spec/unit/type/interface_spec.rb +++ b/spec/unit/type/interface_spec.rb @@ -1,93 +1,93 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec require File.dirname(__FILE__) + '/../../spec_helper' describe Puppet::Type.type(:interface) do it "should have a 'name' parameter'" do Puppet::Type.type(:interface).new(:name => "FastEthernet 0/1")[:name].should == "FastEthernet 0/1" end it "should have a 'device_url' parameter'" do Puppet::Type.type(:interface).new(:name => "FastEthernet 0/1", :device_url => :device)[:device_url].should == :device end it "should have an ensure property" do Puppet::Type.type(:interface).attrtype(:ensure).should == :property end [:description, :speed, :duplex, :native_vlan, :encapsulation, :mode, :allowed_trunk_vlans, :etherchannel, :ipaddress].each do |p| it "should have a #{p} property" do Puppet::Type.type(:interface).attrtype(p).should == :property end end describe "when validating attribute values" do before do @provider = stub 'provider', :class => Puppet::Type.type(:interface).defaultprovider, :clear => nil Puppet::Type.type(:interface).defaultprovider.stubs(:new).returns(@provider) end it "should support :present as a value to :ensure" do Puppet::Type.type(:interface).new(:name => "FastEthernet 0/1", :ensure => :present) end it "should support :shutdown as a value to :ensure" do Puppet::Type.type(:interface).new(:name => "FastEthernet 0/1", :ensure => :shutdown) end it "should support :no_shutdown as a value to :ensure" do Puppet::Type.type(:interface).new(:name => "FastEthernet 0/1", :ensure => :no_shutdown) end describe "especially speed" do it "should allow a number" do Puppet::Type.type(:interface).new(:name => "FastEthernet 0/1", :speed => "100") end it "should allow :auto" do Puppet::Type.type(:interface).new(:name => "FastEthernet 0/1", :speed => :auto) end end describe "especially duplex" do it "should allow :half" do Puppet::Type.type(:interface).new(:name => "FastEthernet 0/1", :duplex => :half) end it "should allow :full" do Puppet::Type.type(:interface).new(:name => "FastEthernet 0/1", :duplex => :full) end it "should allow :auto" do Puppet::Type.type(:interface).new(:name => "FastEthernet 0/1", :duplex => :auto) end end describe "especially ipaddress" do it "should allow ipv4 addresses" do Puppet::Type.type(:interface).new(:name => "FastEthernet 0/1", :ipaddress => "192.168.0.1/24") end it "should allow arrays of ipv4 addresses" do Puppet::Type.type(:interface).new(:name => "FastEthernet 0/1", :ipaddress => ["192.168.0.1/24", "192.168.1.0/24"]) end it "should allow ipv6 addresses" do Puppet::Type.type(:interface).new(:name => "FastEthernet 0/1", :ipaddress => "f0e9::/64") end it "should allow ipv6 options" do Puppet::Type.type(:interface).new(:name => "FastEthernet 0/1", :ipaddress => "f0e9::/64 link-local") Puppet::Type.type(:interface).new(:name => "FastEthernet 0/1", :ipaddress => "f0e9::/64 eui-64") end it "should allow a mix of ipv4 and ipv6" do Puppet::Type.type(:interface).new(:name => "FastEthernet 0/1", :ipaddress => ["192.168.0.1/24", "f0e9::/64 link-local"]) end it "should munge ip addresses to a computer format" do Puppet::Type.type(:interface).new(:name => "FastEthernet 0/1", :ipaddress => "192.168.0.1/24")[:ipaddress].should == [[24, IPAddr.new('192.168.0.1'), nil]] end end end end diff --git a/spec/unit/type/macauthorization_spec.rb b/spec/unit/type/macauthorization_spec.rb index 01a78f196..8ab30834b 100755 --- a/spec/unit/type/macauthorization_spec.rb +++ b/spec/unit/type/macauthorization_spec.rb @@ -1,111 +1,110 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' macauth_type = Puppet::Type.type(:macauthorization) describe Puppet::Type.type(:macauthorization), "when checking macauthorization objects" do before do authplist = {} authplist["rules"] = { "foorule" => "foo" } authplist["rights"] = { "fooright" => "foo" } provider_class = macauth_type.provider(macauth_type.providers[0]) Plist.stubs(:parse_xml).with("/etc/authorization").returns(authplist) macauth_type.stubs(:defaultprovider).returns provider_class @resource = macauth_type.new(:name => 'foo') end describe "when validating attributes" do parameters = [:name,] properties = [:auth_type, :allow_root, :authenticate_user, :auth_class, :comment, :group, :k_of_n, :mechanisms, :rule, :session_owner, :shared, :timeout, :tries] parameters.each do |parameter| it "should have a #{parameter} parameter" do macauth_type.attrclass(parameter).ancestors.should be_include(Puppet::Parameter) end it "should have documentation for its #{parameter} parameter" do macauth_type.attrclass(parameter).doc.should be_instance_of(String) end end properties.each do |property| it "should have a #{property} property" do macauth_type.attrclass(property).ancestors.should be_include(Puppet::Property) end it "should have documentation for its #{property} property" do macauth_type.attrclass(property).doc.should be_instance_of(String) end end end describe "when validating properties" do it "should have a default provider inheriting from Puppet::Provider" do macauth_type.defaultprovider.ancestors.should be_include(Puppet::Provider) end it "should be able to create an instance" do lambda { macauth_type.new(:name => 'foo') }.should_not raise_error end it "should support :present as a value to :ensure" do lambda { macauth_type.new(:name => "foo", :ensure => :present) }.should_not raise_error end it "should support :absent as a value to :ensure" do lambda { macauth_type.new(:name => "foo", :ensure => :absent) }.should_not raise_error end end [:k_of_n, :timeout, :tries].each do |property| describe "when managing the #{property} property" do it "should convert number-looking strings into actual numbers" do prop = macauth_type.attrclass(property).new(:resource => @resource) prop.should = "300" prop.should.must == 300 end it "should support integers as a value" do prop = macauth_type.attrclass(property).new(:resource => @resource) prop.should = 300 prop.should.must == 300 end it "should raise an error for non-integer values" do prop = macauth_type.attrclass(property).new(:resource => @resource) lambda { prop.should = "foo" }.should raise_error(Puppet::Error) end end end [:allow_root, :authenticate_user, :session_owner, :shared].each do |property| describe "when managing the #{property} property" do it "should convert boolean-looking false strings into actual booleans" do prop = macauth_type.attrclass(property).new(:resource => @resource) prop.should = "false" prop.should.must == :false end it "should convert boolean-looking true strings into actual booleans" do prop = macauth_type.attrclass(property).new(:resource => @resource) prop.should = "true" prop.should.must == :true end it "should raise an error for non-boolean values" do prop = macauth_type.attrclass(property).new(:resource => @resource) lambda { prop.should = "foo" }.should raise_error(Puppet::Error) end end end end diff --git a/spec/unit/type/maillist_spec.rb b/spec/unit/type/maillist_spec.rb index 8427f5306..ae5fcd5b3 100755 --- a/spec/unit/type/maillist_spec.rb +++ b/spec/unit/type/maillist_spec.rb @@ -1,42 +1,41 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' maillist = Puppet::Type.type(:maillist) describe maillist do before do @provider_class = Puppet::Type.type(:maillist).provider(:mailman) @provider = stub 'provider', :class => @provider_class, :clear => nil @provider.stubs(:respond_to).with(:aliases).returns(true) @provider_class.stubs(:new).returns(@provider) Puppet::Type.type(:maillist).stubs(:defaultprovider).returns(@provider_class) @maillist = Puppet::Type.type(:maillist).new( :name => 'test' ) @catalog = Puppet::Resource::Catalog.new @maillist.catalog = @catalog end it "should generate aliases unless they already exist" do # Mail List aliases are careful not to stomp on managed Mail Alias aliases # test1 is an unmanaged alias from /etc/aliases Puppet::Type.type(:mailalias).provider(:aliases).stubs(:target_object).returns( StringIO.new("test1: root\n") ) # test2 is a managed alias from the manifest dupe = Puppet::Type.type(:mailalias).new( :name => 'test2' ) @catalog.add_resource dupe @provider.stubs(:aliases).returns({"test1" => 'this will get included', "test2" => 'this will dropped', "test3" => 'this will get included'}) generated = @maillist.generate generated.map{ |x| x.name }.sort.should == ['test1', 'test3'] generated.map{ |x| x.class }.should == [Puppet::Type::Mailalias, Puppet::Type::Mailalias] end end diff --git a/spec/unit/type/mcx_spec.rb b/spec/unit/type/mcx_spec.rb index b35355a29..02f691a52 100755 --- a/spec/unit/type/mcx_spec.rb +++ b/spec/unit/type/mcx_spec.rb @@ -1,80 +1,79 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/type/mcx' mcx_type = Puppet::Type.type(:mcx) describe mcx_type, "when validating attributes" do properties = [:ensure, :content] parameters = [:name, :ds_type, :ds_name] parameters.each do |p| it "should have a #{p} parameter" do mcx_type.attrclass(p).ancestors.should be_include(Puppet::Parameter) end it "should have documentation for its #{p} parameter" do mcx_type.attrclass(p).doc.should be_instance_of(String) end end properties.each do |p| it "should have a #{p} property" do mcx_type.attrclass(p).ancestors.should be_include(Puppet::Property) end it "should have documentation for its #{p} property" do mcx_type.attrclass(p).doc.should be_instance_of(String) end end end describe mcx_type, "default values" do before :each do provider_class = mcx_type.provider(mcx_type.providers[0]) mcx_type.stubs(:defaultprovider).returns provider_class end it "should be nil for :ds_type" do mcx_type.new(:name => '/Foo/bar')[:ds_type].should be_nil end it "should be nil for :ds_name" do mcx_type.new(:name => '/Foo/bar')[:ds_name].should be_nil end it "should be nil for :content" do mcx_type.new(:name => '/Foo/bar')[:content].should be_nil end end describe mcx_type, "when validating properties" do before :each do provider_class = mcx_type.provider(mcx_type.providers[0]) mcx_type.stubs(:defaultprovider).returns provider_class end it "should be able to create an instance" do lambda { mcx_type.new(:name => '/Foo/bar') }.should_not raise_error end it "should support :present as a value to :ensure" do lambda { mcx_type.new(:name => "/Foo/bar", :ensure => :present) }.should_not raise_error end it "should support :absent as a value to :ensure" do lambda { mcx_type.new(:name => "/Foo/bar", :ensure => :absent) }.should_not raise_error end end diff --git a/spec/unit/type/mount_spec.rb b/spec/unit/type/mount_spec.rb index 5bcc438fd..9ef76992a 100755 --- a/spec/unit/type/mount_spec.rb +++ b/spec/unit/type/mount_spec.rb @@ -1,330 +1,329 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe Puppet::Type.type(:mount) do it "should have a :refreshable feature that requires the :remount method" do Puppet::Type.type(:mount).provider_feature(:refreshable).methods.should == [:remount] end it "should have no default value for :ensure" do mount = Puppet::Type.type(:mount).new(:name => "yay") mount.should(:ensure).should be_nil end it "should have :name as the only keyattribut" do Puppet::Type.type(:mount).key_attributes.should == [:name] end end describe Puppet::Type.type(:mount), "when validating attributes" do [:name, :remounts, :provider].each do |param| it "should have a #{param} parameter" do Puppet::Type.type(:mount).attrtype(param).should == :param end end [:ensure, :device, :blockdevice, :fstype, :options, :pass, :dump, :atboot, :target].each do |param| it "should have a #{param} property" do Puppet::Type.type(:mount).attrtype(param).should == :property end end end describe Puppet::Type.type(:mount)::Ensure, "when validating values" do before do @provider = stub 'provider', :class => Puppet::Type.type(:mount).defaultprovider, :clear => nil Puppet::Type.type(:mount).defaultprovider.expects(:new).returns(@provider) end it "should alias :present to :defined as a value to :ensure" do mount = Puppet::Type.type(:mount).new(:name => "yay", :ensure => :present) mount.should(:ensure).should == :defined end it "should support :present as a value to :ensure" do Puppet::Type.type(:mount).new(:name => "yay", :ensure => :present) end it "should support :defined as a value to :ensure" do Puppet::Type.type(:mount).new(:name => "yay", :ensure => :defined) end it "should support :unmounted as a value to :ensure" do Puppet::Type.type(:mount).new(:name => "yay", :ensure => :unmounted) end it "should support :absent as a value to :ensure" do Puppet::Type.type(:mount).new(:name => "yay", :ensure => :absent) end it "should support :mounted as a value to :ensure" do Puppet::Type.type(:mount).new(:name => "yay", :ensure => :mounted) end end describe Puppet::Type.type(:mount)::Ensure do before :each do provider_properties = {} @provider = stub 'provider', :class => Puppet::Type.type(:mount).defaultprovider, :clear => nil, :satisfies? => true, :name => :mock, :property_hash => provider_properties Puppet::Type.type(:mount).defaultprovider.stubs(:new).returns(@provider) @mount = Puppet::Type.type(:mount).new(:name => "yay", :check => :ensure) @ensure = @mount.property(:ensure) end def mount_stub(params) Puppet::Type.type(:mount).validproperties.each do |prop| unless params[prop] params[prop] = :absent @mount[prop] = :absent end end params.each do |param, value| @provider.stubs(param).returns(value) end end describe Puppet::Type.type(:mount)::Ensure, "when changing the host" do def test_ensure_change(options) @provider.stubs(:get).with(:ensure).returns options[:from] @provider.stubs(:ensure).returns options[:from] @provider.stubs(:mounted?).returns([:mounted,:ghost].include? options[:from]) @provider.expects(:create).times(options[:create] || 0) @provider.expects(:destroy).times(options[:destroy] || 0) @provider.expects(:mount).never @provider.expects(:unmount).times(options[:unmount] || 0) @ensure.stubs(:syncothers) @ensure.should = options[:to] @ensure.sync (!!@provider.property_hash[:needs_mount]).should == (!!options[:mount]) end it "should create itself when changing from :ghost to :present" do test_ensure_change(:from => :ghost, :to => :present, :create => 1) end it "should create itself when changing from :absent to :present" do test_ensure_change(:from => :absent, :to => :present, :create => 1) end it "should create itself and unmount when changing from :ghost to :unmounted" do test_ensure_change(:from => :ghost, :to => :unmounted, :create => 1, :unmount => 1) end it "should unmount resource when changing from :mounted to :unmounted" do test_ensure_change(:from => :mounted, :to => :unmounted, :unmount => 1) end it "should create itself when changing from :absent to :unmounted" do test_ensure_change(:from => :absent, :to => :unmounted, :create => 1) end it "should unmount resource when changing from :ghost to :absent" do test_ensure_change(:from => :ghost, :to => :absent, :unmount => 1) end it "should unmount and destroy itself when changing from :mounted to :absent" do test_ensure_change(:from => :mounted, :to => :absent, :destroy => 1, :unmount => 1) end it "should destroy itself when changing from :unmounted to :absent" do test_ensure_change(:from => :unmounted, :to => :absent, :destroy => 1) end it "should create itself when changing from :ghost to :mounted" do test_ensure_change(:from => :ghost, :to => :mounted, :create => 1) end it "should create itself and mount when changing from :absent to :mounted" do test_ensure_change(:from => :absent, :to => :mounted, :create => 1, :mount => 1) end it "should mount resource when changing from :unmounted to :mounted" do test_ensure_change(:from => :unmounted, :to => :mounted, :mount => 1) end it "should be in sync if it is :absent and should be :absent" do @ensure.should = :absent @ensure.safe_insync?(:absent).should == true end it "should be out of sync if it is :absent and should be :defined" do @ensure.should = :defined @ensure.safe_insync?(:absent).should == false end it "should be out of sync if it is :absent and should be :mounted" do @ensure.should = :mounted @ensure.safe_insync?(:absent).should == false end it "should be out of sync if it is :absent and should be :unmounted" do @ensure.should = :unmounted @ensure.safe_insync?(:absent).should == false end it "should be out of sync if it is :mounted and should be :absent" do @ensure.should = :absent @ensure.safe_insync?(:mounted).should == false end it "should be in sync if it is :mounted and should be :defined" do @ensure.should = :defined @ensure.safe_insync?(:mounted).should == true end it "should be in sync if it is :mounted and should be :mounted" do @ensure.should = :mounted @ensure.safe_insync?(:mounted).should == true end it "should be out in sync if it is :mounted and should be :unmounted" do @ensure.should = :unmounted @ensure.safe_insync?(:mounted).should == false end it "should be out of sync if it is :unmounted and should be :absent" do @ensure.should = :absent @ensure.safe_insync?(:unmounted).should == false end it "should be in sync if it is :unmounted and should be :defined" do @ensure.should = :defined @ensure.safe_insync?(:unmounted).should == true end it "should be out of sync if it is :unmounted and should be :mounted" do @ensure.should = :mounted @ensure.safe_insync?(:unmounted).should == false end it "should be in sync if it is :unmounted and should be :unmounted" do @ensure.should = :unmounted @ensure.safe_insync?(:unmounted).should == true end it "should be out of sync if it is :ghost and should be :absent" do @ensure.should = :absent @ensure.safe_insync?(:ghost).should == false end it "should be out of sync if it is :ghost and should be :defined" do @ensure.should = :defined @ensure.safe_insync?(:ghost).should == false end it "should be out of sync if it is :ghost and should be :mounted" do @ensure.should = :mounted @ensure.safe_insync?(:ghost).should == false end it "should be out of sync if it is :ghost and should be :unmounted" do @ensure.should = :unmounted @ensure.safe_insync?(:ghost).should == false end end describe Puppet::Type.type(:mount), "when responding to refresh" do pending "2.6.x specifies slightly different behavior and the desired behavior needs to be clarified and revisited. See ticket #4904" do it "should remount if it is supposed to be mounted" do @mount[:ensure] = "mounted" @provider.expects(:remount) @mount.refresh end it "should not remount if it is supposed to be present" do @mount[:ensure] = "present" @provider.expects(:remount).never @mount.refresh end it "should not remount if it is supposed to be absent" do @mount[:ensure] = "absent" @provider.expects(:remount).never @mount.refresh end it "should not remount if it is supposed to be defined" do @mount[:ensure] = "defined" @provider.expects(:remount).never @mount.refresh end it "should not remount if it is supposed to be unmounted" do @mount[:ensure] = "unmounted" @provider.expects(:remount).never @mount.refresh end it "should not remount swap filesystems" do @mount[:ensure] = "mounted" @mount[:fstype] = "swap" @provider.expects(:remount).never @mount.refresh end end end end describe Puppet::Type.type(:mount), "when modifying an existing mount entry" do before do @provider = stub 'provider', :class => Puppet::Type.type(:mount).defaultprovider, :clear => nil, :satisfies? => true, :name => :mock, :remount => nil Puppet::Type.type(:mount).defaultprovider.stubs(:new).returns(@provider) @mount = Puppet::Type.type(:mount).new(:name => "yay", :ensure => :mounted) {:device => "/foo/bar", :blockdevice => "/other/bar", :target => "/what/ever", :fstype => 'eh', :options => "", :pass => 0, :dump => 0, :atboot => 0, :ensure => :mounted}.each do |param, value| @mount.provider.stubs(param).returns value @mount[param] = value end @mount.provider.stubs(:mounted?).returns true # stub this to not try to create state.yaml Puppet::Util::Storage.stubs(:store) @catalog = Puppet::Resource::Catalog.new @catalog.add_resource @mount end it "should use the provider to change the dump value" do @mount.provider.expects(:dump).returns 0 @mount.provider.expects(:dump=).with(1) @mount[:dump] = 1 @catalog.apply end it "should umount before flushing changes to disk" do syncorder = sequence('syncorder') @mount.provider.expects(:options).returns 'soft' @mount.provider.expects(:ensure).returns :mounted @mount.provider.expects(:unmount).in_sequence(syncorder) @mount.provider.expects(:options=).in_sequence(syncorder).with 'hard' @mount.expects(:flush).in_sequence(syncorder) # Call inside syncothers @mount.expects(:flush).in_sequence(syncorder) # I guess transaction or anything calls flush again @mount[:ensure] = :unmounted @mount[:options] = 'hard' @catalog.apply end end diff --git a/spec/unit/type/nagios_spec.rb b/spec/unit/type/nagios_spec.rb index 63122b2c9..d650723c8 100755 --- a/spec/unit/type/nagios_spec.rb +++ b/spec/unit/type/nagios_spec.rb @@ -1,63 +1,62 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/external/nagios' describe "Nagios resource types" do Nagios::Base.eachtype do |name, nagios_type| puppet_type = Puppet::Type.type("nagios_#{name}") it "should have a valid type for #{name}" do puppet_type.should_not be_nil end next unless puppet_type describe puppet_type do it "should be defined as a Puppet resource type" do puppet_type.should_not be_nil end it "should have documentation" do puppet_type.instance_variable_get("@doc").should_not == "" end it "should have #{nagios_type.namevar} as its key attribute" do puppet_type.key_attributes.should == [nagios_type.namevar] end it "should have documentation for its #{nagios_type.namevar} parameter" do puppet_type.attrclass(nagios_type.namevar).instance_variable_get("@doc").should_not be_nil end it "should have an ensure property" do puppet_type.should be_validproperty(:ensure) end it "should have a target property" do puppet_type.should be_validproperty(:target) end it "should have documentation for its target property" do puppet_type.attrclass(:target).instance_variable_get("@doc").should_not be_nil end nagios_type.parameters.reject { |param| param == nagios_type.namevar or param.to_s =~ /^[0-9]/ }.each do |param| it "should have a #{param} property" do puppet_type.should be_validproperty(param) end it "should have documentation for its #{param} property" do puppet_type.attrclass(param).instance_variable_get("@doc").should_not be_nil end end nagios_type.parameters.find_all { |param| param.to_s =~ /^[0-9]/ }.each do |param| it "should have not have a #{param} property" do puppet_type.should_not be_validproperty(:param) end end end end end diff --git a/spec/unit/type/noop_metaparam_spec.rb b/spec/unit/type/noop_metaparam_spec.rb index 5c1a9853a..f4241d417 100755 --- a/spec/unit/type/noop_metaparam_spec.rb +++ b/spec/unit/type/noop_metaparam_spec.rb @@ -1,37 +1,36 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/type' describe Puppet::Type.type(:file).attrclass(:noop) do before do Puppet.settings.stubs(:use) @file = Puppet::Type.newfile :path => "/what/ever" end it "should accept true as a value" do lambda { @file[:noop] = true }.should_not raise_error end it "should accept false as a value" do lambda { @file[:noop] = false }.should_not raise_error end describe "when set on a resource" do it "should default to the :noop setting" do Puppet.settings.expects(:value).with(:noop).returns "myval" @file.noop.should == "myval" end it "should prefer true values from the attribute" do @file[:noop] = true @file.noop.should be_true end it "should prefer false values from the attribute" do @file[:noop] = false @file.noop.should be_false end end end diff --git a/spec/unit/type/package_spec.rb b/spec/unit/type/package_spec.rb index f3b9e6ac5..e75f7d290 100755 --- a/spec/unit/type/package_spec.rb +++ b/spec/unit/type/package_spec.rb @@ -1,240 +1,239 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe Puppet::Type.type(:package) do before do Puppet::Util::Storage.stubs(:store) end it "should have an :installable feature that requires the :install method" do Puppet::Type.type(:package).provider_feature(:installable).methods.should == [:install] end it "should have an :uninstallable feature that requires the :uninstall method" do Puppet::Type.type(:package).provider_feature(:uninstallable).methods.should == [:uninstall] end it "should have an :upgradeable feature that requires :update and :latest methods" do Puppet::Type.type(:package).provider_feature(:upgradeable).methods.should == [:update, :latest] end it "should have a :purgeable feature that requires the :purge latest method" do Puppet::Type.type(:package).provider_feature(:purgeable).methods.should == [:purge] end it "should have a :versionable feature" do Puppet::Type.type(:package).provider_feature(:versionable).should_not be_nil end it "should default to being installed" do pkg = Puppet::Type.type(:package).new(:name => "yay") pkg.should(:ensure).should == :present end describe "when validating attributes" do [:name, :source, :instance, :status, :adminfile, :responsefile, :configfiles, :category, :platform, :root, :vendor, :description, :allowcdrom].each do |param| it "should have a #{param} parameter" do Puppet::Type.type(:package).attrtype(param).should == :param end end it "should have an ensure property" do Puppet::Type.type(:package).attrtype(:ensure).should == :property end end describe "when validating attribute values" do before do @provider = stub 'provider', :class => Puppet::Type.type(:package).defaultprovider, :clear => nil Puppet::Type.type(:package).defaultprovider.expects(:new).returns(@provider) end it "should support :present as a value to :ensure" do Puppet::Type.type(:package).new(:name => "yay", :ensure => :present) end it "should alias :installed to :present as a value to :ensure" do pkg = Puppet::Type.type(:package).new(:name => "yay", :ensure => :installed) pkg.should(:ensure).should == :present end it "should support :absent as a value to :ensure" do Puppet::Type.type(:package).new(:name => "yay", :ensure => :absent) end it "should support :purged as a value to :ensure if the provider has the :purgeable feature" do @provider.expects(:satisfies?).with([:purgeable]).returns(true) Puppet::Type.type(:package).new(:name => "yay", :ensure => :purged) end it "should not support :purged as a value to :ensure if the provider does not have the :purgeable feature" do @provider.expects(:satisfies?).with([:purgeable]).returns(false) proc { Puppet::Type.type(:package).new(:name => "yay", :ensure => :purged) }.should raise_error(Puppet::Error) end it "should support :latest as a value to :ensure if the provider has the :upgradeable feature" do @provider.expects(:satisfies?).with([:upgradeable]).returns(true) Puppet::Type.type(:package).new(:name => "yay", :ensure => :latest) end it "should not support :latest as a value to :ensure if the provider does not have the :upgradeable feature" do @provider.expects(:satisfies?).with([:upgradeable]).returns(false) proc { Puppet::Type.type(:package).new(:name => "yay", :ensure => :latest) }.should raise_error(Puppet::Error) end it "should support version numbers as a value to :ensure if the provider has the :versionable feature" do @provider.expects(:satisfies?).with([:versionable]).returns(true) Puppet::Type.type(:package).new(:name => "yay", :ensure => "1.0") end it "should not support version numbers as a value to :ensure if the provider does not have the :versionable feature" do @provider.expects(:satisfies?).with([:versionable]).returns(false) proc { Puppet::Type.type(:package).new(:name => "yay", :ensure => "1.0") }.should raise_error(Puppet::Error) end it "should accept any string as an argument to :source" do proc { Puppet::Type.type(:package).new(:name => "yay", :source => "stuff") }.should_not raise_error(Puppet::Error) end end module PackageEvaluationTesting def setprops(properties) @provider.stubs(:properties).returns(properties) end end describe Puppet::Type.type(:package) do before :each do @provider = stub 'provider', :class => Puppet::Type.type(:package).defaultprovider, :clear => nil, :satisfies? => true, :name => :mock Puppet::Type.type(:package).defaultprovider.stubs(:new).returns(@provider) Puppet::Type.type(:package).defaultprovider.stubs(:instances).returns([]) @package = Puppet::Type.type(:package).new(:name => "yay") @catalog = Puppet::Resource::Catalog.new @catalog.add_resource(@package) end describe Puppet::Type.type(:package), "when it should be purged" do include PackageEvaluationTesting before { @package[:ensure] = :purged } it "should do nothing if it is :purged" do @provider.expects(:properties).returns(:ensure => :purged).at_least_once @catalog.apply end [:absent, :installed, :present, :latest].each do |state| it "should purge if it is #{state.to_s}" do @provider.stubs(:properties).returns(:ensure => state) @provider.expects(:purge) @catalog.apply end end end describe Puppet::Type.type(:package), "when it should be absent" do include PackageEvaluationTesting before { @package[:ensure] = :absent } [:purged, :absent].each do |state| it "should do nothing if it is #{state.to_s}" do @provider.expects(:properties).returns(:ensure => state).at_least_once @catalog.apply end end [:installed, :present, :latest].each do |state| it "should uninstall if it is #{state.to_s}" do @provider.stubs(:properties).returns(:ensure => state) @provider.expects(:uninstall) @catalog.apply end end end describe Puppet::Type.type(:package), "when it should be present" do include PackageEvaluationTesting before { @package[:ensure] = :present } [:present, :latest, "1.0"].each do |state| it "should do nothing if it is #{state.to_s}" do @provider.expects(:properties).returns(:ensure => state).at_least_once @catalog.apply end end [:purged, :absent].each do |state| it "should install if it is #{state.to_s}" do @provider.stubs(:properties).returns(:ensure => state) @provider.expects(:install) @catalog.apply end end end describe Puppet::Type.type(:package), "when it should be latest" do include PackageEvaluationTesting before { @package[:ensure] = :latest } [:purged, :absent].each do |state| it "should upgrade if it is #{state.to_s}" do @provider.stubs(:properties).returns(:ensure => state) @provider.expects(:update) @catalog.apply end end it "should upgrade if the current version is not equal to the latest version" do @provider.stubs(:properties).returns(:ensure => "1.0") @provider.stubs(:latest).returns("2.0") @provider.expects(:update) @catalog.apply end it "should do nothing if it is equal to the latest version" do @provider.stubs(:properties).returns(:ensure => "1.0") @provider.stubs(:latest).returns("1.0") @provider.expects(:update).never @catalog.apply end it "should do nothing if the provider returns :present as the latest version" do @provider.stubs(:properties).returns(:ensure => :present) @provider.stubs(:latest).returns("1.0") @provider.expects(:update).never @catalog.apply end end describe Puppet::Type.type(:package), "when it should be a specific version" do include PackageEvaluationTesting before { @package[:ensure] = "1.0" } [:purged, :absent].each do |state| it "should install if it is #{state.to_s}" do @provider.stubs(:properties).returns(:ensure => state) @provider.expects(:install) @catalog.apply end end it "should do nothing if the current version is equal to the desired version" do @provider.stubs(:properties).returns(:ensure => "1.0") @provider.expects(:install).never @catalog.apply end it "should install if the current version is not equal to the specified version" do @provider.stubs(:properties).returns(:ensure => "2.0") @provider.expects(:install) @catalog.apply end end end end diff --git a/spec/unit/type/resources_spec.rb b/spec/unit/type/resources_spec.rb index 9e1f09588..aedc58c7c 100755 --- a/spec/unit/type/resources_spec.rb +++ b/spec/unit/type/resources_spec.rb @@ -1,102 +1,101 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' resources = Puppet::Type.type(:resources) # There are still plenty of tests to port over from test/. describe resources do describe "when initializing" do it "should fail if the specified resource type does not exist" do Puppet::Type.stubs(:type).with { |x| x.to_s.downcase == "resources"}.returns resources Puppet::Type.expects(:type).with("nosuchtype").returns nil lambda { resources.new :name => "nosuchtype" }.should raise_error(Puppet::Error) end it "should not fail when the specified resource type exists" do lambda { resources.new :name => "file" }.should_not raise_error end it "should set its :resource_type attribute" do resources.new(:name => "file").resource_type.should == Puppet::Type.type(:file) end end describe "#generate" do before do @host1 = Puppet::Type.type(:host).new(:name => 'localhost', :ip => '127.0.0.1') @catalog = Puppet::Resource::Catalog.new @context = Puppet::Transaction.new(@catalog) end describe "when dealing with non-purging resources" do before do @resources = Puppet::Type.type(:resources).new(:name => 'host') end it "should not generate any resource" do @resources.generate.should be_empty end end describe "when the catalog contains a purging resource" do before do @resources = Puppet::Type.type(:resources).new(:name => 'host', :purge => true) @purgeable_resource = Puppet::Type.type(:host).new(:name => 'localhost', :ip => '127.0.0.1') @catalog.add_resource @resources end it "should not generate a duplicate of that resource" do Puppet::Type.type(:host).stubs(:instances).returns [@host1] @catalog.add_resource @host1 @resources.generate.collect { |r| r.ref }.should_not include(@host1.ref) end it "should not include the skipped users" do res = Puppet::Type.type(:resources).new :name => :user, :purge => true res.catalog = Puppet::Resource::Catalog.new users = [ Puppet::Type.type(:user).new(:name => "root") ] Puppet::Type.type(:user).expects(:instances).returns users list = res.generate names = list.collect { |r| r[:name] } names.should_not be_include("root") end describe "when generating a purgeable resource" do it "should be included in the generated resources" do Puppet::Type.type(:host).stubs(:instances).returns [@purgeable_resource] @resources.generate.collect { |r| r.ref }.should include(@purgeable_resource.ref) end end describe "when the instance's do not have an ensure property" do it "should not be included in the generated resources" do @no_ensure_resource = Puppet::Type.type(:exec).new(:name => '/usr/bin/env echo') Puppet::Type.type(:host).stubs(:instances).returns [@no_ensure_resource] @resources.generate.collect { |r| r.ref }.should_not include(@no_ensure_resource.ref) end end describe "when the instance's ensure property does not accept absent" do it "should not be included in the generated resources" do @no_absent_resource = Puppet::Type.type(:service).new(:name => 'foobar') Puppet::Type.type(:host).stubs(:instances).returns [@no_absent_resource] @resources.generate.collect { |r| r.ref }.should_not include(@no_absent_resource.ref) end end describe "when checking the instance fails" do it "should not be included in the generated resources" do @purgeable_resource = Puppet::Type.type(:host).new(:name => 'foobar') Puppet::Type.type(:host).stubs(:instances).returns [@purgeable_resource] @resources.expects(:check).with(@purgeable_resource).returns(false) @resources.generate.collect { |r| r.ref }.should_not include(@purgeable_resource.ref) end end end end end diff --git a/spec/unit/type/schedule_spec.rb b/spec/unit/type/schedule_spec.rb index c4189d410..7599411e4 100755 --- a/spec/unit/type/schedule_spec.rb +++ b/spec/unit/type/schedule_spec.rb @@ -1,305 +1,304 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' module ScheduleTesting def format(time) time.strftime("%H:%M:%S") end def diff(unit, incr, method, count) diff = Time.now.to_i.send(method, incr * count) Time.at(diff) end def day(method, count) diff(:hour, 3600 * 24, method, count) end def hour(method, count) diff(:hour, 3600, method, count) end def min(method, count) diff(:min, 60, method, count) end end describe Puppet::Type.type(:schedule) do before :each do Puppet[:ignoreschedules] = false @schedule = Puppet::Type.type(:schedule).new(:name => "testing") end describe Puppet::Type.type(:schedule) do include ScheduleTesting it "should default to :distance for period-matching" do @schedule[:periodmatch].should == :distance end it "should default to a :repeat of 1" do @schedule[:repeat].should == 1 end it "should never match when the period is :never" do @schedule[:period] = :never @schedule.match?.should be_false end end describe Puppet::Type.type(:schedule), "when producing default schedules" do include ScheduleTesting %w{hourly daily weekly monthly never}.each do |period| period = period.to_sym it "should produce a #{period} schedule with the period set appropriately" do schedules = Puppet::Type.type(:schedule).mkdefaultschedules schedules.find { |s| s[:name] == period.to_s and s[:period] == period }.should be_instance_of(Puppet::Type.type(:schedule)) end end it "should produce a schedule named puppet with a period of hourly and a repeat of 2" do schedules = Puppet::Type.type(:schedule).mkdefaultschedules schedules.find { |s| s[:name] == "puppet" and s[:period] == :hourly and s[:repeat] == 2 }.should be_instance_of(Puppet::Type.type(:schedule)) end end describe Puppet::Type.type(:schedule), "when matching ranges" do include ScheduleTesting it "should match when the start time is before the current time and the end time is after the current time" do @schedule[:range] = "#{format(Time.now - 10)} - #{format(Time.now + 10)}" @schedule.match?.should be_true end it "should not match when the start time is after the current time" do @schedule[:range] = "#{format(Time.now + 5)} - #{format(Time.now + 10)}" @schedule.match?.should be_false end it "should not match when the end time is previous to the current time" do @schedule[:range] = "#{format(Time.now - 10)} - #{format(Time.now - 5)}" @schedule.match?.should be_false end end describe Puppet::Type.type(:schedule), "when matching hourly by distance" do include ScheduleTesting before do @schedule[:period] = :hourly @schedule[:periodmatch] = :distance end it "should match an hour ago" do @schedule.match?(hour("-", 1)).should be_true end it "should not match now" do @schedule.match?(Time.now).should be_false end it "should not match 59 minutes ago" do @schedule.match?(min("-", 59)).should be_false end end describe Puppet::Type.type(:schedule), "when matching daily by distance" do include ScheduleTesting before do @schedule[:period] = :daily @schedule[:periodmatch] = :distance end it "should match when the previous time was one day ago" do @schedule.match?(day("-", 1)).should be_true end it "should not match when the previous time is now" do @schedule.match?(Time.now).should be_false end it "should not match when the previous time was 23 hours ago" do @schedule.match?(hour("-", 23)).should be_false end end describe Puppet::Type.type(:schedule), "when matching weekly by distance" do include ScheduleTesting before do @schedule[:period] = :weekly @schedule[:periodmatch] = :distance end it "should match seven days ago" do @schedule.match?(day("-", 7)).should be_true end it "should not match now" do @schedule.match?(Time.now).should be_false end it "should not match six days ago" do @schedule.match?(day("-", 6)).should be_false end end describe Puppet::Type.type(:schedule), "when matching monthly by distance" do include ScheduleTesting before do @schedule[:period] = :monthly @schedule[:periodmatch] = :distance end it "should match 32 days ago" do @schedule.match?(day("-", 32)).should be_true end it "should not match now" do @schedule.match?(Time.now).should be_false end it "should not match 27 days ago" do @schedule.match?(day("-", 27)).should be_false end end describe Puppet::Type.type(:schedule), "when matching hourly by number" do include ScheduleTesting before do @schedule[:period] = :hourly @schedule[:periodmatch] = :number end it "should match if the times are one minute apart and the current minute is 0" do current = Time.utc(2008, 1, 1, 0, 0, 0) previous = Time.utc(2007, 12, 31, 23, 59, 0) Time.stubs(:now).returns(current) @schedule.match?(previous).should be_true end it "should not match if the times are 59 minutes apart and the current minute is 59" do current = Time.utc(2009, 2, 1, 12, 59, 0) previous = Time.utc(2009, 2, 1, 12, 0, 0) Time.stubs(:now).returns(current) @schedule.match?(previous).should be_false end end describe Puppet::Type.type(:schedule), "when matching daily by number" do include ScheduleTesting before do @schedule[:period] = :daily @schedule[:periodmatch] = :number end it "should match if the times are one minute apart and the current minute and hour are 0" do current = Time.utc(2010, "nov", 7, 0, 0, 0) # Now set the previous time to one minute before that previous = current - 60 Time.stubs(:now).returns(current) @schedule.match?(previous).should be_true end it "should not match if the times are 23 hours and 58 minutes apart and the current hour is 23 and the current minute is 59" do # Reset the previous time to 00:00:00 previous = Time.utc(2010, "nov", 7, 0, 0, 0) # Set the current time to 23:59 now = previous + (23 * 3600) + (59 * 60) Time.stubs(:now).returns(now) @schedule.match?(previous).should be_false end end describe Puppet::Type.type(:schedule), "when matching weekly by number" do include ScheduleTesting before do @schedule[:period] = :weekly @schedule[:periodmatch] = :number end it "should match if the previous time is prior to the most recent Sunday" do now = Time.utc(2010, "nov", 11, 0, 0, 0) # Thursday Time.stubs(:now).returns(now) previous = Time.utc(2010, "nov", 6, 23, 59, 59) # Sat @schedule.match?(previous).should be_true end it "should not match if the previous time is after the most recent Saturday" do now = Time.utc(2010, "nov", 11, 0, 0, 0) # Thursday Time.stubs(:now).returns(now) previous = Time.utc(2010, "nov", 7, 0, 0, 0) # Sunday @schedule.match?(previous).should be_false end end describe Puppet::Type.type(:schedule), "when matching monthly by number" do include ScheduleTesting before do @schedule[:period] = :monthly @schedule[:periodmatch] = :number end it "should match when the previous time is prior to the first day of this month" do now = Time.utc(2010, "nov", 8, 00, 59, 59) Time.stubs(:now).returns(now) previous = Time.utc(2010, "oct", 31, 23, 59, 59) @schedule.match?(previous).should be_true end it "should not match when the previous time is after the last day of last month" do now = Time.utc(2010, "nov", 8, 00, 59, 59) Time.stubs(:now).returns(now) previous = Time.utc(2010, "nov", 1, 0, 0, 0) @schedule.match?(previous).should be_false end end describe Puppet::Type.type(:schedule), "when matching with a repeat greater than one" do include ScheduleTesting before do @schedule[:period] = :daily @schedule[:repeat] = 2 end it "should fail if the periodmatch is 'number'" do @schedule[:periodmatch] = :number proc { @schedule[:repeat] = 2 }.should raise_error(Puppet::Error) end it "should match if the previous run was further away than the distance divided by the repeat" do previous = Time.now - (3600 * 13) @schedule.match?(previous).should be_true end it "should not match if the previous run was closer than the distance divided by the repeat" do previous = Time.now - (3600 * 11) @schedule.match?(previous).should be_false end end end diff --git a/spec/unit/type/selboolean_spec.rb b/spec/unit/type/selboolean_spec.rb index a64724432..aa495af4a 100755 --- a/spec/unit/type/selboolean_spec.rb +++ b/spec/unit/type/selboolean_spec.rb @@ -1,45 +1,44 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe Puppet::Type.type(:selboolean), "when validating attributes" do [:name, :persistent].each do |param| it "should have a #{param} parameter" do Puppet::Type.type(:selboolean).attrtype(param).should == :param end end it "should have a value property" do Puppet::Type.type(:selboolean).attrtype(:value).should == :property end end describe Puppet::Type.type(:selboolean), "when validating values" do before do @class = Puppet::Type.type(:selboolean) @provider_class = stub 'provider_class', :name => "fake", :suitable? => true, :supports_parameter? => true @class.stubs(:defaultprovider).returns(@provider_class) @class.stubs(:provider).returns(@provider_class) @provider = stub 'provider', :class => @provider_class, :clear => nil @provider_class.stubs(:new).returns(@provider) end it "should support :on as a value to :value" do Puppet::Type.type(:selboolean).new(:name => "yay", :value => :on) end it "should support :off as a value to :value" do Puppet::Type.type(:selboolean).new(:name => "yay", :value => :off) end it "should support :true as a value to :persistent" do Puppet::Type.type(:selboolean).new(:name => "yay", :value => :on, :persistent => :true) end it "should support :false as a value to :persistent" do Puppet::Type.type(:selboolean).new(:name => "yay", :value => :on, :persistent => :false) end end diff --git a/spec/unit/type/selmodule_spec.rb b/spec/unit/type/selmodule_spec.rb index a9e193f3e..c067de01d 100755 --- a/spec/unit/type/selmodule_spec.rb +++ b/spec/unit/type/selmodule_spec.rb @@ -1,18 +1,17 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe Puppet::Type.type(:selmodule), "when validating attributes" do [:name, :selmoduledir, :selmodulepath].each do |param| it "should have a #{param} parameter" do Puppet::Type.type(:selmodule).attrtype(param).should == :param end end [:ensure, :syncversion].each do |param| it "should have a #{param} property" do Puppet::Type.type(:selmodule).attrtype(param).should == :property end end end diff --git a/spec/unit/type/service_spec.rb b/spec/unit/type/service_spec.rb index 3391f704c..40270e7c8 100755 --- a/spec/unit/type/service_spec.rb +++ b/spec/unit/type/service_spec.rb @@ -1,234 +1,233 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe Puppet::Type.type(:service) do it "should have an :enableable feature that requires the :enable, :disable, and :enabled? methods" do Puppet::Type.type(:service).provider_feature(:enableable).methods.should == [:disable, :enable, :enabled?] end it "should have a :refreshable feature that requires the :restart method" do Puppet::Type.type(:service).provider_feature(:refreshable).methods.should == [:restart] end end describe Puppet::Type.type(:service), "when validating attributes" do [:name, :binary, :hasstatus, :path, :pattern, :start, :restart, :stop, :status, :hasrestart, :control].each do |param| it "should have a #{param} parameter" do Puppet::Type.type(:service).attrtype(param).should == :param end end [:ensure, :enable].each do |param| it "should have an #{param} property" do Puppet::Type.type(:service).attrtype(param).should == :property end end end describe Puppet::Type.type(:service), "when validating attribute values" do before do @provider = stub 'provider', :class => Puppet::Type.type(:service).defaultprovider, :clear => nil, :controllable? => false Puppet::Type.type(:service).defaultprovider.stubs(:new).returns(@provider) end it "should support :running as a value to :ensure" do Puppet::Type.type(:service).new(:name => "yay", :ensure => :running) end it "should support :stopped as a value to :ensure" do Puppet::Type.type(:service).new(:name => "yay", :ensure => :stopped) end it "should alias the value :true to :running in :ensure" do svc = Puppet::Type.type(:service).new(:name => "yay", :ensure => true) svc.should(:ensure).should == :running end it "should alias the value :false to :stopped in :ensure" do svc = Puppet::Type.type(:service).new(:name => "yay", :ensure => false) svc.should(:ensure).should == :stopped end it "should support :true as a value to :enable" do Puppet::Type.type(:service).new(:name => "yay", :enable => :true) end it "should support :false as a value to :enable" do Puppet::Type.type(:service).new(:name => "yay", :enable => :false) end it "should support :true as a value to :hasstatus" do Puppet::Type.type(:service).new(:name => "yay", :hasstatus => :true) end it "should support :false as a value to :hasstatus" do Puppet::Type.type(:service).new(:name => "yay", :hasstatus => :false) end it "should specify :true as the default value of hasstatus" do Puppet::Type.type(:service).new(:name => "yay")[:hasstatus].should == :true end it "should support :true as a value to :hasrestart" do Puppet::Type.type(:service).new(:name => "yay", :hasrestart => :true) end it "should support :false as a value to :hasrestart" do Puppet::Type.type(:service).new(:name => "yay", :hasrestart => :false) end it "should allow setting the :enable parameter if the provider has the :enableable feature" do Puppet::Type.type(:service).defaultprovider.stubs(:supports_parameter?).returns(true) Puppet::Type.type(:service).defaultprovider.expects(:supports_parameter?).with(Puppet::Type.type(:service).attrclass(:enable)).returns(true) svc = Puppet::Type.type(:service).new(:name => "yay", :enable => true) svc.should(:enable).should == :true end it "should not allow setting the :enable parameter if the provider is missing the :enableable feature" do Puppet::Type.type(:service).defaultprovider.stubs(:supports_parameter?).returns(true) Puppet::Type.type(:service).defaultprovider.expects(:supports_parameter?).with(Puppet::Type.type(:service).attrclass(:enable)).returns(false) svc = Puppet::Type.type(:service).new(:name => "yay", :enable => true) svc.should(:enable).should be_nil end it "should split paths on ':'" do FileTest.stubs(:exist?).returns(true) FileTest.stubs(:directory?).returns(true) svc = Puppet::Type.type(:service).new(:name => "yay", :path => "/one/two:/three/four") svc[:path].should == %w{/one/two /three/four} end it "should accept arrays of paths joined by ':'" do FileTest.stubs(:exist?).returns(true) FileTest.stubs(:directory?).returns(true) svc = Puppet::Type.type(:service).new(:name => "yay", :path => ["/one:/two", "/three:/four"]) svc[:path].should == %w{/one /two /three /four} end end describe Puppet::Type.type(:service), "when setting default attribute values" do it "should default to the provider's default path if one is available" do FileTest.stubs(:directory?).returns(true) FileTest.stubs(:exist?).returns(true) Puppet::Type.type(:service).defaultprovider.stubs(:respond_to?).returns(true) Puppet::Type.type(:service).defaultprovider.stubs(:defpath).returns("testing") svc = Puppet::Type.type(:service).new(:name => "other") svc[:path].should == ["testing"] end it "should default 'pattern' to the binary if one is provided" do svc = Puppet::Type.type(:service).new(:name => "other", :binary => "/some/binary") svc[:pattern].should == "/some/binary" end it "should default 'pattern' to the name if no pattern is provided" do svc = Puppet::Type.type(:service).new(:name => "other") svc[:pattern].should == "other" end it "should default 'control' to the upcased service name with periods replaced by underscores if the provider supports the 'controllable' feature" do provider = stub 'provider', :controllable? => true, :class => Puppet::Type.type(:service).defaultprovider, :clear => nil Puppet::Type.type(:service).defaultprovider.stubs(:new).returns(provider) svc = Puppet::Type.type(:service).new(:name => "nfs.client") svc[:control].should == "NFS_CLIENT_START" end end describe Puppet::Type.type(:service), "when retrieving the host's current state" do before do @service = Puppet::Type.type(:service).new(:name => "yay") end it "should use the provider's status to determine whether the service is running" do @service.provider.expects(:status).returns(:yepper) @service[:ensure] = :running @service.property(:ensure).retrieve.should == :yepper end it "should ask the provider whether it is enabled" do @service.provider.class.stubs(:supports_parameter?).returns(true) @service.provider.expects(:enabled?).returns(:yepper) @service[:enable] = true @service.property(:enable).retrieve.should == :yepper end end describe Puppet::Type.type(:service), "when changing the host" do before do @service = Puppet::Type.type(:service).new(:name => "yay") end it "should start the service if it is supposed to be running" do @service[:ensure] = :running @service.provider.expects(:start) @service.property(:ensure).sync end it "should stop the service if it is supposed to be stopped" do @service[:ensure] = :stopped @service.provider.expects(:stop) @service.property(:ensure).sync end it "should enable the service if it is supposed to be enabled" do @service.provider.class.stubs(:supports_parameter?).returns(true) @service[:enable] = true @service.provider.expects(:enable) @service.property(:enable).sync end it "should disable the service if it is supposed to be disabled" do @service.provider.class.stubs(:supports_parameter?).returns(true) @service[:enable] = false @service.provider.expects(:disable) @service.property(:enable).sync end it "should sync the service's enable state when changing the state of :ensure if :enable is being managed" do @service.provider.class.stubs(:supports_parameter?).returns(true) @service[:enable] = false @service[:ensure] = :stopped @service.property(:enable).expects(:retrieve).returns("whatever") @service.property(:enable).expects(:insync?).returns(false) @service.property(:enable).expects(:sync) @service.provider.stubs(:stop) @service.property(:ensure).sync end end describe Puppet::Type.type(:service), "when refreshing the service" do before do @service = Puppet::Type.type(:service).new(:name => "yay") end it "should restart the service if it is running" do @service[:ensure] = :running @service.provider.expects(:status).returns(:running) @service.provider.expects(:restart) @service.refresh end it "should restart the service if it is running, even if it is supposed to stopped" do @service[:ensure] = :stopped @service.provider.expects(:status).returns(:running) @service.provider.expects(:restart) @service.refresh end it "should not restart the service if it is not running" do @service[:ensure] = :running @service.provider.expects(:status).returns(:stopped) @service.refresh end it "should add :ensure as a property if it is not being managed" do @service.provider.expects(:status).returns(:running) @service.provider.expects(:restart) @service.refresh end end diff --git a/spec/unit/type/ssh_authorized_key_spec.rb b/spec/unit/type/ssh_authorized_key_spec.rb index 7cbf44c28..a5f167165 100755 --- a/spec/unit/type/ssh_authorized_key_spec.rb +++ b/spec/unit/type/ssh_authorized_key_spec.rb @@ -1,152 +1,151 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' ssh_authorized_key = Puppet::Type.type(:ssh_authorized_key) describe ssh_authorized_key do before do @class = Puppet::Type.type(:ssh_authorized_key) @provider_class = stub 'provider_class', :name => "fake", :suitable? => true, :supports_parameter? => true @class.stubs(:defaultprovider).returns(@provider_class) @class.stubs(:provider).returns(@provider_class) @provider = stub 'provider', :class => @provider_class, :file_path => "/tmp/whatever", :clear => nil @provider_class.stubs(:new).returns(@provider) @catalog = Puppet::Resource::Catalog.new end it "should have a name parameter" do @class.attrtype(:name).should == :param end it "should have :name be its namevar" do @class.key_attributes.should == [:name] end it "should have a :provider parameter" do @class.attrtype(:provider).should == :param end it "should have an ensure property" do @class.attrtype(:ensure).should == :property end it "should support :present as a value for :ensure" do proc { @class.new(:name => "whev", :ensure => :present, :user => "nobody") }.should_not raise_error end it "should support :absent as a value for :ensure" do proc { @class.new(:name => "whev", :ensure => :absent, :user => "nobody") }.should_not raise_error end it "should have an type property" do @class.attrtype(:type).should == :property end it "should support ssh-dss as an type value" do proc { @class.new(:name => "whev", :type => "ssh-dss", :user => "nobody") }.should_not raise_error end it "should support ssh-rsa as an type value" do proc { @class.new(:name => "whev", :type => "ssh-rsa", :user => "nobody") }.should_not raise_error end it "should support :dsa as an type value" do proc { @class.new(:name => "whev", :type => :dsa, :user => "nobody") }.should_not raise_error end it "should support :rsa as an type value" do proc { @class.new(:name => "whev", :type => :rsa, :user => "nobody") }.should_not raise_error end it "should not support values other than ssh-dss, ssh-rsa, dsa, rsa in the ssh_authorized_key_type" do proc { @class.new(:name => "whev", :type => :something) }.should raise_error(Puppet::Error) end it "should have an key property" do @class.attrtype(:key).should == :property end it "should have an user property" do @class.attrtype(:user).should == :property end it "should have an options property" do @class.attrtype(:options).should == :property end it "'s options property should return well formed string of arrays from is_to_s" do resource = @class.new(:name => "whev", :type => :rsa, :user => "nobody", :options => ["a","b","c"]) resource.property(:options).is_to_s(["a","b","c"]).should == "a,b,c" end it "'s options property should return well formed string of arrays from is_to_s" do resource = @class.new(:name => "whev", :type => :rsa, :user => "nobody", :options => ["a","b","c"]) resource.property(:options).should_to_s(["a","b","c"]).should == "a,b,c" end it "should have a target property" do @class.attrtype(:target).should == :property end describe "when neither user nor target is specified" do it "should raise an error" do proc do @class.create( :name => "Test", :key => "AAA", :type => "ssh-rsa", :ensure => :present) end.should raise_error(Puppet::Error) end end describe "when both target and user are specified" do it "should use target" do resource = @class.create( :name => "Test", :user => "root", :target => "/tmp/blah") resource.should(:target).should == "/tmp/blah" end end describe "when user is specified" do it "should determine target" do resource = @class.create( :name => "Test", :user => "root") target = File.expand_path("~root/.ssh/authorized_keys") resource.should(:target).should == target end # Bug #2124 - ssh_authorized_key always changes target if target is not defined it "should not raise spurious change events" do resource = @class.new(:name => "Test", :user => "root") target = File.expand_path("~root/.ssh/authorized_keys") resource.property(:target).safe_insync?(target).should == true end end describe "when calling validate" do it "should not crash on a non-existant user" do resource = @class.create( :name => "Test", :user => "ihopesuchuserdoesnotexist") proc { resource.validate }.should_not raise_error end end end diff --git a/spec/unit/type/sshkey_spec.rb b/spec/unit/type/sshkey_spec.rb index d476e1908..ba3406976 100755 --- a/spec/unit/type/sshkey_spec.rb +++ b/spec/unit/type/sshkey_spec.rb @@ -1,71 +1,70 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' sshkey = Puppet::Type.type(:sshkey) describe sshkey do before do @class = sshkey end it "should have :name its namevar" do @class.key_attributes.should == [:name] end describe "when validating attributes" do [:name, :provider].each do |param| it "should have a #{param} parameter" do @class.attrtype(param).should == :param end end [:host_aliases, :ensure, :key, :type].each do |property| it "should have a #{property} property" do @class.attrtype(property).should == :property end end end describe "when validating values" do it "should support ssh-dss as a type value" do proc { @class.new(:name => "foo", :type => "ssh-dss") }.should_not raise_error end it "should support ssh-rsa as a type value" do proc { @class.new(:name => "whev", :type => "ssh-rsa") }.should_not raise_error end it "should alias :dsa to ssh-dss as a value for type" do key = @class.new(:name => "whev", :type => :dsa) key.should(:type).should == :'ssh-dss' end it "should alias :rsa to ssh-rsa as a value for type" do key = @class.new(:name => "whev", :type => :rsa) key.should(:type).should == :'ssh-rsa' end it "should not support values other than ssh-dss, ssh-rsa, dsa, rsa for type" do proc { @class.new(:name => "whev", :type => :'ssh-dsa') }.should raise_error(Puppet::Error) end it "should accept one host_alias" do proc { @class.new(:name => "foo", :host_aliases => 'foo.bar.tld') }.should_not raise_error end it "should accept multiple host_aliases as an array" do proc { @class.new(:name => "foo", :host_aliases => ['foo.bar.tld','10.0.9.9']) }.should_not raise_error end it "should not accept spaces in any host_alias" do proc { @class.new(:name => "foo", :host_aliases => ['foo.bar.tld','foo bar']) }.should raise_error(Puppet::Error) end it "should not accept aliases in the resourcename" do proc { @class.new(:name => 'host,host.domain,ip') }.should raise_error(Puppet::Error) end end end diff --git a/spec/unit/type/stage_spec.rb b/spec/unit/type/stage_spec.rb index a43e4bffc..f5fed6c3c 100755 --- a/spec/unit/type/stage_spec.rb +++ b/spec/unit/type/stage_spec.rb @@ -1,9 +1,8 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe Puppet::Type.type(:stage) do it "should have a 'name' parameter'" do Puppet::Type.type(:stage).new(:name => :foo)[:name].should == :foo end end diff --git a/spec/unit/type/tidy_spec.rb b/spec/unit/type/tidy_spec.rb index dec1e189c..cb030634b 100755 --- a/spec/unit/type/tidy_spec.rb +++ b/spec/unit/type/tidy_spec.rb @@ -1,425 +1,424 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/file_bucket/dipper' tidy = Puppet::Type.type(:tidy) describe tidy do before do @basepath = Puppet.features.posix? ? "/what/ever" : "C:/tmp" Puppet.settings.stubs(:use) # for an unknown reason some of these specs fails when run individually # with a failed expectation on File.lstat in the autoloader. File.stubs(:lstat) end it "should use :lstat when stating a file" do resource = tidy.new :path => "/foo/bar", :age => "1d" stat = mock 'stat' File.expects(:lstat).with("/foo/bar").returns stat resource.stat("/foo/bar").should == stat end [:age, :size, :path, :matches, :type, :recurse, :rmdirs].each do |param| it "should have a #{param} parameter" do Puppet::Type.type(:tidy).attrclass(param).ancestors.should be_include(Puppet::Parameter) end it "should have documentation for its #{param} param" do Puppet::Type.type(:tidy).attrclass(param).doc.should be_instance_of(String) end end describe "when validating parameter values" do describe "for 'recurse'" do before do @tidy = Puppet::Type.type(:tidy).new :path => "/tmp", :age => "100d" end it "should allow 'true'" do lambda { @tidy[:recurse] = true }.should_not raise_error end it "should allow 'false'" do lambda { @tidy[:recurse] = false }.should_not raise_error end it "should allow integers" do lambda { @tidy[:recurse] = 10 }.should_not raise_error end it "should allow string representations of integers" do lambda { @tidy[:recurse] = "10" }.should_not raise_error end it "should allow 'inf'" do lambda { @tidy[:recurse] = "inf" }.should_not raise_error end it "should not allow arbitrary values" do lambda { @tidy[:recurse] = "whatever" }.should raise_error end end describe "for 'matches'" do before do @tidy = Puppet::Type.type(:tidy).new :path => "/tmp", :age => "100d" end it "should object if matches is given with recurse is not specified" do lambda { @tidy[:matches] = '*.doh' }.should raise_error end it "should object if matches is given and recurse is 0" do lambda { @tidy[:recurse] = 0; @tidy[:matches] = '*.doh' }.should raise_error end it "should object if matches is given and recurse is false" do lambda { @tidy[:recurse] = false; @tidy[:matches] = '*.doh' }.should raise_error end it "should not object if matches is given and recurse is > 0" do lambda { @tidy[:recurse] = 1; @tidy[:matches] = '*.doh' }.should_not raise_error end it "should not object if matches is given and recurse is true" do lambda { @tidy[:recurse] = true; @tidy[:matches] = '*.doh' }.should_not raise_error end end end describe "when matching files by age" do convertors = { :second => 1, :minute => 60 } convertors[:hour] = convertors[:minute] * 60 convertors[:day] = convertors[:hour] * 24 convertors[:week] = convertors[:day] * 7 convertors.each do |unit, multiple| it "should consider a #{unit} to be #{multiple} seconds" do @tidy = Puppet::Type.type(:tidy).new :path => @basepath, :age => "5#{unit.to_s[0..0]}" @tidy[:age].should == 5 * multiple end end end describe "when matching files by size" do convertors = { :b => 0, :kb => 1, :mb => 2, :gb => 3, :tb => 4 } convertors.each do |unit, multiple| it "should consider a #{unit} to be 1024^#{multiple} bytes" do @tidy = Puppet::Type.type(:tidy).new :path => @basepath, :size => "5#{unit}" total = 5 multiple.times { total *= 1024 } @tidy[:size].should == total end end end describe "when tidying" do before do @tidy = Puppet::Type.type(:tidy).new :path => @basepath @stat = stub 'stat', :ftype => "directory" File.stubs(:lstat).with(@basepath).returns @stat end describe "and generating files" do it "should set the backup on the file if backup is set on the tidy instance" do @tidy[:backup] = "whatever" Puppet::Type.type(:file).expects(:new).with { |args| args[:backup] == "whatever" } @tidy.mkfile(@basepath) end it "should set the file's path to the tidy's path" do Puppet::Type.type(:file).expects(:new).with { |args| args[:path] == @basepath } @tidy.mkfile(@basepath) end it "should configure the file for deletion" do Puppet::Type.type(:file).expects(:new).with { |args| args[:ensure] == :absent } @tidy.mkfile(@basepath) end it "should force deletion on the file" do Puppet::Type.type(:file).expects(:new).with { |args| args[:force] == true } @tidy.mkfile(@basepath) end it "should do nothing if the targeted file does not exist" do File.expects(:lstat).with(@basepath).raises Errno::ENOENT @tidy.generate.should == [] end end describe "and recursion is not used" do it "should generate a file resource if the file should be tidied" do @tidy.expects(:tidy?).with(@basepath).returns true file = Puppet::Type.type(:file).new(:path => @basepath+"/eh") @tidy.expects(:mkfile).with(@basepath).returns file @tidy.generate.should == [file] end it "should do nothing if the file should not be tidied" do @tidy.expects(:tidy?).with(@basepath).returns false @tidy.expects(:mkfile).never @tidy.generate.should == [] end end describe "and recursion is used" do before do @tidy[:recurse] = true Puppet::FileServing::Fileset.any_instance.stubs(:stat).returns mock("stat") @fileset = Puppet::FileServing::Fileset.new(@basepath) Puppet::FileServing::Fileset.stubs(:new).returns @fileset end it "should use a Fileset for infinite recursion" do Puppet::FileServing::Fileset.expects(:new).with(@basepath, :recurse => true).returns @fileset @fileset.expects(:files).returns %w{. one two} @tidy.stubs(:tidy?).returns false @tidy.generate end it "should use a Fileset for limited recursion" do @tidy[:recurse] = 42 Puppet::FileServing::Fileset.expects(:new).with(@basepath, :recurse => true, :recurselimit => 42).returns @fileset @fileset.expects(:files).returns %w{. one two} @tidy.stubs(:tidy?).returns false @tidy.generate end it "should generate a file resource for every file that should be tidied but not for files that should not be tidied" do @fileset.expects(:files).returns %w{. one two} @tidy.expects(:tidy?).with(@basepath).returns true @tidy.expects(:tidy?).with(@basepath+"/one").returns true @tidy.expects(:tidy?).with(@basepath+"/two").returns false file = Puppet::Type.type(:file).new(:path => @basepath+"/eh") @tidy.expects(:mkfile).with(@basepath).returns file @tidy.expects(:mkfile).with(@basepath+"/one").returns file @tidy.generate end end describe "and determining whether a file matches provided glob patterns" do before do @tidy = Puppet::Type.type(:tidy).new :path => @basepath, :recurse => 1 @tidy[:matches] = %w{*foo* *bar*} @stat = mock 'stat' @matcher = @tidy.parameter(:matches) end it "should always convert the globs to an array" do @matcher.value = "*foo*" @matcher.value.should == %w{*foo*} end it "should return true if any pattern matches the last part of the file" do @matcher.value = %w{*foo* *bar*} @matcher.must be_tidy("/file/yaybarness", @stat) end it "should return false if no pattern matches the last part of the file" do @matcher.value = %w{*foo* *bar*} @matcher.should_not be_tidy("/file/yayness", @stat) end end describe "and determining whether a file is too old" do before do @tidy = Puppet::Type.type(:tidy).new :path => @basepath @stat = stub 'stat' @tidy[:age] = "1s" @tidy[:type] = "mtime" @ager = @tidy.parameter(:age) end it "should use the age type specified" do @tidy[:type] = :ctime @stat.expects(:ctime).returns(Time.now) @ager.tidy?(@basepath, @stat) end it "should return false if the file is more recent than the specified age" do @stat.expects(:mtime).returns(Time.now) @ager.should_not be_tidy(@basepath, @stat) end it "should return true if the file is older than the specified age" do @stat.expects(:mtime).returns(Time.now - 10) @ager.must be_tidy(@basepath, @stat) end end describe "and determining whether a file is too large" do before do @tidy = Puppet::Type.type(:tidy).new :path => @basepath @stat = stub 'stat', :ftype => "file" @tidy[:size] = "1kb" @sizer = @tidy.parameter(:size) end it "should return false if the file is smaller than the specified size" do @stat.expects(:size).returns(4) # smaller than a kilobyte @sizer.should_not be_tidy(@basepath, @stat) end it "should return true if the file is larger than the specified size" do @stat.expects(:size).returns(1500) # larger than a kilobyte @sizer.must be_tidy(@basepath, @stat) end it "should return true if the file is equal to the specified size" do @stat.expects(:size).returns(1024) @sizer.must be_tidy(@basepath, @stat) end end describe "and determining whether a file should be tidied" do before do @tidy = Puppet::Type.type(:tidy).new :path => @basepath @stat = stub 'stat', :ftype => "file" File.stubs(:lstat).with(@basepath).returns @stat end it "should not try to recurse if the file does not exist" do @tidy[:recurse] = true File.stubs(:lstat).with(@basepath).returns nil @tidy.generate.should == [] end it "should not be tidied if the file does not exist" do File.expects(:lstat).with(@basepath).raises Errno::ENOENT @tidy.should_not be_tidy(@basepath) end it "should not be tidied if the user has no access to the file" do File.expects(:lstat).with(@basepath).raises Errno::EACCES @tidy.should_not be_tidy(@basepath) end it "should not be tidied if it is a directory and rmdirs is set to false" do stat = mock 'stat', :ftype => "directory" File.expects(:lstat).with(@basepath).returns stat @tidy.should_not be_tidy(@basepath) end it "should return false if it does not match any provided globs" do @tidy[:recurse] = 1 @tidy[:matches] = "globs" matches = @tidy.parameter(:matches) matches.expects(:tidy?).with(@basepath, @stat).returns false @tidy.should_not be_tidy(@basepath) end it "should return false if it does not match aging requirements" do @tidy[:age] = "1d" ager = @tidy.parameter(:age) ager.expects(:tidy?).with(@basepath, @stat).returns false @tidy.should_not be_tidy(@basepath) end it "should return false if it does not match size requirements" do @tidy[:size] = "1b" sizer = @tidy.parameter(:size) sizer.expects(:tidy?).with(@basepath, @stat).returns false @tidy.should_not be_tidy(@basepath) end it "should tidy a file if age and size are set but only size matches" do @tidy[:size] = "1b" @tidy[:age] = "1d" @tidy.parameter(:size).stubs(:tidy?).returns true @tidy.parameter(:age).stubs(:tidy?).returns false @tidy.should be_tidy(@basepath) end it "should tidy a file if age and size are set but only age matches" do @tidy[:size] = "1b" @tidy[:age] = "1d" @tidy.parameter(:size).stubs(:tidy?).returns false @tidy.parameter(:age).stubs(:tidy?).returns true @tidy.should be_tidy(@basepath) end it "should tidy all files if neither age nor size is set" do @tidy.must be_tidy(@basepath) end it "should sort the results inversely by path length, so files are added to the catalog before their directories" do @tidy[:recurse] = true @tidy[:rmdirs] = true fileset = Puppet::FileServing::Fileset.new(@basepath) Puppet::FileServing::Fileset.expects(:new).returns fileset fileset.expects(:files).returns %w{. one one/two} @tidy.stubs(:tidy?).returns true @tidy.generate.collect { |r| r[:path] }.should == [@basepath+"/one/two", @basepath+"/one", @basepath] end end it "should configure directories to require their contained files if rmdirs is enabled, so the files will be deleted first" do @tidy[:recurse] = true @tidy[:rmdirs] = true fileset = mock 'fileset' Puppet::FileServing::Fileset.expects(:new).with(@basepath, :recurse => true).returns fileset fileset.expects(:files).returns %w{. one two one/subone two/subtwo one/subone/ssone} @tidy.stubs(:tidy?).returns true result = @tidy.generate.inject({}) { |hash, res| hash[res[:path]] = res; hash } { @basepath => [ @basepath+"/one", @basepath+"/two" ], @basepath+"/one" => [@basepath+"/one/subone"], @basepath+"/two" => [@basepath+"/two/subtwo"], @basepath+"/one/subone" => [@basepath+"/one/subone/ssone"] }.each do |parent, children| children.each do |child| ref = Puppet::Resource.new(:file, child) result[parent][:require].find { |req| req.to_s == ref.to_s }.should_not be_nil end end end end end diff --git a/spec/unit/type/user_spec.rb b/spec/unit/type/user_spec.rb index 92c88abfb..71c9e1857 100755 --- a/spec/unit/type/user_spec.rb +++ b/spec/unit/type/user_spec.rb @@ -1,336 +1,335 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' user = Puppet::Type.type(:user) describe user do before do ENV["PATH"] += File::PATH_SEPARATOR + "/usr/sbin" unless ENV["PATH"].split(File::PATH_SEPARATOR).include?("/usr/sbin") @provider = stub 'provider' @resource = stub 'resource', :resource => nil, :provider => @provider, :line => nil, :file => nil end it "should have a default provider inheriting from Puppet::Provider" do user.defaultprovider.ancestors.should be_include(Puppet::Provider) end it "should be able to create a instance" do user.new(:name => "foo").should_not be_nil end it "should have an allows_duplicates feature" do user.provider_feature(:allows_duplicates).should_not be_nil end it "should have an manages_homedir feature" do user.provider_feature(:manages_homedir).should_not be_nil end it "should have an manages_passwords feature" do user.provider_feature(:manages_passwords).should_not be_nil end it "should have a manages_solaris_rbac feature" do user.provider_feature(:manages_solaris_rbac).should_not be_nil end it "should have a manages_expiry feature" do user.provider_feature(:manages_expiry).should_not be_nil end it "should have a manages_password_age feature" do user.provider_feature(:manages_password_age).should_not be_nil end it "should have a system_users feature" do user.provider_feature(:system_users).should_not be_nil end describe "instances" do it "should have a valid provider" do user.new(:name => "foo").provider.class.ancestors.should be_include(Puppet::Provider) end it "should delegate existence questions to its provider" do instance = user.new(:name => "foo") instance.provider.expects(:exists?).returns "eh" instance.exists?.should == "eh" end end properties = [:ensure, :uid, :gid, :home, :comment, :shell, :password, :password_min_age, :password_max_age, :groups, :roles, :auths, :profiles, :project, :keys, :expiry] properties.each do |property| it "should have a #{property} property" do user.attrclass(property).ancestors.should be_include(Puppet::Property) end it "should have documentation for its #{property} property" do user.attrclass(property).doc.should be_instance_of(String) end end list_properties = [:groups, :roles, :auths] list_properties.each do |property| it "should have a list '#{property}'" do user.attrclass(property).ancestors.should be_include(Puppet::Property::List) end end it "should have an ordered list 'profiles'" do user.attrclass(:profiles).ancestors.should be_include(Puppet::Property::OrderedList) end it "should have key values 'keys'" do user.attrclass(:keys).ancestors.should be_include(Puppet::Property::KeyValue) end describe "when retrieving all current values" do before do @user = user.new(:name => "foo", :uid => 10) end it "should return a hash containing values for all set properties" do @user[:gid] = 10 @user.property(:ensure).expects(:retrieve).returns :present @user.property(:uid).expects(:retrieve).returns 15 @user.property(:gid).expects(:retrieve).returns 15 values = @user.retrieve [@user.property(:uid), @user.property(:gid)].each { |property| values.should be_include(property) } end it "should set all values to :absent if the user is absent" do @user.property(:ensure).expects(:retrieve).returns :absent @user.property(:uid).expects(:retrieve).never @user.retrieve[@user.property(:uid)].should == :absent end it "should include the result of retrieving each property's current value if the user is present" do @user.property(:ensure).expects(:retrieve).returns :present @user.property(:uid).expects(:retrieve).returns 15 @user.retrieve[@user.property(:uid)].should == 15 end end describe "when managing the ensure property" do before do @ensure = user.attrclass(:ensure).new(:resource => @resource) end it "should support a :present value" do lambda { @ensure.should = :present }.should_not raise_error end it "should support an :absent value" do lambda { @ensure.should = :absent }.should_not raise_error end it "should call :create on the provider when asked to sync to the :present state" do @provider.expects(:create) @ensure.should = :present @ensure.sync end it "should call :delete on the provider when asked to sync to the :absent state" do @provider.expects(:delete) @ensure.should = :absent @ensure.sync end describe "and determining the current state" do it "should return :present when the provider indicates the user exists" do @provider.expects(:exists?).returns true @ensure.retrieve.should == :present end it "should return :absent when the provider indicates the user does not exist" do @provider.expects(:exists?).returns false @ensure.retrieve.should == :absent end end end describe "when managing the uid property" do it "should convert number-looking strings into actual numbers" do uid = user.attrclass(:uid).new(:resource => @resource) uid.should = "50" uid.should.must == 50 end it "should support UIDs as numbers" do uid = user.attrclass(:uid).new(:resource => @resource) uid.should = 50 uid.should.must == 50 end it "should :absent as a value" do uid = user.attrclass(:uid).new(:resource => @resource) uid.should = :absent uid.should.must == :absent end end describe "when managing the gid" do it "should :absent as a value" do gid = user.attrclass(:gid).new(:resource => @resource) gid.should = :absent gid.should.must == :absent end it "should convert number-looking strings into actual numbers" do gid = user.attrclass(:gid).new(:resource => @resource) gid.should = "50" gid.should.must == 50 end it "should support GIDs specified as integers" do gid = user.attrclass(:gid).new(:resource => @resource) gid.should = 50 gid.should.must == 50 end it "should support groups specified by name" do gid = user.attrclass(:gid).new(:resource => @resource) gid.should = "foo" gid.should.must == "foo" end describe "when testing whether in sync" do before do @gid = user.attrclass(:gid).new(:resource => @resource, :should => %w{foo bar}) end it "should return true if no 'should' values are set" do @gid = user.attrclass(:gid).new(:resource => @resource) @gid.must be_safe_insync(500) end it "should return true if any of the specified groups are equal to the current integer" do Puppet::Util.expects(:gid).with("foo").returns 300 Puppet::Util.expects(:gid).with("bar").returns 500 @gid.must be_safe_insync(500) end it "should return false if none of the specified groups are equal to the current integer" do Puppet::Util.expects(:gid).with("foo").returns 300 Puppet::Util.expects(:gid).with("bar").returns 500 @gid.should_not be_safe_insync(700) end end describe "when syncing" do before do @gid = user.attrclass(:gid).new(:resource => @resource, :should => %w{foo bar}) end it "should use the first found, specified group as the desired value and send it to the provider" do Puppet::Util.expects(:gid).with("foo").returns nil Puppet::Util.expects(:gid).with("bar").returns 500 @provider.expects(:gid=).with 500 @gid.sync end end end describe "when managing expiry" do before do @expiry = user.attrclass(:expiry).new(:resource => @resource) end it "should fail if given an invalid date" do lambda { @expiry.should = "200-20-20" }.should raise_error(Puppet::Error) end end describe "when managing minimum password age" do before do @age = user.attrclass(:password_min_age).new(:resource => @resource) end it "should accept a negative minimum age" do expect { @age.should = -1 }.should_not raise_error end it "should fail with an empty minimum age" do expect { @age.should = '' }.should raise_error(Puppet::Error) end end describe "when managing maximum password age" do before do @age = user.attrclass(:password_max_age).new(:resource => @resource) end it "should accept a negative maximum age" do expect { @age.should = -1 }.should_not raise_error end it "should fail with an empty maximum age" do expect { @age.should = '' }.should raise_error(Puppet::Error) end end describe "when managing passwords" do before do @password = user.attrclass(:password).new(:resource => @resource, :should => "mypass") end it "should not include the password in the change log when adding the password" do @password.change_to_s(:absent, "mypass").should_not be_include("mypass") end it "should not include the password in the change log when changing the password" do @password.change_to_s("other", "mypass").should_not be_include("mypass") end it "should fail if a ':' is included in the password" do lambda { @password.should = "some:thing" }.should raise_error(Puppet::Error) end it "should allow the value to be set to :absent" do lambda { @password.should = :absent }.should_not raise_error end end describe "when manages_solaris_rbac is enabled" do before do @provider.stubs(:satisfies?).returns(false) @provider.expects(:satisfies?).with([:manages_solaris_rbac]).returns(true) end it "should support a :role value for ensure" do @ensure = user.attrclass(:ensure).new(:resource => @resource) lambda { @ensure.should = :role }.should_not raise_error end end describe "when user has roles" do before do # To test this feature, we have to support it. user.new(:name => "foo").provider.class.stubs(:feature?).returns(true) end it "should autorequire roles" do testuser = Puppet::Type.type(:user).new(:name => "testuser") testuser[:roles] = "testrole" testrole = Puppet::Type.type(:user).new(:name => "testrole") config = Puppet::Resource::Catalog.new :testing do |conf| [testuser, testrole].each { |resource| conf.add_resource resource } end Puppet::Type::User::ProviderDirectoryservice.stubs(:get_macosx_version_major).returns "10.5" rel = testuser.autorequire[0] rel.source.ref.should == testrole.ref rel.target.ref.should == testuser.ref end end end diff --git a/spec/unit/type/vlan_spec.rb b/spec/unit/type/vlan_spec.rb old mode 100644 new mode 100755 index 607d7116d..2983a58e9 --- a/spec/unit/type/vlan_spec.rb +++ b/spec/unit/type/vlan_spec.rb @@ -1,40 +1,40 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec require File.dirname(__FILE__) + '/../../spec_helper' describe Puppet::Type.type(:vlan) do it "should have a 'name' parameter'" do Puppet::Type.type(:vlan).new(:name => "200")[:name].should == "200" end it "should have a 'device_url' parameter'" do Puppet::Type.type(:vlan).new(:name => "200", :device_url => :device)[:device_url].should == :device end it "should have an ensure property" do Puppet::Type.type(:vlan).attrtype(:ensure).should == :property end it "should have a description property" do Puppet::Type.type(:vlan).attrtype(:description).should == :property end describe "when validating attribute values" do before do @provider = stub 'provider', :class => Puppet::Type.type(:vlan).defaultprovider, :clear => nil Puppet::Type.type(:vlan).defaultprovider.stubs(:new).returns(@provider) end it "should support :present as a value to :ensure" do Puppet::Type.type(:vlan).new(:name => "200", :ensure => :present) end it "should support :absent as a value to :ensure" do Puppet::Type.type(:vlan).new(:name => "200", :ensure => :absent) end it "should fail if vlan name is not a number" do lambda { Puppet::Type.type(:vlan).new(:name => "notanumber", :ensure => :present) }.should raise_error end end end diff --git a/spec/unit/type/whit_spec.rb b/spec/unit/type/whit_spec.rb index cc5365ed6..4d0949900 100755 --- a/spec/unit/type/whit_spec.rb +++ b/spec/unit/type/whit_spec.rb @@ -1,11 +1,10 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' whit = Puppet::Type.type(:whit).new(:name => "Foo::Bar") describe whit do it "should stringify in a way that users will regognise" do whit.to_s.should == "(Foo::Bar)" end end diff --git a/spec/unit/type/zfs_spec.rb b/spec/unit/type/zfs_spec.rb index a08de574f..e53c25e02 100755 --- a/spec/unit/type/zfs_spec.rb +++ b/spec/unit/type/zfs_spec.rb @@ -1,45 +1,44 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' zfs = Puppet::Type.type(:zfs) describe zfs do properties = [:ensure, :mountpoint, :compression, :copies, :quota, :reservation, :sharenfs, :snapdir] properties.each do |property| it "should have a #{property} property" do zfs.attrclass(property).ancestors.should be_include(Puppet::Property) end end parameters = [:name] parameters.each do |parameter| it "should have a #{parameter} parameter" do zfs.attrclass(parameter).ancestors.should be_include(Puppet::Parameter) end end it "should autorequire the containing zfss and the zpool" do provider = mock "provider" provider.stubs(:name).returns(:solaris) zfs.stubs(:defaultprovider).returns(provider) Puppet::Type.type(:zpool).stubs(:defaultprovider).returns(provider) foo_pool = Puppet::Type.type(:zpool).new(:name => "foo") foo_bar_zfs = Puppet::Type.type(:zfs).new(:name => "foo/bar") foo_bar_baz_zfs = Puppet::Type.type(:zfs).new(:name => "foo/bar/baz") foo_bar_baz_buz_zfs = Puppet::Type.type(:zfs).new(:name => "foo/bar/baz/buz") config = Puppet::Resource::Catalog.new :testing do |conf| [foo_pool, foo_bar_zfs, foo_bar_baz_zfs, foo_bar_baz_buz_zfs].each { |resource| conf.add_resource resource } end req = foo_bar_baz_buz_zfs.autorequire.collect { |edge| edge.source.ref } [foo_pool.ref, foo_bar_zfs.ref, foo_bar_baz_zfs.ref].each { |ref| req.include?(ref).should == true } end end diff --git a/spec/unit/type/zone_spec.rb b/spec/unit/type/zone_spec.rb index 5c7a760e1..eb3d33bb0 100755 --- a/spec/unit/type/zone_spec.rb +++ b/spec/unit/type/zone_spec.rb @@ -1,80 +1,79 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' zone = Puppet::Type.type(:zone) describe zone do before do zone = Puppet::Type.type(:zone) provider = stub 'provider' provider.stubs(:name).returns(:solaris) zone.stubs(:defaultprovider).returns(provider) resource = stub 'resource', :resource => nil, :provider => provider, :line => nil, :file => nil end parameters = [:create_args, :install_args, :sysidcfg, :path, :realhostname] parameters.each do |parameter| it "should have a #{parameter} parameter" do zone.attrclass(parameter).ancestors.should be_include(Puppet::Parameter) end end properties = [:ip, :iptype, :autoboot, :pool, :shares, :inherit] properties.each do |property| it "should have a #{property} property" do zone.attrclass(property).ancestors.should be_include(Puppet::Property) end end it "should be invalid when :path is missing" do lambda { zone.new(:name => "dummy") }.should raise_error end it "should be invalid when :ip is missing a \":\" and iptype is :shared" do lambda { zone.new(:name => "dummy", :ip => "if") }.should raise_error end it "should be invalid when :ip has a \":\" and iptype is :exclusive" do lambda { zone.new(:name => "dummy", :ip => "if:1.2.3.4", :iptype => :exclusive) }.should raise_error end it "should be invalid when :ip has two \":\" and iptype is :exclusive" do lambda { zone.new(:name => "dummy", :ip => "if:1.2.3.4:2.3.4.5", :iptype => :exclusive) }.should raise_error end it "should be valid when :iptype is :shared and using interface and ip" do zone.new(:name => "dummy", :path => "/dummy", :ip => "if:1.2.3.4") end it "should be valid when :iptype is :shared and using interface, ip and default route" do zone.new(:name => "dummy", :path => "/dummy", :ip => "if:1.2.3.4:2.3.4.5") end it "should be valid when :iptype is :exclusive and using interface" do zone.new(:name => "dummy", :path => "/dummy", :ip => "if", :iptype => :exclusive) end it "should auto-require :dataset entries" do fs = 'random-pool/some-zfs' # ick provider = stub 'zfs::provider' provider.stubs(:name).returns(:solaris) Puppet::Type.type(:zfs).stubs(:defaultprovider).returns(provider) catalog = Puppet::Resource::Catalog.new zfs_instance = Puppet::Type.type(:zfs).new(:name => fs) catalog.add_resource zfs_instance zone_instance = zone.new(:name => "dummy", :path => "/foo", :ip => 'en1:1.0.0.0', :dataset => fs) catalog.add_resource zone_instance catalog.relationship_graph.dependencies(zone_instance).should == [zfs_instance] end end diff --git a/spec/unit/type/zpool_spec.rb b/spec/unit/type/zpool_spec.rb index 21a5ba0c6..9f1800073 100755 --- a/spec/unit/type/zpool_spec.rb +++ b/spec/unit/type/zpool_spec.rb @@ -1,110 +1,109 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' zpool = Puppet::Type.type(:zpool) describe zpool do before do @provider = stub 'provider' @resource = stub 'resource', :resource => nil, :provider => @provider, :line => nil, :file => nil end properties = [:ensure, :disk, :mirror, :raidz, :spare, :log] properties.each do |property| it "should have a #{property} property" do zpool.attrclass(property).ancestors.should be_include(Puppet::Property) end end parameters = [:pool, :raid_parity] parameters.each do |parameter| it "should have a #{parameter} parameter" do zpool.attrclass(parameter).ancestors.should be_include(Puppet::Parameter) end end end vdev_property = Puppet::Property::VDev describe vdev_property do before do vdev_property.initvars @resource = stub 'resource', :[]= => nil, :property => nil @property = vdev_property.new(:resource => @resource) end it "should be insync if the devices are the same" do @property.should = ["dev1 dev2"] @property.safe_insync?(["dev2 dev1"]).must be_true end it "should be out of sync if the devices are not the same" do @property.should = ["dev1 dev3"] @property.safe_insync?(["dev2 dev1"]).must be_false end it "should be insync if the devices are the same and the should values are comma seperated" do @property.should = ["dev1", "dev2"] @property.safe_insync?(["dev2 dev1"]).must be_true end it "should be out of sync if the device is absent and should has a value" do @property.should = ["dev1", "dev2"] @property.safe_insync?(:absent).must be_false end it "should be insync if the device is absent and should is absent" do @property.should = [:absent] @property.safe_insync?(:absent).must be_true end end multi_vdev_property = Puppet::Property::MultiVDev describe multi_vdev_property do before do multi_vdev_property.initvars @resource = stub 'resource', :[]= => nil, :property => nil @property = multi_vdev_property.new(:resource => @resource) end it "should be insync if the devices are the same" do @property.should = ["dev1 dev2"] @property.safe_insync?(["dev2 dev1"]).must be_true end it "should be out of sync if the devices are not the same" do @property.should = ["dev1 dev3"] @property.safe_insync?(["dev2 dev1"]).must be_false end it "should be out of sync if the device is absent and should has a value" do @property.should = ["dev1", "dev2"] @property.safe_insync?(:absent).must be_false end it "should be insync if the device is absent and should is absent" do @property.should = [:absent] @property.safe_insync?(:absent).must be_true end describe "when there are multiple lists of devices" do it "should be in sync if each group has the same devices" do @property.should = ["dev1 dev2", "dev3 dev4"] @property.safe_insync?(["dev2 dev1", "dev3 dev4"]).must be_true end it "should be out of sync if any group has the different devices" do @property.should = ["dev1 devX", "dev3 dev4"] @property.safe_insync?(["dev2 dev1", "dev3 dev4"]).must be_false end it "should be out of sync if devices are in the wrong group" do @property.should = ["dev1 dev2", "dev3 dev4"] @property.safe_insync?(["dev2 dev3", "dev1 dev4"]).must be_false end end end diff --git a/spec/unit/type_spec.rb b/spec/unit/type_spec.rb index 9859c5e08..ca291c4fa 100755 --- a/spec/unit/type_spec.rb +++ b/spec/unit/type_spec.rb @@ -1,584 +1,583 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe Puppet::Type do it "should include the Cacher module" do Puppet::Type.ancestors.should be_include(Puppet::Util::Cacher) end it "should consider a parameter to be valid if it is a valid parameter" do Puppet::Type.type(:mount).should be_valid_parameter(:path) end it "should consider a parameter to be valid if it is a valid property" do Puppet::Type.type(:mount).should be_valid_parameter(:fstype) end it "should consider a parameter to be valid if it is a valid metaparam" do Puppet::Type.type(:mount).should be_valid_parameter(:noop) end it "should use its catalog as its expirer" do catalog = Puppet::Resource::Catalog.new resource = Puppet::Type.type(:mount).new(:name => "foo", :fstype => "bar", :pass => 1, :ensure => :present) resource.catalog = catalog resource.expirer.should equal(catalog) end it "should do nothing when asked to expire when it has no catalog" do resource = Puppet::Type.type(:mount).new(:name => "foo", :fstype => "bar", :pass => 1, :ensure => :present) lambda { resource.expire }.should_not raise_error end it "should be able to retrieve a property by name" do resource = Puppet::Type.type(:mount).new(:name => "foo", :fstype => "bar", :pass => 1, :ensure => :present) resource.property(:fstype).must be_instance_of(Puppet::Type.type(:mount).attrclass(:fstype)) end it "should be able to retrieve a parameter by name" do resource = Puppet::Type.type(:mount).new(:name => "foo", :fstype => "bar", :pass => 1, :ensure => :present) resource.parameter(:name).must be_instance_of(Puppet::Type.type(:mount).attrclass(:name)) end it "should be able to retrieve a property by name using the :parameter method" do resource = Puppet::Type.type(:mount).new(:name => "foo", :fstype => "bar", :pass => 1, :ensure => :present) resource.parameter(:fstype).must be_instance_of(Puppet::Type.type(:mount).attrclass(:fstype)) end it "should be able to retrieve all set properties" do resource = Puppet::Type.type(:mount).new(:name => "foo", :fstype => "bar", :pass => 1, :ensure => :present) props = resource.properties props.should_not be_include(nil) [:fstype, :ensure, :pass].each do |name| props.should be_include(resource.parameter(name)) end end it "should have a method for setting default values for resources" do Puppet::Type.type(:mount).new(:name => "foo").should respond_to(:set_default) end it "should do nothing for attributes that have no defaults and no specified value" do Puppet::Type.type(:mount).new(:name => "foo").parameter(:noop).should be_nil end it "should have a method for adding tags" do Puppet::Type.type(:mount).new(:name => "foo").should respond_to(:tags) end it "should use the tagging module" do Puppet::Type.type(:mount).ancestors.should be_include(Puppet::Util::Tagging) end it "should delegate to the tagging module when tags are added" do resource = Puppet::Type.type(:mount).new(:name => "foo") resource.stubs(:tag).with(:mount) resource.expects(:tag).with(:tag1, :tag2) resource.tags = [:tag1,:tag2] end it "should add the current type as tag" do resource = Puppet::Type.type(:mount).new(:name => "foo") resource.stubs(:tag) resource.expects(:tag).with(:mount) resource.tags = [:tag1,:tag2] end it "should have a method to know if the resource is exported" do Puppet::Type.type(:mount).new(:name => "foo").should respond_to(:exported?) end it "should have a method to know if the resource is virtual" do Puppet::Type.type(:mount).new(:name => "foo").should respond_to(:virtual?) end it "should consider its version to be its catalog version" do resource = Puppet::Type.type(:mount).new(:name => "foo") catalog = Puppet::Resource::Catalog.new catalog.version = 50 catalog.add_resource resource resource.version.should == 50 end it "should consider its version to be zero if it has no catalog" do Puppet::Type.type(:mount).new(:name => "foo").version.should == 0 end it "should provide source_descriptors" do resource = Puppet::Type.type(:mount).new(:name => "foo") catalog = Puppet::Resource::Catalog.new catalog.version = 50 catalog.add_resource resource resource.source_descriptors.should == {:tags=>["mount", "foo"], :path=>"/Mount[foo]"} end it "should consider its type to be the name of its class" do Puppet::Type.type(:mount).new(:name => "foo").type.should == :mount end it "should use any provided noop value" do Puppet::Type.type(:mount).new(:name => "foo", :noop => true).must be_noop end it "should use the global noop value if none is provided" do Puppet[:noop] = true Puppet::Type.type(:mount).new(:name => "foo").must be_noop end it "should not be noop if in a non-host_config catalog" do resource = Puppet::Type.type(:mount).new(:name => "foo") catalog = Puppet::Resource::Catalog.new catalog.add_resource resource resource.should_not be_noop end describe "when creating an event" do before do @resource = Puppet::Type.type(:mount).new :name => "foo" end it "should have the resource's reference as the resource" do @resource.event.resource.should == "Mount[foo]" end it "should have the resource's log level as the default log level" do @resource[:loglevel] = :warning @resource.event.default_log_level.should == :warning end {:file => "/my/file", :line => 50, :tags => %{foo bar}}.each do |attr, value| it "should set the #{attr}" do @resource.stubs(attr).returns value @resource.event.send(attr).should == value end end it "should allow specification of event attributes" do @resource.event(:status => "noop").status.should == "noop" end end describe "when choosing a default provider" do it "should choose the provider with the highest specificity" do # Make a fake type type = Puppet::Type.newtype(:defaultprovidertest) do newparam(:name) do end end basic = type.provide(:basic) {} greater = type.provide(:greater) {} basic.stubs(:specificity).returns 1 greater.stubs(:specificity).returns 2 type.defaultprovider.should equal(greater) end end describe "when initializing" do describe "and passed a TransObject" do it "should fail" do trans = Puppet::TransObject.new("/foo", :mount) lambda { Puppet::Type.type(:mount).new(trans) }.should raise_error(Puppet::DevError) end end describe "and passed a Puppet::Resource instance" do it "should set its title to the title of the resource if the resource type is equal to the current type" do resource = Puppet::Resource.new(:mount, "/foo", :parameters => {:name => "/other"}) Puppet::Type.type(:mount).new(resource).title.should == "/foo" end it "should set its title to the resource reference if the resource type is not equal to the current type" do resource = Puppet::Resource.new(:user, "foo") Puppet::Type.type(:mount).new(resource).title.should == "User[foo]" end [:line, :file, :catalog, :exported, :virtual].each do |param| it "should copy '#{param}' from the resource if present" do resource = Puppet::Resource.new(:mount, "/foo") resource.send(param.to_s + "=", "foo") resource.send(param.to_s + "=", "foo") Puppet::Type.type(:mount).new(resource).send(param).should == "foo" end end it "should copy any tags from the resource" do resource = Puppet::Resource.new(:mount, "/foo") resource.tag "one", "two" tags = Puppet::Type.type(:mount).new(resource).tags tags.should be_include("one") tags.should be_include("two") end it "should copy the resource's parameters as its own" do resource = Puppet::Resource.new(:mount, "/foo", :parameters => {:atboot => true, :fstype => "boo"}) params = Puppet::Type.type(:mount).new(resource).to_hash params[:fstype].should == "boo" params[:atboot].should == true end end describe "and passed a Hash" do it "should extract the title from the hash" do Puppet::Type.type(:mount).new(:title => "/yay").title.should == "/yay" end it "should work when hash keys are provided as strings" do Puppet::Type.type(:mount).new("title" => "/yay").title.should == "/yay" end it "should work when hash keys are provided as symbols" do Puppet::Type.type(:mount).new(:title => "/yay").title.should == "/yay" end it "should use the name from the hash as the title if no explicit title is provided" do Puppet::Type.type(:mount).new(:name => "/yay").title.should == "/yay" end it "should use the Resource Type's namevar to determine how to find the name in the hash" do Puppet::Type.type(:file).new(:path => "/yay").title.should == "/yay" end [:catalog].each do |param| it "should extract '#{param}' from the hash if present" do Puppet::Type.type(:mount).new(:name => "/yay", param => "foo").send(param).should == "foo" end end it "should use any remaining hash keys as its parameters" do resource = Puppet::Type.type(:mount).new(:title => "/foo", :catalog => "foo", :atboot => true, :fstype => "boo") resource[:fstype].must == "boo" resource[:atboot].must == true end end it "should fail if any invalid attributes have been provided" do lambda { Puppet::Type.type(:mount).new(:title => "/foo", :nosuchattr => "whatever") }.should raise_error(Puppet::Error) end it "should set its name to the resource's title if the resource does not have a :name or namevar parameter set" do resource = Puppet::Resource.new(:mount, "/foo") Puppet::Type.type(:mount).new(resource).name.should == "/foo" end it "should fail if no title, name, or namevar are provided" do lambda { Puppet::Type.type(:file).new(:atboot => true) }.should raise_error(Puppet::Error) end it "should set the attributes in the order returned by the class's :allattrs method" do Puppet::Type.type(:mount).stubs(:allattrs).returns([:name, :atboot, :noop]) resource = Puppet::Resource.new(:mount, "/foo", :parameters => {:name => "myname", :atboot => "myboot", :noop => "whatever"}) set = [] Puppet::Type.type(:mount).any_instance.stubs(:newattr).with do |param, hash| set << param true end.returns(stub_everything("a property")) Puppet::Type.type(:mount).new(resource) set[-1].should == :noop set[-2].should == :atboot end it "should always set the name and then default provider before anything else" do Puppet::Type.type(:mount).stubs(:allattrs).returns([:provider, :name, :atboot]) resource = Puppet::Resource.new(:mount, "/foo", :parameters => {:name => "myname", :atboot => "myboot"}) set = [] Puppet::Type.type(:mount).any_instance.stubs(:newattr).with do |param, hash| set << param true end.returns(stub_everything("a property")) Puppet::Type.type(:mount).new(resource) set[0].should == :name set[1].should == :provider end # This one is really hard to test :/ it "should each default immediately if no value is provided" do defaults = [] Puppet::Type.type(:package).any_instance.stubs(:set_default).with { |value| defaults << value; true } Puppet::Type.type(:package).new :name => "whatever" defaults[0].should == :provider end it "should retain a copy of the originally provided parameters" do Puppet::Type.type(:mount).new(:name => "foo", :atboot => true, :noop => false).original_parameters.should == {:atboot => true, :noop => false} end it "should delete the name via the namevar from the originally provided parameters" do Puppet::Type.type(:file).new(:name => "/foo").original_parameters[:path].should be_nil end end it "should have a class method for converting a hash into a Puppet::Resource instance" do Puppet::Type.type(:mount).must respond_to(:hash2resource) end describe "when converting a hash to a Puppet::Resource instance" do before do @type = Puppet::Type.type(:mount) end it "should treat a :title key as the title of the resource" do @type.hash2resource(:name => "/foo", :title => "foo").title.should == "foo" end it "should use the name from the hash as the title if no explicit title is provided" do @type.hash2resource(:name => "foo").title.should == "foo" end it "should use the Resource Type's namevar to determine how to find the name in the hash" do @type.stubs(:key_attributes).returns([ :myname ]) @type.hash2resource(:myname => "foo").title.should == "foo" end [:catalog].each do |attr| it "should use any provided #{attr}" do @type.hash2resource(:name => "foo", attr => "eh").send(attr).should == "eh" end end it "should set all provided parameters on the resource" do @type.hash2resource(:name => "foo", :fstype => "boo", :boot => "fee").to_hash.should == {:name => "foo", :fstype => "boo", :boot => "fee"} end it "should not set the title as a parameter on the resource" do @type.hash2resource(:name => "foo", :title => "eh")[:title].should be_nil end it "should not set the catalog as a parameter on the resource" do @type.hash2resource(:name => "foo", :catalog => "eh")[:catalog].should be_nil end it "should treat hash keys equivalently whether provided as strings or symbols" do resource = @type.hash2resource("name" => "foo", "title" => "eh", "fstype" => "boo") resource.title.should == "eh" resource[:name].should == "foo" resource[:fstype].should == "boo" end end describe "when retrieving current property values" do before do @resource = Puppet::Type.type(:mount).new(:name => "foo", :fstype => "bar", :pass => 1, :ensure => :present) @resource.property(:ensure).stubs(:retrieve).returns :absent end it "should fail if its provider is unsuitable" do @resource = Puppet::Type.type(:mount).new(:name => "foo", :fstype => "bar", :pass => 1, :ensure => :present) @resource.provider.class.expects(:suitable?).returns false lambda { @resource.retrieve_resource }.should raise_error(Puppet::Error) end it "should return a Puppet::Resource instance with its type and title set appropriately" do result = @resource.retrieve_resource result.should be_instance_of(Puppet::Resource) result.type.should == "Mount" result.title.should == "foo" end it "should set the name of the returned resource if its own name and title differ" do @resource[:name] = "my name" @resource.title = "other name" @resource.retrieve_resource[:name].should == "my name" end it "should provide a value for all set properties" do values = @resource.retrieve_resource [:ensure, :fstype, :pass].each { |property| values[property].should_not be_nil } end it "should provide a value for 'ensure' even if no desired value is provided" do @resource = Puppet::Type.type(:file).new(:path => "/my/file/that/can't/exist") end it "should not call retrieve on non-ensure properties if the resource is absent and should consider the property absent" do @resource.property(:ensure).expects(:retrieve).returns :absent @resource.property(:fstype).expects(:retrieve).never @resource.retrieve_resource[:fstype].should == :absent end it "should include the result of retrieving each property's current value if the resource is present" do @resource.property(:ensure).expects(:retrieve).returns :present @resource.property(:fstype).expects(:retrieve).returns 15 @resource.retrieve_resource[:fstype] == 15 end end describe ".title_patterns" do describe "when there's one namevar" do before do @type_class = Puppet::Type.type(:notify) @type_class.stubs(:key_attributes).returns([:one]) end it "should have a default pattern for when there's one namevar" do patterns = @type_class.title_patterns patterns.length.should == 1 patterns[0].length.should == 2 end it "should have a regexp that captures the entire string" do patterns = @type_class.title_patterns string = "abc\n\tdef" patterns[0][0] =~ string $1.should == "abc\n\tdef" end end end describe "when in a catalog" do before do @catalog = Puppet::Resource::Catalog.new @container = Puppet::Type.type(:component).new(:name => "container") @one = Puppet::Type.type(:file).new(:path => "/file/one") @two = Puppet::Type.type(:file).new(:path => "/file/two") @catalog.add_resource @container @catalog.add_resource @one @catalog.add_resource @two @catalog.add_edge @container, @one @catalog.add_edge @container, @two end it "should have no parent if there is no in edge" do @container.parent.should be_nil end it "should set its parent to its in edge" do @one.parent.ref.should == @container.ref end after do @catalog.clear(true) end end it "should have a 'stage' metaparam" do Puppet::Type.metaparamclass(:stage).should be_instance_of(Class) end end describe Puppet::Type::RelationshipMetaparam do it "should be a subclass of Puppet::Parameter" do Puppet::Type::RelationshipMetaparam.superclass.should equal(Puppet::Parameter) end it "should be able to produce a list of subclasses" do Puppet::Type::RelationshipMetaparam.should respond_to(:subclasses) end describe "when munging relationships" do before do @resource = Puppet::Type.type(:mount).new :name => "/foo" @metaparam = Puppet::Type.metaparamclass(:require).new :resource => @resource end it "should accept Puppet::Resource instances" do ref = Puppet::Resource.new(:file, "/foo") @metaparam.munge(ref)[0].should equal(ref) end it "should turn any string into a Puppet::Resource" do @metaparam.munge("File[/ref]")[0].should be_instance_of(Puppet::Resource) end end it "should be able to validate relationships" do Puppet::Type.metaparamclass(:require).new(:resource => mock("resource")).should respond_to(:validate_relationship) end it "should fail if any specified resource is not found in the catalog" do catalog = mock 'catalog' resource = stub 'resource', :catalog => catalog, :ref => "resource" param = Puppet::Type.metaparamclass(:require).new(:resource => resource, :value => %w{Foo[bar] Class[test]}) catalog.expects(:resource).with("Foo[bar]").returns "something" catalog.expects(:resource).with("Class[Test]").returns nil param.expects(:fail).with { |string| string.include?("Class[Test]") } param.validate_relationship end end describe Puppet::Type.metaparamclass(:check) do it "should warn and create an instance of ':audit'" do file = Puppet::Type.type(:file).new :path => "/foo" file.expects(:warning) file[:check] = :mode file[:audit].should == [:mode] end end describe Puppet::Type.metaparamclass(:audit) do before do @resource = Puppet::Type.type(:file).new :path => "/foo" end it "should default to being nil" do @resource[:audit].should be_nil end it "should specify all possible properties when asked to audit all properties" do @resource[:audit] = :all list = @resource.class.properties.collect { |p| p.name } @resource[:audit].should == list end it "should accept the string 'all' to specify auditing all possible properties" do @resource[:audit] = 'all' list = @resource.class.properties.collect { |p| p.name } @resource[:audit].should == list end it "should fail if asked to audit an invalid property" do lambda { @resource[:audit] = :foobar }.should raise_error(Puppet::Error) end it "should create an attribute instance for each auditable property" do @resource[:audit] = :mode @resource.parameter(:mode).should_not be_nil end it "should accept properties specified as a string" do @resource[:audit] = "mode" @resource.parameter(:mode).should_not be_nil end it "should not create attribute instances for parameters, only properties" do @resource[:audit] = :noop @resource.parameter(:noop).should be_nil end describe "when generating the uniqueness key" do it "should include all of the key_attributes in alphabetical order by attribute name" do Puppet::Type.type(:file).stubs(:key_attributes).returns [:path, :mode, :owner] Puppet::Type.type(:file).stubs(:title_patterns).returns( [ [ /(.*)/, [ [:path, lambda{|x| x} ] ] ] ] ) res = Puppet::Type.type(:file).new( :title => '/my/file', :path => '/my/file', :owner => 'root', :content => 'hello' ) res.uniqueness_key.should == [ nil, 'root', '/my/file'] end end end diff --git a/spec/unit/util/autoload/file_cache_spec.rb b/spec/unit/util/autoload/file_cache_spec.rb index 97ca4912d..cdde9bb48 100755 --- a/spec/unit/util/autoload/file_cache_spec.rb +++ b/spec/unit/util/autoload/file_cache_spec.rb @@ -1,159 +1,158 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/util/autoload/file_cache' class FileCacheTester include Puppet::Util::Autoload::FileCache end describe Puppet::Util::Autoload::FileCache do before do @cacher = FileCacheTester.new end after do Puppet::Util::Autoload::FileCache.clear end describe "when checking whether files exist" do it "should have a method for testing whether a file exists" do @cacher.should respond_to(:file_exist?) end it "should use lstat to determine whether a file exists" do File.expects(:lstat).with("/my/file") @cacher.file_exist?("/my/file") end it "should consider a file as absent if its lstat fails" do File.expects(:lstat).with("/my/file").raises Errno::ENOENT @cacher.should_not be_file_exist("/my/file") end it "should consider a file as absent if the directory is absent" do File.expects(:lstat).with("/my/file").raises Errno::ENOTDIR @cacher.should_not be_file_exist("/my/file") end it "should consider a file as absent permissions are missing" do File.expects(:lstat).with("/my/file").raises Errno::EACCES @cacher.should_not be_file_exist("/my/file") end it "should raise non-fs exceptions" do File.expects(:lstat).with("/my/file").raises ArgumentError lambda { @cacher.file_exist?("/my/file") }.should raise_error(ArgumentError) end it "should consider a file as present if its lstat succeeds" do File.expects(:lstat).with("/my/file").returns mock("stat") @cacher.should be_file_exist("/my/file") end it "should not stat a file twice in quick succession when the file is missing" do File.expects(:lstat).with("/my/file").once.raises Errno::ENOENT @cacher.should_not be_file_exist("/my/file") @cacher.should_not be_file_exist("/my/file") end it "should not stat a file twice in quick succession when the file is present" do File.expects(:lstat).with("/my/file").once.returns mock("stat") @cacher.should be_file_exist("/my/file") @cacher.should be_file_exist("/my/file") end it "should expire cached data after 15 seconds" do now = Time.now later = now + 16 Time.expects(:now).times(3).returns(now).then.returns(later).then.returns(later) File.expects(:lstat).with("/my/file").times(2).returns(mock("stat")).then.raises Errno::ENOENT @cacher.should be_file_exist("/my/file") @cacher.should_not be_file_exist("/my/file") end it "should share cached data across autoload instances" do File.expects(:lstat).with("/my/file").once.returns mock("stat") other = Puppet::Util::Autoload.new("bar", "tmp") @cacher.should be_file_exist("/my/file") other.should be_file_exist("/my/file") end end describe "when checking whether files exist" do before do @stat = stub 'stat', :directory? => true end it "should have a method for determining whether a directory exists" do @cacher.should respond_to(:directory_exist?) end it "should use lstat to determine whether a directory exists" do File.expects(:lstat).with("/my/file").returns @stat @cacher.directory_exist?("/my/file") end it "should consider a directory as absent if its lstat fails" do File.expects(:lstat).with("/my/file").raises Errno::ENOENT @cacher.should_not be_directory_exist("/my/file") end it "should consider a file as absent if the directory is absent" do File.expects(:lstat).with("/my/file").raises Errno::ENOTDIR @cacher.should_not be_directory_exist("/my/file") end it "should consider a file as absent permissions are missing" do File.expects(:lstat).with("/my/file").raises Errno::EACCES @cacher.should_not be_directory_exist("/my/file") end it "should raise non-fs exceptions" do File.expects(:lstat).with("/my/file").raises ArgumentError lambda { @cacher.directory_exist?("/my/file") }.should raise_error(ArgumentError) end it "should consider a directory as present if its lstat succeeds and the stat is of a directory" do @stat.expects(:directory?).returns true File.expects(:lstat).with("/my/file").returns @stat @cacher.should be_directory_exist("/my/file") end it "should consider a directory as absent if its lstat succeeds and the stat is not of a directory" do @stat.expects(:directory?).returns false File.expects(:lstat).with("/my/file").returns @stat @cacher.should_not be_directory_exist("/my/file") end it "should not stat a directory twice in quick succession when the file is missing" do File.expects(:lstat).with("/my/file").once.raises Errno::ENOENT @cacher.should_not be_directory_exist("/my/file") @cacher.should_not be_directory_exist("/my/file") end it "should not stat a directory twice in quick succession when the file is present" do File.expects(:lstat).with("/my/file").once.returns @stat @cacher.should be_directory_exist("/my/file") @cacher.should be_directory_exist("/my/file") end it "should not consider a file to be a directory based on cached data" do @stat.stubs(:directory?).returns false File.stubs(:lstat).with("/my/file").returns @stat @cacher.file_exist?("/my/file") @cacher.should_not be_directory_exist("/my/file") end it "should share cached data across autoload instances" do File.expects(:lstat).with("/my/file").once.returns @stat other = Puppet::Util::Autoload.new("bar", "tmp") @cacher.should be_directory_exist("/my/file") other.should be_directory_exist("/my/file") end end end diff --git a/spec/unit/util/autoload_spec.rb b/spec/unit/util/autoload_spec.rb index 59a491ba8..6d49b57dc 100755 --- a/spec/unit/util/autoload_spec.rb +++ b/spec/unit/util/autoload_spec.rb @@ -1,120 +1,119 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/util/autoload' describe Puppet::Util::Autoload do before do @autoload = Puppet::Util::Autoload.new("foo", "tmp") @autoload.stubs(:eachdir).yields "/my/dir" end it "should use the Cacher module" do Puppet::Util::Autoload.ancestors.should be_include(Puppet::Util::Cacher) end describe "when building the search path" do it "should collect all of the plugins and lib directories that exist in the current environment's module path" do Puppet.settings.expects(:value).with(:environment).returns "foo" Puppet.settings.expects(:value).with(:modulepath, :foo).returns "/a:/b:/c" Dir.expects(:entries).with("/a").returns %w{one two} Dir.expects(:entries).with("/b").returns %w{one two} FileTest.stubs(:directory?).returns false FileTest.expects(:directory?).with("/a").returns true FileTest.expects(:directory?).with("/b").returns true %w{/a/one/plugins /a/two/lib /b/one/plugins /b/two/lib}.each do |d| FileTest.expects(:directory?).with(d).returns true end @autoload.module_directories.should == %w{/a/one/plugins /a/two/lib /b/one/plugins /b/two/lib} end it "should not look for lib directories in directories starting with '.'" do Puppet.settings.expects(:value).with(:environment).returns "foo" Puppet.settings.expects(:value).with(:modulepath, :foo).returns "/a" Dir.expects(:entries).with("/a").returns %w{. ..} FileTest.expects(:directory?).with("/a").returns true FileTest.expects(:directory?).with("/a/./lib").never FileTest.expects(:directory?).with("/a/./plugins").never FileTest.expects(:directory?).with("/a/../lib").never FileTest.expects(:directory?).with("/a/../plugins").never @autoload.module_directories end it "should include the module directories, the Puppet libdir, and all of the Ruby load directories" do Puppet.stubs(:[]).with(:libdir).returns(%w{/libdir1 /lib/dir/two /third/lib/dir}.join(File::PATH_SEPARATOR)) @autoload.expects(:module_directories).returns %w{/one /two} @autoload.search_directories.should == %w{/one /two /libdir1 /lib/dir/two /third/lib/dir} + $LOAD_PATH end it "should include in its search path all of the search directories that have a subdirectory matching the autoload path" do @autoload = Puppet::Util::Autoload.new("foo", "loaddir") @autoload.expects(:search_directories).returns %w{/one /two /three} FileTest.expects(:directory?).with("/one/loaddir").returns true FileTest.expects(:directory?).with("/two/loaddir").returns false FileTest.expects(:directory?).with("/three/loaddir").returns true @autoload.searchpath.should == ["/one/loaddir", "/three/loaddir"] end end it "should include its FileCache module" do Puppet::Util::Autoload.ancestors.should be_include(Puppet::Util::Autoload::FileCache) end describe "when loading a file" do before do @autoload.stubs(:searchpath).returns %w{/a} end [RuntimeError, LoadError, SyntaxError].each do |error| it "should die with Puppet::Error if a #{error.to_s} exception is thrown" do @autoload.stubs(:file_exist?).returns true Kernel.expects(:load).raises error lambda { @autoload.load("foo") }.should raise_error(Puppet::Error) end end it "should not raise an error if the file is missing" do @autoload.load("foo").should == false end it "should register loaded files with the main loaded file list so they are not reloaded by ruby" do @autoload.stubs(:file_exist?).returns true Kernel.stubs(:load) @autoload.load("myfile") $LOADED_FEATURES.should be_include("tmp/myfile.rb") end end describe "when loading all files" do before do @autoload.stubs(:searchpath).returns %w{/a} Dir.stubs(:glob).returns "/path/to/file.rb" @autoload.class.stubs(:loaded?).returns(false) end [RuntimeError, LoadError, SyntaxError].each do |error| it "should die an if a #{error.to_s} exception is thrown" do Kernel.expects(:require).raises error lambda { @autoload.loadall }.should raise_error(Puppet::Error) end end it "should require the full path to the file" do Kernel.expects(:require).with("/path/to/file.rb") @autoload.loadall end end end diff --git a/spec/unit/util/backups_spec.rb b/spec/unit/util/backups_spec.rb index c580a4588..611c19304 100755 --- a/spec/unit/util/backups_spec.rb +++ b/spec/unit/util/backups_spec.rb @@ -1,158 +1,157 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/util/backups' describe Puppet::Util::Backups do before do FileTest.stubs(:exists?).returns true end describe "when backing up a file" do it "should noop if the file does not exist" do FileTest.expects(:exists?).returns false file = Puppet::Type.type(:file).new(:name => '/no/such/file') file.expects(:bucket).never file.perform_backup end it "should succeed silently if self[:backup] is false" do file = Puppet::Type.type(:file).new(:name => '/no/such/file', :backup => false) file.expects(:bucket).never FileTest.expects(:exists?).never file.perform_backup end it "a bucket should be used when provided" do path = '/my/file' File.stubs(:stat).with(path).returns(mock('stat', :ftype => 'file')) file = Puppet::Type.type(:file).new(:name => path, :backup => 'foo') bucket = stub('bucket', 'name' => 'foo') file.stubs(:bucket).returns bucket bucket.expects(:backup).with(path).returns("mysum") file.perform_backup end it "should propagate any exceptions encountered when backing up to a filebucket" do path = '/my/file' File.stubs(:stat).with(path).returns(mock('stat', :ftype => 'file')) file = Puppet::Type.type(:file).new(:name => path, :backup => 'foo') bucket = stub('bucket', 'name' => 'foo') file.stubs(:bucket).returns bucket bucket.expects(:backup).raises ArgumentError lambda { file.perform_backup }.should raise_error(ArgumentError) end describe "and no filebucket is configured" do it "should remove any local backup if one exists" do path = '/my/file' FileTest.stubs(:exists?).returns true backup = path + ".foo" File.expects(:lstat).with(backup).returns stub("stat", :ftype => "file") File.expects(:unlink).with(backup) FileUtils.stubs(:cp_r) file = Puppet::Type.type(:file).new(:name => path, :backup => '.foo') file.perform_backup end it "should fail when the old backup can't be removed" do path = '/my/file' FileTest.stubs(:exists?).returns true backup = path + ".foo" File.expects(:lstat).with(backup).returns stub("stat", :ftype => "file") File.expects(:unlink).raises ArgumentError FileUtils.expects(:cp_r).never file = Puppet::Type.type(:file).new(:name => path, :backup => '.foo') lambda { file.perform_backup }.should raise_error(Puppet::Error) end it "should not try to remove backups that don't exist" do path = '/my/file' FileTest.stubs(:exists?).returns true backup = path + ".foo" File.expects(:lstat).with(backup).raises(Errno::ENOENT) File.expects(:unlink).never FileUtils.stubs(:cp_r) file = Puppet::Type.type(:file).new(:name => path, :backup => '.foo') file.perform_backup end it "a copy should be created in the local directory" do path = '/my/file' FileTest.stubs(:exists?).with(path).returns true FileUtils.expects(:cp_r).with(path, path + ".foo", :preserve => true) file = Puppet::Type.type(:file).new(:name => path, :backup => '.foo') file.perform_backup.should be_true end it "should propagate exceptions if no backup can be created" do path = '/my/file' FileTest.stubs(:exists?).with(path).returns true FileUtils.expects(:cp_r).raises ArgumentError file = Puppet::Type.type(:file).new(:name => path, :backup => '.foo') lambda { file.perform_backup }.should raise_error(Puppet::Error) end end end describe "when backing up a directory" do it "a bucket should work when provided" do path = '/my/dir' File.stubs(:file?).returns true Find.expects(:find).with(path).yields("/my/dir/file") bucket = stub('bucket', :name => "eh") bucket.expects(:backup).with("/my/dir/file").returns true file = Puppet::Type.type(:file).new(:name => path, :backup => 'foo') file.stubs(:bucket).returns bucket File.stubs(:stat).with(path).returns(stub('stat', :ftype => 'directory')) file.perform_backup end it "should do nothing when recursing" do path = '/my/dir' bucket = stub('bucket', :name => "eh") bucket.expects(:backup).never file = Puppet::Type.type(:file).new(:name => path, :backup => 'foo', :recurse => true) file.stubs(:bucket).returns bucket File.stubs(:stat).with(path).returns(stub('stat', :ftype => 'directory')) Find.expects(:find).never file.perform_backup end end end diff --git a/spec/unit/util/cache_accumulator_spec.rb b/spec/unit/util/cache_accumulator_spec.rb index f4741c530..9c35cc353 100755 --- a/spec/unit/util/cache_accumulator_spec.rb +++ b/spec/unit/util/cache_accumulator_spec.rb @@ -1,75 +1,74 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/util/rails/cache_accumulator' describe Puppet::Util::CacheAccumulator do before :each do @test_class = Class.new do attr_accessor :name include Puppet::Util::CacheAccumulator accumulates :name def initialize(n) self.name = n end end end it 'should delegate to underlying find_or_create_by_* method and accumulate results' do @test_class.expects(:find_or_create_by_name).with('foo').returns(@test_class.new('foo')).once obj = @test_class.accumulate_by_name('foo') obj.name.should == 'foo' @test_class.accumulate_by_name('foo').should == obj end it 'should delegate bulk lookups to find with appropriate arguments and returning result count' do @test_class.expects(:find).with( :all, :conditions => {:name => ['a', 'b', 'c']} ).returns(['a','b','c'].collect {|n| @test_class.new(n)}).once @test_class.accumulate_by_name('a', 'b', 'c').should == 3 end it 'should only need find_or_create_by_name lookup for missing bulk entries' do @test_class.expects(:find).with( :all, :conditions => {:name => ['a', 'b']} ).returns([ @test_class.new('a') ]).once @test_class.expects(:find_or_create_by_name).with('b').returns(@test_class.new('b')).once @test_class.expects(:find_or_create_by_name).with('a').never @test_class.accumulate_by_name('a','b').should == 1 @test_class.accumulate_by_name('a').name.should == 'a' @test_class.accumulate_by_name('b').name.should == 'b' end it 'should keep consumer classes separate' do @alt_class = Class.new do attr_accessor :name include Puppet::Util::CacheAccumulator accumulates :name def initialize(n) self.name = n end end name = 'foo' @test_class.expects(:find_or_create_by_name).with(name).returns(@test_class.new(name)).once @alt_class.expects(:find_or_create_by_name).with(name).returns(@alt_class.new(name)).once [@test_class, @alt_class].each do |klass| klass.accumulate_by_name(name).name.should == name klass.accumulate_by_name(name).class.should == klass end end it 'should clear accumulated cache with reset_*_accumulator' do # figure out how to test this appropriately... end end diff --git a/spec/unit/util/cacher_spec.rb b/spec/unit/util/cacher_spec.rb index 890960693..2e43b4e20 100755 --- a/spec/unit/util/cacher_spec.rb +++ b/spec/unit/util/cacher_spec.rb @@ -1,185 +1,184 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/util/cacher' class ExpirerTest include Puppet::Util::Cacher::Expirer end class CacheTest @@init_count = 0 include Puppet::Util::Cacher cached_attr(:instance_cache) { Time.now } end describe Puppet::Util::Cacher::Expirer do before do @expirer = ExpirerTest.new end it "should be able to test whether a timestamp is expired" do @expirer.should respond_to(:dependent_data_expired?) end it "should be able to expire all values" do @expirer.should respond_to(:expire) end it "should consider any value to be valid if it has never been expired" do @expirer.should_not be_dependent_data_expired(Time.now) end it "should consider any value created after expiration to be expired" do @expirer.expire @expirer.should be_dependent_data_expired(Time.now - 1) end end describe Puppet::Util::Cacher do it "should be extended with the Expirer module" do Puppet::Util::Cacher.singleton_class.ancestors.should be_include(Puppet::Util::Cacher::Expirer) end it "should support defining cached attributes" do CacheTest.methods.should be_include("cached_attr") end it "should default to the Cacher module as its expirer" do CacheTest.new.expirer.should equal(Puppet::Util::Cacher) end describe "when using cached attributes" do before do @expirer = ExpirerTest.new @object = CacheTest.new @object.stubs(:expirer).returns @expirer end it "should create a getter for the cached attribute" do @object.should respond_to(:instance_cache) end it "should return a value calculated from the provided block" do time = Time.now Time.stubs(:now).returns time @object.instance_cache.should equal(time) end it "should return the cached value from the getter every time if the value is not expired" do @object.instance_cache.should equal(@object.instance_cache) end it "should regenerate and return a new value using the provided block if the value has been expired" do value = @object.instance_cache @expirer.expire @object.instance_cache.should_not equal(value) end it "should be able to trigger expiration on its expirer" do @expirer.expects(:expire) @object.expire end it "should do nothing when asked to expire when no expirer is available" do cacher = CacheTest.new class << cacher def expirer nil end end lambda { cacher.expire }.should_not raise_error end it "should be able to cache false values" do @object.expects(:init_instance_cache).returns false @object.instance_cache.should be_false @object.instance_cache.should be_false end it "should cache values again after expiration" do @object.instance_cache @expirer.expire @object.instance_cache.should equal(@object.instance_cache) end it "should always consider a value expired if it has no expirer" do @object.stubs(:expirer).returns nil @object.instance_cache.should_not equal(@object.instance_cache) end it "should allow writing of the attribute" do @object.should respond_to(:instance_cache=) end it "should correctly configure timestamps for expiration when the cached attribute is written to" do @object.instance_cache = "foo" @expirer.expire @object.instance_cache.should_not == "foo" end it "should allow specification of a ttl for cached attributes" do klass = Class.new do include Puppet::Util::Cacher end klass.cached_attr(:myattr, :ttl => 5) { Time.now } klass.attr_ttl(:myattr).should == 5 end it "should allow specification of a ttl as a string" do klass = Class.new do include Puppet::Util::Cacher end klass.cached_attr(:myattr, :ttl => "5") { Time.now } klass.attr_ttl(:myattr).should == 5 end it "should fail helpfully if the ttl cannot be converted to an integer" do klass = Class.new do include Puppet::Util::Cacher end lambda { klass.cached_attr(:myattr, :ttl => "yep") { Time.now } }.should raise_error(ArgumentError) end it "should not check for a ttl expiration if the class does not support that method" do klass = Class.new do extend Puppet::Util::Cacher end klass.singleton_class.cached_attr(:myattr) { "eh" } klass.myattr end it "should automatically expire cached attributes whose ttl has expired, even if no expirer is present" do klass = Class.new do def self.to_s "CacheTestClass" end include Puppet::Util::Cacher attr_accessor :value end klass.cached_attr(:myattr, :ttl => 5) { self.value += 1; self.value } now = Time.now later = Time.now + 15 instance = klass.new instance.value = 0 instance.myattr.should == 1 Time.expects(:now).returns later # This call should get the new Time value, which should expire the old value instance.myattr.should == 2 end end end diff --git a/spec/unit/util/checksums_spec.rb b/spec/unit/util/checksums_spec.rb index 4e7bc9d18..146544201 100755 --- a/spec/unit/util/checksums_spec.rb +++ b/spec/unit/util/checksums_spec.rb @@ -1,161 +1,161 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Created by Luke Kanies on 2007-9-22. # Copyright (c) 2007. All rights reserved. require 'spec_helper' require 'puppet/util/checksums' describe Puppet::Util::Checksums do before do @summer = Object.new @summer.extend(Puppet::Util::Checksums) end content_sums = [:md5, :md5lite, :sha1, :sha1lite] file_only = [:ctime, :mtime, :none] content_sums.each do |sumtype| it "should be able to calculate #{sumtype} sums from strings" do @summer.should be_respond_to(sumtype) end end [content_sums, file_only].flatten.each do |sumtype| it "should be able to calculate #{sumtype} sums from files" do @summer.should be_respond_to(sumtype.to_s + "_file") end end [content_sums, file_only].flatten.each do |sumtype| it "should be able to calculate #{sumtype} sums from stream" do @summer.should be_respond_to(sumtype.to_s + "_stream") end end it "should have a method for determining whether a given string is a checksum" do @summer.should respond_to(:checksum?) end %w{{md5}asdfasdf {sha1}asdfasdf {ctime}asdasdf {mtime}asdfasdf}.each do |sum| it "should consider #{sum} to be a checksum" do @summer.should be_checksum(sum) end end %w{{nosuchsum}asdfasdf {a}asdfasdf {ctime}}.each do |sum| it "should not consider #{sum} to be a checksum" do @summer.should_not be_checksum(sum) end end it "should have a method for stripping a sum type from an existing checksum" do @summer.sumtype("{md5}asdfasdfa").should == "md5" end it "should have a method for stripping the data from a checksum" do @summer.sumdata("{md5}asdfasdfa").should == "asdfasdfa" end it "should return a nil sumtype if the checksum does not mention a checksum type" do @summer.sumtype("asdfasdfa").should be_nil end {:md5 => Digest::MD5, :sha1 => Digest::SHA1}.each do |sum, klass| describe("when using #{sum}") do it "should use #{klass} to calculate string checksums" do klass.expects(:hexdigest).with("mycontent").returns "whatever" @summer.send(sum, "mycontent").should == "whatever" end it "should use incremental #{klass} sums to calculate file checksums" do digest = mock 'digest' klass.expects(:new).returns digest file = "/path/to/my/file" fh = mock 'filehandle' fh.expects(:read).with(4096).times(3).returns("firstline").then.returns("secondline").then.returns(nil) #fh.expects(:read).with(512).returns("secondline") #fh.expects(:read).with(512).returns(nil) File.expects(:open).with(file, "r").yields(fh) digest.expects(:<<).with "firstline" digest.expects(:<<).with "secondline" digest.expects(:hexdigest).returns :mydigest @summer.send(sum.to_s + "_file", file).should == :mydigest end it "should yield #{klass} to the given block to calculate stream checksums" do digest = mock 'digest' klass.expects(:new).returns digest digest.expects(:hexdigest).returns :mydigest @summer.send(sum.to_s + "_stream") do |sum| sum.should == digest end.should == :mydigest end end end {:md5lite => Digest::MD5, :sha1lite => Digest::SHA1}.each do |sum, klass| describe("when using #{sum}") do it "should use #{klass} to calculate string checksums from the first 512 characters of the string" do content = "this is a test" * 100 klass.expects(:hexdigest).with(content[0..511]).returns "whatever" @summer.send(sum, content).should == "whatever" end it "should use #{klass} to calculate a sum from the first 512 characters in the file" do digest = mock 'digest' klass.expects(:new).returns digest file = "/path/to/my/file" fh = mock 'filehandle' fh.expects(:read).with(512).returns('my content') File.expects(:open).with(file, "r").yields(fh) digest.expects(:<<).with "my content" digest.expects(:hexdigest).returns :mydigest @summer.send(sum.to_s + "_file", file).should == :mydigest end end end [:ctime, :mtime].each do |sum| describe("when using #{sum}") do it "should use the '#{sum}' on the file to determine the ctime" do file = "/my/file" stat = mock 'stat', sum => "mysum" File.expects(:stat).with(file).returns(stat) @summer.send(sum.to_s + "_file", file).should == "mysum" end it "should return nil for streams" do expectation = stub "expectation" expectation.expects(:do_something!).at_least_once @summer.send(sum.to_s + "_stream"){ |checksum| checksum << "anything" ; expectation.do_something! }.should be_nil end end end describe "when using the none checksum" do it "should return an empty string" do @summer.none_file("/my/file").should == "" end it "should return an empty string for streams" do expectation = stub "expectation" expectation.expects(:do_something!).at_least_once @summer.none_stream{ |checksum| checksum << "anything" ; expectation.do_something! }.should == "" end end end diff --git a/spec/unit/util/command_line_spec.rb b/spec/unit/util/command_line_spec.rb index 6cf90475b..81612ee5c 100755 --- a/spec/unit/util/command_line_spec.rb +++ b/spec/unit/util/command_line_spec.rb @@ -1,143 +1,142 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/util/command_line' describe Puppet::Util::CommandLine do include PuppetSpec::Files before do @tty = stub("tty", :tty? => true ) @pipe = stub("pipe", :tty? => false) end it "should pull off the first argument if it looks like a subcommand" do command_line = Puppet::Util::CommandLine.new("puppet", %w{ client --help whatever.pp }, @tty ) command_line.subcommand_name.should == "client" command_line.args.should == %w{ --help whatever.pp } end it "should use 'apply' if the first argument looks like a .pp file" do command_line = Puppet::Util::CommandLine.new("puppet", %w{ whatever.pp }, @tty ) command_line.subcommand_name.should == "apply" command_line.args.should == %w{ whatever.pp } end it "should use 'apply' if the first argument looks like a .rb file" do command_line = Puppet::Util::CommandLine.new("puppet", %w{ whatever.rb }, @tty ) command_line.subcommand_name.should == "apply" command_line.args.should == %w{ whatever.rb } end it "should use 'apply' if the first argument looks like a flag" do command_line = Puppet::Util::CommandLine.new("puppet", %w{ --debug }, @tty ) command_line.subcommand_name.should == "apply" command_line.args.should == %w{ --debug } end it "should use 'apply' if the first argument is -" do command_line = Puppet::Util::CommandLine.new("puppet", %w{ - }, @tty ) command_line.subcommand_name.should == "apply" command_line.args.should == %w{ - } end it "should return nil if the first argument is --help" do command_line = Puppet::Util::CommandLine.new("puppet", %w{ --help }, @tty ) command_line.subcommand_name.should == nil end it "should return nil if there are no arguments on a tty" do command_line = Puppet::Util::CommandLine.new("puppet", [], @tty ) command_line.subcommand_name.should == nil command_line.args.should == [] end it "should use 'apply' if there are no arguments on a pipe" do command_line = Puppet::Util::CommandLine.new("puppet", [], @pipe ) command_line.subcommand_name.should == "apply" command_line.args.should == [] end it "should return the executable name if it is not puppet" do command_line = Puppet::Util::CommandLine.new("puppetmasterd", [], @tty ) command_line.subcommand_name.should == "puppetmasterd" end it "should translate subcommand names into their legacy equivalent" do command_line = Puppet::Util::CommandLine.new("puppet", ["master"], @tty) command_line.legacy_executable_name.should == "puppetmasterd" end it "should leave legacy command names alone" do command_line = Puppet::Util::CommandLine.new("puppetmasterd", [], @tty) command_line.legacy_executable_name.should == "puppetmasterd" end describe "when the subcommand is not implemented" do it "should find and invoke an executable with a hyphenated name" do commandline = Puppet::Util::CommandLine.new("puppet", ['whatever', 'argument'], @tty) Puppet::Util.expects(:which).with('puppet-whatever').returns('/dev/null/puppet-whatever') commandline.expects(:system).with('/dev/null/puppet-whatever', 'argument') commandline.execute end describe "and an external implementation cannot be found" do it "should abort and show the usage message" do commandline = Puppet::Util::CommandLine.new("puppet", ['whatever', 'argument'], @tty) Puppet::Util.expects(:which).with('puppet-whatever').returns(nil) commandline.expects(:system).never - text = Puppet::Faces[:help, :current].help + text = Puppet::Face[:help, :current].help commandline.expects(:puts).with { |x| x =~ /Unknown Puppet subcommand/ } commandline.expects(:puts).with text commandline.execute end end end describe 'when loading commands' do before do @core_apps = %w{describe filebucket kick queue resource agent cert apply doc master} @command_line = Puppet::Util::CommandLine.new("foo", %w{ client --help whatever.pp }, @tty ) end it "should expose available_subcommands as a class method" do @core_apps.each do |command| @command_line.available_subcommands.should include command end end it 'should be able to find all existing commands' do @core_apps.each do |command| @command_line.available_subcommands.should include command end end describe 'when multiple paths have applications' do before do @dir=tmpdir('command_line_plugin_test') @appdir="#{@dir}/puppet/application" FileUtils.mkdir_p(@appdir) FileUtils.touch("#{@appdir}/foo.rb") $LOAD_PATH.unshift(@dir) # WARNING: MUST MATCH THE AFTER ACTIONS! end it 'should be able to find commands from both paths' do found = @command_line.available_subcommands found.should include 'foo' @core_apps.each { |cmd| found.should include cmd } end after do $LOAD_PATH.shift # WARNING: MUST MATCH THE BEFORE ACTIONS! end end end end diff --git a/spec/unit/util/constant_inflector_spec.rb b/spec/unit/util/constant_inflector_spec.rb index 20283cb59..cf2e8f892 100755 --- a/spec/unit/util/constant_inflector_spec.rb +++ b/spec/unit/util/constant_inflector_spec.rb @@ -1,70 +1,70 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Created by Luke Kanies on 2008-02-12. # Copyright (c) 2007. All rights reserved. require 'spec_helper' require 'puppet/util/constant_inflector' describe Puppet::Util::ConstantInflector, "when converting file names to constants" do before do @inflector = Object.new @inflector.extend(Puppet::Util::ConstantInflector) end it "should capitalize terms" do @inflector.file2constant("file").should == "File" end it "should switch all '/' characters to double colons" do @inflector.file2constant("file/other").should == "File::Other" end it "should remove underscores and capitalize the proceeding letter" do @inflector.file2constant("file_other").should == "FileOther" end it "should correctly replace as many underscores as exist in the file name" do @inflector.file2constant("two_under_scores/with_some_more_underscores").should == "TwoUnderScores::WithSomeMoreUnderscores" end it "should collapse multiple underscores" do @inflector.file2constant("many___scores").should == "ManyScores" end it "should correctly handle file names deeper than two directories" do @inflector.file2constant("one_two/three_four/five_six").should == "OneTwo::ThreeFour::FiveSix" end end describe Puppet::Util::ConstantInflector, "when converting constnats to file names" do before do @inflector = Object.new @inflector.extend(Puppet::Util::ConstantInflector) end it "should convert them to a string if necessary" do @inflector.constant2file(Puppet::Util::ConstantInflector).should be_instance_of(String) end it "should accept string inputs" do @inflector.constant2file("Puppet::Util::ConstantInflector").should be_instance_of(String) end it "should downcase all terms" do @inflector.constant2file("Puppet").should == "puppet" end it "should convert '::' to '/'" do @inflector.constant2file("Puppet::Util::Constant").should == "puppet/util/constant" end it "should convert mid-word capitalization to an underscore" do @inflector.constant2file("OneTwo::ThreeFour").should == "one_two/three_four" end it "should correctly handle constants with more than two parts" do @inflector.constant2file("OneTwoThree::FourFiveSixSeven").should == "one_two_three/four_five_six_seven" end end diff --git a/spec/unit/util/errors_spec.rb b/spec/unit/util/errors_spec.rb index 9b4984ce3..d51a15ef4 100755 --- a/spec/unit/util/errors_spec.rb +++ b/spec/unit/util/errors_spec.rb @@ -1,38 +1,37 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/util/errors' class ErrorTester include Puppet::Util::Errors attr_accessor :line, :file end describe Puppet::Util::Errors do before do @tester = ErrorTester.new end it "should provide a 'fail' method" do @tester.should respond_to(:fail) end it "should provide a 'devfail' method" do @tester.should respond_to(:devfail) end it "should raise any provided error when failing" do lambda { @tester.fail(Puppet::ParseError, "stuff") }.should raise_error(Puppet::ParseError) end it "should default to Puppet::Error when failing" do lambda { @tester.fail("stuff") }.should raise_error(Puppet::Error) end it "should have a method for converting error context into a string" do @tester.file = "/my/file" @tester.line = 50 @tester.error_context.should == " at /my/file:50" end end diff --git a/spec/unit/util/execution_spec.rb b/spec/unit/util/execution_spec.rb index 337a05ffe..5b8b8a527 100755 --- a/spec/unit/util/execution_spec.rb +++ b/spec/unit/util/execution_spec.rb @@ -1,49 +1,48 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe Puppet::Util::Execution do include Puppet::Util::Execution describe "#withenv" do before :each do @original_path = ENV["PATH"] @new_env = {:PATH => "/some/bogus/path"} end it "should change environment variables within the block then reset environment variables to their original values" do withenv @new_env do ENV["PATH"].should == "/some/bogus/path" end ENV["PATH"].should == @original_path end it "should reset environment variables to their original values even if the block fails" do begin withenv @new_env do ENV["PATH"].should == "/some/bogus/path" raise "This is a failure" end rescue end ENV["PATH"].should == @original_path end it "should reset environment variables even when they are set twice" do # Setting Path & Environment parameters in Exec type can cause weirdness @new_env["PATH"] = "/someother/bogus/path" withenv @new_env do # When assigning duplicate keys, can't guarantee order of evaluation ENV["PATH"].should =~ /\/some.*\/bogus\/path/ end ENV["PATH"].should == @original_path end it "should remove any new environment variables after the block ends" do @new_env[:FOO] = "bar" withenv @new_env do ENV["FOO"].should == "bar" end ENV["FOO"].should == nil end end end diff --git a/spec/unit/util/execution_stub_spec.rb b/spec/unit/util/execution_stub_spec.rb index 2a478f008..34987689c 100755 --- a/spec/unit/util/execution_stub_spec.rb +++ b/spec/unit/util/execution_stub_spec.rb @@ -1,35 +1,34 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe Puppet::Util::ExecutionStub do it "should use the provided stub code when 'set' is called" do Puppet::Util::ExecutionStub.set do |command, options| command.should == ['/bin/foo', 'bar'] "stub output" end Puppet::Util::ExecutionStub.current_value.should_not == nil Puppet::Util.execute(['/bin/foo', 'bar']).should == "stub output" end it "should automatically restore normal execution at the conclusion of each spec test" do # Note: this test relies on the previous test creating a stub. Puppet::Util::ExecutionStub.current_value.should == nil end it "should restore normal execution after 'reset' is called" do true_command = Puppet::Util.which('true') # Note: "true" exists at different paths in different OSes stub_call_count = 0 Puppet::Util::ExecutionStub.set do |command, options| command.should == [true_command] stub_call_count += 1 'stub called' end Puppet::Util.execute([true_command]).should == 'stub called' stub_call_count.should == 1 Puppet::Util::ExecutionStub.reset Puppet::Util::ExecutionStub.current_value.should == nil Puppet::Util.execute([true_command]).should == '' stub_call_count.should == 1 end end diff --git a/spec/unit/util/feature_spec.rb b/spec/unit/util/feature_spec.rb index e7632fc4d..15375e0b1 100755 --- a/spec/unit/util/feature_spec.rb +++ b/spec/unit/util/feature_spec.rb @@ -1,72 +1,71 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/util/feature' describe Puppet::Util::Feature do before do @features = Puppet::Util::Feature.new("features") @features.stubs(:warn) end it "should consider undefined features to be absent" do @features.should_not be_defined_feature end it "should be able to add new features" do @features.add(:myfeature) {} @features.should respond_to(:myfeature?) end it "should call associated code when loading a feature" do $loaded_feature = false @features.add(:myfeature) { $loaded_feature = true} $loaded_feature.should be_true end it "should consider a feature absent when the feature load fails" do @features.add(:failer) { raise "foo" } @features.should_not be_failer end it "should consider a feature to be absent when the feature load returns false" do @features.add(:failer) { false } @features.should_not be_failer end it "should consider a feature to be present when the feature load returns true" do @features.add(:available) { true } @features.should be_available end it "should cache the results of a feature load" do $loaded_feature = 0 @features.add(:myfeature) { $loaded_feature += 1 } @features.myfeature? @features.myfeature? $loaded_feature.should == 1 end it "should support features with libraries" do lambda { @features.add(:puppet, :libs => %w{puppet}) }.should_not raise_error end it "should consider a feature to be present if all of its libraries are present" do @features.add(:myfeature, :libs => %w{foo bar}) @features.expects(:require).with("foo") @features.expects(:require).with("bar") @features.should be_myfeature end it "should log and consider a feature to be absent if any of its libraries are absent" do @features.add(:myfeature, :libs => %w{foo bar}) @features.expects(:require).with("foo").raises(LoadError) @features.stubs(:require).with("bar") Puppet.expects(:debug) @features.should_not be_myfeature end end diff --git a/spec/unit/util/file_locking_spec.rb b/spec/unit/util/file_locking_spec.rb index 32712429f..261474263 100755 --- a/spec/unit/util/file_locking_spec.rb +++ b/spec/unit/util/file_locking_spec.rb @@ -1,160 +1,159 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/util/file_locking' class FileLocker include Puppet::Util::FileLocking end describe Puppet::Util::FileLocking do it "should have a module method for getting a read lock on files" do Puppet::Util::FileLocking.should respond_to(:readlock) end it "should have a module method for getting a write lock on files" do Puppet::Util::FileLocking.should respond_to(:writelock) end it "should have an instance method for getting a read lock on files" do FileLocker.new.private_methods.should be_include("readlock") end it "should have an instance method for getting a write lock on files" do FileLocker.new.private_methods.should be_include("writelock") end describe "when acquiring a read lock" do before do File.stubs(:exists?).with('/file').returns true File.stubs(:file?).with('/file').returns true end it "should use a global shared mutex" do Puppet::Util.expects(:synchronize_on).with('/file',Sync::SH).once Puppet::Util::FileLocking.readlock '/file' end it "should use a shared lock on the file" do Puppet::Util.expects(:synchronize_on).with('/file',Sync::SH).yields fh = mock 'filehandle' File.expects(:open).with("/file").yields fh fh.expects(:lock_shared).yields "locked_fh" result = nil Puppet::Util::FileLocking.readlock('/file') { |l| result = l } result.should == "locked_fh" end it "should only work on regular files" do File.expects(:file?).with('/file').returns false proc { Puppet::Util::FileLocking.readlock('/file') }.should raise_error(ArgumentError) end it "should create missing files" do Puppet::Util.expects(:synchronize_on).with('/file',Sync::SH).yields File.expects(:exists?).with('/file').returns false File.expects(:open).with('/file').once Puppet::Util::FileLocking.readlock('/file') end end describe "when acquiring a write lock" do before do Puppet::Util.stubs(:synchronize_on).yields File.stubs(:file?).with('/file').returns true File.stubs(:exists?).with('/file').returns true end it "should fail if the parent directory does not exist" do FileTest.expects(:directory?).with("/my/dir").returns false File.stubs(:file?).with('/my/dir/file').returns true File.stubs(:exists?).with('/my/dir/file').returns true lambda { Puppet::Util::FileLocking.writelock('/my/dir/file') }.should raise_error(Puppet::DevError) end it "should use a global exclusive mutex" do Puppet::Util.expects(:synchronize_on).with("/file",Sync::EX) Puppet::Util::FileLocking.writelock '/file' end it "should use any specified mode when opening the file" do File.expects(:open).with("/file", File::Constants::CREAT | File::Constants::WRONLY , :mymode) Puppet::Util::FileLocking.writelock('/file', :mymode) end it "should use the mode of the existing file if no mode is specified" do File.expects(:stat).with("/file").returns(mock("stat", :mode => 0755)) File.expects(:open).with("/file", File::Constants::CREAT | File::Constants::WRONLY, 0755) Puppet::Util::FileLocking.writelock('/file') end it "should use 0600 as the mode if no mode is specified and the file does not exist" do File.expects(:stat).raises(Errno::ENOENT) File.expects(:open).with("/file", File::Constants::CREAT | File::Constants::WRONLY, 0600) Puppet::Util::FileLocking.writelock('/file') end it "should create an exclusive file lock" do fh = mock 'fh' File.expects(:open).yields fh fh.expects(:lock_exclusive) Puppet::Util::FileLocking.writelock('/file') end it "should allow the caller to write to the locked file" do fh = mock 'fh' File.expects(:open).yields fh lfh = mock 'locked_filehandle' fh.expects(:lock_exclusive).yields(lfh) lfh.stubs(:seek) lfh.stubs(:truncate) lfh.expects(:print).with "foo" Puppet::Util::FileLocking.writelock('/file') do |f| f.print "foo" end end it "should truncate the file under an exclusive lock" do fh = mock 'fh' File.expects(:open).yields fh lfh = mock 'locked_filehandle' fh.expects(:lock_exclusive).yields(lfh) lfh.expects(:seek).with(0, IO::SEEK_SET) lfh.expects(:truncate).with(0) lfh.stubs(:print) Puppet::Util::FileLocking.writelock('/file') do |f| f.print "foo" end end it "should only work on regular files" do File.expects(:file?).with('/file').returns false proc { Puppet::Util::FileLocking.writelock('/file') }.should raise_error(ArgumentError) end it "should create missing files" do Puppet::Util.expects(:synchronize_on).with('/file',Sync::EX).yields File.expects(:exists?).with('/file').returns false File.expects(:open).with('/file', File::Constants::CREAT | File::Constants::WRONLY, 0600).once Puppet::Util::FileLocking.writelock('/file') end end end diff --git a/spec/unit/util/filetype_spec.rb b/spec/unit/util/filetype_spec.rb index 492691e0b..a2c0da660 100755 --- a/spec/unit/util/filetype_spec.rb +++ b/spec/unit/util/filetype_spec.rb @@ -1,100 +1,99 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/util/filetype' # XXX Import all of the tests into this file. describe Puppet::Util::FileType do describe "when backing up a file" do before do @file = Puppet::Util::FileType.filetype(:flat).new("/my/file") end it "should do nothing if the file does not exist" do File.expects(:exists?).with("/my/file").returns false @file.expects(:bucket).never @file.backup end it "should use its filebucket to backup the file if it exists" do File.expects(:exists?).with("/my/file").returns true bucket = mock 'bucket' bucket.expects(:backup).with("/my/file") @file.expects(:bucket).returns bucket @file.backup end it "should use the default filebucket" do bucket = mock 'bucket' bucket.expects(:bucket).returns "mybucket" Puppet::Type.type(:filebucket).expects(:mkdefaultbucket).returns bucket @file.bucket.should == "mybucket" end end describe "the flat filetype" do before do @type = Puppet::Util::FileType.filetype(:flat) end it "should exist" do @type.should_not be_nil end describe "when the file already exists" do it "should return the file's contents when asked to read it" do file = @type.new("/my/file") File.expects(:exist?).with("/my/file").returns true File.expects(:read).with("/my/file").returns "my text" file.read.should == "my text" end it "should unlink the file when asked to remove it" do file = @type.new("/my/file") File.expects(:exist?).with("/my/file").returns true File.expects(:unlink).with("/my/file") file.remove end end describe "when the file does not exist" do it "should return an empty string when asked to read the file" do file = @type.new("/my/file") File.expects(:exist?).with("/my/file").returns false file.read.should == "" end end describe "when writing the file" do before do @file = @type.new("/my/file") FileUtils.stubs(:cp) @tempfile = stub 'tempfile', :print => nil, :close => nil, :flush => nil, :path => "/other/file" Tempfile.stubs(:new).returns @tempfile end it "should first create a temp file and copy its contents over to the file location" do Tempfile.expects(:new).with("puppet").returns @tempfile @tempfile.expects(:print).with("my text") @tempfile.expects(:flush) @tempfile.expects(:close) FileUtils.expects(:cp).with(@tempfile.path, "/my/file") @file.write "my text" end it "should set the selinux default context on the file" do @file.expects(:set_selinux_default_context).with("/my/file") @file.write "eh" end end end end diff --git a/spec/unit/util/inline_docs_spec.rb b/spec/unit/util/inline_docs_spec.rb index 3baecc426..1d88180b3 100755 --- a/spec/unit/util/inline_docs_spec.rb +++ b/spec/unit/util/inline_docs_spec.rb @@ -1,32 +1,31 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/util/inline_docs' class InlineDoccer include Puppet::Util::InlineDocs end describe Puppet::Util::InlineDocs do describe "when included" do it "should create a class method for specifying that docs should be associated" do InlineDoccer.expects(:use_docs=).with true InlineDoccer.associates_doc end it "should default to not associating docs" do (!! InlineDoccer.use_docs).should be_false end it "should create an instance method for setting documentation" do instance = InlineDoccer.new instance.doc = "foo" instance.doc.should == "foo" end it "should default to an empty string for docs" do InlineDoccer.new.doc.should == "" end end end diff --git a/spec/unit/util/ldap/connection_spec.rb b/spec/unit/util/ldap/connection_spec.rb index 3fb5e388e..f97c72d77 100755 --- a/spec/unit/util/ldap/connection_spec.rb +++ b/spec/unit/util/ldap/connection_spec.rb @@ -1,169 +1,169 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Created by Luke Kanies on 2008-3-19. # Copyright (c) 2006. All rights reserved. require 'spec_helper' require 'puppet/util/ldap/connection' # So our mocks and such all work, even when ldap isn't available. unless Puppet.features.ldap? class LDAP class Conn def initialize(*args) end end class SSLConn < Conn; end LDAP_OPT_PROTOCOL_VERSION = 1 LDAP_OPT_REFERRALS = 2 LDAP_OPT_ON = 3 end end describe Puppet::Util::Ldap::Connection do before do Puppet.features.stubs(:ldap?).returns true @ldapconn = mock 'ldap' LDAP::Conn.stubs(:new).returns(@ldapconn) LDAP::SSLConn.stubs(:new).returns(@ldapconn) @ldapconn.stub_everything @connection = Puppet::Util::Ldap::Connection.new("host", "port") end describe "when creating connections" do it "should require the host and port" do lambda { Puppet::Util::Ldap::Connection.new("myhost") }.should raise_error(ArgumentError) end it "should allow specification of a user and password" do lambda { Puppet::Util::Ldap::Connection.new("myhost", "myport", :user => "blah", :password => "boo") }.should_not raise_error end it "should allow specification of ssl" do lambda { Puppet::Util::Ldap::Connection.new("myhost", "myport", :ssl => :tsl) }.should_not raise_error end it "should support requiring a new connection" do lambda { Puppet::Util::Ldap::Connection.new("myhost", "myport", :reset => true) }.should_not raise_error end it "should fail if ldap is unavailable" do Puppet.features.expects(:ldap?).returns(false) lambda { Puppet::Util::Ldap::Connection.new("host", "port") }.should raise_error(Puppet::Error) end it "should use neither ssl nor tls by default" do LDAP::Conn.expects(:new).with("host", "port").returns(@ldapconn) @connection.start end it "should use LDAP::SSLConn if ssl is requested" do LDAP::SSLConn.expects(:new).with("host", "port").returns(@ldapconn) @connection.ssl = true @connection.start end it "should use LDAP::SSLConn and tls if tls is requested" do LDAP::SSLConn.expects(:new).with("host", "port", true).returns(@ldapconn) @connection.ssl = :tls @connection.start end it "should set the protocol version to 3 and enable referrals" do @ldapconn.expects(:set_option).with(LDAP::LDAP_OPT_PROTOCOL_VERSION, 3) @ldapconn.expects(:set_option).with(LDAP::LDAP_OPT_REFERRALS, LDAP::LDAP_OPT_ON) @connection.start end it "should bind with the provided user and password" do @connection.user = "myuser" @connection.password = "mypassword" @ldapconn.expects(:simple_bind).with("myuser", "mypassword") @connection.start end it "should bind with no user and password if none has been provided" do @ldapconn.expects(:simple_bind).with(nil, nil) @connection.start end end describe "when closing connections" do it "should not close connections that are not open" do @connection.stubs(:connection).returns(@ldapconn) @ldapconn.expects(:bound?).returns false @ldapconn.expects(:unbind).never @connection.close end end it "should have a class-level method for creating a default connection" do Puppet::Util::Ldap::Connection.should respond_to(:instance) end describe "when creating a default connection" do before do Puppet.settings.stubs(:value).returns "whatever" end it "should use the :ldapserver setting to determine the host" do Puppet.settings.expects(:value).with(:ldapserver).returns "myserv" Puppet::Util::Ldap::Connection.expects(:new).with { |host, port, options| host == "myserv" } Puppet::Util::Ldap::Connection.instance end it "should use the :ldapport setting to determine the port" do Puppet.settings.expects(:value).with(:ldapport).returns "456" Puppet::Util::Ldap::Connection.expects(:new).with { |host, port, options| port == "456" } Puppet::Util::Ldap::Connection.instance end it "should set ssl to :tls if tls is enabled" do Puppet.settings.expects(:value).with(:ldaptls).returns true Puppet::Util::Ldap::Connection.expects(:new).with { |host, port, options| options[:ssl] == :tls } Puppet::Util::Ldap::Connection.instance end it "should set ssl to 'true' if ssl is enabled and tls is not" do Puppet.settings.expects(:value).with(:ldaptls).returns false Puppet.settings.expects(:value).with(:ldapssl).returns true Puppet::Util::Ldap::Connection.expects(:new).with { |host, port, options| options[:ssl] == true } Puppet::Util::Ldap::Connection.instance end it "should set ssl to false if neither ssl nor tls are enabled" do Puppet.settings.expects(:value).with(:ldaptls).returns false Puppet.settings.expects(:value).with(:ldapssl).returns false Puppet::Util::Ldap::Connection.expects(:new).with { |host, port, options| options[:ssl] == false } Puppet::Util::Ldap::Connection.instance end it "should set the ldapuser if one is set" do Puppet.settings.expects(:value).with(:ldapuser).returns "foo" Puppet::Util::Ldap::Connection.expects(:new).with { |host, port, options| options[:user] == "foo" } Puppet::Util::Ldap::Connection.instance end it "should set the ldapuser and ldappassword if both is set" do Puppet.settings.expects(:value).with(:ldapuser).returns "foo" Puppet.settings.expects(:value).with(:ldappassword).returns "bar" Puppet::Util::Ldap::Connection.expects(:new).with { |host, port, options| options[:user] == "foo" and options[:password] == "bar" } Puppet::Util::Ldap::Connection.instance end end end diff --git a/spec/unit/util/ldap/generator_spec.rb b/spec/unit/util/ldap/generator_spec.rb index 7c820759f..b3e664d6b 100755 --- a/spec/unit/util/ldap/generator_spec.rb +++ b/spec/unit/util/ldap/generator_spec.rb @@ -1,54 +1,54 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Created by Luke Kanies on 2008-3-28. # Copyright (c) 2008. All rights reserved. require 'spec_helper' require 'puppet/util/ldap/generator' describe Puppet::Util::Ldap::Generator do before do @generator = Puppet::Util::Ldap::Generator.new(:uno) end it "should require a parameter name at initialization" do lambda { Puppet::Util::Ldap::Generator.new }.should raise_error end it "should always return its name as a string" do g = Puppet::Util::Ldap::Generator.new(:myname) g.name.should == "myname" end it "should provide a method for declaring the source parameter" do @generator.from(:dos) end it "should always return a set source as a string" do @generator.from(:dos) @generator.source.should == "dos" end it "should return the source as nil if there is no source" do @generator.source.should be_nil end it "should return itself when declaring the source" do @generator.from(:dos).should equal(@generator) end it "should run the provided block when asked to generate the value" do @generator.with { "yayness" } @generator.generate.should == "yayness" end it "should pass in any provided value to the block" do @generator.with { |value| value.upcase } @generator.generate("myval").should == "MYVAL" end it "should return itself when declaring the code used for generating" do @generator.with { |value| value.upcase }.should equal(@generator) end end diff --git a/spec/unit/util/ldap/manager_spec.rb b/spec/unit/util/ldap/manager_spec.rb index a1b3f01ea..5cce626b5 100755 --- a/spec/unit/util/ldap/manager_spec.rb +++ b/spec/unit/util/ldap/manager_spec.rb @@ -1,654 +1,654 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Created by Luke Kanies on 2008-3-19. # Copyright (c) 2006. All rights reserved. require 'spec_helper' require 'puppet/util/ldap/manager' # If the ldap classes aren't available, go ahead and # create some, so our tests will pass. unless defined?(LDAP::Mod) class LDAP LDAP_MOD_ADD = :adding LDAP_MOD_REPLACE = :replacing LDAP_MOD_DELETE = :deleting class ResultError < RuntimeError; end class Mod def initialize(*args) end end end end describe Puppet::Util::Ldap::Manager do before do @manager = Puppet::Util::Ldap::Manager.new end it "should return self when specifying objectclasses" do @manager.manages(:one, :two).should equal(@manager) end it "should allow specification of what objectclasses are managed" do @manager.manages(:one, :two).objectclasses.should == [:one, :two] end it "should return self when specifying the relative base" do @manager.at("yay").should equal(@manager) end it "should allow specification of the relative base" do @manager.at("yay").location.should == "yay" end it "should return self when specifying the attribute map" do @manager.maps(:one => :two).should equal(@manager) end it "should allow specification of the rdn attribute" do @manager.named_by(:uid).rdn.should == :uid end it "should allow specification of the attribute map" do @manager.maps(:one => :two).puppet2ldap.should == {:one => :two} end it "should have a no-op 'and' method that just returns self" do @manager.and.should equal(@manager) end it "should allow specification of generated attributes" do @manager.generates(:thing).should be_instance_of(Puppet::Util::Ldap::Generator) end describe "when generating attributes" do before do @generator = stub 'generator', :source => "one", :name => "myparam" Puppet::Util::Ldap::Generator.stubs(:new).with(:myparam).returns @generator end it "should create a generator to do the parameter generation" do Puppet::Util::Ldap::Generator.expects(:new).with(:myparam).returns @generator @manager.generates(:myparam) end it "should return the generator from the :generates method" do @manager.generates(:myparam).should equal(@generator) end it "should not replace already present values" do @manager.generates(:myparam) attrs = {"myparam" => "testing"} @generator.expects(:generate).never @manager.generate attrs attrs["myparam"].should == "testing" end it "should look for the parameter as a string, not a symbol" do @manager.generates(:myparam) @generator.expects(:generate).with("yay").returns %w{double yay} attrs = {"one" => "yay"} @manager.generate attrs attrs["myparam"].should == %w{double yay} end it "should fail if a source is specified and no source value is not defined" do @manager.generates(:myparam) lambda { @manager.generate "two" => "yay" }.should raise_error(ArgumentError) end it "should use the source value to generate the new value if a source attribute is specified" do @manager.generates(:myparam) @generator.expects(:generate).with("yay").returns %w{double yay} @manager.generate "one" => "yay" end it "should not pass in any value if no source attribute is specified" do @generator.stubs(:source).returns nil @manager.generates(:myparam) @generator.expects(:generate).with.returns %w{double yay} @manager.generate "one" => "yay" end it "should convert any results to arrays of strings if necessary" do @generator.expects(:generate).returns :test @manager.generates(:myparam) attrs = {"one" => "two"} @manager.generate(attrs) attrs["myparam"].should == ["test"] end it "should add the result to the passed-in attribute hash" do @generator.expects(:generate).returns %w{test} @manager.generates(:myparam) attrs = {"one" => "two"} @manager.generate(attrs) attrs["myparam"].should == %w{test} end end it "should be considered invalid if it is missing a location" do @manager.manages :me @manager.maps :me => :you @manager.should_not be_valid end it "should be considered invalid if it is missing an objectclass list" do @manager.maps :me => :you @manager.at "ou=yayness" @manager.should_not be_valid end it "should be considered invalid if it is missing an attribute map" do @manager.manages :me @manager.at "ou=yayness" @manager.should_not be_valid end it "should be considered valid if it has an attribute map, location, and objectclass list" do @manager.maps :me => :you @manager.manages :me @manager.at "ou=yayness" @manager.should be_valid end it "should calculate an instance's dn using the :ldapbase setting and the relative base" do Puppet.settings.expects(:value).with(:ldapbase).returns "dc=testing" @manager.at "ou=mybase" @manager.dn("me").should == "cn=me,ou=mybase,dc=testing" end it "should use the specified rdn when calculating an instance's dn" do Puppet.settings.expects(:value).with(:ldapbase).returns "dc=testing" @manager.named_by :uid @manager.at "ou=mybase" @manager.dn("me").should =~ /^uid=me/ end it "should calculate its base using the :ldapbase setting and the relative base" do Puppet.settings.expects(:value).with(:ldapbase).returns "dc=testing" @manager.at "ou=mybase" @manager.base.should == "ou=mybase,dc=testing" end describe "when generating its search filter" do it "should using a single 'objectclass=' filter if a single objectclass is specified" do @manager.manages("testing") @manager.filter.should == "objectclass=testing" end it "should create an LDAP AND filter if multiple objectclasses are specified" do @manager.manages "testing", "okay", "done" @manager.filter.should == "(&(objectclass=testing)(objectclass=okay)(objectclass=done))" end end it "should have a method for converting a Puppet attribute name to an LDAP attribute name as a string" do @manager.maps :puppet_attr => :ldap_attr @manager.ldap_name(:puppet_attr).should == "ldap_attr" end it "should have a method for converting an LDAP attribute name to a Puppet attribute name" do @manager.maps :puppet_attr => :ldap_attr @manager.puppet_name(:ldap_attr).should == :puppet_attr end it "should have a :create method for creating ldap entries" do @manager.should respond_to(:create) end it "should have a :delete method for deleting ldap entries" do @manager.should respond_to(:delete) end it "should have a :modify method for modifying ldap entries" do @manager.should respond_to(:modify) end it "should have a method for finding an entry by name in ldap" do @manager.should respond_to(:find) end describe "when converting ldap entries to hashes for providers" do before do @manager.maps :uno => :one, :dos => :two @result = @manager.entry2provider("dn" => ["cn=one,ou=people,dc=madstop"], "one" => ["two"], "three" => %w{four}, "objectclass" => %w{yay ness}) end it "should set the name to the short portion of the dn" do @result[:name].should == "one" end it "should remove the objectclasses" do @result["objectclass"].should be_nil end it "should remove any attributes that are not mentioned in the map" do @result["three"].should be_nil end it "should rename convert to symbols all attributes to their puppet names" do @result[:uno].should == %w{two} end it "should set the value of all unset puppet attributes as :absent" do @result[:dos].should == :absent end end describe "when using an ldap connection" do before do @ldapconn = mock 'ldapconn' @conn = stub 'connection', :connection => @ldapconn, :start => nil, :close => nil Puppet::Util::Ldap::Connection.stubs(:new).returns(@conn) end it "should fail unless a block is given" do lambda { @manager.connect }.should raise_error(ArgumentError) end it "should open the connection with its server set to :ldapserver" do Puppet.settings.stubs(:value).returns(false) Puppet.settings.expects(:value).with(:ldapserver).returns("myserver") Puppet::Util::Ldap::Connection.expects(:new).with { |*args| args[0] == "myserver" }.returns @conn @manager.connect { |c| } end it "should open the connection with its port set to the :ldapport" do Puppet.settings.stubs(:value).returns(false) Puppet.settings.expects(:value).with(:ldapport).returns("28") Puppet::Util::Ldap::Connection.expects(:new).with { |*args| args[1] == "28" }.returns @conn @manager.connect { |c| } end it "should open the connection with no user if :ldapuser is not set" do Puppet.settings.stubs(:value).returns(false) Puppet.settings.expects(:value).with(:ldapuser).returns("") Puppet::Util::Ldap::Connection.expects(:new).with { |*args| args[2][:user].nil? }.returns @conn @manager.connect { |c| } end it "should open the connection with its user set to the :ldapuser if it is set" do Puppet.settings.stubs(:value).returns(false) Puppet.settings.expects(:value).with(:ldapuser).returns("mypass") Puppet::Util::Ldap::Connection.expects(:new).with { |*args| args[2][:user] == "mypass" }.returns @conn @manager.connect { |c| } end it "should open the connection with no password if :ldappassword is not set" do Puppet.settings.stubs(:value).returns(false) Puppet.settings.expects(:value).with(:ldappassword).returns("") Puppet::Util::Ldap::Connection.expects(:new).with { |*args| args[2][:password].nil? }.returns @conn @manager.connect { |c| } end it "should open the connection with its password set to the :ldappassword if it is set" do Puppet.settings.stubs(:value).returns(false) Puppet.settings.expects(:value).with(:ldappassword).returns("mypass") Puppet::Util::Ldap::Connection.expects(:new).with { |*args| args[2][:password] == "mypass" }.returns @conn @manager.connect { |c| } end it "should set ssl to :tls if ldaptls is enabled" do Puppet.settings.stubs(:value).returns(false) Puppet.settings.expects(:value).with(:ldaptls).returns(true) Puppet::Util::Ldap::Connection.expects(:new).with { |*args| args[2][:ssl] == :tls }.returns @conn @manager.connect { |c| } end it "should set ssl to true if ldapssl is enabled" do Puppet.settings.stubs(:value).returns(false) Puppet.settings.expects(:value).with(:ldapssl).returns(true) Puppet::Util::Ldap::Connection.expects(:new).with { |*args| args[2][:ssl] == true }.returns @conn @manager.connect { |c| } end it "should set ssl to false if neither ldaptls nor ldapssl is enabled" do Puppet.settings.stubs(:value).returns(false) Puppet.settings.expects(:value).with(:ldapssl).returns(false) Puppet::Util::Ldap::Connection.expects(:new).with { |*args| args[2][:ssl] == false }.returns @conn @manager.connect { |c| } end it "should open, yield, and then close the connection" do @conn.expects(:start) @conn.expects(:close) Puppet::Util::Ldap::Connection.expects(:new).returns(@conn) @ldapconn.expects(:test) @manager.connect { |c| c.test } end it "should close the connection even if there's an exception in the passed block" do @conn.expects(:close) lambda { @manager.connect { |c| raise ArgumentError } }.should raise_error(ArgumentError) end end describe "when using ldap" do before do @conn = mock 'connection' @manager.stubs(:connect).yields @conn @manager.stubs(:objectclasses).returns [:oc1, :oc2] @manager.maps :one => :uno, :two => :dos, :three => :tres, :four => :quatro end describe "to create entries" do it "should convert the first argument to its :create method to a full dn and pass the resulting argument list to its connection" do @manager.expects(:dn).with("myname").returns "mydn" @conn.expects(:add).with { |name, attrs| name == "mydn" } @manager.create("myname", {"attr" => "myattrs"}) end it "should add the objectclasses to the attributes" do @manager.expects(:dn).with("myname").returns "mydn" @conn.expects(:add).with { |name, attrs| attrs["objectClass"].include?("oc1") and attrs["objectClass"].include?("oc2") } @manager.create("myname", {:one => :testing}) end it "should add the rdn to the attributes" do @manager.expects(:dn).with("myname").returns "mydn" @conn.expects(:add).with { |name, attrs| attrs["cn"] == %w{myname} } @manager.create("myname", {:one => :testing}) end it "should add 'top' to the objectclasses if it is not listed" do @manager.expects(:dn).with("myname").returns "mydn" @conn.expects(:add).with { |name, attrs| attrs["objectClass"].include?("top") } @manager.create("myname", {:one => :testing}) end it "should add any generated values that are defined" do generator = stub 'generator', :source => :one, :name => "myparam" Puppet::Util::Ldap::Generator.expects(:new).with(:myparam).returns generator @manager.generates(:myparam) @manager.stubs(:dn).with("myname").returns "mydn" generator.expects(:generate).with(:testing).returns ["generated value"] @conn.expects(:add).with { |name, attrs| attrs["myparam"] == ["generated value"] } @manager.create("myname", {:one => :testing}) end it "should convert any generated values to arrays of strings if necessary" do generator = stub 'generator', :source => :one, :name => "myparam" Puppet::Util::Ldap::Generator.expects(:new).with(:myparam).returns generator @manager.generates(:myparam) @manager.stubs(:dn).returns "mydn" generator.expects(:generate).returns :generated @conn.expects(:add).with { |name, attrs| attrs["myparam"] == ["generated"] } @manager.create("myname", {:one => :testing}) end end describe "do delete entries" do it "should convert the first argument to its :delete method to a full dn and pass the resulting argument list to its connection" do @manager.expects(:dn).with("myname").returns "mydn" @conn.expects(:delete).with("mydn") @manager.delete("myname") end end describe "to modify entries" do it "should convert the first argument to its :modify method to a full dn and pass the resulting argument list to its connection" do @manager.expects(:dn).with("myname").returns "mydn" @conn.expects(:modify).with("mydn", :mymods) @manager.modify("myname", :mymods) end end describe "to find a single entry" do it "should use the dn of the provided name as the search base, a scope of 0, and 'objectclass=*' as the filter for a search2 call" do @manager.expects(:dn).with("myname").returns "mydn" @conn.expects(:search2).with("mydn", 0, "objectclass=*") @manager.find("myname") end it "should return nil if an exception is thrown because no result is found" do @manager.expects(:dn).with("myname").returns "mydn" @conn.expects(:search2).raises LDAP::ResultError @manager.find("myname").should be_nil end it "should return a converted provider hash if the result is found" do @manager.expects(:dn).with("myname").returns "mydn" result = {"one" => "two"} @conn.expects(:search2).yields result @manager.expects(:entry2provider).with(result).returns "myprovider" @manager.find("myname").should == "myprovider" end end describe "to search for multiple entries" do before do @manager.stubs(:filter).returns "myfilter" end it "should use the manager's search base as the dn of the provided name as the search base" do @manager.expects(:base).returns "mybase" @conn.expects(:search2).with { |base, scope, filter| base == "mybase" } @manager.search end it "should use a scope of 1" do @conn.expects(:search2).with { |base, scope, filter| scope == 1 } @manager.search end it "should use any specified search filter" do @manager.expects(:filter).never @conn.expects(:search2).with { |base, scope, filter| filter == "boo" } @manager.search("boo") end it "should turn its objectclass list into its search filter if one is not specified" do @manager.expects(:filter).returns "yay" @conn.expects(:search2).with { |base, scope, filter| filter == "yay" } @manager.search end it "should return nil if no result is found" do @conn.expects(:search2) @manager.search.should be_nil end it "should return an array of the found results converted to provider hashes" do # LAK: AFAICT, it's impossible to yield multiple times in an expectation. one = {"dn" => "cn=one,dc=madstop,dc=com", "one" => "two"} @conn.expects(:search2).yields(one) @manager.expects(:entry2provider).with(one).returns "myprov" @manager.search.should == ["myprov"] end end end describe "when an instance" do before do @name = "myname" @manager.maps :one => :uno, :two => :dos, :three => :tres, :four => :quatro end describe "is being updated" do it "should get created if the current attribute list is empty and the desired attribute list has :ensure == :present" do @manager.expects(:create) @manager.update(@name, {}, {:ensure => :present}) end it "should get created if the current attribute list has :ensure == :absent and the desired attribute list has :ensure == :present" do @manager.expects(:create) @manager.update(@name, {:ensure => :absent}, {:ensure => :present}) end it "should get deleted if the current attribute list has :ensure == :present and the desired attribute list has :ensure == :absent" do @manager.expects(:delete) @manager.update(@name, {:ensure => :present}, {:ensure => :absent}) end it "should get modified if both attribute lists have :ensure == :present" do @manager.expects(:modify) @manager.update(@name, {:ensure => :present, :one => :two}, {:ensure => :present, :one => :three}) end end describe "is being deleted" do it "should call the :delete method with its name and manager" do @manager.expects(:delete).with(@name) @manager.update(@name, {}, {:ensure => :absent}) end end describe "is being created" do before do @is = {} @should = {:ensure => :present, :one => :yay, :two => :absent} end it "should call the :create method with its name" do @manager.expects(:create).with { |name, attrs| name == @name } @manager.update(@name, @is, @should) end it "should call the :create method with its property hash converted to ldap attribute names" do @manager.expects(:create).with { |name, attrs| attrs["uno"] == ["yay"] } @manager.update(@name, @is, @should) end it "should convert the property names to strings" do @manager.expects(:create).with { |name, attrs| attrs["uno"] == ["yay"] } @manager.update(@name, @is, @should) end it "should convert the property values to arrays if necessary" do @manager.expects(:create).with { |name, attrs| attrs["uno"] == ["yay"] } @manager.update(@name, @is, @should) end it "should convert the property values to strings if necessary" do @manager.expects(:create).with { |name, attrs| attrs["uno"] == ["yay"] } @manager.update(@name, @is, @should) end it "should not include :ensure in the properties sent" do @manager.expects(:create).with { |*args| args[1][:ensure].nil? } @manager.update(@name, @is, @should) end it "should not include attributes set to :absent in the properties sent" do @manager.expects(:create).with { |*args| args[1][:dos].nil? } @manager.update(@name, @is, @should) end end describe "is being modified" do it "should call the :modify method with its name and an array of LDAP::Mod instances" do LDAP::Mod.stubs(:new).returns "whatever" @is = {:one => :yay} @should = {:one => :yay, :two => :foo} @manager.expects(:modify).with { |name, mods| name == @name } @manager.update(@name, @is, @should) end it "should create the LDAP::Mod with the property name converted to the ldap name as a string" do @is = {:one => :yay} @should = {:one => :yay, :two => :foo} mod = mock 'module' LDAP::Mod.expects(:new).with { |form, name, value| name == "dos" }.returns mod @manager.stubs(:modify) @manager.update(@name, @is, @should) end it "should create an LDAP::Mod instance of type LDAP_MOD_ADD for each attribute being added, with the attribute value converted to a string of arrays" do @is = {:one => :yay} @should = {:one => :yay, :two => :foo} mod = mock 'module' LDAP::Mod.expects(:new).with(LDAP::LDAP_MOD_ADD, "dos", ["foo"]).returns mod @manager.stubs(:modify) @manager.update(@name, @is, @should) end it "should create an LDAP::Mod instance of type LDAP_MOD_DELETE for each attribute being deleted" do @is = {:one => :yay, :two => :foo} @should = {:one => :yay, :two => :absent} mod = mock 'module' LDAP::Mod.expects(:new).with(LDAP::LDAP_MOD_DELETE, "dos", []).returns mod @manager.stubs(:modify) @manager.update(@name, @is, @should) end it "should create an LDAP::Mod instance of type LDAP_MOD_REPLACE for each attribute being modified, with the attribute converted to a string of arrays" do @is = {:one => :yay, :two => :four} @should = {:one => :yay, :two => :five} mod = mock 'module' LDAP::Mod.expects(:new).with(LDAP::LDAP_MOD_REPLACE, "dos", ["five"]).returns mod @manager.stubs(:modify) @manager.update(@name, @is, @should) end it "should pass all created Mod instances to the modify method" do @is = {:one => :yay, :two => :foo, :three => :absent} @should = {:one => :yay, :two => :foe, :three => :fee, :four => :fie} LDAP::Mod.expects(:new).times(3).returns("mod1").then.returns("mod2").then.returns("mod3") @manager.expects(:modify).with do |name, mods| mods.sort == %w{mod1 mod2 mod3}.sort end @manager.update(@name, @is, @should) end end end end diff --git a/spec/unit/util/loadedfile_spec.rb b/spec/unit/util/loadedfile_spec.rb index 6b6949b2f..dcea53e45 100755 --- a/spec/unit/util/loadedfile_spec.rb +++ b/spec/unit/util/loadedfile_spec.rb @@ -1,72 +1,71 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'tempfile' require 'puppet/util/loadedfile' describe Puppet::Util::LoadedFile do include PuppetSpec::Files before(:each) do @f = Tempfile.new('loadedfile_test') @f.puts "yayness" @f.flush @loaded = Puppet::Util::LoadedFile.new(@f.path) fake_ctime = Time.now - (2 * Puppet[:filetimeout]) @stat = stub('stat', :ctime => fake_ctime) @fake_now = Time.now + (2 * Puppet[:filetimeout]) end it "should accept files that don't exist" do nofile = tmpfile('testfile') File.exists?(nofile).should == false lambda{ Puppet::Util::LoadedFile.new(nofile) }.should_not raise_error end it "should recognize when the file has not changed" do # Use fake "now" so that we can be sure changed? actually checks, without sleeping # for Puppet[:filetimeout] seconds. Time.stubs(:now).returns(@fake_now) @loaded.changed?.should == false end it "should recognize when the file has changed" do # Fake File.stat so we don't have to depend on the filesystem granularity. Doing a flush() # just didn't do the job. File.stubs(:stat).returns(@stat) # Use fake "now" so that we can be sure changed? actually checks, without sleeping # for Puppet[:filetimeout] seconds. Time.stubs(:now).returns(@fake_now) @loaded.changed?.should be_an_instance_of(Time) end it "should not catch a change until the timeout has elapsed" do # Fake File.stat so we don't have to depend on the filesystem granularity. Doing a flush() # just didn't do the job. File.stubs(:stat).returns(@stat) @loaded.changed?.should be(false) # Use fake "now" so that we can be sure changed? actually checks, without sleeping # for Puppet[:filetimeout] seconds. Time.stubs(:now).returns(@fake_now) @loaded.changed?.should_not be(false) end it "should consider a file changed when that file is missing" do @f.close! # Use fake "now" so that we can be sure changed? actually checks, without sleeping # for Puppet[:filetimeout] seconds. Time.stubs(:now).returns(@fake_now) @loaded.changed?.should_not be(false) end it "should disable checking if Puppet[:filetimeout] is negative" do Puppet[:filetimeout] = -1 @loaded.changed?.should_not be(false) end after(:each) do @f.close end end diff --git a/spec/unit/util/log/destinations_spec.rb b/spec/unit/util/log/destinations_spec.rb index a05736980..873c5f0c7 100755 --- a/spec/unit/util/log/destinations_spec.rb +++ b/spec/unit/util/log/destinations_spec.rb @@ -1,37 +1,36 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/util/log' describe Puppet::Util::Log.desttypes[:report] do before do @dest = Puppet::Util::Log.desttypes[:report] end it "should require a report at initialization" do @dest.new("foo").report.should == "foo" end it "should send new messages to the report" do report = mock 'report' dest = @dest.new(report) report.expects(:<<).with("my log") dest.handle "my log" end end describe Puppet::Util::Log.desttypes[:file] do before do File.stubs(:open) # prevent actually creating the file @class = Puppet::Util::Log.desttypes[:file] end it "should default to autoflush false" do @class.new('/tmp/log').autoflush.should == false end end diff --git a/spec/unit/util/log_spec.rb b/spec/unit/util/log_spec.rb index 9eacf58ae..78411d187 100755 --- a/spec/unit/util/log_spec.rb +++ b/spec/unit/util/log_spec.rb @@ -1,227 +1,226 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/util/log' describe Puppet::Util::Log do it "should write a given message to the specified destination" do arraydest = [] Puppet::Util::Log.newdestination(Puppet::Test::LogCollector.new(arraydest)) Puppet::Util::Log.new(:level => :notice, :message => "foo") message = arraydest.last.message message.should == "foo" end describe Puppet::Util::Log::DestConsole do before do @console = Puppet::Util::Log::DestConsole.new end it "should colorize if Puppet[:color] is :ansi" do Puppet[:color] = :ansi @console.colorize(:alert, "abc").should == "\e[0;31mabc\e[0m" end it "should colorize if Puppet[:color] is 'yes'" do Puppet[:color] = "yes" @console.colorize(:alert, "abc").should == "\e[0;31mabc\e[0m" end it "should htmlize if Puppet[:color] is :html" do Puppet[:color] = :html @console.colorize(:alert, "abc").should == "abc" end it "should do nothing if Puppet[:color] is false" do Puppet[:color] = false @console.colorize(:alert, "abc").should == "abc" end it "should do nothing if Puppet[:color] is invalid" do Puppet[:color] = "invalid option" @console.colorize(:alert, "abc").should == "abc" end end describe "instances" do before do Puppet::Util::Log.stubs(:newmessage) end [:level, :message, :time, :remote].each do |attr| it "should have a #{attr} attribute" do log = Puppet::Util::Log.new :level => :notice, :message => "A test message" log.should respond_to(attr) log.should respond_to(attr.to_s + "=") end end it "should fail if created without a level" do lambda { Puppet::Util::Log.new(:message => "A test message") }.should raise_error(ArgumentError) end it "should fail if created without a message" do lambda { Puppet::Util::Log.new(:level => :notice) }.should raise_error(ArgumentError) end it "should make available the level passed in at initialization" do Puppet::Util::Log.new(:level => :notice, :message => "A test message").level.should == :notice end it "should make available the message passed in at initialization" do Puppet::Util::Log.new(:level => :notice, :message => "A test message").message.should == "A test message" end # LAK:NOTE I don't know why this behavior is here, I'm just testing what's in the code, # at least at first. it "should always convert messages to strings" do Puppet::Util::Log.new(:level => :notice, :message => :foo).message.should == "foo" end it "should flush the log queue when the first destination is specified" do Puppet::Util::Log.close_all Puppet::Util::Log.expects(:flushqueue) Puppet::Util::Log.newdestination(:console) end it "should convert the level to a symbol if it's passed in as a string" do Puppet::Util::Log.new(:level => "notice", :message => :foo).level.should == :notice end it "should fail if the level is not a symbol or string" do lambda { Puppet::Util::Log.new(:level => 50, :message => :foo) }.should raise_error(ArgumentError) end it "should fail if the provided level is not valid" do Puppet::Util::Log.expects(:validlevel?).with(:notice).returns false lambda { Puppet::Util::Log.new(:level => :notice, :message => :foo) }.should raise_error(ArgumentError) end it "should set its time to the initialization time" do time = mock 'time' Time.expects(:now).returns time Puppet::Util::Log.new(:level => "notice", :message => :foo).time.should equal(time) end it "should make available any passed-in tags" do log = Puppet::Util::Log.new(:level => "notice", :message => :foo, :tags => %w{foo bar}) log.tags.should be_include("foo") log.tags.should be_include("bar") end it "should use an passed-in source" do Puppet::Util::Log.any_instance.expects(:source=).with "foo" Puppet::Util::Log.new(:level => "notice", :message => :foo, :source => "foo") end [:file, :line].each do |attr| it "should use #{attr} if provided" do Puppet::Util::Log.any_instance.expects(attr.to_s + "=").with "foo" Puppet::Util::Log.new(:level => "notice", :message => :foo, attr => "foo") end end it "should default to 'Puppet' as its source" do Puppet::Util::Log.new(:level => "notice", :message => :foo).source.should == "Puppet" end it "should register itself with Log" do Puppet::Util::Log.expects(:newmessage) Puppet::Util::Log.new(:level => "notice", :message => :foo) end it "should update Log autoflush when Puppet[:autoflush] is set" do Puppet::Util::Log.expects(:autoflush=).once.with(true) Puppet[:autoflush] = true end it "should have a method for determining if a tag is present" do Puppet::Util::Log.new(:level => "notice", :message => :foo).should respond_to(:tagged?) end it "should match a tag if any of the tags are equivalent to the passed tag as a string" do Puppet::Util::Log.new(:level => "notice", :message => :foo, :tags => %w{one two}).should be_tagged(:one) end it "should tag itself with its log level" do Puppet::Util::Log.new(:level => "notice", :message => :foo).should be_tagged(:notice) end it "should return its message when converted to a string" do Puppet::Util::Log.new(:level => "notice", :message => :foo).to_s.should == "foo" end it "should include its time, source, level, and message when prepared for reporting" do log = Puppet::Util::Log.new(:level => "notice", :message => :foo) report = log.to_report report.should be_include("notice") report.should be_include("foo") report.should be_include(log.source) report.should be_include(log.time.to_s) end describe "when setting the source as a RAL object" do it "should tag itself with any tags the source has" do source = Puppet::Type.type(:file).new :path => "/foo/bar" log = Puppet::Util::Log.new(:level => "notice", :message => :foo, :source => source) source.tags.each do |tag| log.tags.should be_include(tag) end end it "should use the source_descriptors" do source = stub "source" source.stubs(:source_descriptors).returns(:tags => ["tag","tag2"], :path => "path", :version => 100) log = Puppet::Util::Log.new(:level => "notice", :message => :foo) log.expects(:tag).with("tag") log.expects(:tag).with("tag2") log.source = source log.source.should == "path" end it "should copy over any file and line information" do source = Puppet::Type.type(:file).new :path => "/foo/bar" source.file = "/my/file" source.line = 50 log = Puppet::Util::Log.new(:level => "notice", :message => :foo, :source => source) log.file.should == "/my/file" log.line.should == 50 end end describe "when setting the source as a non-RAL object" do it "should not try to copy over file, version, line, or tag information" do source = Puppet::Module.new("foo") source.expects(:file).never log = Puppet::Util::Log.new(:level => "notice", :message => :foo, :source => source) end end end describe "to_yaml" do it "should not include the @version attribute" do log = Puppet::Util::Log.new(:level => "notice", :message => :foo, :version => 100) log.to_yaml_properties.should_not include('@version') end it "should include attributes @level, @message, @source, @tags, and @time" do log = Puppet::Util::Log.new(:level => "notice", :message => :foo, :version => 100) log.to_yaml_properties.should == %w{@level @message @source @tags @time} end it "should include attributes @file and @line if specified" do log = Puppet::Util::Log.new(:level => "notice", :message => :foo, :file => "foo", :line => 35) log.to_yaml_properties.should include('@file') log.to_yaml_properties.should include('@line') end end end diff --git a/spec/unit/util/logging_spec.rb b/spec/unit/util/logging_spec.rb index bc2eaff43..6a77e70ef 100755 --- a/spec/unit/util/logging_spec.rb +++ b/spec/unit/util/logging_spec.rb @@ -1,120 +1,119 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/util/logging' class LoggingTester include Puppet::Util::Logging end describe Puppet::Util::Logging do before do @logger = LoggingTester.new end Puppet::Util::Log.eachlevel do |level| it "should have a method for sending '#{level}' logs" do @logger.should respond_to(level) end end it "should have a method for sending a log with a specified log level" do @logger.expects(:to_s).returns "I'm a string!" Puppet::Util::Log.expects(:create).with { |args| args[:source] == "I'm a string!" and args[:level] == "loglevel" and args[:message] == "mymessage" } @logger.send_log "loglevel", "mymessage" end describe "when sending a log" do it "should use the Log's 'create' entrance method" do Puppet::Util::Log.expects(:create) @logger.notice "foo" end it "should send itself converted to a string as the log source" do @logger.expects(:to_s).returns "I'm a string!" Puppet::Util::Log.expects(:create).with { |args| args[:source] == "I'm a string!" } @logger.notice "foo" end it "should queue logs sent without a specified destination" do Puppet::Util::Log.close_all Puppet::Util::Log.expects(:queuemessage) @logger.notice "foo" end it "should use the path of any provided resource type" do resource = Puppet::Type.type(:mount).new :name => "foo" resource.expects(:path).returns "/path/to/mount".to_sym Puppet::Util::Log.expects(:create).with { |args| args[:source] == "/path/to/mount" } resource.notice "foo" end it "should use the path of any provided resource parameter" do resource = Puppet::Type.type(:mount).new :name => "foo" param = resource.parameter(:name) param.expects(:path).returns "/path/to/param".to_sym Puppet::Util::Log.expects(:create).with { |args| args[:source] == "/path/to/param" } param.notice "foo" end it "should send the provided argument as the log message" do Puppet::Util::Log.expects(:create).with { |args| args[:message] == "foo" } @logger.notice "foo" end it "should join any provided arguments into a single string for the message" do Puppet::Util::Log.expects(:create).with { |args| args[:message] == "foo bar baz" } @logger.notice ["foo", "bar", "baz"] end [:file, :line, :tags].each do |attr| it "should include #{attr} if available" do @logger.singleton_class.send(:attr_accessor, attr) @logger.send(attr.to_s + "=", "myval") Puppet::Util::Log.expects(:create).with { |args| args[attr] == "myval" } @logger.notice "foo" end end end describe "when sending a deprecation warning" do before do @logger.clear_deprecation_warnings end it "should the message with warn" do @logger.expects(:warning).with('foo') @logger.deprecation_warning 'foo' end it "should only log each unique message once" do @logger.expects(:warning).with('foo').once 5.times { @logger.deprecation_warning 'foo' } end it "should only log the first 100 messages" do (1..100).each { |i| @logger.expects(:warning).with(i).once @logger.deprecation_warning i } @logger.expects(:warning).with(101).never @logger.deprecation_warning 101 end end end diff --git a/spec/unit/util/metric_spec.rb b/spec/unit/util/metric_spec.rb index b0d320478..07a9e4945 100755 --- a/spec/unit/util/metric_spec.rb +++ b/spec/unit/util/metric_spec.rb @@ -1,95 +1,94 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/util/metric' describe Puppet::Util::Metric do before do @metric = Puppet::Util::Metric.new("foo") end it "should be aliased to Puppet::Metric" do Puppet::Util::Metric.should equal(Puppet::Metric) end [:type, :name, :value, :label, :basedir].each do |name| it "should have a #{name} attribute" do @metric.should respond_to(name) @metric.should respond_to(name.to_s + "=") end end it "should default to the :rrdir as the basedir "do Puppet.settings.expects(:value).with(:rrddir).returns "myrrd" @metric.basedir.should == "myrrd" end it "should use any provided basedir" do @metric.basedir = "foo" @metric.basedir.should == "foo" end it "should require a name at initialization" do lambda { Puppet::Util::Metric.new }.should raise_error(ArgumentError) end it "should always convert its name to a string" do Puppet::Util::Metric.new(:foo).name.should == "foo" end it "should support a label" do Puppet::Util::Metric.new("foo", "mylabel").label.should == "mylabel" end it "should autogenerate a label if none is provided" do Puppet::Util::Metric.new("foo_bar").label.should == "Foo bar" end it "should have a method for adding values" do @metric.should respond_to(:newvalue) end it "should have a method for returning values" do @metric.should respond_to(:values) end it "should require a name and value for its values" do lambda { @metric.newvalue }.should raise_error(ArgumentError) end it "should support a label for values" do @metric.newvalue("foo", 10, "label") @metric.values[0][1].should == "label" end it "should autogenerate value labels if none is provided" do @metric.newvalue("foo_bar", 10) @metric.values[0][1].should == "Foo bar" end it "should return its values sorted by label" do @metric.newvalue("foo", 10, "b") @metric.newvalue("bar", 10, "a") @metric.values.should == [["bar", "a", 10], ["foo", "b", 10]] end it "should use an array indexer method to retrieve individual values" do @metric.newvalue("foo", 10) @metric["foo"].should == 10 end it "should return nil if the named value cannot be found" do @metric["foo"].should == 0 end # LAK: I'm not taking the time to develop these tests right now. # I expect they should actually be extracted into a separate class # anyway. it "should be able to graph metrics using RRDTool" it "should be able to create a new RRDTool database" it "should be able to store metrics into an RRDTool database" end diff --git a/spec/unit/util/monkey_patches_spec.rb b/spec/unit/util/monkey_patches_spec.rb index 4ff6438ce..4b609ad09 100755 --- a/spec/unit/util/monkey_patches_spec.rb +++ b/spec/unit/util/monkey_patches_spec.rb @@ -1,56 +1,55 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/util/monkey_patches' describe "yaml deserialization" do it "should call yaml_initialize when deserializing objects that have that method defined" do class Puppet::TestYamlInitializeClass attr_reader :foo def yaml_initialize(tag, var) var.should == {'foo' => 100} instance_variables.should == [] @foo = 200 end end obj = YAML.load("--- !ruby/object:Puppet::TestYamlInitializeClass\n foo: 100") obj.foo.should == 200 end it "should not call yaml_initialize if not defined" do class Puppet::TestYamlNonInitializeClass attr_reader :foo end obj = YAML.load("--- !ruby/object:Puppet::TestYamlNonInitializeClass\n foo: 100") obj.foo.should == 100 end end # In Ruby > 1.8.7 this is a builtin, otherwise we monkey patch the method in describe "Array#combination" do it "should fail if wrong number of arguments given" do lambda { [1,2,3].combination() }.should raise_error(ArgumentError, /wrong number/) lambda { [1,2,3].combination(1,2) }.should raise_error(ArgumentError, /wrong number/) end it "should return an empty array if combo size than array size or negative" do [1,2,3].combination(4).to_a.should == [] [1,2,3].combination(-1).to_a.should == [] end it "should return an empty array with an empty array if combo size == 0" do [1,2,3].combination(0).to_a.should == [[]] end it "should all provide all combinations of size passed in" do [1,2,3,4].combination(1).to_a.should == [[1], [2], [3], [4]] [1,2,3,4].combination(2).to_a.should == [[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]] [1,2,3,4].combination(3).to_a.should == [[1, 2, 3], [1, 2, 4], [1, 3, 4], [2, 3, 4]] end end diff --git a/spec/unit/util/nagios_maker_spec.rb b/spec/unit/util/nagios_maker_spec.rb index 7245cc3fc..b61f4fe9d 100755 --- a/spec/unit/util/nagios_maker_spec.rb +++ b/spec/unit/util/nagios_maker_spec.rb @@ -1,126 +1,126 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Created by Luke Kanies on 2007-11-18. # Copyright (c) 2007. All rights reserved. require 'spec_helper' require 'puppet/util/nagios_maker' describe Puppet::Util::NagiosMaker do before do @module = Puppet::Util::NagiosMaker @nagtype = stub 'nagios type', :parameters => [], :namevar => :name Nagios::Base.stubs(:type).with(:test).returns(@nagtype) @provider = stub 'provider', :nagios_type => nil @type = stub 'type', :newparam => nil, :newproperty => nil, :provide => @provider, :desc => nil, :ensurable => nil end it "should be able to create a new nagios type" do @module.should respond_to(:create_nagios_type) end it "should fail if it cannot find the named Naginator type" do Nagios::Base.stubs(:type).returns(nil) lambda { @module.create_nagios_type(:no_such_type) }.should raise_error(Puppet::DevError) end it "should create a new RAL type with the provided name prefixed with 'nagios_'" do Puppet::Type.expects(:newtype).with(:nagios_test).returns(@type) @module.create_nagios_type(:test) end it "should mark the created type as ensurable" do @type.expects(:ensurable) Puppet::Type.expects(:newtype).with(:nagios_test).returns(@type) @module.create_nagios_type(:test) end it "should create a namevar parameter for the nagios type's name parameter" do @type.expects(:newparam).with(:name, :namevar => true) Puppet::Type.expects(:newtype).with(:nagios_test).returns(@type) @module.create_nagios_type(:test) end it "should create a property for all non-namevar parameters" do @nagtype.stubs(:parameters).returns([:one, :two]) @type.expects(:newproperty).with(:one) @type.expects(:newproperty).with(:two) @type.expects(:newproperty).with(:target) Puppet::Type.expects(:newtype).with(:nagios_test).returns(@type) @module.create_nagios_type(:test) end it "should skip parameters that start with integers" do @nagtype.stubs(:parameters).returns(["2dcoords".to_sym, :other]) @type.expects(:newproperty).with(:other) @type.expects(:newproperty).with(:target) Puppet::Type.expects(:newtype).with(:nagios_test).returns(@type) @module.create_nagios_type(:test) end it "should deduplicate the parameter list" do @nagtype.stubs(:parameters).returns([:one, :one]) @type.expects(:newproperty).with(:one) @type.expects(:newproperty).with(:target) Puppet::Type.expects(:newtype).with(:nagios_test).returns(@type) @module.create_nagios_type(:test) end it "should create a target property" do @type.expects(:newproperty).with(:target) Puppet::Type.expects(:newtype).with(:nagios_test).returns(@type) @module.create_nagios_type(:test) end end describe Puppet::Util::NagiosMaker, " when creating the naginator provider" do before do @module = Puppet::Util::NagiosMaker @provider = stub 'provider', :nagios_type => nil @nagtype = stub 'nagios type', :parameters => [], :namevar => :name Nagios::Base.stubs(:type).with(:test).returns(@nagtype) @type = stub 'type', :newparam => nil, :ensurable => nil, :newproperty => nil, :desc => nil Puppet::Type.stubs(:newtype).with(:nagios_test).returns(@type) end it "should add a naginator provider" do @type.expects(:provide).with { |name, options| name == :naginator }.returns @provider @module.create_nagios_type(:test) end it "should set Puppet::Provider::Naginator as the parent class of the provider" do @type.expects(:provide).with { |name, options| options[:parent] == Puppet::Provider::Naginator }.returns @provider @module.create_nagios_type(:test) end it "should use /etc/nagios/$name.cfg as the default target" do @type.expects(:provide).with { |name, options| options[:default_target] == "/etc/nagios/nagios_test.cfg" }.returns @provider @module.create_nagios_type(:test) end it "should trigger the lookup of the Nagios class" do @type.expects(:provide).returns @provider @provider.expects(:nagios_type) @module.create_nagios_type(:test) end end diff --git a/spec/unit/util/network_device/cisco/device_spec.rb b/spec/unit/util/network_device/cisco/device_spec.rb old mode 100644 new mode 100755 index 31aec920e..82b0666e6 --- a/spec/unit/util/network_device/cisco/device_spec.rb +++ b/spec/unit/util/network_device/cisco/device_spec.rb @@ -1,521 +1,521 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec require File.dirname(__FILE__) + '/../../../../spec_helper' require 'puppet/util/network_device/cisco/device' describe Puppet::Util::NetworkDevice::Cisco::Device do before(:each) do @transport = stub_everything 'transport', :is_a? => true, :command => "" @cisco = Puppet::Util::NetworkDevice::Cisco::Device.new("telnet://user:password@localhost:23/") @cisco.transport = @transport end describe "when creating the device" do it "should find the enable password from the url" do cisco = Puppet::Util::NetworkDevice::Cisco::Device.new("telnet://user:password@localhost:23/?enable=enable_password") cisco.enable_password.should == "enable_password" end it "should find the enable password from the options" do cisco = Puppet::Util::NetworkDevice::Cisco::Device.new("telnet://user:password@localhost:23/?enable=enable_password", :enable_password => "mypass") cisco.enable_password.should == "mypass" end end describe "when connecting to the physical device" do it "should connect to the transport" do @transport.expects(:connect) @cisco.command end it "should attempt to login" do @cisco.expects(:login) @cisco.command end it "should tell the device to not page" do @transport.expects(:command).with("terminal length 0") @cisco.command end it "should enter the enable password if returned prompt is not privileged" do @transport.stubs(:command).yields("Switch>").returns("") @cisco.expects(:enable) @cisco.command end it "should find device capabilities" do @cisco.expects(:find_capabilities) @cisco.command end it "should execute given command" do @transport.expects(:command).with("mycommand") @cisco.command("mycommand") end it "should yield to the command block if one is provided" do @transport.expects(:command).with("mycommand") @cisco.command do |c| c.command("mycommand") end end it "should close the device transport" do @transport.expects(:close) @cisco.command end describe "when login in" do it "should not login if transport handles login" do @transport.expects(:handles_login?).returns(true) @transport.expects(:command).never @transport.expects(:expect).never @cisco.login end it "should send username if one has been provided" do @transport.expects(:command).with("user", :prompt => /^Password:/) @cisco.login end it "should send password after the username" do @transport.expects(:command).with("user", :prompt => /^Password:/) @transport.expects(:command).with("password") @cisco.login end it "should expect the Password: prompt if no user was sent" do @cisco.url.user = '' @transport.expects(:expect).with(/^Password:/) @transport.expects(:command).with("password") @cisco.login end end describe "when entering enable password" do it "should raise an error if no enable password has been set" do @cisco.enable_password = nil lambda{ @cisco.enable }.should raise_error end it "should send the enable command and expect an enable prompt" do @cisco.enable_password = 'mypass' @transport.expects(:command).with("enable", :prompt => /^Password:/) @cisco.enable end it "should send the enable password" do @cisco.enable_password = 'mypass' @transport.stubs(:command).with("enable", :prompt => /^Password:/) @transport.expects(:command).with("mypass") @cisco.enable end end end describe "when finding network device capabilities" do it "should try to execute sh vlan brief" do @transport.expects(:command).with("sh vlan brief").returns("") @cisco.find_capabilities end it "should detect errors" do @transport.stubs(:command).with("sh vlan brief").returns(< "FastEthernet0/1", "Fa0/1" => "FastEthernet0/1", "FastEth 0/1" => "FastEthernet0/1", "Gi1" => "GigEthernet1", "Di9" => "Dialer9", "Ethernet 0/0/1" => "Ethernet0/0/1", "E0" => "Ethernet0", "ATM 0/1.1" => "ATM0/1.1", "VLAN99" => "VLAN99" }.each do |input,expected| it "should canonicalize #{input} to #{expected}" do @cisco.canonalize_ifname(input).should == expected end end describe "when updating device vlans" do describe "when removing a vlan" do it "should issue the no vlan command" do @transport.expects(:command).with("no vlan 200") @cisco.update_vlan("200", {:ensure => :present, :name => "200"}, { :ensure=> :absent}) end end describe "when updating a vlan" do it "should issue the vlan command to enter global vlan modifications" do @transport.expects(:command).with("vlan 200") @cisco.update_vlan("200", {:ensure => :present, :name => "200"}, { :ensure=> :present, :name => "200"}) end it "should issue the name command to modify the vlan description" do @transport.expects(:command).with("name myvlan") @cisco.update_vlan("200", {:ensure => :present, :name => "200"}, { :ensure=> :present, :name => "200", :description => "myvlan"}) end end end describe "when parsing interface" do it "should parse interface output" do @cisco.expects(:parse_interface).returns({ :ensure => :present }) @cisco.interface("FastEthernet0/1").should == { :ensure => :present } end it "should parse trunking and merge results" do @cisco.stubs(:parse_interface).returns({ :ensure => :present }) @cisco.expects(:parse_trunking).returns({ :native_vlan => "100" }) @cisco.interface("FastEthernet0/1").should == { :ensure => :present, :native_vlan => "100" } end it "should return an absent interface if parse_interface returns nothing" do @cisco.stubs(:parse_interface).returns({}) @cisco.interface("FastEthernet0/1").should == { :ensure => :absent } end it "should parse ip address information and merge results" do @cisco.stubs(:parse_interface).returns({ :ensure => :present }) @cisco.expects(:parse_interface_config).returns({ :ipaddress => [24,IPAddr.new('192.168.0.24'), nil] }) @cisco.interface("FastEthernet0/1").should == { :ensure => :present, :ipaddress => [24,IPAddr.new('192.168.0.24'), nil] } end it "should parse the sh interface command" do @transport.stubs(:command).with("sh interface FastEthernet0/1").returns(< :absent, :duplex => :auto, :speed => :auto } end it "should be able to parse the sh vlan brief command output" do @cisco.stubs(:support_vlan_brief?).returns(true) @transport.stubs(:command).with("sh vlan brief").returns(<{:status=>"active", :interfaces=>["FastEthernet0/1", "FastEthernet0/2"], :description=>"management", :name=>"100"}, "1"=>{:status=>"active", :interfaces=>["FastEthernet0/3", "FastEthernet0/4", "FastEthernet0/5", "FastEthernet0/6", "FastEthernet0/7", "FastEthernet0/8", "FastEthernet0/9", "FastEthernet0/10", "FastEthernet0/11", "FastEthernet0/12", "FastEthernet0/13", "FastEthernet0/14", "FastEthernet0/15", "FastEthernet0/16", "FastEthernet0/17", "FastEthernet0/18", "FastEthernet0/23", "FastEthernet0/24"], :description=>"default", :name=>"1"}, "10"=>{:status=>"active", :interfaces=>[], :description=>"VLAN0010", :name=>"10"}} end it "should parse trunk switchport information" do @transport.stubs(:command).with("sh interface FastEthernet0/21 switchport").returns(< :trunk, :encapsulation => :dot1q, :allowed_trunk_vlans=>:all, } end it "should parse trunk switchport information with allowed vlans" do @transport.stubs(:command).with("sh interface GigabitEthernet 0/1 switchport").returns(< :trunk, :encapsulation => :dot1q, :allowed_trunk_vlans=>"1,99", } end it "should parse access switchport information" do @transport.stubs(:command).with("sh interface FastEthernet0/1 switchport").returns(< :access, :native_vlan => "100" } end it "should parse ip addresses" do @transport.stubs(:command).with("sh running-config interface Vlan 1 | begin interface").returns(<[[24, IPAddr.new('192.168.0.24'), 'secondary'], [24, IPAddr.new('192.168.0.1'), nil], [64, IPAddr.new('2001:07a8:71c1::'), "eui-64"]]} end it "should parse etherchannel membership" do @transport.stubs(:command).with("sh running-config interface Gi0/17 | begin interface").returns(<"1"} end end end # static access # Switch#sh interfaces FastEthernet 0/1 switchport # Name: Fa0/1 # Switchport: Enabled # Administrative mode: static access # Operational Mode: static access # Administrative Trunking Encapsulation: isl # Operational Trunking Encapsulation: isl # Negotiation of Trunking: Disabled # Access Mode VLAN: 100 (SHDSL) # Trunking Native Mode VLAN: 1 (default) # Trunking VLANs Enabled: NONE # Pruning VLANs Enabled: NONE # # Priority for untagged frames: 0 # Override vlan tag priority: FALSE # Voice VLAN: none # Appliance trust: none # Self Loopback: No # Switch# # c2960#sh interfaces GigabitEthernet 0/1 switchport # Name: Gi0/1 # Switchport: Enabled # Administrative Mode: trunk # Operational Mode: trunk # Administrative Trunking Encapsulation: dot1q # Operational Trunking Encapsulation: dot1q # Negotiation of Trunking: On # Access Mode VLAN: 1 (default) # Trunking Native Mode VLAN: 1 (default) # Administrative Native VLAN tagging: enabled # Voice VLAN: none # Administrative private-vlan host-association: none # Administrative private-vlan mapping: none # Administrative private-vlan trunk native VLAN: none # Administrative private-vlan trunk Native VLAN tagging: enabled # Administrative private-vlan trunk encapsulation: dot1q # Administrative private-vlan trunk normal VLANs: none # Administrative private-vlan trunk associations: none # Administrative private-vlan trunk mappings: none # Operational private-vlan: none # Trunking VLANs Enabled: 1,99 # Pruning VLANs Enabled: 2-1001 # Capture Mode Disabled # Capture VLANs Allowed: ALL # # Protected: false # Unknown unicast blocked: disabled # Unknown multicast blocked: disabled # Appliance trust: none # c2960# # c2960#sh interfaces GigabitEthernet 0/2 switchport # Name: Gi0/2 # Switchport: Enabled # Administrative Mode: static access # Operational Mode: static access # Administrative Trunking Encapsulation: dot1q # Operational Trunking Encapsulation: native # Negotiation of Trunking: Off # Access Mode VLAN: 99 (MGMT) # Trunking Native Mode VLAN: 1 (default) # Administrative Native VLAN tagging: enabled # Voice VLAN: none # Administrative private-vlan host-association: none # Administrative private-vlan mapping: none # Administrative private-vlan trunk native VLAN: none # Administrative private-vlan trunk Native VLAN tagging: enabled # Administrative private-vlan trunk encapsulation: dot1q # Administrative private-vlan trunk normal VLANs: none # Administrative private-vlan trunk associations: none # Administrative private-vlan trunk mappings: none # Operational private-vlan: none # Trunking VLANs Enabled: ALL # Pruning VLANs Enabled: 2-1001 # Capture Mode Disabled # Capture VLANs Allowed: ALL # # Protected: false # Unknown unicast blocked: disabled # Unknown multicast blocked: disabled # Appliance trust: none # c2960# # c877#sh interfaces FastEthernet 1 switchport # Name: Fa1 # Switchport: Enabled # Administrative Mode: trunk # Operational Mode: trunk # Administrative Trunking Encapsulation: dot1q # Operational Trunking Encapsulation: dot1q # Negotiation of Trunking: Disabled # Access Mode VLAN: 0 ((Inactive)) # Trunking Native Mode VLAN: 1 (default) # Trunking VLANs Enabled: ALL # Trunking VLANs Active: 1 # Protected: false # Priority for untagged frames: 0 # Override vlan tag priority: FALSE # Voice VLAN: none # Appliance trust: none # c2960#sh etherchannel summary # Flags: D - down P - bundled in port-channel # I - stand-alone s - suspended # H - Hot-standby (LACP only) # R - Layer3 S - Layer2 # U - in use f - failed to allocate aggregator # # M - not in use, minimum links not met # u - unsuitable for bundling # w - waiting to be aggregated # d - default port # # # Number of channel-groups in use: 1 # Number of aggregators: 1 # # Group Port-channel Protocol Ports # ------+-------------+-----------+----------------------------------------------- # 1 Po1(SU) LACP Gi0/17(P) Gi0/18(P) # # c2960# diff --git a/spec/unit/util/network_device/cisco/interface_spec.rb b/spec/unit/util/network_device/cisco/interface_spec.rb old mode 100644 new mode 100755 index f6aa14747..24217750c --- a/spec/unit/util/network_device/cisco/interface_spec.rb +++ b/spec/unit/util/network_device/cisco/interface_spec.rb @@ -1,89 +1,89 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec require File.dirname(__FILE__) + '/../../../../spec_helper' require 'puppet/util/network_device' require 'puppet/util/network_device/cisco/interface' describe Puppet::Util::NetworkDevice::Cisco::Interface do before(:each) do @transport = stub_everything 'transport' @interface = Puppet::Util::NetworkDevice::Cisco::Interface.new("FastEthernet0/1",@transport) end it "should include IPCalc" do @interface.class.include?(Puppet::Util::NetworkDevice::IPCalc) end describe "when updating the physical device" do it "should enter global configuration mode" do @transport.expects(:command).with("conf t") @interface.update end it "should enter interface configuration mode" do @transport.expects(:command).with("interface FastEthernet0/1") @interface.update end it "should 'execute' all differing properties" do @interface.expects(:execute).with(:description, "b") @interface.expects(:execute).with(:mode, :access).never @interface.update({ :description => "a", :mode => :access }, { :description => "b", :mode => :access }) end it "should execute in cisco ios defined order" do speed = states('speed').starts_as('notset') @interface.expects(:execute).with(:speed, :auto).then(speed.is('set')) @interface.expects(:execute).with(:duplex, :auto).when(speed.is('set')) @interface.update({ :duplex => :half, :speed => "10" }, { :duplex => :auto, :speed => :auto }) end it "should execute absent properties with a no prefix" do @interface.expects(:execute).with(:description, "a", "no ") @interface.update({ :description => "a"}, { }) end it "should exit twice" do @transport.expects(:command).with("exit").twice @interface.update end end describe "when executing commands" do it "should execute string commands directly" do @transport.expects(:command).with("speed auto") @interface.execute(:speed, :auto) end it "should execute string commands with the given prefix" do @transport.expects(:command).with("no speed auto") @interface.execute(:speed, :auto, "no ") end it "should stop at executing the first command that works for array" do @transport.expects(:command).with("channel-group 1").yields("% Invalid command") @transport.expects(:command).with("port group 1") @interface.execute(:etherchannel, "1") end it "should execute the block for block commands" do @transport.expects(:command).with("ip address 192.168.0.1 255.255.255.0") @interface.execute(:ipaddress, [[24, IPAddr.new('192.168.0.1'), nil]]) end it "should execute the block for block commands" do @transport.expects(:command).with("ipv6 address fe08::/76 link-local") @interface.execute(:ipaddress, [[76, IPAddr.new('fe08::'), 'link-local']]) end end describe "when sending commands to the device" do it "should detect errors" do Puppet.expects(:err) @transport.stubs(:command).yields("% Invalid Command") @interface.command("sh ver") end end -end \ No newline at end of file +end diff --git a/spec/unit/util/network_device/ipcalc_spec.rb b/spec/unit/util/network_device/ipcalc_spec.rb old mode 100644 new mode 100755 index 6f55a66e4..0418c6a84 --- a/spec/unit/util/network_device/ipcalc_spec.rb +++ b/spec/unit/util/network_device/ipcalc_spec.rb @@ -1,63 +1,63 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec require File.dirname(__FILE__) + '/../../../spec_helper' require 'puppet/util/network_device/ipcalc' describe Puppet::Util::NetworkDevice::IPCalc do class TestIPCalc include Puppet::Util::NetworkDevice::IPCalc end before(:each) do @ipcalc = TestIPCalc.new end describe "when parsing ip/prefix" do it "should parse ipv4 without prefixes" do @ipcalc.parse('127.0.0.1').should == [32,IPAddr.new('127.0.0.1')] end it "should parse ipv4 with prefixes" do @ipcalc.parse('127.0.1.2/8').should == [8,IPAddr.new('127.0.1.2')] end it "should parse ipv6 without prefixes" do @ipcalc.parse('FE80::21A:2FFF:FE30:ECF0').should == [128,IPAddr.new('FE80::21A:2FFF:FE30:ECF0')] end it "should parse ipv6 with prefixes" do @ipcalc.parse('FE80::21A:2FFF:FE30:ECF0/56').should == [56,IPAddr.new('FE80::21A:2FFF:FE30:ECF0')] end end describe "when building netmask" do it "should produce the correct ipv4 netmask from prefix length" do @ipcalc.netmask(Socket::AF_INET, 27).should == IPAddr.new('255.255.255.224') end it "should produce the correct ipv6 netmask from prefix length" do @ipcalc.netmask(Socket::AF_INET6, 56).should == IPAddr.new('ffff:ffff:ffff:ff00::0') end end describe "when building wildmask" do it "should produce the correct ipv4 wildmask from prefix length" do @ipcalc.wildmask(Socket::AF_INET, 27).should == IPAddr.new('0.0.0.31') end it "should produce the correct ipv6 wildmask from prefix length" do @ipcalc.wildmask(Socket::AF_INET6, 126).should == IPAddr.new('::3') end end describe "when computing prefix length from netmask" do it "should produce the correct ipv4 prefix length" do @ipcalc.prefix_length(IPAddr.new('255.255.255.224')).should == 27 end it "should produce the correct ipv6 prefix length" do @ipcalc.prefix_length(IPAddr.new('fffe::0')).should == 15 end end -end \ No newline at end of file +end diff --git a/spec/unit/util/network_device/transport/base_spec.rb b/spec/unit/util/network_device/transport/base_spec.rb old mode 100644 new mode 100755 index 5d52574f7..c186d72e5 --- a/spec/unit/util/network_device/transport/base_spec.rb +++ b/spec/unit/util/network_device/transport/base_spec.rb @@ -1,42 +1,42 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec require File.dirname(__FILE__) + '/../../../../spec_helper' require 'puppet/util/network_device/transport/base' describe Puppet::Util::NetworkDevice::Transport::Base do class TestTransport < Puppet::Util::NetworkDevice::Transport::Base end before(:each) do @transport = TestTransport.new end describe "when sending commands" do it "should send the command to the telnet session" do @transport.expects(:send).with("line") @transport.command("line") end it "should expect an output matching the given prompt" do @transport.expects(:expect).with(/prompt/) @transport.command("line", :prompt => /prompt/) end it "should expect an output matching the default prompt" do @transport.default_prompt = /defprompt/ @transport.expects(:expect).with(/defprompt/) @transport.command("line") end it "should yield telnet output to the given block" do @transport.expects(:expect).yields("output") @transport.command("line") { |out| out.should == "output" } end it "should return telnet output to the caller" do @transport.expects(:expect).returns("output") @transport.command("line").should == "output" end end -end \ No newline at end of file +end diff --git a/spec/unit/util/network_device/transport/ssh_spec.rb b/spec/unit/util/network_device/transport/ssh_spec.rb old mode 100644 new mode 100755 index 706dee43a..0e91ed9f9 --- a/spec/unit/util/network_device/transport/ssh_spec.rb +++ b/spec/unit/util/network_device/transport/ssh_spec.rb @@ -1,211 +1,211 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec require File.dirname(__FILE__) + '/../../../../spec_helper' require 'puppet/util/network_device/transport/ssh' describe Puppet::Util::NetworkDevice::Transport::Ssh, :if => Puppet.features.ssh? do before(:each) do @transport = Puppet::Util::NetworkDevice::Transport::Ssh.new() end it "should handle login through the transport" do @transport.should be_handles_login end it "should connect to the given host and port" do Net::SSH.expects(:start).with { |host, user, args| host == "localhost" && args[:port] == 22 }.returns stub_everything @transport.host = "localhost" @transport.port = 22 @transport.connect end it "should connect using the given username and password" do Net::SSH.expects(:start).with { |host, user, args| user == "user" && args[:password] == "pass" }.returns stub_everything @transport.user = "user" @transport.password = "pass" @transport.connect end describe "when connected" do before(:each) do @ssh = stub_everything 'ssh' @channel = stub_everything 'channel' Net::SSH.stubs(:start).returns @ssh @ssh.stubs(:open_channel).yields(@channel) @transport.stubs(:expect) end it "should open a channel" do @ssh.expects(:open_channel) @transport.connect end it "should request a pty" do @channel.expects(:request_pty) @transport.connect end it "should create a shell channel" do @channel.expects(:send_channel_request).with("shell") @transport.connect end it "should raise an error if shell channel creation fails" do @channel.expects(:send_channel_request).with("shell").yields(@channel, false) lambda { @transport.connect }.should raise_error end it "should register an on_data and on_extended_data callback" do @channel.expects(:send_channel_request).with("shell").yields(@channel, true) @channel.expects(:on_data) @channel.expects(:on_extended_data) @transport.connect end it "should accumulate data to the buffer on data" do @channel.expects(:send_channel_request).with("shell").yields(@channel, true) @channel.expects(:on_data).yields(@channel, "data") @transport.connect @transport.buf.should == "data" end it "should accumulate data to the buffer on extended data" do @channel.expects(:send_channel_request).with("shell").yields(@channel, true) @channel.expects(:on_extended_data).yields(@channel, 1, "data") @transport.connect @transport.buf.should == "data" end it "should mark eof on close" do @channel.expects(:send_channel_request).with("shell").yields(@channel, true) @channel.expects(:on_close).yields(@channel) @transport.connect @transport.should be_eof end it "should expect output to conform to the default prompt" do @channel.expects(:send_channel_request).with("shell").yields(@channel, true) @transport.expects(:default_prompt).returns("prompt") @transport.expects(:expect).with("prompt") @transport.connect end it "should start the ssh loop" do @ssh.expects(:loop) @transport.connect end end describe "when closing" do before(:each) do @ssh = stub_everything 'ssh' @channel = stub_everything 'channel' Net::SSH.stubs(:start).returns @ssh @ssh.stubs(:open_channel).yields(@channel) @channel.stubs(:send_channel_request).with("shell").yields(@channel, true) @transport.stubs(:expect) @transport.connect end it "should close the channel" do @channel.expects(:close) @transport.close end it "should close the ssh session" do @ssh.expects(:close) @transport.close end end describe "when sending commands" do before(:each) do @ssh = stub_everything 'ssh' @channel = stub_everything 'channel' Net::SSH.stubs(:start).returns @ssh @ssh.stubs(:open_channel).yields(@channel) @channel.stubs(:send_channel_request).with("shell").yields(@channel, true) @transport.stubs(:expect) @transport.connect end it "should send data to the ssh channel" do @channel.expects(:send_data).with("data\n") @transport.command("data") end it "should expect the default prompt afterward" do @transport.expects(:default_prompt).returns("prompt") @transport.expects(:expect).with("prompt") @transport.command("data") end it "should expect the given prompt" do @transport.expects(:expect).with("myprompt") @transport.command("data", :prompt => "myprompt") end it "should yield the buffer output to given block" do @transport.expects(:expect).yields("output") @transport.command("data") do |out| out.should == "output" end end it "should return buffer output" do @transport.expects(:expect).returns("output") @transport.command("data").should == "output" end end describe "when expecting output" do before(:each) do @connection = stub_everything 'connection' @socket = stub_everything 'socket' transport = stub 'transport', :socket => @socket @ssh = stub_everything 'ssh', :transport => transport @channel = stub_everything 'channel', :connection => @connection @transport.ssh = @ssh @transport.channel = @channel end it "should process the ssh event loop" do IO.stubs(:select) @transport.buf = "output" @transport.expects(:process_ssh) @transport.expect(/output/) end it "should return the output" do IO.stubs(:select) @transport.buf = "output" @transport.stubs(:process_ssh) @transport.expect(/output/).should == "output" end it "should return the output" do IO.stubs(:select) @transport.buf = "output" @transport.stubs(:process_ssh) @transport.expect(/output/).should == "output" end describe "when processing the ssh loop" do it "should advance one tick in the ssh event loop and exit on eof" do @transport.buf = '' @connection.expects(:process).then.raises(EOFError) @transport.process_ssh end end end end diff --git a/spec/unit/util/network_device/transport/telnet_spec.rb b/spec/unit/util/network_device/transport/telnet_spec.rb old mode 100644 new mode 100755 index 7499b528e..7528e0740 --- a/spec/unit/util/network_device/transport/telnet_spec.rb +++ b/spec/unit/util/network_device/transport/telnet_spec.rb @@ -1,76 +1,76 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec require File.dirname(__FILE__) + '/../../../../spec_helper' require 'puppet/util/network_device/transport/telnet' describe Puppet::Util::NetworkDevice::Transport::Telnet do before(:each) do @transport = Puppet::Util::NetworkDevice::Transport::Telnet.new() end it "should not handle login through the transport" do @transport.should_not be_handles_login end it "should connect to the given host and port" do Net::Telnet.expects(:new).with { |args| args["Host"] == "localhost" && args["Port"] == 23 }.returns stub_everything @transport.host = "localhost" @transport.port = 23 @transport.connect end it "should connect and specify the default prompt" do @transport.default_prompt = "prompt" Net::Telnet.expects(:new).with { |args| args["Prompt"] == "prompt" }.returns stub_everything @transport.host = "localhost" @transport.port = 23 @transport.connect end describe "when connected" do before(:each) do @telnet = stub_everything 'telnet' Net::Telnet.stubs(:new).returns(@telnet) @transport.connect end it "should send line to the telnet session" do @telnet.expects(:puts).with("line") @transport.send("line") end describe "when expecting output" do it "should waitfor output on the telnet session" do @telnet.expects(:waitfor).with(/regex/) @transport.expect(/regex/) end it "should return telnet session output" do @telnet.expects(:waitfor).returns("output") @transport.expect(/regex/).should == "output" end it "should yield telnet session output to the given block" do @telnet.expects(:waitfor).yields("output") @transport.expect(/regex/) { |out| out.should == "output" } end end end describe "when closing" do before(:each) do @telnet = stub_everything 'telnet' Net::Telnet.stubs(:new).returns(@telnet) @transport.connect end it "should close the telnet session" do @telnet.expects(:close) @transport.close end end -end \ No newline at end of file +end diff --git a/spec/unit/util/package_spec.rb b/spec/unit/util/package_spec.rb index 3a1933bd5..78c114afc 100755 --- a/spec/unit/util/package_spec.rb +++ b/spec/unit/util/package_spec.rb @@ -1,21 +1,20 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/util/package' describe Puppet::Util::Package, " versioncmp" do it "should be able to be used as a module function" do Puppet::Util::Package.should respond_to(:versioncmp) end it "should be able to sort a long set of various unordered versions" do ary = %w{ 1.1.6 2.3 1.1a 3.0 1.5 1 2.4 1.1-4 2.3.1 1.2 2.3.0 1.1-3 2.4b 2.4 2.40.2 2.3a.1 3.1 0002 1.1-5 1.1.a 1.06} newary = ary.sort { |a, b| Puppet::Util::Package.versioncmp(a,b) } newary.should == ["0002", "1", "1.06", "1.1-3", "1.1-4", "1.1-5", "1.1.6", "1.1.a", "1.1a", "1.2", "1.5", "2.3", "2.3.0", "2.3.1", "2.3a.1", "2.4", "2.4", "2.4b", "2.40.2", "3.0", "3.1"] end end diff --git a/spec/unit/util/posix_spec.rb b/spec/unit/util/posix_spec.rb index 65f826bd4..db7c5c3a7 100755 --- a/spec/unit/util/posix_spec.rb +++ b/spec/unit/util/posix_spec.rb @@ -1,256 +1,255 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/util/posix' class PosixTest include Puppet::Util::POSIX end describe Puppet::Util::POSIX do before do @posix = PosixTest.new end [:group, :gr].each do |name| it "should return :gid as the field for #{name}" do @posix.idfield(name).should == :gid end it "should return :getgrgid as the id method for #{name}" do @posix.methodbyid(name).should == :getgrgid end it "should return :getgrnam as the name method for #{name}" do @posix.methodbyname(name).should == :getgrnam end end [:user, :pw, :passwd].each do |name| it "should return :uid as the field for #{name}" do @posix.idfield(name).should == :uid end it "should return :getpwuid as the id method for #{name}" do @posix.methodbyid(name).should == :getpwuid end it "should return :getpwnam as the name method for #{name}" do @posix.methodbyname(name).should == :getpwnam end end describe "when retrieving a posix field" do before do @thing = stub 'thing', :field => "asdf" end it "should fail if no id was passed" do lambda { @posix.get_posix_field("asdf", "bar", nil) }.should raise_error(Puppet::DevError) end describe "and the id is an integer" do it "should log an error and return nil if the specified id is greater than the maximum allowed ID" do Puppet.settings.expects(:value).with(:maximum_uid).returns 100 Puppet.expects(:err) @posix.get_posix_field("asdf", "bar", 200).should be_nil end it "should use the method return by :methodbyid and return the specified field" do Etc.expects(:getgrgid).returns @thing @thing.expects(:field).returns "myval" @posix.get_posix_field(:gr, :field, 200).should == "myval" end it "should return nil if the method throws an exception" do Etc.expects(:getgrgid).raises ArgumentError @thing.expects(:field).never @posix.get_posix_field(:gr, :field, 200).should be_nil end end describe "and the id is not an integer" do it "should use the method return by :methodbyid and return the specified field" do Etc.expects(:getgrnam).returns @thing @thing.expects(:field).returns "myval" @posix.get_posix_field(:gr, :field, "asdf").should == "myval" end it "should return nil if the method throws an exception" do Etc.expects(:getgrnam).raises ArgumentError @thing.expects(:field).never @posix.get_posix_field(:gr, :field, "asdf").should be_nil end end end describe "when returning the gid" do before do @posix.stubs(:get_posix_field) end describe "and the group is an integer" do it "should convert integers specified as a string into an integer" do @posix.expects(:get_posix_field).with(:group, :name, 100) @posix.gid("100") end it "should look up the name for the group" do @posix.expects(:get_posix_field).with(:group, :name, 100) @posix.gid(100) end it "should return nil if the group cannot be found" do @posix.expects(:get_posix_field).once.returns nil @posix.expects(:search_posix_field).never @posix.gid(100).should be_nil end it "should use the found name to look up the id" do @posix.expects(:get_posix_field).with(:group, :name, 100).returns "asdf" @posix.expects(:get_posix_field).with(:group, :gid, "asdf").returns 100 @posix.gid(100).should == 100 end # LAK: This is because some platforms have a broken Etc module that always return # the same group. it "should use :search_posix_field if the discovered id does not match the passed-in id" do @posix.expects(:get_posix_field).with(:group, :name, 100).returns "asdf" @posix.expects(:get_posix_field).with(:group, :gid, "asdf").returns 50 @posix.expects(:search_posix_field).with(:group, :gid, 100).returns "asdf" @posix.gid(100).should == "asdf" end end describe "and the group is a string" do it "should look up the gid for the group" do @posix.expects(:get_posix_field).with(:group, :gid, "asdf") @posix.gid("asdf") end it "should return nil if the group cannot be found" do @posix.expects(:get_posix_field).once.returns nil @posix.expects(:search_posix_field).never @posix.gid("asdf").should be_nil end it "should use the found gid to look up the nam" do @posix.expects(:get_posix_field).with(:group, :gid, "asdf").returns 100 @posix.expects(:get_posix_field).with(:group, :name, 100).returns "asdf" @posix.gid("asdf").should == 100 end it "should use :search_posix_field if the discovered name does not match the passed-in name" do @posix.expects(:get_posix_field).with(:group, :gid, "asdf").returns 100 @posix.expects(:get_posix_field).with(:group, :name, 100).returns "boo" @posix.expects(:search_posix_field).with(:group, :gid, "asdf").returns "asdf" @posix.gid("asdf").should == "asdf" end end end describe "when returning the uid" do before do @posix.stubs(:get_posix_field) end describe "and the group is an integer" do it "should convert integers specified as a string into an integer" do @posix.expects(:get_posix_field).with(:passwd, :name, 100) @posix.uid("100") end it "should look up the name for the group" do @posix.expects(:get_posix_field).with(:passwd, :name, 100) @posix.uid(100) end it "should return nil if the group cannot be found" do @posix.expects(:get_posix_field).once.returns nil @posix.expects(:search_posix_field).never @posix.uid(100).should be_nil end it "should use the found name to look up the id" do @posix.expects(:get_posix_field).with(:passwd, :name, 100).returns "asdf" @posix.expects(:get_posix_field).with(:passwd, :uid, "asdf").returns 100 @posix.uid(100).should == 100 end # LAK: This is because some platforms have a broken Etc module that always return # the same group. it "should use :search_posix_field if the discovered id does not match the passed-in id" do @posix.expects(:get_posix_field).with(:passwd, :name, 100).returns "asdf" @posix.expects(:get_posix_field).with(:passwd, :uid, "asdf").returns 50 @posix.expects(:search_posix_field).with(:passwd, :uid, 100).returns "asdf" @posix.uid(100).should == "asdf" end end describe "and the group is a string" do it "should look up the uid for the group" do @posix.expects(:get_posix_field).with(:passwd, :uid, "asdf") @posix.uid("asdf") end it "should return nil if the group cannot be found" do @posix.expects(:get_posix_field).once.returns nil @posix.expects(:search_posix_field).never @posix.uid("asdf").should be_nil end it "should use the found uid to look up the nam" do @posix.expects(:get_posix_field).with(:passwd, :uid, "asdf").returns 100 @posix.expects(:get_posix_field).with(:passwd, :name, 100).returns "asdf" @posix.uid("asdf").should == 100 end it "should use :search_posix_field if the discovered name does not match the passed-in name" do @posix.expects(:get_posix_field).with(:passwd, :uid, "asdf").returns 100 @posix.expects(:get_posix_field).with(:passwd, :name, 100).returns "boo" @posix.expects(:search_posix_field).with(:passwd, :uid, "asdf").returns "asdf" @posix.uid("asdf").should == "asdf" end end end it "should be able to iteratively search for posix values" do @posix.should respond_to(:search_posix_field) end describe "when searching for posix values iteratively" do it "should iterate across all of the structs returned by Etc and return the appropriate field from the first matching value" end end diff --git a/spec/unit/util/pson_spec.rb b/spec/unit/util/pson_spec.rb index 216e8b5a3..63d085a66 100755 --- a/spec/unit/util/pson_spec.rb +++ b/spec/unit/util/pson_spec.rb @@ -1,53 +1,52 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/util/pson' class PsonUtil include Puppet::Util::Pson end describe Puppet::Util::Pson do it "should fail if no data is provided" do lambda { PsonUtil.new.pson_create("type" => "foo") }.should raise_error(ArgumentError) end it "should call 'from_pson' with the provided data" do pson = PsonUtil.new pson.expects(:from_pson).with("mydata") pson.pson_create("type" => "foo", "data" => "mydata") end { 'foo' => '"foo"', 1 => '1', "\x80" => "\"\x80\"", [] => '[]' }.each { |str,pson| it "should be able to encode #{str.inspect}" do str.to_pson.should == pson end } it "should be able to handle arbitrary binary data" do bin_string = (1..20000).collect { |i| ((17*i+13*i*i) % 255).chr }.join PSON.parse(%Q{{ "type": "foo", "data": #{bin_string.to_pson} }})["data"].should == bin_string end it "should be able to handle UTF8 that isn't a real unicode character" do s = ["\355\274\267"] PSON.parse( [s].to_pson ).should == [s] end it "should be able to handle UTF8 for \\xFF" do s = ["\xc3\xbf"] PSON.parse( [s].to_pson ).should == [s] end it "should be able to handle invalid UTF8 bytes" do s = ["\xc3\xc3"] PSON.parse( [s].to_pson ).should == [s] end end diff --git a/spec/unit/util/queue/stomp_spec.rb b/spec/unit/util/queue/stomp_spec.rb index 76df0581f..f67189cf5 100755 --- a/spec/unit/util/queue/stomp_spec.rb +++ b/spec/unit/util/queue/stomp_spec.rb @@ -1,136 +1,135 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/util/queue' describe Puppet::Util::Queue, :if => Puppet.features.stomp? do it 'should load :stomp client appropriately' do Puppet.settings.stubs(:value).returns 'faux_queue_source' Puppet::Util::Queue.queue_type_to_class(:stomp).name.should == 'Puppet::Util::Queue::Stomp' end end describe 'Puppet::Util::Queue::Stomp', :if => Puppet.features.stomp? do before do # So we make sure we never create a real client instance. # Otherwise we'll try to connect, and that's bad. Stomp::Client.stubs(:new).returns stub("client") end it 'should be registered with Puppet::Util::Queue as :stomp type' do Puppet::Util::Queue.queue_type_to_class(:stomp).should == Puppet::Util::Queue::Stomp end describe "when initializing" do it "should create a Stomp client instance" do Stomp::Client.expects(:new).returns stub("stomp_client") Puppet::Util::Queue::Stomp.new end it "should provide helpful failures when the queue source is not a valid source" do # Stub rather than expect, so we can include the source in the error Puppet.settings.stubs(:value).with(:queue_source).returns "-----" lambda { Puppet::Util::Queue::Stomp.new }.should raise_error(ArgumentError) end it "should fail unless the queue source is a stomp URL" do # Stub rather than expect, so we can include the source in the error Puppet.settings.stubs(:value).with(:queue_source).returns "http://foo/bar" lambda { Puppet::Util::Queue::Stomp.new }.should raise_error(ArgumentError) end it "should fail somewhat helpfully if the Stomp client cannot be created" do Stomp::Client.expects(:new).raises RuntimeError lambda { Puppet::Util::Queue::Stomp.new }.should raise_error(ArgumentError) end list = %w{user password host port} {"user" => "myuser", "password" => "mypass", "host" => "foohost", "port" => 42}.each do |name, value| it "should use the #{name} from the queue source as the queueing #{name}" do Puppet.settings.expects(:value).with(:queue_source).returns "stomp://myuser:mypass@foohost:42/" Stomp::Client.expects(:new).with { |*args| args[list.index(name)] == value } Puppet::Util::Queue::Stomp.new end end it "should create a reliable client instance" do Puppet.settings.expects(:value).with(:queue_source).returns "stomp://myuser@foohost:42/" Stomp::Client.expects(:new).with { |*args| args[4] == true } Puppet::Util::Queue::Stomp.new end end describe "when sending a message" do before do @client = stub 'client' Stomp::Client.stubs(:new).returns @client @queue = Puppet::Util::Queue::Stomp.new end it "should send it to the queue client instance" do @client.expects(:send).with { |queue, msg, options| msg == "Smite!" } @queue.send_message('fooqueue', 'Smite!') end it "should send it to the transformed queue name" do @client.expects(:send).with { |queue, msg, options| queue == "/queue/fooqueue" } @queue.send_message('fooqueue', 'Smite!') end it "should send it as a persistent message" do @client.expects(:send).with { |queue, msg, options| options[:persistent] == true } @queue.send_message('fooqueue', 'Smite!') end end describe "when subscribing to a queue" do before do @client = stub 'client', :acknowledge => true Stomp::Client.stubs(:new).returns @client @queue = Puppet::Util::Queue::Stomp.new end it "should subscribe via the queue client instance" do @client.expects(:subscribe) @queue.subscribe('fooqueue') end it "should subscribe to the transformed queue name" do @client.expects(:subscribe).with { |queue, options| queue == "/queue/fooqueue" } @queue.subscribe('fooqueue') end it "should specify that its messages should be acknowledged" do @client.expects(:subscribe).with { |queue, options| options[:ack] == :client } @queue.subscribe('fooqueue') end it "should yield the body of any received message" do message = mock 'message' message.expects(:body).returns "mybody" @client.expects(:subscribe).yields(message) body = nil @queue.subscribe('fooqueue') { |b| body = b } body.should == "mybody" end it "should acknowledge all successfully processed messages" do message = stub 'message', :body => "mybode" @client.stubs(:subscribe).yields(message) @client.expects(:acknowledge).with(message) @queue.subscribe('fooqueue') { |b| "eh" } end end it 'should transform the simple queue name to "/queue/"' do Puppet::Util::Queue::Stomp.new.stompify_target('blah').should == '/queue/blah' end end diff --git a/spec/unit/util/queue_spec.rb b/spec/unit/util/queue_spec.rb index 8ec75c3d8..59ea57d9b 100755 --- a/spec/unit/util/queue_spec.rb +++ b/spec/unit/util/queue_spec.rb @@ -1,96 +1,95 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/util/queue' require 'spec/mocks' def make_test_client_class(n) c = Class.new do class < make_test_client_class('Bogus::Default'), :setup => make_test_client_class('Bogus::Setup') } describe Puppet::Util::Queue do before :all do mod.register_queue_type(client_classes[:default], :default) mod.register_queue_type(client_classes[:setup], :setup) end before :each do @class = Class.new do extend mod end end after :all do instances = mod.instance_hash(:queue_clients) [:default, :setup, :bogus, :aardvark, :conflict, :test_a, :test_b].each{ |x| instances.delete(x) } end context 'when determining a type name from a class' do it 'should handle a simple one-word class name' do mod.queue_type_from_class(make_test_client_class('Foo')).should == :foo end it 'should handle a simple two-word class name' do mod.queue_type_from_class(make_test_client_class('FooBar')).should == :foo_bar end it 'should handle a two-part class name with one terminating word' do mod.queue_type_from_class(make_test_client_class('Foo::Bar')).should == :bar end it 'should handle a two-part class name with two terminating words' do mod.queue_type_from_class(make_test_client_class('Foo::BarBah')).should == :bar_bah end end context 'when registering a queue client class' do c = make_test_client_class('Foo::Bogus') it 'uses the proper default name logic when type is unspecified' do mod.register_queue_type(c) mod.queue_type_to_class(:bogus).should == c end it 'uses an explicit type name when provided' do mod.register_queue_type(c, :aardvark) mod.queue_type_to_class(:aardvark).should == c end it 'throws an exception when type names conflict' do mod.register_queue_type( make_test_client_class('Conflict') ) lambda { mod.register_queue_type( c, :conflict) }.should raise_error end it 'handle multiple, non-conflicting registrations' do a = make_test_client_class('TestA') b = make_test_client_class('TestB') mod.register_queue_type(a) mod.register_queue_type(b) mod.queue_type_to_class(:test_a).should == a mod.queue_type_to_class(:test_b).should == b end it 'throws an exception when type name is unknown' do lambda { mod.queue_type_to_class(:nope) }.should raise_error end end context 'when determining client type' do it 'returns client class based on the :queue_type setting' do Puppet.settings.expects(:value).with(:queue_type).returns(:myqueue) Puppet::Util::Queue.expects(:queue_type_to_class).with(:myqueue).returns "eh" @class.client_class.should == "eh" end end end diff --git a/spec/unit/util/rdoc/parser_spec.rb b/spec/unit/util/rdoc/parser_spec.rb index af2058197..c7f99051f 100755 --- a/spec/unit/util/rdoc/parser_spec.rb +++ b/spec/unit/util/rdoc/parser_spec.rb @@ -1,563 +1,562 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/resource/type_collection' require 'puppet/util/rdoc/parser' require 'puppet/util/rdoc/code_objects' require 'rdoc/options' require 'rdoc/rdoc' describe RDoc::Parser do before :each do File.stubs(:stat).with("init.pp") @top_level = stub_everything 'toplevel', :file_relative_name => "init.pp" @parser = RDoc::Parser.new(@top_level, "module/manifests/init.pp", nil, Options.instance, RDoc::Stats.new) end describe "when scanning files" do it "should parse puppet files with the puppet parser" do @parser.stubs(:scan_top_level) parser = stub 'parser' Puppet::Parser::Parser.stubs(:new).returns(parser) parser.expects(:parse).returns(Puppet::Parser::AST::Hostclass.new('')).at_least_once parser.expects(:file=).with("module/manifests/init.pp") parser.expects(:file=).with("/dev/null/manifests/site.pp") @parser.scan end it "should scan the ast for Puppet files" do parser = stub_everything 'parser' Puppet::Parser::Parser.stubs(:new).returns(parser) parser.expects(:parse).returns(Puppet::Parser::AST::Hostclass.new('')).at_least_once @parser.expects(:scan_top_level) @parser.scan end it "should return a PuppetTopLevel to RDoc" do parser = stub_everything 'parser' Puppet::Parser::Parser.stubs(:new).returns(parser) parser.expects(:parse).returns(Puppet::Parser::AST::Hostclass.new('')).at_least_once @parser.expects(:scan_top_level) @parser.scan.should be_a(RDoc::PuppetTopLevel) end it "should scan the top level even if the file has already parsed" do known_type = stub 'known_types' env = stub 'env' Puppet::Node::Environment.stubs(:new).returns(env) env.stubs(:known_resource_types).returns(known_type) known_type.expects(:watching_file?).with("module/manifests/init.pp").returns(true) @parser.expects(:scan_top_level) @parser.scan end end describe "when scanning top level entities" do before :each do @resource_type_collection = resource_type_collection = stub_everything('resource_type_collection') @parser.instance_eval { @known_resource_types = resource_type_collection } @parser.stubs(:split_module).returns("module") @topcontainer = stub_everything 'topcontainer' @container = stub_everything 'container' @module = stub_everything 'module' @container.stubs(:add_module).returns(@module) @parser.stubs(:get_class_or_module).returns([@container, "module"]) end it "should read any present README as module documentation" do FileTest.stubs(:readable?).returns(true) File.stubs(:open).returns("readme") @parser.stubs(:parse_elements) @module.expects(:comment=).with("readme") @parser.scan_top_level(@topcontainer) end it "should tell the container its module name" do @parser.stubs(:parse_elements) @topcontainer.expects(:module_name=).with("module") @parser.scan_top_level(@topcontainer) end it "should not document our toplevel if it isn't a valid module" do @parser.stubs(:split_module).returns(nil) @topcontainer.expects(:document_self=).with(false) @parser.expects(:parse_elements).never @parser.scan_top_level(@topcontainer) end it "should set the module as global if we parse the global manifests (ie __site__ module)" do @parser.stubs(:split_module).returns(RDoc::Parser::SITE) @parser.stubs(:parse_elements) @topcontainer.expects(:global=).with(true) @parser.scan_top_level(@topcontainer) end it "should attach this module container to the toplevel container" do @parser.stubs(:parse_elements) @container.expects(:add_module).with(RDoc::PuppetModule, "module").returns(@module) @parser.scan_top_level(@topcontainer) end it "should defer ast parsing to parse_elements for this module" do @parser.expects(:parse_elements).with(@module) @parser.scan_top_level(@topcontainer) end it "should defer plugins parsing to parse_plugins for this module" do @parser.input_file_name = "module/lib/puppet/parser/function.rb" @parser.expects(:parse_plugins).with(@module) @parser.scan_top_level(@topcontainer) end end describe "when finding modules from filepath" do before :each do Puppet::Module.stubs(:modulepath).returns("/path/to/modules") end it "should return the module name for modulized puppet manifests" do File.stubs(:expand_path).returns("/path/to/module/manifests/init.pp") File.stubs(:identical?).with("/path/to", "/path/to/modules").returns(true) @parser.split_module("/path/to/modules/mymodule/manifests/init.pp").should == "module" end it "should return for manifests not under module path" do File.stubs(:expand_path).returns("/path/to/manifests/init.pp") File.stubs(:identical?).returns(false) @parser.split_module("/path/to/manifests/init.pp").should == RDoc::Parser::SITE end end describe "when parsing AST elements" do before :each do @klass = stub_everything 'klass', :file => "module/manifests/init.pp", :name => "myclass", :type => :hostclass @definition = stub_everything 'definition', :file => "module/manifests/init.pp", :type => :definition, :name => "mydef" @node = stub_everything 'node', :file => "module/manifests/init.pp", :type => :node, :name => "mynode" @resource_type_collection = resource_type_collection = Puppet::Resource::TypeCollection.new("env") @parser.instance_eval { @known_resource_types = resource_type_collection } @container = stub_everything 'container' end it "should document classes in the parsed file" do @resource_type_collection.add_hostclass(@klass) @parser.expects(:document_class).with("myclass", @klass, @container) @parser.parse_elements(@container) end it "should not document class parsed in an other file" do @klass.stubs(:file).returns("/not/same/path/file.pp") @resource_type_collection.add_hostclass(@klass) @parser.expects(:document_class).with("myclass", @klass, @container).never @parser.parse_elements(@container) end it "should document vardefs for the main class" do @klass.stubs(:name).returns :main @resource_type_collection.add_hostclass(@klass) code = stub 'code', :is_a? => false @klass.stubs(:name).returns("") @klass.stubs(:code).returns(code) @parser.expects(:scan_for_vardef).with(@container, code) @parser.parse_elements(@container) end it "should document definitions in the parsed file" do @resource_type_collection.add_definition(@definition) @parser.expects(:document_define).with("mydef", @definition, @container) @parser.parse_elements(@container) end it "should not document definitions parsed in an other file" do @definition.stubs(:file).returns("/not/same/path/file.pp") @resource_type_collection.add_definition(@definition) @parser.expects(:document_define).with("mydef", @definition, @container).never @parser.parse_elements(@container) end it "should document nodes in the parsed file" do @resource_type_collection.add_node(@node) @parser.expects(:document_node).with("mynode", @node, @container) @parser.parse_elements(@container) end it "should not document node parsed in an other file" do @node.stubs(:file).returns("/not/same/path/file.pp") @resource_type_collection.add_node(@node) @parser.expects(:document_node).with("mynode", @node, @container).never @parser.parse_elements(@container) end end describe "when documenting definition" do before(:each) do @define = stub_everything 'define', :arguments => [], :doc => "mydoc", :file => "file", :line => 42 @class = stub_everything 'class' @parser.stubs(:get_class_or_module).returns([@class, "mydef"]) end it "should register a RDoc method to the current container" do @class.expects(:add_method).with { |m| m.name == "mydef"} @parser.document_define("mydef", @define, @class) end it "should attach the documentation to this method" do @class.expects(:add_method).with { |m| m.comment = "mydoc" } @parser.document_define("mydef", @define, @class) end it "should produce a better error message on unhandled exception" do @class.expects(:add_method).raises(ArgumentError) lambda { @parser.document_define("mydef", @define, @class) }.should raise_error(Puppet::ParseError, /in file at line 42/) end it "should convert all definition parameter to string" do arg = stub 'arg' val = stub 'val' @define.stubs(:arguments).returns({arg => val}) arg.expects(:to_s).returns("arg") val.expects(:to_s).returns("val") @parser.document_define("mydef", @define, @class) end end describe "when documenting nodes" do before :each do @code = stub_everything 'code' @node = stub_everything 'node', :doc => "mydoc", :parent => "parent", :code => @code, :file => "file", :line => 42 @rdoc_node = stub_everything 'rdocnode' @class = stub_everything 'class' @class.stubs(:add_node).returns(@rdoc_node) end it "should add a node to the current container" do @class.expects(:add_node).with("mynode", "parent").returns(@rdoc_node) @parser.document_node("mynode", @node, @class) end it "should associate the node documentation to the rdoc node" do @rdoc_node.expects(:comment=).with("mydoc") @parser.document_node("mynode", @node, @class) end it "should scan for include and require" do @parser.expects(:scan_for_include_or_require).with(@rdoc_node, @code) @parser.document_node("mynode", @node, @class) end it "should scan for variable definition" do @parser.expects(:scan_for_vardef).with(@rdoc_node, @code) @parser.document_node("mynode", @node, @class) end it "should scan for resources if needed" do Puppet.settings.stubs(:[]).with(:document_all).returns(true) @parser.expects(:scan_for_resource).with(@rdoc_node, @code) @parser.document_node("mynode", @node, @class) end it "should produce a better error message on unhandled exception" do @class.stubs(:add_node).raises(ArgumentError) lambda { @parser.document_node("mynode", @node, @class) }.should raise_error(Puppet::ParseError, /in file at line 42/) end end describe "when documenting classes" do before :each do @code = stub_everything 'code' @class = stub_everything 'class', :doc => "mydoc", :parent => "parent", :code => @code, :file => "file", :line => 42 @rdoc_class = stub_everything 'rdoc-class' @module = stub_everything 'class' @module.stubs(:add_class).returns(@rdoc_class) @parser.stubs(:get_class_or_module).returns([@module, "myclass"]) end it "should add a class to the current container" do @module.expects(:add_class).with(RDoc::PuppetClass, "myclass", "parent").returns(@rdoc_class) @parser.document_class("mynode", @class, @module) end it "should set the superclass" do @rdoc_class.expects(:superclass=).with("parent") @parser.document_class("mynode", @class, @module) end it "should associate the node documentation to the rdoc class" do @rdoc_class.expects(:comment=).with("mydoc") @parser.document_class("mynode", @class, @module) end it "should scan for include and require" do @parser.expects(:scan_for_include_or_require).with(@rdoc_class, @code) @parser.document_class("mynode", @class, @module) end it "should scan for resources if needed" do Puppet.settings.stubs(:[]).with(:document_all).returns(true) @parser.expects(:scan_for_resource).with(@rdoc_class, @code) @parser.document_class("mynode", @class, @module) end it "should produce a better error message on unhandled exception" do @module.stubs(:add_class).raises(ArgumentError) lambda { @parser.document_class("mynode", @class, @module) }.should raise_error(Puppet::ParseError, /in file at line 42/) end end describe "when scanning for includes and requires" do def create_stmt(name) stmt_value = stub "#{name}_value", :to_s => "myclass" Puppet::Parser::AST::Function.new( :name => name, :arguments => [stmt_value], :doc => 'mydoc' ) end before(:each) do @class = stub_everything 'class' @code = stub_everything 'code' @code.stubs(:is_a?).with(Puppet::Parser::AST::ASTArray).returns(true) end it "should also scan mono-instruction code" do @class.expects(:add_include).with { |i| i.is_a?(RDoc::Include) and i.name == "myclass" and i.comment == "mydoc" } @parser.scan_for_include_or_require(@class, create_stmt("include")) end it "should register recursively includes to the current container" do @code.stubs(:children).returns([ create_stmt("include") ]) @class.expects(:add_include)#.with { |i| i.is_a?(RDoc::Include) and i.name == "myclass" and i.comment == "mydoc" } @parser.scan_for_include_or_require(@class, [@code]) end it "should register requires to the current container" do @code.stubs(:children).returns([ create_stmt("require") ]) @class.expects(:add_require).with { |i| i.is_a?(RDoc::Include) and i.name == "myclass" and i.comment == "mydoc" } @parser.scan_for_include_or_require(@class, [@code]) end end describe "when scanning for realized virtual resources" do def create_stmt stmt_value = stub "resource_ref", :to_s => "File[\"/tmp/a\"]" Puppet::Parser::AST::Function.new( :name => 'realize', :arguments => [stmt_value], :doc => 'mydoc' ) end before(:each) do @class = stub_everything 'class' @code = stub_everything 'code' @code.stubs(:is_a?).with(Puppet::Parser::AST::ASTArray).returns(true) end it "should also scan mono-instruction code" do @class.expects(:add_realize).with { |i| i.is_a?(RDoc::Include) and i.name == "File[\"/tmp/a\"]" and i.comment == "mydoc" } @parser.scan_for_realize(@class,create_stmt) end it "should register recursively includes to the current container" do @code.stubs(:children).returns([ create_stmt ]) @class.expects(:add_realize).with { |i| i.is_a?(RDoc::Include) and i.name == "File[\"/tmp/a\"]" and i.comment == "mydoc" } @parser.scan_for_realize(@class, [@code]) end end describe "when scanning for variable definition" do before :each do @class = stub_everything 'class' @stmt = stub_everything 'stmt', :name => "myvar", :value => "myvalue", :doc => "mydoc" @stmt.stubs(:is_a?).with(Puppet::Parser::AST::ASTArray).returns(false) @stmt.stubs(:is_a?).with(Puppet::Parser::AST::VarDef).returns(true) @code = stub_everything 'code' @code.stubs(:is_a?).with(Puppet::Parser::AST::ASTArray).returns(true) end it "should recursively register variables to the current container" do @code.stubs(:children).returns([ @stmt ]) @class.expects(:add_constant).with { |i| i.is_a?(RDoc::Constant) and i.name == "myvar" and i.comment == "mydoc" } @parser.scan_for_vardef(@class, [ @code ]) end it "should also scan mono-instruction code" do @class.expects(:add_constant).with { |i| i.is_a?(RDoc::Constant) and i.name == "myvar" and i.comment == "mydoc" } @parser.scan_for_vardef(@class, @stmt) end end describe "when scanning for resources" do before :each do @class = stub_everything 'class' @stmt = Puppet::Parser::AST::Resource.new( :type => "File", :instances => Puppet::Parser::AST::ASTArray.new(:children => [ Puppet::Parser::AST::ResourceInstance.new( :title => Puppet::Parser::AST::Name.new(:value => "myfile"), :parameters => Puppet::Parser::AST::ASTArray.new(:children => []) ) ]), :doc => 'mydoc' ) @code = stub_everything 'code' @code.stubs(:is_a?).with(Puppet::Parser::AST::ASTArray).returns(true) end it "should register a PuppetResource to the current container" do @code.stubs(:children).returns([ @stmt ]) @class.expects(:add_resource).with { |i| i.is_a?(RDoc::PuppetResource) and i.title == "myfile" and i.comment == "mydoc" } @parser.scan_for_resource(@class, [ @code ]) end it "should also scan mono-instruction code" do @class.expects(:add_resource).with { |i| i.is_a?(RDoc::PuppetResource) and i.title == "myfile" and i.comment == "mydoc" } @parser.scan_for_resource(@class, @stmt) end end describe "when parsing plugins" do before :each do @container = stub 'container' end it "should delegate parsing custom facts to parse_facts" do @parser = RDoc::Parser.new(@top_level, "module/manifests/lib/puppet/facter/test.rb", nil, Options.instance, RDoc::Stats.new) @parser.expects(:parse_fact).with(@container) @parser.parse_plugins(@container) end it "should delegate parsing plugins to parse_plugins" do @parser = RDoc::Parser.new(@top_level, "module/manifests/lib/puppet/functions/test.rb", nil, Options.instance, RDoc::Stats.new) @parser.expects(:parse_puppet_plugin).with(@container) @parser.parse_plugins(@container) end end describe "when parsing plugins" do before :each do @container = stub_everything 'container' end it "should add custom functions to the container" do File.stubs(:open).yields("# documentation module Puppet::Parser::Functions newfunction(:myfunc, :type => :rvalue) do |args| File.dirname(args[0]) end end".split("\n")) @container.expects(:add_plugin).with do |plugin| plugin.comment == "documentation\n" #and plugin.name == "myfunc" end @parser.parse_puppet_plugin(@container) end it "should add custom types to the container" do File.stubs(:open).yields("# documentation Puppet::Type.newtype(:mytype) do end".split("\n")) @container.expects(:add_plugin).with do |plugin| plugin.comment == "documentation\n" #and plugin.name == "mytype" end @parser.parse_puppet_plugin(@container) end end describe "when parsing facts" do before :each do @container = stub_everything 'container' File.stubs(:open).yields(["# documentation", "Facter.add('myfact') do", "confine :kernel => :linux", "end"]) end it "should add facts to the container" do @container.expects(:add_fact).with do |fact| fact.comment == "documentation\n" and fact.name == "myfact" end @parser.parse_fact(@container) end it "should add confine to the parsed facts" do ourfact = nil @container.expects(:add_fact).with do |fact| ourfact = fact true end @parser.parse_fact(@container) ourfact.confine.should == { :type => "kernel", :value => ":linux" } end end end diff --git a/spec/unit/util/rdoc_spec.rb b/spec/unit/util/rdoc_spec.rb index 13e22eec9..067b5b8a7 100755 --- a/spec/unit/util/rdoc_spec.rb +++ b/spec/unit/util/rdoc_spec.rb @@ -1,148 +1,147 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/util/rdoc' require 'rdoc/rdoc' describe Puppet::Util::RDoc do describe "when generating RDoc HTML documentation" do before :each do @rdoc = stub_everything 'rdoc' RDoc::RDoc.stubs(:new).returns(@rdoc) end it "should tell the parser to ignore import" do Puppet.expects(:[]=).with(:ignoreimport, true) Puppet::Util::RDoc.rdoc("output", []) end it "should install the Puppet HTML Generator into RDoc generators" do Puppet::Util::RDoc.rdoc("output", []) RDoc::RDoc::GENERATORS["puppet"].file_name.should == "puppet/util/rdoc/generators/puppet_generator.rb" end it "should tell RDoc to generate documentation using the Puppet generator" do @rdoc.expects(:document).with { |args| args.include?("--fmt") and args.include?("puppet") } Puppet::Util::RDoc.rdoc("output", []) end it "should tell RDoc to be quiet" do @rdoc.expects(:document).with { |args| args.include?("--quiet") } Puppet::Util::RDoc.rdoc("output", []) end it "should pass charset to RDoc" do @rdoc.expects(:document).with { |args| args.include?("--charset") and args.include?("utf-8") } Puppet::Util::RDoc.rdoc("output", [], "utf-8") end it "should tell RDoc to force updates of indices when RDoc supports it" do Options::OptionList.stubs(:options).returns([["--force-update", "-U", 0 ]]) @rdoc.expects(:document).with { |args| args.include?("--force-update") } Puppet::Util::RDoc.rdoc("output", []) end it "should not tell RDoc to force updates of indices when RDoc doesn't support it" do Options::OptionList.stubs(:options).returns([]) @rdoc.expects(:document).never.with { |args| args.include?("--force-update") } Puppet::Util::RDoc.rdoc("output", []) end it "should tell RDoc to use the given outputdir" do @rdoc.expects(:document).with { |args| args.include?("--op") and args.include?("myoutputdir") } Puppet::Util::RDoc.rdoc("myoutputdir", []) end it "should tell RDoc to exclude .pp files under any modules//files section" do @rdoc.expects(:document).with { |args| args.include?("--exclude") and args.include?("/modules/[^/]*/files/.*\.pp$") } Puppet::Util::RDoc.rdoc("myoutputdir", []) end it "should give all the source directories to RDoc" do @rdoc.expects(:document).with { |args| args.include?("sourcedir") } Puppet::Util::RDoc.rdoc("output", ["sourcedir"]) end end describe "when running a manifest documentation" do it "should tell the parser to ignore import" do Puppet.expects(:[]=).with(:ignoreimport, true) Puppet::Util::RDoc.manifestdoc([]) end it "should use a parser with the correct environment" do FileTest.stubs(:file?).returns(true) Puppet::Util::RDoc.stubs(:output) parser = stub_everything Puppet::Parser::Parser.stubs(:new).with{ |env| env.is_a?(Puppet::Node::Environment) }.returns(parser) parser.expects(:file=).with("file") parser.expects(:parse) Puppet::Util::RDoc.manifestdoc(["file"]) end it "should puppet parse all given files" do FileTest.stubs(:file?).returns(true) Puppet::Util::RDoc.stubs(:output) parser = stub_everything Puppet::Parser::Parser.stubs(:new).returns(parser) parser.expects(:file=).with("file") parser.expects(:parse) Puppet::Util::RDoc.manifestdoc(["file"]) end it "should call output for each parsed file" do FileTest.stubs(:file?).returns(true) ast = stub_everything parser = stub_everything Puppet::Parser::Parser.stubs(:new).returns(parser) parser.stubs(:parse).returns(ast) Puppet::Util::RDoc.expects(:output).with("file", ast) Puppet::Util::RDoc.manifestdoc(["file"]) end describe "when outputing documentation" do it "should output doc for ast classes, nodes and definitions in order of increasing line number" do byline = sequence('documentation outputs in line order') Puppet::Util::RDoc.expects(:puts).with("im a class\n").in_sequence(byline) Puppet::Util::RDoc.expects(:puts).with("im a node\n").in_sequence(byline) Puppet::Util::RDoc.expects(:puts).with("im a define\n").in_sequence(byline) # any other output must fail Puppet::Util::RDoc.manifestdoc([my_fixture('basic.pp')]) end it "should output resource documentation if needed" do pending "#6634 being fixed" Puppet.settings[:document_all] = true byline = sequence('documentation outputs in line order') Puppet::Util::RDoc.expects(:puts).with("im a class\n").in_sequence(byline) Puppet::Util::RDoc.expects(:puts).with("im a node\n").in_sequence(byline) Puppet::Util::RDoc.expects(:puts).with("im a define\n").in_sequence(byline) Puppet::Util::RDoc.expects(:puts).with("im a resource\n").in_sequence(byline) # any other output must fail Puppet::Util::RDoc.manifestdoc([my_fixture('basic.pp')]) end end end end diff --git a/spec/unit/util/reference_serializer_spec.rb b/spec/unit/util/reference_serializer_spec.rb index d696dc193..de53ab9bb 100755 --- a/spec/unit/util/reference_serializer_spec.rb +++ b/spec/unit/util/reference_serializer_spec.rb @@ -1,52 +1,51 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/util/rails/reference_serializer' class SerializeTester include Puppet::Util::ReferenceSerializer end describe Puppet::Util::ReferenceSerializer do before do @tester = SerializeTester.new end describe "when serializing" do it "should yaml-dump resource references" do ref = Puppet::Resource.new("file", "/foo") @tester.serialize_value(ref).should =~ /^---/ end it "should convert the boolean 'true' into the string 'true'" do @tester.serialize_value(true).should == "true" end it "should convert the boolean 'false' into the string 'false'" do @tester.serialize_value(false).should == "false" end it "should return all other values" do @tester.serialize_value("foo").should == "foo" end end describe "when unserializing" do it "should yaml-load values that look like yaml" do yaml = YAML.dump(%w{a b c}) @tester.unserialize_value(yaml).should == %w{a b c} end it "should convert the string 'true' into the boolean 'true'" do @tester.unserialize_value("true").should == true end it "should convert the string 'false' into the boolean 'false'" do @tester.unserialize_value("false").should == false end it "should return all other values" do @tester.unserialize_value("foo").should == "foo" end end end diff --git a/spec/unit/util/resource_template_spec.rb b/spec/unit/util/resource_template_spec.rb index f83979607..4f7cafdb7 100755 --- a/spec/unit/util/resource_template_spec.rb +++ b/spec/unit/util/resource_template_spec.rb @@ -1,58 +1,57 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/util/resource_template' describe Puppet::Util::ResourceTemplate do describe "when initializing" do it "should fail if the template does not exist" do FileTest.expects(:exist?).with("/my/template").returns false lambda { Puppet::Util::ResourceTemplate.new("/my/template", mock('resource')) }.should raise_error(ArgumentError) end it "should not create the ERB template" do ERB.expects(:new).never FileTest.expects(:exist?).with("/my/template").returns true Puppet::Util::ResourceTemplate.new("/my/template", mock('resource')) end end describe "when evaluating" do before do FileTest.stubs(:exist?).returns true File.stubs(:read).returns "eh" @template = stub 'template', :result => nil ERB.stubs(:new).returns @template @resource = mock 'resource' @wrapper = Puppet::Util::ResourceTemplate.new("/my/template", @resource) end it "should set all of the resource's parameters as instance variables" do @resource.expects(:to_hash).returns(:one => "uno", :two => "dos") @template.expects(:result).with do |bind| eval("@one", bind) == "uno" and eval("@two", bind) == "dos" end @wrapper.evaluate end it "should create a template instance with the contents of the file" do File.expects(:read).with("/my/template").returns "yay" ERB.expects(:new).with("yay", 0, "-").returns(@template) @wrapper.stubs :set_resource_variables @wrapper.evaluate end it "should return the result of the template" do @wrapper.stubs :set_resource_variables @wrapper.expects(:binding).returns "mybinding" @template.expects(:result).with("mybinding").returns "myresult" @wrapper.evaluate.should == "myresult" end end end diff --git a/spec/unit/util/run_mode_spec.rb b/spec/unit/util/run_mode_spec.rb index 168936f44..c8d2b31f6 100755 --- a/spec/unit/util/run_mode_spec.rb +++ b/spec/unit/util/run_mode_spec.rb @@ -1,51 +1,50 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe Puppet::Util::RunMode do before do @run_mode = Puppet::Util::RunMode.new('fake') end it "should have confdir /etc/puppet when run as root" do Puppet.features.stubs(:root?).returns(true) @run_mode.conf_dir.should == '/etc/puppet' end it "should have confdir ~/.puppet when run as non-root" do Puppet.features.stubs(:root?).returns(false) @run_mode.expects(:expand_path).with("~/.puppet").returns("~/.puppet") @run_mode.conf_dir.should == "~/.puppet" end it "should have vardir /var/lib/puppet when run as root" do Puppet.features.stubs(:root?).returns(true) @run_mode.var_dir.should == '/var/lib/puppet' end it "should have vardir ~/.puppet/var when run as non-root" do Puppet.features.stubs(:root?).returns(false) @run_mode.expects(:expand_path).with("~/.puppet/var").returns("~/.puppet/var") @run_mode.var_dir.should == "~/.puppet/var" end it "should have rundir depend on vardir" do @run_mode.run_dir.should == '$vardir/run' end it "should have logopts return an array with $vardir/log if runmode is not master" do @run_mode.expects(:master?).returns false @run_mode.logopts.should == ["$vardir/log", "The Puppet log directory."] end it "should have logopts return a hash with $vardir/log and other metadata if runmode is master" do @run_mode.expects(:master?).returns true @run_mode.logopts.should == { :default => "$vardir/log", :mode => 0750, :owner => "service", :group => "service", :desc => "The Puppet log directory.", } end end diff --git a/spec/unit/util/selinux_spec.rb b/spec/unit/util/selinux_spec.rb index bad52f09f..0eaf43cbb 100755 --- a/spec/unit/util/selinux_spec.rb +++ b/spec/unit/util/selinux_spec.rb @@ -1,278 +1,277 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/util/selinux' include Puppet::Util::SELinux unless defined?(Selinux) module Selinux def self.is_selinux_enabled false end end end describe Puppet::Util::SELinux do describe "selinux_support?" do before do end it "should return :true if this system has SELinux enabled" do Selinux.expects(:is_selinux_enabled).returns 1 selinux_support?.should be_true end it "should return :false if this system lacks SELinux" do Selinux.expects(:is_selinux_enabled).returns 0 selinux_support?.should be_false end it "should return nil if /proc/mounts does not exist" do File.stubs(:open).with("/proc/mounts").raises("No such file or directory - /proc/mounts") read_mounts.should == nil end end describe "filesystem detection" do before :each do fh = stub 'fh', :close => nil File.stubs(:open).with("/proc/mounts").returns fh fh.expects(:read_nonblock).times(2).returns("rootfs / rootfs rw 0 0\n/dev/root / ext3 rw,relatime,errors=continue,user_xattr,acl,data=ordered 0 0\n/dev /dev tmpfs rw,relatime,mode=755 0 0\n/proc /proc proc rw,relatime 0 0\n/sys /sys sysfs rw,relatime 0 0\n192.168.1.1:/var/export /mnt/nfs nfs rw,relatime,vers=3,rsize=32768,wsize=32768,namlen=255,hard,nointr,proto=tcp,timeo=600,retrans=2,sec=sys,mountaddr=192.168.1.1,mountvers=3,mountproto=udp,addr=192.168.1.1 0 0\n").then.raises EOFError end it "should parse the contents of /proc/mounts" do read_mounts.should == { '/' => 'ext3', '/sys' => 'sysfs', '/mnt/nfs' => 'nfs', '/proc' => 'proc', '/dev' => 'tmpfs' } end it "should match a path on / to ext3" do find_fs('/etc/puppet/testfile').should == "ext3" end it "should match a path on /mnt/nfs to nfs" do find_fs('/mnt/nfs/testfile/foobar').should == "nfs" end it "should reture true for a capable filesystem" do selinux_label_support?('/etc/puppet/testfile').should be_true end it "should return false for a noncapable filesystem" do selinux_label_support?('/mnt/nfs/testfile').should be_false end it "should follow symlinks when determining file systems" do self.stubs(:realpath).with('/mnt/symlink/testfile').returns('/mnt/nfs/dest/testfile') selinux_label_support?('/mnt/symlink/testfile').should be_false end end describe "realpath" do it "should handle files that don't exist" do # Since I'm stubbing Pathname.new for this test, # I need to also stub the internal calls to Pathname.new, # which happen in Pathname.dirname and Parthname.basename # I want those to return real Pathname objects, # so I'm creating them before the stub is in place. realpaths = Hash.new {|hash, path| hash[path] = Pathname.new(path) } paths = ['symlink', '/mnt'] paths.each { |path| realpaths[path] } realpaths['/mnt/symlink'] = stubs "Pathname" realpaths['/mnt/symlink'].stubs(:realpath).returns(realpaths['/mnt/nfs/dest']) realpaths['/mnt/symlink'].stubs(:exist?).returns(true) realpaths['/mnt/symlink/nonexistant'] = stubs "Pathname" realpaths['/mnt/symlink/nonexistant'].stubs(:realpath).raises(Errno::ENOENT) realpaths['/mnt/symlink/nonexistant'].stubs(:exist?).returns(false) realpaths['/mnt/symlink/nonexistant'].stubs(:dirname).returns(realpaths['/mnt/symlink']) realpaths['/mnt/symlink/nonexistant'].stubs(:basename).returns(realpaths['nonexistant']) realpaths.each do |path, value| Pathname.stubs(:new).with(path).returns(value) end realpath('/mnt/symlink/nonexistant').should == '/mnt/nfs/dest/nonexistant' end end describe "get_selinux_current_context" do it "should return nil if no SELinux support" do self.expects(:selinux_support?).returns false get_selinux_current_context("/foo").should be_nil end it "should return a context" do self.expects(:selinux_support?).returns true Selinux.expects(:lgetfilecon).with("/foo").returns [0, "user_u:role_r:type_t:s0"] get_selinux_current_context("/foo").should == "user_u:role_r:type_t:s0" end it "should return nil if lgetfilecon fails" do self.expects(:selinux_support?).returns true Selinux.expects(:lgetfilecon).with("/foo").returns -1 get_selinux_current_context("/foo").should be_nil end end describe "get_selinux_default_context" do it "should return nil if no SELinux support" do self.expects(:selinux_support?).returns false get_selinux_default_context("/foo").should be_nil end it "should return a context if a default context exists" do self.expects(:selinux_support?).returns true fstat = stub 'File::Stat', :mode => 0 File.expects(:lstat).with("/foo").returns fstat self.expects(:find_fs).with("/foo").returns "ext3" Selinux.expects(:matchpathcon).with("/foo", 0).returns [0, "user_u:role_r:type_t:s0"] get_selinux_default_context("/foo").should == "user_u:role_r:type_t:s0" end it "should return nil if matchpathcon returns failure" do self.expects(:selinux_support?).returns true fstat = stub 'File::Stat', :mode => 0 File.expects(:lstat).with("/foo").returns fstat self.expects(:find_fs).with("/foo").returns "ext3" Selinux.expects(:matchpathcon).with("/foo", 0).returns -1 get_selinux_default_context("/foo").should be_nil end it "should return nil if selinux_label_support returns false" do self.expects(:selinux_support?).returns true self.expects(:find_fs).with("/foo").returns "nfs" get_selinux_default_context("/foo").should be_nil end end describe "parse_selinux_context" do it "should return nil if no context is passed" do parse_selinux_context(:seluser, nil).should be_nil end it "should return nil if the context is 'unlabeled'" do parse_selinux_context(:seluser, "unlabeled").should be_nil end it "should return the user type when called with :seluser" do parse_selinux_context(:seluser, "user_u:role_r:type_t:s0").should == "user_u" end it "should return the role type when called with :selrole" do parse_selinux_context(:selrole, "user_u:role_r:type_t:s0").should == "role_r" end it "should return the type type when called with :seltype" do parse_selinux_context(:seltype, "user_u:role_r:type_t:s0").should == "type_t" end it "should return nil for :selrange when no range is returned" do parse_selinux_context(:selrange, "user_u:role_r:type_t").should be_nil end it "should return the range type when called with :selrange" do parse_selinux_context(:selrange, "user_u:role_r:type_t:s0").should == "s0" end describe "with a variety of SELinux range formats" do ['s0', 's0:c3', 's0:c3.c123', 's0:c3,c5,c8', 'TopSecret', 'TopSecret,Classified', 'Patient_Record'].each do |range| it "should parse range '#{range}'" do parse_selinux_context(:selrange, "user_u:role_r:type_t:#{range}").should == range end end end end describe "set_selinux_context" do before :each do fh = stub 'fh', :close => nil File.stubs(:open).with("/proc/mounts").returns fh fh.stubs(:read_nonblock).returns( "rootfs / rootfs rw 0 0\n/dev/root / ext3 rw,relatime,errors=continue,user_xattr,acl,data=ordered 0 0\n"+ "/dev /dev tmpfs rw,relatime,mode=755 0 0\n/proc /proc proc rw,relatime 0 0\n"+ "/sys /sys sysfs rw,relatime 0 0\n" ).then.raises EOFError end it "should return nil if there is no SELinux support" do self.expects(:selinux_support?).returns false set_selinux_context("/foo", "user_u:role_r:type_t:s0").should be_nil end it "should return nil if selinux_label_support returns false" do self.expects(:selinux_support?).returns true self.expects(:selinux_label_support?).with("/foo").returns false set_selinux_context("/foo", "user_u:role_r:type_t:s0").should be_nil end it "should use lsetfilecon to set a context" do self.expects(:selinux_support?).returns true Selinux.expects(:lsetfilecon).with("/foo", "user_u:role_r:type_t:s0").returns 0 set_selinux_context("/foo", "user_u:role_r:type_t:s0").should be_true end it "should use lsetfilecon to set user_u user context" do self.expects(:selinux_support?).returns true Selinux.expects(:lgetfilecon).with("/foo").returns [0, "foo:role_r:type_t:s0"] Selinux.expects(:lsetfilecon).with("/foo", "user_u:role_r:type_t:s0").returns 0 set_selinux_context("/foo", "user_u", :seluser).should be_true end it "should use lsetfilecon to set role_r role context" do self.expects(:selinux_support?).returns true Selinux.expects(:lgetfilecon).with("/foo").returns [0, "user_u:foo:type_t:s0"] Selinux.expects(:lsetfilecon).with("/foo", "user_u:role_r:type_t:s0").returns 0 set_selinux_context("/foo", "role_r", :selrole).should be_true end it "should use lsetfilecon to set type_t type context" do self.expects(:selinux_support?).returns true Selinux.expects(:lgetfilecon).with("/foo").returns [0, "user_u:role_r:foo:s0"] Selinux.expects(:lsetfilecon).with("/foo", "user_u:role_r:type_t:s0").returns 0 set_selinux_context("/foo", "type_t", :seltype).should be_true end it "should use lsetfilecon to set s0:c3,c5 range context" do self.expects(:selinux_support?).returns true Selinux.expects(:lgetfilecon).with("/foo").returns [0, "user_u:role_r:type_t:s0"] Selinux.expects(:lsetfilecon).with("/foo", "user_u:role_r:type_t:s0:c3,c5").returns 0 set_selinux_context("/foo", "s0:c3,c5", :selrange).should be_true end end describe "set_selinux_default_context" do it "should return nil if there is no SELinux support" do self.expects(:selinux_support?).returns false set_selinux_default_context("/foo").should be_nil end it "should return nil if no default context exists" do self.expects(:get_selinux_default_context).with("/foo").returns nil set_selinux_default_context("/foo").should be_nil end it "should do nothing and return nil if the current context matches the default context" do self.expects(:get_selinux_default_context).with("/foo").returns "user_u:role_r:type_t" self.expects(:get_selinux_current_context).with("/foo").returns "user_u:role_r:type_t" set_selinux_default_context("/foo").should be_nil end it "should set and return the default context if current and default do not match" do self.expects(:get_selinux_default_context).with("/foo").returns "user_u:role_r:type_t" self.expects(:get_selinux_current_context).with("/foo").returns "olduser_u:role_r:type_t" self.expects(:set_selinux_context).with("/foo", "user_u:role_r:type_t").returns true set_selinux_default_context("/foo").should == "user_u:role_r:type_t" end end end diff --git a/spec/unit/util/settings/file_setting_spec.rb b/spec/unit/util/settings/file_setting_spec.rb index 3d3a3ca0c..734b41f3a 100755 --- a/spec/unit/util/settings/file_setting_spec.rb +++ b/spec/unit/util/settings/file_setting_spec.rb @@ -1,254 +1,253 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/util/settings' require 'puppet/util/settings/file_setting' describe Puppet::Util::Settings::FileSetting do FileSetting = Puppet::Util::Settings::FileSetting before do @basepath = Puppet.features.posix? ? "/somepath" : "C:/somepath" end describe "when determining whether the service user should be used" do before do @settings = mock 'settings' @settings.stubs(:[]).with(:mkusers).returns false @settings.stubs(:service_user_available?).returns true end it "should be true if the service user is available" do @settings.expects(:service_user_available?).returns true setting = FileSetting.new(:settings => @settings, :owner => "root", :desc => "a setting") setting.should be_use_service_user end it "should be true if 'mkusers' is set" do @settings.expects(:[]).with(:mkusers).returns true setting = FileSetting.new(:settings => @settings, :owner => "root", :desc => "a setting") setting.should be_use_service_user end it "should be false if the service user is not available and 'mkusers' is unset" do setting = FileSetting.new(:settings => @settings, :owner => "root", :desc => "a setting") setting.should be_use_service_user end end describe "when setting the owner" do it "should allow the file to be owned by root" do root_owner = lambda { FileSetting.new(:settings => mock("settings"), :owner => "root", :desc => "a setting") } root_owner.should_not raise_error end it "should allow the file to be owned by the service user" do service_owner = lambda { FileSetting.new(:settings => mock("settings"), :owner => "service", :desc => "a setting") } service_owner.should_not raise_error end it "should allow the ownership of the file to be unspecified" do no_owner = lambda { FileSetting.new(:settings => mock("settings"), :desc => "a setting") } no_owner.should_not raise_error end it "should not allow other owners" do invalid_owner = lambda { FileSetting.new(:settings => mock("settings"), :owner => "invalid", :desc => "a setting") } invalid_owner.should raise_error(FileSetting::SettingError) end end describe "when reading the owner" do it "should be root when the setting specifies root" do setting = FileSetting.new(:settings => mock("settings"), :owner => "root", :desc => "a setting") setting.owner.should == "root" end it "should be the owner of the service when the setting specifies service and the service user should be used" do settings = mock("settings") settings.stubs(:[]).returns "the_service" setting = FileSetting.new(:settings => settings, :owner => "service", :desc => "a setting") setting.expects(:use_service_user?).returns true setting.owner.should == "the_service" end it "should be the root when the setting specifies service and the service user should not be used" do settings = mock("settings") settings.stubs(:[]).returns "the_service" setting = FileSetting.new(:settings => settings, :owner => "service", :desc => "a setting") setting.expects(:use_service_user?).returns false setting.owner.should == "root" end it "should be nil when the owner is unspecified" do FileSetting.new(:settings => mock("settings"), :desc => "a setting").owner.should be_nil end end describe "when setting the group" do it "should allow the group to be service" do service_group = lambda { FileSetting.new(:settings => mock("settings"), :group => "service", :desc => "a setting") } service_group.should_not raise_error end it "should allow the group to be unspecified" do no_group = lambda { FileSetting.new(:settings => mock("settings"), :desc => "a setting") } no_group.should_not raise_error end it "should not allow invalid groups" do invalid_group = lambda { FileSetting.new(:settings => mock("settings"), :group => "invalid", :desc => "a setting") } invalid_group.should raise_error(FileSetting::SettingError) end end describe "when reading the group" do it "should be service when the setting specifies service" do setting = FileSetting.new(:settings => mock("settings", :[] => "the_service"), :group => "service", :desc => "a setting") setting.group.should == "the_service" end it "should be nil when the group is unspecified" do FileSetting.new(:settings => mock("settings"), :desc => "a setting").group.should be_nil end end it "should be able to be converted into a resource" do FileSetting.new(:settings => mock("settings"), :desc => "eh").should respond_to(:to_resource) end describe "when being converted to a resource" do before do @settings = mock 'settings' @file = Puppet::Util::Settings::FileSetting.new(:settings => @settings, :desc => "eh", :name => :mydir, :section => "mysect") @settings.stubs(:value).with(:mydir).returns @basepath end it "should skip files that cannot determine their types" do @file.expects(:type).returns nil @file.to_resource.should be_nil end it "should skip non-existent files if 'create_files' is not enabled" do @file.expects(:create_files?).returns false @file.expects(:type).returns :file File.expects(:exist?).with(@basepath).returns false @file.to_resource.should be_nil end it "should manage existent files even if 'create_files' is not enabled" do @file.expects(:create_files?).returns false @file.expects(:type).returns :file File.expects(:exist?).with(@basepath).returns true @file.to_resource.should be_instance_of(Puppet::Resource) end describe "on POSIX systems", :if => Puppet.features.posix? do it "should skip files in /dev" do @settings.stubs(:value).with(:mydir).returns "/dev/file" @file.to_resource.should be_nil end end it "should skip files whose paths are not strings" do @settings.stubs(:value).with(:mydir).returns :foo @file.to_resource.should be_nil end it "should return a file resource with the path set appropriately" do resource = @file.to_resource resource.type.should == "File" resource.title.should == @basepath end it "should fully qualified returned files if necessary (#795)" do @settings.stubs(:value).with(:mydir).returns "myfile" @file.to_resource.title.should == File.join(Dir.getwd, "myfile") end it "should set the mode on the file if a mode is provided" do @file.mode = 0755 @file.to_resource[:mode].should == 0755 end it "should not set the mode on a the file if manage_internal_file_permissions is disabled" do Puppet[:manage_internal_file_permissions] = false @file.stubs(:mode).returns(0755) @file.to_resource[:mode].should == nil end it "should set the owner if running as root and the owner is provided" do Puppet.features.expects(:root?).returns true @file.stubs(:owner).returns "foo" @file.to_resource[:owner].should == "foo" end it "should not set the owner if manage_internal_file_permissions is disabled" do Puppet[:manage_internal_file_permissions] = false Puppet.features.stubs(:root?).returns true @file.stubs(:owner).returns "foo" @file.to_resource[:owner].should == nil end it "should set the group if running as root and the group is provided" do Puppet.features.expects(:root?).returns true @file.stubs(:group).returns "foo" @file.to_resource[:group].should == "foo" end it "should not set the group if manage_internal_file_permissions is disabled" do Puppet[:manage_internal_file_permissions] = false Puppet.features.stubs(:root?).returns true @file.stubs(:group).returns "foo" @file.to_resource[:group].should == nil end it "should not set owner if not running as root" do Puppet.features.expects(:root?).returns false @file.stubs(:owner).returns "foo" @file.to_resource[:owner].should be_nil end it "should not set group if not running as root" do Puppet.features.expects(:root?).returns false @file.stubs(:group).returns "foo" @file.to_resource[:group].should be_nil end it "should set :ensure to the file type" do @file.expects(:type).returns :directory @file.to_resource[:ensure].should == :directory end it "should set the loglevel to :debug" do @file.to_resource[:loglevel].should == :debug end it "should set the backup to false" do @file.to_resource[:backup].should be_false end it "should tag the resource with the settings section" do @file.expects(:section).returns "mysect" @file.to_resource.should be_tagged("mysect") end it "should tag the resource with the setting name" do @file.to_resource.should be_tagged("mydir") end it "should tag the resource with 'settings'" do @file.to_resource.should be_tagged("settings") end end end diff --git a/spec/unit/util/settings_spec.rb b/spec/unit/util/settings_spec.rb index a26cf86b8..aa50c8f3a 100755 --- a/spec/unit/util/settings_spec.rb +++ b/spec/unit/util/settings_spec.rb @@ -1,1108 +1,1107 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe Puppet::Util::Settings do describe "when specifying defaults" do before do @settings = Puppet::Util::Settings.new end it "should start with no defined parameters" do @settings.params.length.should == 0 end it "should allow specification of default values associated with a section as an array" do @settings.setdefaults(:section, :myvalue => ["defaultval", "my description"]) end it "should not allow duplicate parameter specifications" do @settings.setdefaults(:section, :myvalue => ["a", "b"]) lambda { @settings.setdefaults(:section, :myvalue => ["c", "d"]) }.should raise_error(ArgumentError) end it "should allow specification of default values associated with a section as a hash" do @settings.setdefaults(:section, :myvalue => {:default => "defaultval", :desc => "my description"}) end it "should consider defined parameters to be valid" do @settings.setdefaults(:section, :myvalue => ["defaultval", "my description"]) @settings.valid?(:myvalue).should be_true end it "should require a description when defaults are specified with an array" do lambda { @settings.setdefaults(:section, :myvalue => ["a value"]) }.should raise_error(ArgumentError) end it "should require a description when defaults are specified with a hash" do lambda { @settings.setdefaults(:section, :myvalue => {:default => "a value"}) }.should raise_error(ArgumentError) end it "should raise an error if we can't guess the type" do lambda { @settings.setdefaults(:section, :myvalue => {:default => Object.new, :desc => "An impossible object"}) }.should raise_error(ArgumentError) end it "should support specifying owner, group, and mode when specifying files" do @settings.setdefaults(:section, :myvalue => {:default => "/some/file", :owner => "service", :mode => "boo", :group => "service", :desc => "whatever"}) end it "should support specifying a short name" do @settings.setdefaults(:section, :myvalue => {:default => "w", :desc => "b", :short => "m"}) end it "should support specifying the setting type" do @settings.setdefaults(:section, :myvalue => {:default => "/w", :desc => "b", :type => :setting}) @settings.setting(:myvalue).should be_instance_of(Puppet::Util::Settings::Setting) end it "should fail if an invalid setting type is specified" do lambda { @settings.setdefaults(:section, :myvalue => {:default => "w", :desc => "b", :type => :foo}) }.should raise_error(ArgumentError) end it "should fail when short names conflict" do @settings.setdefaults(:section, :myvalue => {:default => "w", :desc => "b", :short => "m"}) lambda { @settings.setdefaults(:section, :myvalue => {:default => "w", :desc => "b", :short => "m"}) }.should raise_error(ArgumentError) end end describe "when setting values" do before do @settings = Puppet::Util::Settings.new @settings.setdefaults :main, :myval => ["val", "desc"] @settings.setdefaults :main, :bool => [true, "desc"] end it "should provide a method for setting values from other objects" do @settings[:myval] = "something else" @settings[:myval].should == "something else" end it "should support a getopt-specific mechanism for setting values" do @settings.handlearg("--myval", "newval") @settings[:myval].should == "newval" end it "should support a getopt-specific mechanism for turning booleans off" do @settings[:bool] = true @settings.handlearg("--no-bool", "") @settings[:bool].should == false end it "should support a getopt-specific mechanism for turning booleans on" do # Turn it off first @settings[:bool] = false @settings.handlearg("--bool", "") @settings[:bool].should == true end it "should consider a cli setting with no argument to be a boolean" do # Turn it off first @settings[:bool] = false @settings.handlearg("--bool") @settings[:bool].should == true end it "should consider a cli setting with an empty string as an argument to be a boolean, if the setting itself is a boolean" do # Turn it off first @settings[:bool] = false @settings.handlearg("--bool", "") @settings[:bool].should == true end it "should consider a cli setting with an empty string as an argument to be an empty argument, if the setting itself is not a boolean" do @settings[:myval] = "bob" @settings.handlearg("--myval", "") @settings[:myval].should == "" end it "should consider a cli setting with a boolean as an argument to be a boolean" do # Turn it off first @settings[:bool] = false @settings.handlearg("--bool", "true") @settings[:bool].should == true end it "should not consider a cli setting of a non boolean with a boolean as an argument to be a boolean" do # Turn it off first @settings[:myval] = "bob" @settings.handlearg("--no-myval", "") @settings[:myval].should == "" end it "should clear the cache when setting getopt-specific values" do @settings.setdefaults :mysection, :one => ["whah", "yay"], :two => ["$one yay", "bah"] @settings[:two].should == "whah yay" @settings.handlearg("--one", "else") @settings[:two].should == "else yay" end it "should not clear other values when setting getopt-specific values" do @settings[:myval] = "yay" @settings.handlearg("--no-bool", "") @settings[:myval].should == "yay" end it "should clear the list of used sections" do @settings.expects(:clearused) @settings[:myval] = "yay" end it "should call passed blocks when values are set" do values = [] @settings.setdefaults(:section, :hooker => {:default => "yay", :desc => "boo", :hook => lambda { |v| values << v }}) values.should == [] @settings[:hooker] = "something" values.should == %w{something} end it "should call passed blocks when values are set via the command line" do values = [] @settings.setdefaults(:section, :hooker => {:default => "yay", :desc => "boo", :hook => lambda { |v| values << v }}) values.should == [] @settings.handlearg("--hooker", "yay") values.should == %w{yay} end it "should provide an option to call passed blocks during definition" do values = [] @settings.setdefaults(:section, :hooker => {:default => "yay", :desc => "boo", :call_on_define => true, :hook => lambda { |v| values << v }}) values.should == %w{yay} end it "should pass the fully interpolated value to the hook when called on definition" do values = [] @settings.setdefaults(:section, :one => ["test", "a"]) @settings.setdefaults(:section, :hooker => {:default => "$one/yay", :desc => "boo", :call_on_define => true, :hook => lambda { |v| values << v }}) values.should == %w{test/yay} end it "should munge values using the setting-specific methods" do @settings[:bool] = "false" @settings[:bool].should == false end it "should prefer cli values to values set in Ruby code" do @settings.handlearg("--myval", "cliarg") @settings[:myval] = "memarg" @settings[:myval].should == "cliarg" end it "should clear the list of environments" do Puppet::Node::Environment.expects(:clear).at_least(1) @settings[:myval] = "memarg" end it "should raise an error if we try to set 'name'" do lambda{ @settings[:name] = "foo" }.should raise_error(ArgumentError) end it "should raise an error if we try to set 'run_mode'" do lambda{ @settings[:run_mode] = "foo" }.should raise_error(ArgumentError) end it "should warn and use [master] if we ask for [puppetmasterd]" do Puppet.expects(:warning) @settings.set_value(:myval, "foo", :puppetmasterd) @settings.stubs(:run_mode).returns(:master) @settings.value(:myval).should == "foo" end it "should warn and use [agent] if we ask for [puppetd]" do Puppet.expects(:warning) @settings.set_value(:myval, "foo", :puppetd) @settings.stubs(:run_mode).returns(:agent) @settings.value(:myval).should == "foo" end end describe "when returning values" do before do @settings = Puppet::Util::Settings.new @settings.setdefaults :section, :config => ["/my/file", "eh"], :one => ["ONE", "a"], :two => ["$one TWO", "b"], :three => ["$one $two THREE", "c"], :four => ["$two $three FOUR", "d"] FileTest.stubs(:exist?).returns true end it "should provide a mechanism for returning set values" do @settings[:one] = "other" @settings[:one].should == "other" end it "should interpolate default values for other parameters into returned parameter values" do @settings[:one].should == "ONE" @settings[:two].should == "ONE TWO" @settings[:three].should == "ONE ONE TWO THREE" end it "should interpolate default values that themselves need to be interpolated" do @settings[:four].should == "ONE TWO ONE ONE TWO THREE FOUR" end it "should provide a method for returning uninterpolated values" do @settings[:two] = "$one tw0" @settings.uninterpolated_value(:two).should == "$one tw0" @settings.uninterpolated_value(:four).should == "$two $three FOUR" end it "should interpolate set values for other parameters into returned parameter values" do @settings[:one] = "on3" @settings[:two] = "$one tw0" @settings[:three] = "$one $two thr33" @settings[:four] = "$one $two $three f0ur" @settings[:one].should == "on3" @settings[:two].should == "on3 tw0" @settings[:three].should == "on3 on3 tw0 thr33" @settings[:four].should == "on3 on3 tw0 on3 on3 tw0 thr33 f0ur" end it "should not cache interpolated values such that stale information is returned" do @settings[:two].should == "ONE TWO" @settings[:one] = "one" @settings[:two].should == "one TWO" end it "should not cache values such that information from one environment is returned for another environment" do text = "[env1]\none = oneval\n[env2]\none = twoval\n" @settings.stubs(:read_file).returns(text) @settings.parse @settings.value(:one, "env1").should == "oneval" @settings.value(:one, "env2").should == "twoval" end it "should have a run_mode that defaults to user" do @settings.run_mode.should == :user end end describe "when choosing which value to return" do before do @settings = Puppet::Util::Settings.new @settings.setdefaults :section, :config => ["/my/file", "a"], :one => ["ONE", "a"], :two => ["TWO", "b"] FileTest.stubs(:exist?).returns true Puppet.stubs(:run_mode).returns stub('run_mode', :name => :mymode) end it "should return default values if no values have been set" do @settings[:one].should == "ONE" end it "should return values set on the cli before values set in the configuration file" do text = "[main]\none = fileval\n" @settings.stubs(:read_file).returns(text) @settings.handlearg("--one", "clival") @settings.parse @settings[:one].should == "clival" end it "should return values set on the cli before values set in Ruby" do @settings[:one] = "rubyval" @settings.handlearg("--one", "clival") @settings[:one].should == "clival" end it "should return values set in the mode-specific section before values set in the main section" do text = "[main]\none = mainval\n[mymode]\none = modeval\n" @settings.stubs(:read_file).returns(text) @settings.parse @settings[:one].should == "modeval" end it "should not return values outside of its search path" do text = "[other]\none = oval\n" file = "/some/file" @settings.stubs(:read_file).returns(text) @settings.parse @settings[:one].should == "ONE" end it "should return values in a specified environment" do text = "[env]\none = envval\n" @settings.stubs(:read_file).returns(text) @settings.parse @settings.value(:one, "env").should == "envval" end it 'should use the current environment for $environment' do @settings.setdefaults :main, :myval => ["$environment/foo", "mydocs"] @settings.value(:myval, "myenv").should == "myenv/foo" end it "should interpolate found values using the current environment" do text = "[main]\none = mainval\n[myname]\none = nameval\ntwo = $one/two\n" @settings.stubs(:read_file).returns(text) @settings.parse @settings.value(:two, "myname").should == "nameval/two" end it "should return values in a specified environment before values in the main or name sections" do text = "[env]\none = envval\n[main]\none = mainval\n[myname]\none = nameval\n" @settings.stubs(:read_file).returns(text) @settings.parse @settings.value(:one, "env").should == "envval" end end describe "when parsing its configuration" do before do @settings = Puppet::Util::Settings.new @settings.stubs(:service_user_available?).returns true @file = "/some/file" @settings.setdefaults :section, :user => ["suser", "doc"], :group => ["sgroup", "doc"] @settings.setdefaults :section, :config => ["/some/file", "eh"], :one => ["ONE", "a"], :two => ["$one TWO", "b"], :three => ["$one $two THREE", "c"] FileTest.stubs(:exist?).returns true end it "should not ignore the report setting" do @settings.setdefaults :section, :report => ["false", "a"] myfile = stub "myfile" @settings[:config] = myfile text = <<-CONF [puppetd] report=true CONF @settings.expects(:read_file).returns(text) @settings.parse @settings[:report].should be_true end it "should use its current ':config' value for the file to parse" do myfile = Puppet.features.posix? ? "/my/file" : "C:/myfile" # do not stub expand_path here, as this leads to a stack overflow, when mocha tries to use it @settings[:config] = myfile File.expects(:read).with(myfile).returns "[main]" @settings.parse end it "should fail if no configuration setting is defined" do @settings = Puppet::Util::Settings.new lambda { @settings.parse }.should raise_error(RuntimeError) end it "should not try to parse non-existent files" do FileTest.expects(:exist?).with("/some/file").returns false File.expects(:read).with("/some/file").never @settings.parse end it "should set a timer that triggers reparsing, even if the file does not exist" do FileTest.expects(:exist?).returns false @settings.expects(:set_filetimeout_timer) @settings.parse end it "should return values set in the configuration file" do text = "[main] one = fileval " @settings.expects(:read_file).returns(text) @settings.parse @settings[:one].should == "fileval" end #484 - this should probably be in the regression area it "should not throw an exception on unknown parameters" do text = "[main]\nnosuchparam = mval\n" @settings.expects(:read_file).returns(text) lambda { @settings.parse }.should_not raise_error end it "should convert booleans in the configuration file into Ruby booleans" do text = "[main] one = true two = false " @settings.expects(:read_file).returns(text) @settings.parse @settings[:one].should == true @settings[:two].should == false end it "should convert integers in the configuration file into Ruby Integers" do text = "[main] one = 65 " @settings.expects(:read_file).returns(text) @settings.parse @settings[:one].should == 65 end it "should support specifying all metadata (owner, group, mode) in the configuration file" do @settings.setdefaults :section, :myfile => ["/myfile", "a"] text = "[main] myfile = /other/file {owner = service, group = service, mode = 644} " @settings.expects(:read_file).returns(text) @settings.parse @settings[:myfile].should == "/other/file" @settings.metadata(:myfile).should == {:owner => "suser", :group => "sgroup", :mode => "644"} end it "should support specifying a single piece of metadata (owner, group, or mode) in the configuration file" do @settings.setdefaults :section, :myfile => ["/myfile", "a"] text = "[main] myfile = /other/file {owner = service} " file = "/some/file" @settings.expects(:read_file).returns(text) @settings.parse @settings[:myfile].should == "/other/file" @settings.metadata(:myfile).should == {:owner => "suser"} end it "should call hooks associated with values set in the configuration file" do values = [] @settings.setdefaults :section, :mysetting => {:default => "defval", :desc => "a", :hook => proc { |v| values << v }} text = "[main] mysetting = setval " @settings.expects(:read_file).returns(text) @settings.parse values.should == ["setval"] end it "should not call the same hook for values set multiple times in the configuration file" do values = [] @settings.setdefaults :section, :mysetting => {:default => "defval", :desc => "a", :hook => proc { |v| values << v }} text = "[user] mysetting = setval [main] mysetting = other " @settings.expects(:read_file).returns(text) @settings.parse values.should == ["setval"] end it "should pass the environment-specific value to the hook when one is available" do values = [] @settings.setdefaults :section, :mysetting => {:default => "defval", :desc => "a", :hook => proc { |v| values << v }} @settings.setdefaults :section, :environment => ["yay", "a"] @settings.setdefaults :section, :environments => ["yay,foo", "a"] text = "[main] mysetting = setval [yay] mysetting = other " @settings.expects(:read_file).returns(text) @settings.parse values.should == ["other"] end it "should pass the interpolated value to the hook when one is available" do values = [] @settings.setdefaults :section, :base => {:default => "yay", :desc => "a", :hook => proc { |v| values << v }} @settings.setdefaults :section, :mysetting => {:default => "defval", :desc => "a", :hook => proc { |v| values << v }} text = "[main] mysetting = $base/setval " @settings.expects(:read_file).returns(text) @settings.parse values.should == ["yay/setval"] end it "should allow empty values" do @settings.setdefaults :section, :myarg => ["myfile", "a"] text = "[main] myarg = " @settings.stubs(:read_file).returns(text) @settings.parse @settings[:myarg].should == "" end describe "and when reading a non-positive filetimeout value from the config file" do before do @settings.setdefaults :foo, :filetimeout => [5, "eh"] somefile = "/some/file" text = "[main] filetimeout = -1 " File.expects(:read).with(somefile).returns(text) File.expects(:expand_path).with(somefile).returns somefile @settings[:config] = somefile end it "should not set a timer" do EventLoop::Timer.expects(:new).never @settings.parse end end end describe "when reparsing its configuration" do before do @settings = Puppet::Util::Settings.new @settings.setdefaults :section, :config => ["/test/file", "a"], :one => ["ONE", "a"], :two => ["$one TWO", "b"], :three => ["$one $two THREE", "c"] FileTest.stubs(:exist?).returns true end it "should use a LoadedFile instance to determine if the file has changed" do file = mock 'file' Puppet::Util::LoadedFile.expects(:new).with("/test/file").returns file file.expects(:changed?) @settings.stubs(:parse) @settings.reparse end it "should not create the LoadedFile instance and should not parse if the file does not exist" do FileTest.expects(:exist?).with("/test/file").returns false Puppet::Util::LoadedFile.expects(:new).never @settings.expects(:parse).never @settings.reparse end it "should not reparse if the file has not changed" do file = mock 'file' Puppet::Util::LoadedFile.expects(:new).with("/test/file").returns file file.expects(:changed?).returns false @settings.expects(:parse).never @settings.reparse end it "should reparse if the file has changed" do file = stub 'file', :file => "/test/file" Puppet::Util::LoadedFile.expects(:new).with("/test/file").returns file file.expects(:changed?).returns true @settings.expects(:parse) @settings.reparse end it "should use a cached LoadedFile instance" do first = mock 'first' second = mock 'second' Puppet::Util::LoadedFile.expects(:new).times(2).with("/test/file").returns(first).then.returns(second) @settings.file.should equal(first) Puppet::Util::Cacher.expire @settings.file.should equal(second) end it "should replace in-memory values with on-file values" do # Init the value text = "[main]\none = disk-init\n" file = mock 'file' file.stubs(:changed?).returns(true) file.stubs(:file).returns("/test/file") @settings[:one] = "init" @settings.file = file # Now replace the value text = "[main]\none = disk-replace\n" # This is kinda ridiculous - the reason it parses twice is that # it goes to parse again when we ask for the value, because the # mock always says it should get reparsed. @settings.stubs(:read_file).returns(text) @settings.reparse @settings[:one].should == "disk-replace" end it "should retain parameters set by cli when configuration files are reparsed" do @settings.handlearg("--one", "clival") text = "[main]\none = on-disk\n" @settings.stubs(:read_file).returns(text) @settings.parse @settings[:one].should == "clival" end it "should remove in-memory values that are no longer set in the file" do # Init the value text = "[main]\none = disk-init\n" @settings.expects(:read_file).returns(text) @settings.parse @settings[:one].should == "disk-init" # Now replace the value text = "[main]\ntwo = disk-replace\n" @settings.expects(:read_file).returns(text) @settings.parse #@settings.reparse # The originally-overridden value should be replaced with the default @settings[:one].should == "ONE" # and we should now have the new value in memory @settings[:two].should == "disk-replace" end it "should retain in-memory values if the file has a syntax error" do # Init the value text = "[main]\none = initial-value\n" @settings.expects(:read_file).returns(text) @settings.parse @settings[:one].should == "initial-value" # Now replace the value with something bogus text = "[main]\nkenny = killed-by-what-follows\n1 is 2, blah blah florp\n" @settings.expects(:read_file).returns(text) @settings.parse # The originally-overridden value should not be replaced with the default @settings[:one].should == "initial-value" # and we should not have the new value in memory @settings[:kenny].should be_nil end end it "should provide a method for creating a catalog of resources from its configuration" do Puppet::Util::Settings.new.should respond_to(:to_catalog) end describe "when creating a catalog" do before do @settings = Puppet::Util::Settings.new @settings.stubs(:service_user_available?).returns true @prefix = Puppet.features.posix? ? "" : "C:" end it "should add all file resources to the catalog if no sections have been specified" do @settings.setdefaults :main, :maindir => [@prefix+"/maindir", "a"], :seconddir => [@prefix+"/seconddir", "a"] @settings.setdefaults :other, :otherdir => [@prefix+"/otherdir", "a"] catalog = @settings.to_catalog [@prefix+"/maindir", @prefix+"/seconddir", @prefix+"/otherdir"].each do |path| catalog.resource(:file, path).should be_instance_of(Puppet::Resource) end end it "should add only files in the specified sections if section names are provided" do @settings.setdefaults :main, :maindir => [@prefix+"/maindir", "a"] @settings.setdefaults :other, :otherdir => [@prefix+"/otherdir", "a"] catalog = @settings.to_catalog(:main) catalog.resource(:file, @prefix+"/otherdir").should be_nil catalog.resource(:file, @prefix+"/maindir").should be_instance_of(Puppet::Resource) end it "should not try to add the same file twice" do @settings.setdefaults :main, :maindir => [@prefix+"/maindir", "a"] @settings.setdefaults :other, :otherdir => [@prefix+"/maindir", "a"] lambda { @settings.to_catalog }.should_not raise_error end it "should ignore files whose :to_resource method returns nil" do @settings.setdefaults :main, :maindir => [@prefix+"/maindir", "a"] @settings.setting(:maindir).expects(:to_resource).returns nil Puppet::Resource::Catalog.any_instance.expects(:add_resource).never @settings.to_catalog end describe "when adding users and groups to the catalog" do before do Puppet.features.stubs(:root?).returns true @settings.setdefaults :foo, :mkusers => [true, "e"], :user => ["suser", "doc"], :group => ["sgroup", "doc"] @settings.setdefaults :other, :otherdir => {:default => "/otherdir", :desc => "a", :owner => "service", :group => "service"} @catalog = @settings.to_catalog end it "should add each specified user and group to the catalog if :mkusers is a valid setting, is enabled, and we're running as root" do @catalog.resource(:user, "suser").should be_instance_of(Puppet::Resource) @catalog.resource(:group, "sgroup").should be_instance_of(Puppet::Resource) end it "should only add users and groups to the catalog from specified sections" do @settings.setdefaults :yay, :yaydir => {:default => "/yaydir", :desc => "a", :owner => "service", :group => "service"} catalog = @settings.to_catalog(:other) catalog.resource(:user, "jane").should be_nil catalog.resource(:group, "billy").should be_nil end it "should not add users or groups to the catalog if :mkusers not running as root" do Puppet.features.stubs(:root?).returns false catalog = @settings.to_catalog catalog.resource(:user, "suser").should be_nil catalog.resource(:group, "sgroup").should be_nil end it "should not add users or groups to the catalog if :mkusers is not a valid setting" do Puppet.features.stubs(:root?).returns true settings = Puppet::Util::Settings.new settings.setdefaults :other, :otherdir => {:default => "/otherdir", :desc => "a", :owner => "service", :group => "service"} catalog = settings.to_catalog catalog.resource(:user, "suser").should be_nil catalog.resource(:group, "sgroup").should be_nil end it "should not add users or groups to the catalog if :mkusers is a valid setting but is disabled" do @settings[:mkusers] = false catalog = @settings.to_catalog catalog.resource(:user, "suser").should be_nil catalog.resource(:group, "sgroup").should be_nil end it "should not try to add users or groups to the catalog twice" do @settings.setdefaults :yay, :yaydir => {:default => "/yaydir", :desc => "a", :owner => "service", :group => "service"} # This would fail if users/groups were added twice lambda { @settings.to_catalog }.should_not raise_error end it "should set :ensure to :present on each created user and group" do @catalog.resource(:user, "suser")[:ensure].should == :present @catalog.resource(:group, "sgroup")[:ensure].should == :present end it "should set each created user's :gid to the service group" do @settings.to_catalog.resource(:user, "suser")[:gid].should == "sgroup" end it "should not attempt to manage the root user" do Puppet.features.stubs(:root?).returns true @settings.setdefaults :foo, :foodir => {:default => "/foodir", :desc => "a", :owner => "root", :group => "service"} @settings.to_catalog.resource(:user, "root").should be_nil end end end it "should be able to be converted to a manifest" do Puppet::Util::Settings.new.should respond_to(:to_manifest) end describe "when being converted to a manifest" do it "should produce a string with the code for each resource joined by two carriage returns" do @settings = Puppet::Util::Settings.new @settings.setdefaults :main, :maindir => ["/maindir", "a"], :seconddir => ["/seconddir", "a"] main = stub 'main_resource', :ref => "File[/maindir]" main.expects(:to_manifest).returns "maindir" second = stub 'second_resource', :ref => "File[/seconddir]" second.expects(:to_manifest).returns "seconddir" @settings.setting(:maindir).expects(:to_resource).returns main @settings.setting(:seconddir).expects(:to_resource).returns second @settings.to_manifest.split("\n\n").sort.should == %w{maindir seconddir} end end describe "when using sections of the configuration to manage the local host" do before do @settings = Puppet::Util::Settings.new @settings.stubs(:service_user_available?).returns true @settings.setdefaults :main, :noop => [false, ""] @settings.setdefaults :main, :maindir => ["/maindir", "a"], :seconddir => ["/seconddir", "a"] @settings.setdefaults :main, :user => ["suser", "doc"], :group => ["sgroup", "doc"] @settings.setdefaults :other, :otherdir => {:default => "/otherdir", :desc => "a", :owner => "service", :group => "service", :mode => 0755} @settings.setdefaults :third, :thirddir => ["/thirddir", "b"] @settings.setdefaults :files, :myfile => {:default => "/myfile", :desc => "a", :mode => 0755} end it "should provide a method that writes files with the correct modes" do @settings.should respond_to(:write) end it "should provide a method that creates directories with the correct modes" do Puppet::Util::SUIDManager.expects(:asuser).with("suser", "sgroup").yields Dir.expects(:mkdir).with("/otherdir", 0755) @settings.mkdir(:otherdir) end it "should create a catalog with the specified sections" do @settings.expects(:to_catalog).with(:main, :other).returns Puppet::Resource::Catalog.new("foo") @settings.use(:main, :other) end it "should canonicalize the sections" do @settings.expects(:to_catalog).with(:main, :other).returns Puppet::Resource::Catalog.new("foo") @settings.use("main", "other") end it "should ignore sections that have already been used" do @settings.expects(:to_catalog).with(:main).returns Puppet::Resource::Catalog.new("foo") @settings.use(:main) @settings.expects(:to_catalog).with(:other).returns Puppet::Resource::Catalog.new("foo") @settings.use(:main, :other) end it "should ignore tags and schedules when creating files and directories" it "should be able to provide all of its parameters in a format compatible with GetOpt::Long" do pending "Not converted from test/unit yet" end it "should convert the created catalog to a RAL catalog" do @catalog = Puppet::Resource::Catalog.new("foo") @settings.expects(:to_catalog).with(:main).returns @catalog @catalog.expects(:to_ral).returns @catalog @settings.use(:main) end it "should specify that it is not managing a host catalog" do catalog = Puppet::Resource::Catalog.new("foo") catalog.expects(:apply) @settings.expects(:to_catalog).returns catalog catalog.stubs(:to_ral).returns catalog catalog.expects(:host_config=).with false @settings.use(:main) end it "should support a method for re-using all currently used sections" do @settings.expects(:to_catalog).with(:main, :third).times(2).returns Puppet::Resource::Catalog.new("foo") @settings.use(:main, :third) @settings.reuse end it "should fail with an appropriate message if any resources fail" do @catalog = Puppet::Resource::Catalog.new("foo") @catalog.stubs(:to_ral).returns @catalog @settings.expects(:to_catalog).returns @catalog @trans = mock("transaction") @catalog.expects(:apply).yields(@trans) @trans.expects(:any_failed?).returns(true) report = mock 'report' @trans.expects(:report).returns report log = mock 'log', :to_s => "My failure", :level => :err report.expects(:logs).returns [log] @settings.expects(:raise).with { |msg| msg.include?("My failure") } @settings.use(:whatever) end end describe "when dealing with printing configs" do before do @settings = Puppet::Util::Settings.new #these are the magic default values @settings.stubs(:value).with(:configprint).returns("") @settings.stubs(:value).with(:genconfig).returns(false) @settings.stubs(:value).with(:genmanifest).returns(false) @settings.stubs(:value).with(:environment).returns(nil) end describe "when checking print_config?" do it "should return false when the :configprint, :genconfig and :genmanifest are not set" do @settings.print_configs?.should be_false end it "should return true when :configprint has a value" do @settings.stubs(:value).with(:configprint).returns("something") @settings.print_configs?.should be_true end it "should return true when :genconfig has a value" do @settings.stubs(:value).with(:genconfig).returns(true) @settings.print_configs?.should be_true end it "should return true when :genmanifest has a value" do @settings.stubs(:value).with(:genmanifest).returns(true) @settings.print_configs?.should be_true end end describe "when printing configs" do describe "when :configprint has a value" do it "should call print_config_options" do @settings.stubs(:value).with(:configprint).returns("something") @settings.expects(:print_config_options) @settings.print_configs end it "should get the value of the option using the environment" do @settings.stubs(:value).with(:configprint).returns("something") @settings.stubs(:include?).with("something").returns(true) @settings.expects(:value).with(:environment).returns("env") @settings.expects(:value).with("something", "env").returns("foo") @settings.stubs(:puts).with("foo") @settings.print_configs end it "should print the value of the option" do @settings.stubs(:value).with(:configprint).returns("something") @settings.stubs(:include?).with("something").returns(true) @settings.stubs(:value).with("something", nil).returns("foo") @settings.expects(:puts).with("foo") @settings.print_configs end it "should print the value pairs if there are multiple options" do @settings.stubs(:value).with(:configprint).returns("bar,baz") @settings.stubs(:include?).with("bar").returns(true) @settings.stubs(:include?).with("baz").returns(true) @settings.stubs(:value).with("bar", nil).returns("foo") @settings.stubs(:value).with("baz", nil).returns("fud") @settings.expects(:puts).with("bar = foo") @settings.expects(:puts).with("baz = fud") @settings.print_configs end it "should print a whole bunch of stuff if :configprint = all" it "should return true after printing" do @settings.stubs(:value).with(:configprint).returns("something") @settings.stubs(:include?).with("something").returns(true) @settings.stubs(:value).with("something", nil).returns("foo") @settings.stubs(:puts).with("foo") @settings.print_configs.should be_true end it "should return false if a config param is not found" do @settings.stubs :puts @settings.stubs(:value).with(:configprint).returns("something") @settings.stubs(:include?).with("something").returns(false) @settings.print_configs.should be_false end end describe "when genconfig is true" do before do @settings.stubs :puts end it "should call to_config" do @settings.stubs(:value).with(:genconfig).returns(true) @settings.expects(:to_config) @settings.print_configs end it "should return true from print_configs" do @settings.stubs(:value).with(:genconfig).returns(true) @settings.stubs(:to_config) @settings.print_configs.should be_true end end describe "when genmanifest is true" do before do @settings.stubs :puts end it "should call to_config" do @settings.stubs(:value).with(:genmanifest).returns(true) @settings.expects(:to_manifest) @settings.print_configs end it "should return true from print_configs" do @settings.stubs(:value).with(:genmanifest).returns(true) @settings.stubs(:to_manifest) @settings.print_configs.should be_true end end end end describe "when setting a timer to trigger configuration file reparsing" do before do @settings = Puppet::Util::Settings.new @settings.setdefaults :foo, :filetimeout => [5, "eh"] end it "should do nothing if no filetimeout setting is available" do @settings.expects(:value).with(:filetimeout).returns nil EventLoop::Timer.expects(:new).never @settings.set_filetimeout_timer end it "should always convert the timer interval to an integer" do @settings.expects(:value).with(:filetimeout).returns "10" EventLoop::Timer.expects(:new).with(:interval => 10, :start? => true, :tolerance => 1) @settings.set_filetimeout_timer end it "should do nothing if the filetimeout setting is not greater than 0" do @settings.expects(:value).with(:filetimeout).returns -2 EventLoop::Timer.expects(:new).never @settings.set_filetimeout_timer end it "should create a timer with its interval set to the filetimeout, start? set to true, and a tolerance of 1" do @settings.expects(:value).with(:filetimeout).returns 5 EventLoop::Timer.expects(:new).with(:interval => 5, :start? => true, :tolerance => 1) @settings.set_filetimeout_timer end it "should reparse when the timer goes off" do EventLoop::Timer.expects(:new).with(:interval => 5, :start? => true, :tolerance => 1).yields @settings.expects(:reparse) @settings.set_filetimeout_timer end end describe "when determining if the service user is available" do it "should return false if there is no user setting" do Puppet::Util::Settings.new.should_not be_service_user_available end it "should return false if the user provider says the user is missing" do settings = Puppet::Util::Settings.new settings.setdefaults :main, :user => ["foo", "doc"] user = mock 'user' user.expects(:exists?).returns false Puppet::Type.type(:user).expects(:new).with { |args| args[:name] == "foo" }.returns user settings.should_not be_service_user_available end it "should return true if the user provider says the user is present" do settings = Puppet::Util::Settings.new settings.setdefaults :main, :user => ["foo", "doc"] user = mock 'user' user.expects(:exists?).returns true Puppet::Type.type(:user).expects(:new).with { |args| args[:name] == "foo" }.returns user settings.should be_service_user_available end it "should cache the result" end end diff --git a/spec/unit/util/storage_spec.rb b/spec/unit/util/storage_spec.rb index 85d6596e4..90c11aa69 100755 --- a/spec/unit/util/storage_spec.rb +++ b/spec/unit/util/storage_spec.rb @@ -1,234 +1,233 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'yaml' require 'puppet/util/storage' describe Puppet::Util::Storage do include PuppetSpec::Files before(:all) do @basepath = Puppet.features.posix? ? "/somepath" : "C:/somepath" Puppet[:statedir] = tmpdir("statedir") end after(:all) do Puppet.settings.clear end before(:each) do Puppet::Util::Storage.clear end describe "when caching a symbol" do it "should return an empty hash" do Puppet::Util::Storage.cache(:yayness).should == {} Puppet::Util::Storage.cache(:more_yayness).should == {} end it "should add the symbol to its internal state" do Puppet::Util::Storage.cache(:yayness) Puppet::Util::Storage.state.should == {:yayness=>{}} end it "should not clobber existing state when caching additional objects" do Puppet::Util::Storage.cache(:yayness) Puppet::Util::Storage.state.should == {:yayness=>{}} Puppet::Util::Storage.cache(:bubblyness) Puppet::Util::Storage.state.should == {:yayness=>{},:bubblyness=>{}} end end describe "when caching a Puppet::Type" do before(:all) do @file_test = Puppet::Type.type(:file).new(:name => @basepath+"/yayness", :check => %w{checksum type}) @exec_test = Puppet::Type.type(:exec).new(:name => @basepath+"/bin/ls /yayness") end it "should return an empty hash" do Puppet::Util::Storage.cache(@file_test).should == {} Puppet::Util::Storage.cache(@exec_test).should == {} end it "should add the resource ref to its internal state" do Puppet::Util::Storage.state.should == {} Puppet::Util::Storage.cache(@file_test) Puppet::Util::Storage.state.should == {"File[#{@basepath}/yayness]"=>{}} Puppet::Util::Storage.cache(@exec_test) Puppet::Util::Storage.state.should == {"File[#{@basepath}/yayness]"=>{}, "Exec[#{@basepath}/bin/ls /yayness]"=>{}} end end describe "when caching something other than a resource or symbol" do it "should cache by converting to a string" do data = Puppet::Util::Storage.cache(42) data[:yay] = true Puppet::Util::Storage.cache("42")[:yay].should be_true end end it "should clear its internal state when clear() is called" do Puppet::Util::Storage.cache(:yayness) Puppet::Util::Storage.state.should == {:yayness=>{}} Puppet::Util::Storage.clear Puppet::Util::Storage.state.should == {} end describe "when loading from the state file" do before do Puppet.settings.stubs(:use).returns(true) end describe "when the state file/directory does not exist" do before(:each) do transient = Tempfile.new('storage_test') @path = transient.path() transient.close!() end it "should not fail to load()" do FileTest.exists?(@path).should be_false Puppet[:statedir] = @path proc { Puppet::Util::Storage.load }.should_not raise_error Puppet[:statefile] = @path proc { Puppet::Util::Storage.load }.should_not raise_error end it "should not lose its internal state when load() is called" do FileTest.exists?(@path).should be_false Puppet::Util::Storage.cache(:yayness) Puppet::Util::Storage.state.should == {:yayness=>{}} Puppet[:statefile] = @path proc { Puppet::Util::Storage.load }.should_not raise_error Puppet::Util::Storage.state.should == {:yayness=>{}} end end describe "when the state file/directory exists" do before(:each) do @state_file = Tempfile.new('storage_test') @saved_statefile = Puppet[:statefile] Puppet[:statefile] = @state_file.path end it "should overwrite its internal state if load() is called" do # Should the state be overwritten even if Puppet[:statefile] is not valid YAML? Puppet::Util::Storage.cache(:yayness) Puppet::Util::Storage.state.should == {:yayness=>{}} proc { Puppet::Util::Storage.load }.should_not raise_error Puppet::Util::Storage.state.should == {} end it "should restore its internal state if the state file contains valid YAML" do test_yaml = {'File["/yayness"]'=>{"name"=>{:a=>:b,:c=>:d}}} YAML.expects(:load).returns(test_yaml) proc { Puppet::Util::Storage.load }.should_not raise_error Puppet::Util::Storage.state.should == test_yaml end it "should initialize with a clear internal state if the state file does not contain valid YAML" do @state_file.write(:booness) @state_file.flush proc { Puppet::Util::Storage.load }.should_not raise_error Puppet::Util::Storage.state.should == {} end it "should raise an error if the state file does not contain valid YAML and cannot be renamed" do @state_file.write(:booness) @state_file.flush YAML.expects(:load).raises(Puppet::Error) File.expects(:rename).raises(SystemCallError) proc { Puppet::Util::Storage.load }.should raise_error end it "should attempt to rename the state file if the file is corrupted" do # We fake corruption by causing YAML.load to raise an exception YAML.expects(:load).raises(Puppet::Error) File.expects(:rename).at_least_once proc { Puppet::Util::Storage.load }.should_not raise_error end it "should fail gracefully on load() if the state file is not a regular file" do @state_file.close!() Dir.mkdir(Puppet[:statefile]) proc { Puppet::Util::Storage.load }.should_not raise_error Dir.rmdir(Puppet[:statefile]) end it "should fail gracefully on load() if it cannot get a read lock on the state file" do Puppet::Util::FileLocking.expects(:readlock).yields(false) test_yaml = {'File["/yayness"]'=>{"name"=>{:a=>:b,:c=>:d}}} YAML.expects(:load).returns(test_yaml) proc { Puppet::Util::Storage.load }.should_not raise_error Puppet::Util::Storage.state.should == test_yaml end after(:each) do @state_file.close!() Puppet[:statefile] = @saved_statefile end end end describe "when storing to the state file" do before(:each) do @state_file = Tempfile.new('storage_test') @saved_statefile = Puppet[:statefile] Puppet[:statefile] = @state_file.path end it "should create the state file if it does not exist" do @state_file.close!() FileTest.exists?(Puppet[:statefile]).should be_false Puppet::Util::Storage.cache(:yayness) proc { Puppet::Util::Storage.store }.should_not raise_error FileTest.exists?(Puppet[:statefile]).should be_true end it "should raise an exception if the state file is not a regular file" do @state_file.close!() Dir.mkdir(Puppet[:statefile]) Puppet::Util::Storage.cache(:yayness) proc { Puppet::Util::Storage.store }.should raise_error Dir.rmdir(Puppet[:statefile]) end it "should raise an exception if it cannot get a write lock on the state file" do Puppet::Util::FileLocking.expects(:writelock).yields(false) Puppet::Util::Storage.cache(:yayness) proc { Puppet::Util::Storage.store }.should raise_error end it "should load() the same information that it store()s" do Puppet::Util::Storage.cache(:yayness) Puppet::Util::Storage.state.should == {:yayness=>{}} proc { Puppet::Util::Storage.store }.should_not raise_error Puppet::Util::Storage.clear Puppet::Util::Storage.state.should == {} proc { Puppet::Util::Storage.load }.should_not raise_error Puppet::Util::Storage.state.should == {:yayness=>{}} end after(:each) do @state_file.close!() Puppet[:statefile] = @saved_statefile end end end diff --git a/spec/unit/util/tagging_spec.rb b/spec/unit/util/tagging_spec.rb index 5a3cc97a5..018871bef 100755 --- a/spec/unit/util/tagging_spec.rb +++ b/spec/unit/util/tagging_spec.rb @@ -1,102 +1,102 @@ -#!/usr/bin/env ruby +#!/usr/bin/env rspec # # Created by Luke Kanies on 2008-01-19. # Copyright (c) 2007. All rights reserved. require 'spec_helper' require 'puppet/util/tagging' describe Puppet::Util::Tagging, "when adding tags" do before do @tagger = Object.new @tagger.extend(Puppet::Util::Tagging) end it "should have a method for adding tags" do @tagger.should be_respond_to(:tag) end it "should have a method for returning all tags" do @tagger.should be_respond_to(:tags) end it "should add tags to the returned tag list" do @tagger.tag("one") @tagger.tags.should be_include("one") end it "should not add duplicate tags to the returned tag list" do @tagger.tag("one") @tagger.tag("one") @tagger.tags.should == ["one"] end it "should return a duplicate of the tag list, rather than the original" do @tagger.tag("one") tags = @tagger.tags tags << "two" @tagger.tags.should_not be_include("two") end it "should add all provided tags to the tag list" do @tagger.tag("one", "two") @tagger.tags.should be_include("one") @tagger.tags.should be_include("two") end it "should fail on tags containing '*' characters" do lambda { @tagger.tag("bad*tag") }.should raise_error(Puppet::ParseError) end it "should fail on tags starting with '-' characters" do lambda { @tagger.tag("-badtag") }.should raise_error(Puppet::ParseError) end it "should fail on tags containing ' ' characters" do lambda { @tagger.tag("bad tag") }.should raise_error(Puppet::ParseError) end it "should allow alpha tags" do lambda { @tagger.tag("good_tag") }.should_not raise_error(Puppet::ParseError) end it "should allow tags containing '.' characters" do lambda { @tagger.tag("good.tag") }.should_not raise_error(Puppet::ParseError) end it "should provide a method for testing tag validity" do @tagger.singleton_class.publicize_methods(:valid_tag?) { @tagger.should be_respond_to(:valid_tag?) } end it "should add qualified classes as tags" do @tagger.tag("one::two") @tagger.tags.should be_include("one::two") end it "should add each part of qualified classes as tags" do @tagger.tag("one::two::three") @tagger.tags.should be_include("one") @tagger.tags.should be_include("two") @tagger.tags.should be_include("three") end it "should indicate when the object is tagged with a provided tag" do @tagger.tag("one") @tagger.should be_tagged("one") end it "should indicate when the object is not tagged with a provided tag" do @tagger.should_not be_tagged("one") end it "should indicate when the object is tagged with any tag in an array" do @tagger.tag("one") @tagger.should be_tagged("one","two","three") end it "should indicate when the object is not tagged with any tag in an array" do @tagger.tag("one") @tagger.should_not be_tagged("two","three") end end diff --git a/spec/unit/util/user_attr_spec.rb b/spec/unit/util/user_attr_spec.rb index fc7c177be..2d6ba8b5a 100755 --- a/spec/unit/util/user_attr_spec.rb +++ b/spec/unit/util/user_attr_spec.rb @@ -1,47 +1,46 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/util/user_attr' describe UserAttr do before do user_attr = ["foo::::type=role", "bar::::type=normal;profile=foobar"] File.stubs(:readlines).returns(user_attr) end describe "when getting attributes by name" do it "should return nil if there is no entry for that name" do UserAttr.get_attributes_by_name('baz').should == nil end it "should return a hash if there is an entry in /etc/user_attr" do UserAttr.get_attributes_by_name('foo').class.should == Hash end it "should return a hash with the name value from /etc/user_attr" do UserAttr.get_attributes_by_name('foo')[:name].should == 'foo' end #this test is contrived #there are a bunch of possible parameters that could be in the hash #the role/normal is just a the convention of the file describe "when the name is a role" do it "should contain :type = role" do UserAttr.get_attributes_by_name('foo')[:type].should == 'role' end end describe "when the name is not a role" do it "should contain :type = normal" do UserAttr.get_attributes_by_name('bar')[:type].should == 'normal' end end describe "when the name has more attributes" do it "should contain all the attributes" do UserAttr.get_attributes_by_name('bar')[:profile].should == 'foobar' end end end end diff --git a/spec/unit/util/warnings_spec.rb b/spec/unit/util/warnings_spec.rb index b0a6d027f..cc2c44711 100755 --- a/spec/unit/util/warnings_spec.rb +++ b/spec/unit/util/warnings_spec.rb @@ -1,39 +1,38 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' describe Puppet::Util::Warnings do before(:all) do @msg1 = "booness" @msg2 = "more booness" end {:notice => "notice_once", :warning => "warnonce"}.each do |log, method| describe "when registring '#{log}' messages" do it "should always return nil" do Puppet::Util::Warnings.send(method, @msg1).should be(nil) end it "should issue a warning" do Puppet.expects(log).with(@msg1) Puppet::Util::Warnings.send(method, @msg1) end it "should issue a warning exactly once per unique message" do Puppet.expects(log).with(@msg1).once Puppet::Util::Warnings.send(method, @msg1) Puppet::Util::Warnings.send(method, @msg1) end it "should issue multiple warnings for multiple unique messages" do Puppet.expects(log).times(2) Puppet::Util::Warnings.send(method, @msg1) Puppet::Util::Warnings.send(method, @msg2) end end end after(:each) do Puppet::Util::Warnings.clear_warnings end end diff --git a/spec/unit/util/zaml_spec.rb b/spec/unit/util/zaml_spec.rb index b211b4b30..d77cf99d2 100755 --- a/spec/unit/util/zaml_spec.rb +++ b/spec/unit/util/zaml_spec.rb @@ -1,63 +1,62 @@ -#!/usr/bin/env ruby - +#!/usr/bin/env rspec require 'spec_helper' require 'puppet/util/monkey_patches' describe "Pure ruby yaml implementation" do { 7 => "--- 7", 3.14159 => "--- 3.14159", 'test' => "--- test", [] => "--- []", :symbol => "--- !ruby/sym symbol", {:a => "A"} => "--- \n !ruby/sym a: A", {:a => "x\ny"} => "--- \n !ruby/sym a: |-\n x\n y" }.each { |o,y| it "should convert the #{o.class} #{o.inspect} to yaml" do o.to_yaml.should == y end it "should produce yaml for the #{o.class} #{o.inspect} that can be reconstituted" do YAML.load(o.to_yaml).should == o end } # # Can't test for equality on raw objects { Object.new => "--- !ruby/object {}", [Object.new] => "--- \n - !ruby/object {}", {Object.new => Object.new} => "--- \n ? !ruby/object {}\n : !ruby/object {}" }.each { |o,y| it "should convert the #{o.class} #{o.inspect} to yaml" do o.to_yaml.should == y end it "should produce yaml for the #{o.class} #{o.inspect} that can be reconstituted" do lambda { YAML.load(o.to_yaml) }.should_not raise_error end } it "should emit proper labels and backreferences for common objects" do # Note: this test makes assumptions about the names ZAML chooses # for labels. x = [1, 2] y = [3, 4] z = [x, y, x, y] z.to_yaml.should == "--- \n - &id001\n - 1\n - 2\n - &id002\n - 3\n - 4\n - *id001\n - *id002" z2 = YAML.load(z.to_yaml) z2.should == z z2[0].should equal(z2[2]) z2[1].should equal(z2[3]) end it "should emit proper labels and backreferences for recursive objects" do x = [1, 2] x << x x.to_yaml.should == "--- &id001\n \n - 1\n - 2\n - *id001" x2 = YAML.load(x.to_yaml) x2.should be_a(Array) x2.length.should == 3 x2[0].should == 1 x2[1].should == 2 x2[2].should equal(x2) end end diff --git a/spec/watchr.rb b/spec/watchr.rb old mode 100644 new mode 100755