diff --git a/spec/integration/network/formats_spec.rb b/spec/integration/network/formats_spec.rb index f6e234de3..faf667439 100755 --- a/spec/integration/network/formats_spec.rb +++ b/spec/integration/network/formats_spec.rb @@ -1,104 +1,104 @@ #!/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), :'fails_on_ruby_1.9.2' => true do +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 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/server/mongrel_spec.rb b/spec/integration/network/server/mongrel_spec.rb index a92ba83a1..aef708dc5 100755 --- a/spec/integration/network/server/mongrel_spec.rb +++ b/spec/integration/network/server/mongrel_spec.rb @@ -1,70 +1,70 @@ #!/usr/bin/env rspec require 'spec_helper' require 'puppet/network/server' require 'net/http' -describe Puppet::Network::Server, :'fails_on_ruby_1.9.2' => true do +describe Puppet::Network::Server do describe "when using mongrel", :if => Puppet.features.mongrel? do # This reduces the odds of conflicting port numbers between concurrent runs # of the suite on the same machine dramatically. def port 20001 + ($$ % 40000) end before :each do Puppet[:servertype] = 'mongrel' Puppet[:server] = '127.0.0.1' @params = { :port => port, :handlers => [ :node ] } @server = Puppet::Network::Server.new(@params) end after :each do @server.unlisten if @server.listening? end describe "before listening" do it "should not be reachable at the specified address and port" do lambda { Net::HTTP.get('127.0.0.1', '/', port) }. should raise_error(Errno::ECONNREFUSED) end end describe "when listening" do it "should be reachable on the specified address and port" do @server.listen expect { Net::HTTP.get('127.0.0.1', '/', port) }.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 expect { Net::HTTP.get('127.0.0.1', '/', port) }. should raise_error Errno::ECONNREFUSED end end end end diff --git a/spec/integration/node_spec.rb b/spec/integration/node_spec.rb index 5abb880a3..7efe524c4 100755 --- a/spec/integration/node_spec.rb +++ b/spec/integration/node_spec.rb @@ -1,92 +1,92 @@ #!/usr/bin/env rspec require 'spec_helper' require 'puppet/node' describe Puppet::Node do describe "when delegating indirection calls" do before do Puppet::Node.indirection.reset_terminus_class Puppet::Node.indirection.cache_class = nil @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", :'fails_on_ruby_1.9.2' => true do + 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/provider/package_spec.rb b/spec/integration/provider/package_spec.rb index e0d628f4b..2c6a92d74 100755 --- a/spec/integration/provider/package_spec.rb +++ b/spec/integration/provider/package_spec.rb @@ -1,44 +1,44 @@ #!/usr/bin/env rspec require 'spec_helper' -describe "Package provider", :'fails_on_ruby_1.9.2' => true do +describe "Package provider" do include PuppetSpec::Files 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 options = {:name => "nosuch#{provider.name}", :provider => provider.name} # The MSI provider requires that source be specified as it is # what actually determines if the package exists. if provider.name == :msi options[:source] = tmpfile("msi_package") end pkg = Puppet::Type.newpackage(options) lambda { pkg.provider.install }.should raise_error end it "should be able to get a list of existing packages", :fails_on_windows => true do if provider.name == :msi Puppet[:vardir] = tmpdir('msi_package_var_dir') end # the instances method requires root priviledges on gentoo # if the eix cache is outdated (to run eix-update) so make # sure we dont actually run eix-update if provider.name == :portage provider.stubs(:update_eix).returns('Database contains 15240 packages in 155 categories') end 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 483507d5f..b906b20ae 100755 --- a/spec/integration/provider/service/init_spec.rb +++ b/spec/integration/provider/service/init_spec.rb @@ -1,30 +1,30 @@ #!/usr/bin/env rspec require 'spec_helper' provider = Puppet::Type.type(:service).provider(:init) -describe provider, :'fails_on_ruby_1.9.2' => true do +describe provider do describe "when running on FreeBSD", :if => (Facter.value(:operatingsystem) == "FreeBSD") do it "should set its default path to include /etc/rc.d and /usr/local/etc/rc.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 running on Archlinux", :if => (Facter.value(:operatingsystem) == "Archlinux") do it "should set its default path to include /etc/rc.d" do provider.defpath.should == "/etc/rc.d" end end describe "when not running on FreeBSD, HP-UX or Archlinux", :if => (! %w{HP-UX FreeBSD Archlinux}.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/transaction_spec.rb b/spec/integration/transaction_spec.rb index f9b6c23e8..c5928a33a 100755 --- a/spec/integration/transaction_spec.rb +++ b/spec/integration/transaction_spec.rb @@ -1,346 +1,346 @@ #!/usr/bin/env rspec require 'spec_helper' require 'puppet/transaction' 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 def usr_bin_touch(path) Puppet.features.microsoft_windows? ? "#{ENV['windir']}/system32/cmd.exe /c \"type NUL >> \"#{path}\"\"" : "/usr/bin/touch #{path}" end def touch(path) Puppet.features.microsoft_windows? ? "cmd.exe /c \"type NUL >> \"#{path}\"\"" : "touch #{path}" 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 => make_absolute("/foo/bar"), :backup => false catalog.add_resource resource child_resource = Puppet::Type.type(:file).new :path => make_absolute("/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 => make_absolute("/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 => make_absolute("/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 it "should not apply device resources on normal host" do catalog = Puppet::Resource::Catalog.new resource = Puppet::Type.type(:interface).new :name => "FastEthernet 0/1" catalog.add_resource resource transaction = Puppet::Transaction.new(catalog) transaction.for_network_device = false transaction.expects(:apply).never.with(resource, nil) transaction.evaluate transaction.resource_status(resource).should be_skipped end it "should not apply host resources on device" do catalog = Puppet::Resource::Catalog.new resource = Puppet::Type.type(:file).new :path => make_absolute("/foo/bar"), :backup => false catalog.add_resource resource transaction = Puppet::Transaction.new(catalog) transaction.for_network_device = true transaction.expects(:apply).never.with(resource, nil) transaction.evaluate transaction.resource_status(resource).should be_skipped end it "should apply device resources on device" do catalog = Puppet::Resource::Catalog.new resource = Puppet::Type.type(:interface).new :name => "FastEthernet 0/1" catalog.add_resource resource transaction = Puppet::Transaction.new(catalog) transaction.for_network_device = true transaction.expects(:apply).with(resource, nil) transaction.evaluate transaction.resource_status(resource).should_not be_skipped end it "should apply resources appliable on host and device on a device" do catalog = Puppet::Resource::Catalog.new resource = Puppet::Type.type(:schedule).new :name => "test" catalog.add_resource resource transaction = Puppet::Transaction.new(catalog) transaction.for_network_device = true transaction.expects(:apply).with(resource, nil) transaction.evaluate transaction.resource_status(resource).should_not be_skipped 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(File.expand_path("/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", :'fails_on_ruby_1.9.2' => true do + 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 => Puppet.features.microsoft_windows? ? "#{ENV['windir']}/system32" : "/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 => "#{File.expand_path('/bin/mkdir')} /this/path/cannot/possibly/exist", :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 => "#{File.expand_path('/bin/mkdir')} /this/path/cannot/possibly/exist", :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/unit/application/face_base_spec.rb b/spec/unit/application/face_base_spec.rb index c50117ffc..5edac6cbb 100755 --- a/spec/unit/application/face_base_spec.rb +++ b/spec/unit/application/face_base_spec.rb @@ -1,394 +1,394 @@ #!/usr/bin/env rspec require 'spec_helper' require 'puppet/application/face_base' require 'tmpdir' class Puppet::Application::FaceBase::Basetest < Puppet::Application::FaceBase end describe Puppet::Application::FaceBase do let :app do 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 "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 face based on the type" do app.face.name.should == :basetest end it "should find the action" do app.action.should be app.action.name.should == :foo end end it "should stop if the first thing found is not an action" do app.command_line.stubs(:args).returns %w{banana count_args} expect { app.run }.to exit_with 1 @logs.first.should_not be_nil @logs.first.message.should =~ /has no 'banana' action/ end it "should use the default action if not given any arguments" do app.command_line.stubs(:args).returns [] action = stub(:options => [], :render_as => nil) Puppet::Face[:basetest, '0.0.1'].expects(:get_default_action).returns(action) app.stubs(:main) app.run app.action.should == action app.arguments.should == [ { } ] end it "should use the default action if not given a valid one" do app.command_line.stubs(:args).returns %w{bar} action = stub(:options => [], :render_as => nil) Puppet::Face[:basetest, '0.0.1'].expects(:get_default_action).returns(action) app.stubs(:main) app.run app.action.should == action app.arguments.should == [ 'bar', { } ] end it "should have no action if not given a valid one and there is no default action" do app.command_line.stubs(:args).returns %w{bar} Puppet::Face[:basetest, '0.0.1'].expects(:get_default_action).returns(nil) app.stubs(:main) expect { app.run }.to exit_with 1 @logs.first.message.should =~ /has no 'bar' action./ end [%w{something_I_cannot_do}, %w{something_I_cannot_do argument}].each do |input| it "should report unknown actions nicely" do app.command_line.stubs(:args).returns input Puppet::Face[:basetest, '0.0.1'].expects(:get_default_action).returns(nil) app.stubs(:main) expect { app.run }.to exit_with 1 @logs.first.message.should =~ /has no 'something_I_cannot_do' action/ end end [%w{something_I_cannot_do --unknown-option}, %w{something_I_cannot_do argument --unknown-option}].each do |input| it "should report unknown actions even if there are unknown options" do app.command_line.stubs(:args).returns input Puppet::Face[:basetest, '0.0.1'].expects(:get_default_action).returns(nil) app.stubs(:main) expect { app.run }.to exit_with 1 @logs.first.message.should =~ /has no 'something_I_cannot_do' action/ end 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.command_line.send(:parse_global_options) 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.command_line.send(:parse_global_options) app.preinit app.parse_options Puppet[:syslogfacility].should == "user1" end end - it "should handle application-level options", :'fails_on_ruby_1.9.2' => true do + it "should handle application-level options" do app.command_line.stubs(:args).returns %w{--verbose return_true} app.command_line.send(:parse_global_options) app.preinit app.parse_options app.face.name.should == :basetest 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.command_line.send(:parse_global_options) 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.command_line.send(:parse_global_options) app.preinit app.parse_options app.setup app.arguments.should == ['bar', 'baz', 'quux', { :mandatory => "--bar" }] end end describe "#main" do before :each do app.stubs(:puts) # don't dump text to screen. app.face = Puppet::Face[:basetest, '0.0.1'] app.action = app.face.get_action(:foo) app.arguments = ["myname", "myarg"] end it "should send the specified verb and name to the face" do app.face.expects(:foo).with(*app.arguments) expect { app.main }.to exit_with 0 end it "should lookup help when it cannot do anything else" do app.action = nil Puppet::Face[:help, :current].expects(:help).with(:basetest) expect { app.main }.to exit_with 1 end it "should use its render method to render any result" do app.expects(:render).with(app.arguments.length + 1, ["myname", "myarg"]) expect { app.main }.to exit_with 0 end end describe "error reporting" do before :each do app.stubs(:puts) # don't dump text to screen. app.render_as = :json app.face = Puppet::Face[:basetest, '0.0.1'] app.arguments = [{}] # we always have options in there... end it "should exit 0 when the action returns true" do app.action = app.face.get_action :return_true expect { app.main }.to exit_with 0 end it "should exit 0 when the action returns false" do app.action = app.face.get_action :return_false expect { app.main }.to exit_with 0 end it "should exit 0 when the action returns nil" do app.action = app.face.get_action :return_nil expect { app.main }.to exit_with 0 end it "should exit non-0 when the action raises" do app.action = app.face.get_action :return_raise expect { app.main }.not_to exit_with 0 end it "should use the exit code set by the action" do app.action = app.face.get_action :with_specific_exit_code expect { app.main }.to exit_with 5 end end describe "#render" do before :each do app.face = Puppet::Face[:basetest, '0.0.1'] app.action = app.face.get_action(:foo) end context "default rendering" do before :each do app.setup end ["hello", 1, 1.0].each do |input| it "should just return a #{input.class.name}" do app.render(input, {}).should == input end end [[1, 2], ["one"], [{ 1 => 1 }]].each do |input| it "should render #{input.class} using JSON" do app.render(input, {}).should == input.to_pson.chomp end end it "should render a non-trivially-keyed Hash with using JSON" do hash = { [1,2] => 3, [2,3] => 5, [3,4] => 7 } app.render(hash, {}).should == hash.to_pson.chomp end it "should render a {String,Numeric}-keyed Hash into a table" do object = Object.new hash = { "one" => 1, "two" => [], "three" => {}, "four" => object, 5 => 5, 6.0 => 6 } # Gotta love ASCII-betical sort order. Hope your objects are better # structured for display than my test one is. --daniel 2011-04-18 app.render(hash, {}).should == < { "1" => '1' * 40, "2" => '2' * 40, '3' => '3' * 40 }, "text" => { "a" => 'a' * 40, 'b' => 'b' * 40, 'c' => 'c' * 40 } } app.render(hash, {}).should == <"1111111111111111111111111111111111111111", "2"=>"2222222222222222222222222222222222222222", "3"=>"3333333333333333333333333333333333333333"} text {"a"=>"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "b"=>"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", "c"=>"cccccccccccccccccccccccccccccccccccccccc"} EOT end describe "when setting the rendering method" do after do # need to reset the when_rendering block so that other tests can set it later app.action.instance_variable_set("@when_rendering", {}) end it "should invoke the action rendering hook while rendering" do app.action.set_rendering_method_for(:console, proc { |value| "bi-winning!" }) app.render("bi-polar?", {}).should == "bi-winning!" end it "should invoke the action rendering hook with args and options while rendering" do app.action.instance_variable_set("@when_rendering", {}) app.action.when_invoked = proc { |name, options| 'just need to match arity for rendering' } app.action.set_rendering_method_for( :console, proc { |value, name, options| "I'm #{name}, no wait, I'm #{options[:altername]}" } ) app.render("bi-polar?", ['bob', {:altername => 'sue'}]).should == "I'm bob, no wait, I'm sue" end end it "should render JSON when asked for json" do app.render_as = :json json = app.render({ :one => 1, :two => 2 }, {}) json.should =~ /"one":\s*1\b/ json.should =~ /"two":\s*2\b/ PSON.parse(json).should == { "one" => 1, "two" => 2 } end end it "should fail early if asked to render an invalid format" do app.command_line.stubs(:args).returns %w{--render-as interpretive-dance return_true} app.command_line.send(:parse_global_options) # We shouldn't get here, thanks to the exception, and our expectation on # it, but this helps us fail if that slips up and all. --daniel 2011-04-27 Puppet::Face[:help, :current].expects(:help).never Puppet.expects(:err).with("Could not parse application options: I don't know how to render 'interpretive-dance'") expect { app.run }.to exit_with 1 #expect { # expect { app.run }.to exit_with 1 #}.to have_printed(/I don't know how to render 'interpretive-dance'/) end it "should work if asked to render a NetworkHandler format" do app.command_line.stubs(:args).returns %w{count_args a b c --render-as yaml} expect { expect { app.run }.to exit_with 0 }.to have_printed(/--- 3/) end it "should invoke when_rendering hook 's' when asked to render-as 's'" do app.command_line.stubs(:args).returns %w{with_s_rendering_hook --render-as s} app.action = app.face.get_action(:with_s_rendering_hook) expect { expect { app.run }.to exit_with 0 }.to have_printed(/you invoked the 's' rendering hook/) end end end diff --git a/spec/unit/application/facts_spec.rb b/spec/unit/application/facts_spec.rb index 7a7c36597..00f79fb67 100755 --- a/spec/unit/application/facts_spec.rb +++ b/spec/unit/application/facts_spec.rb @@ -1,28 +1,28 @@ #!/usr/bin/env rspec require 'spec_helper' require 'puppet/application/facts' describe Puppet::Application::Facts do before :each do subject.command_line.stubs(:subcommand_name).returns 'facts' end it "should fail if no key is given to find" do subject.command_line.stubs(:args).returns %w{find} expect { expect { subject.run }.to exit_with 1 }.to have_printed /err: puppet facts find takes 1 argument, but you gave 0/ @logs.first.to_s.should =~ /puppet facts find takes 1 argument, but you gave 0/ end - it "should return facts if a key is given to find", :'fails_on_ruby_1.9.2' => true do + it "should return facts if a key is given to find" do Puppet::Node::Facts.indirection.reset_terminus_class subject.command_line.stubs(:args).returns %w{find whatever --render-as yaml} expect { expect { subject.run }.to exit_with 0 }.should have_printed(/object:Puppet::Node::Facts/) @logs.should be_empty end end diff --git a/spec/unit/application/resource_spec.rb b/spec/unit/application/resource_spec.rb index 20b1d54c4..bc9474018 100755 --- a/spec/unit/application/resource_spec.rb +++ b/spec/unit/application/resource_spec.rb @@ -1,220 +1,220 @@ #!/usr/bin/env rspec require 'spec_helper' require 'puppet/application/resource' describe Puppet::Application::Resource do include PuppetSpec::Files before :each do @resource_app = Puppet::Application[:resource] Puppet::Util::Log.stubs(:newdestination) Puppet::Resource.indirection.stubs(:terminus_class=) end describe "in preinit" do - it "should init extra_params to empty array", :'fails_on_ruby_1.9.2' => true do + it "should init extra_params to empty array" do @resource_app.preinit @resource_app.extra_params.should == [] end it "should load Facter facts" do Facter.expects(:loadfacts).once @resource_app.preinit end end describe "when handling options" do [:debug, :verbose, :edit].each do |option| it "should store argument value when calling handle_#{option}" do @resource_app.options.expects(:[]=).with(option, 'arg') @resource_app.send("handle_#{option}".to_sym, 'arg') end end it "should set options[:host] to given host" do @resource_app.handle_host(:whatever) @resource_app.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_app.expects(:puts).with(['type1','type2']) expect { @resource_app.handle_types(nil) }.to exit_with 0 end it "should add param to extra_params list" do @resource_app.extra_params = [ :param1 ] @resource_app.handle_param("whatever") @resource_app.extra_params.should == [ :param1, :whatever ] end it "should get a parameter in the printed data if extra_params are passed" do tty = stub("tty", :tty? => true ) path = tmpfile('testfile') command_line = Puppet::Util::CommandLine.new("puppet", [ 'resource', 'file', path ], tty ) @resource_app.stubs(:command_line).returns command_line # provider is a parameter that should always be available @resource_app.extra_params = [ :provider ] expect { @resource_app.main }.to have_printed /provider\s+=>/ end end describe "during setup" do before :each do Puppet::Log.stubs(:newdestination) Puppet.stubs(:parse_config) end it "should set console as the log destination" do Puppet::Log.expects(:newdestination).with(:console) @resource_app.setup end it "should set log level to debug if --debug was passed" do @resource_app.options.stubs(:[]).with(:debug).returns(true) @resource_app.setup Puppet::Log.level.should == :debug end it "should set log level to info if --verbose was passed" do @resource_app.options.stubs(:[]).with(:debug).returns(false) @resource_app.options.stubs(:[]).with(:verbose).returns(true) @resource_app.setup Puppet::Log.level.should == :info end it "should Parse puppet config" do Puppet.expects(:parse_config) @resource_app.setup end end describe "when running" do before :each do @type = stub_everything 'type', :properties => [] @resource_app.command_line.stubs(:args).returns(['mytype']) Puppet::Type.stubs(:type).returns(@type) @res = stub_everything "resource" @res.stubs(:prune_parameters).returns(@res) @report = stub_everything "report" end it "should raise an error if no type is given" do @resource_app.command_line.stubs(:args).returns([]) lambda { @resource_app.main }.should raise_error(RuntimeError, "You must specify the type to display") end it "should raise an error when editing a remote host" do @resource_app.options.stubs(:[]).with(:edit).returns(true) @resource_app.host = 'host' lambda { @resource_app.main }.should raise_error(RuntimeError, "You cannot edit a remote host") end it "should raise an error if the type is not found" do Puppet::Type.stubs(:type).returns(nil) lambda { @resource_app.main }.should raise_error(RuntimeError, 'Could not find type mytype') end describe "with a host" do before :each do @resource_app.stubs(:puts) @resource_app.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_app.command_line.stubs(:args).returns(['type']) Puppet::Resource.indirection.expects(:search).with('https://host:8139/production/resources/type/', {}).returns([]) @resource_app.main end it "should describe the given resource" do @resource_app.command_line.stubs(:args).returns(['type', 'name']) Puppet::Resource.indirection.expects(:find).with('https://host:8139/production/resources/type/name').returns(@res) @resource_app.main end it "should add given parameters to the object" do @resource_app.command_line.stubs(:args).returns(['type','name','param=temp']) Puppet::Resource.indirection.expects(:save). with(@res, 'https://host:8139/production/resources/type/name'). returns([@res, @report]) Puppet::Resource.expects(:new).with('type', 'name', :parameters => {'param' => 'temp'}).returns(@res) @resource_app.main end end describe "without a host" do before :each do @resource_app.stubs(:puts) @resource_app.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('mytype/', {}).returns([]) @resource_app.main end it "should describe the given resource" do @resource_app.command_line.stubs(:args).returns(['type','name']) Puppet::Resource.indirection.expects(:find).with('type/name').returns(@res) @resource_app.main end it "should add given parameters to the object" do @resource_app.command_line.stubs(:args).returns(['type','name','param=temp']) Puppet::Resource.indirection.expects(:save).with(@res, 'type/name').returns([@res, @report]) Puppet::Resource.expects(:new).with('type', 'name', :parameters => {'param' => 'temp'}).returns(@res) @resource_app.main end end end describe "when handling file type" do before :each do Facter.stubs(:loadfacts) @resource_app.preinit end it "should raise an exception if no file specified" do @resource_app.command_line.stubs(:args).returns(['file']) lambda { @resource_app.main }.should raise_error(RuntimeError, /Listing all file instances is not supported/) end it "should output a file resource when given a file path" do path = File.expand_path('/etc') res = Puppet::Type.type(:file).new(:path => path).to_resource Puppet::Resource.indirection.expects(:find).returns(res) @resource_app.command_line.stubs(:args).returns(['file', path]) @resource_app.expects(:puts).with do |args| args.should =~ /file \{ '#{Regexp.escape(path)}'/m end @resource_app.main end end end diff --git a/spec/unit/application_spec.rb b/spec/unit/application_spec.rb index 39c76ab15..bd7ea1340 100755 --- a/spec/unit/application_spec.rb +++ b/spec/unit/application_spec.rb @@ -1,590 +1,590 @@ #!/usr/bin/env rspec require 'spec_helper' require 'puppet/application' require 'puppet' require 'getoptlong' describe Puppet::Application do before do Puppet::Util::Instrumentation.stubs(:init) @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 "application defaults" do it "should fail if required app default values are missing" do @app.stubs(:app_defaults).returns({ :foo => 'bar' }) Puppet.expects(:err).with(regexp_matches(/missing required app default setting/)) expect { @app.run }.to exit_with 1 end 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", :'fails_on_ruby_1.9.2' => true do + it "should not find classes outside the namespace" do expect { @klass.find("String") }.to exit_with 1 end it "should exit if it can't find a class" do @klass.expects(:puts).with do |value| value =~ /Unable to find application 'ThisShallNeverEverEverExist'/ and value =~ /puppet\/application\/thisshallneverevereverexist/ and value =~ /no such file to load|cannot load such file/ end expect { @klass.find("ThisShallNeverEverEverExist") }.to exit_with 1 end it "#12114: should prevent File namespace collisions" do # have to require the file face once, then the second time around it would fail @klass.find("File").should == Puppet::Application::File @klass.find("File").should == Puppet::Application::File 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 # These tests may look a little weird and repetative in its current state; # it used to illustrate several ways that the run_mode could be changed # at run time; there are fewer ways now, but it would still be nice to # get to a point where it was entirely impossible. describe "when dealing with run_mode" do class TestApp < Puppet::Application run_mode :master def run_command # no-op end end it "should sadly and frighteningly allow run_mode to change at runtime via #initialize_app_defaults" do Puppet.features.stubs(:syslog?).returns(true) Puppet[:run_mode].should == :user expect { app = TestApp.new app.initialize_app_defaults Puppet[:run_mode].should == :master }.to_not raise_error end it "should sadly and frighteningly allow run_mode to change at runtime via #run" do expect { app = TestApp.new app.run app.class.run_mode.name.should == :master Puppet[:run_mode].should == :master }.should_not raise_error end end it "it should not allow initialize_app_defaults to be called multiple times" do app = Puppet::Application.new expect { app.initialize_app_defaults }.to_not raise_error expect { app.initialize_app_defaults }.to raise_error end it "should explode when an invalid run mode is set at runtime, for great victory" do class InvalidRunModeTestApp < Puppet::Application run_mode :abracadabra def run_command # no-op end end expect { app = InvalidRunModeTestApp.new app.initialize_app_defaults }.to raise_error end 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 it "should initialize the Puppet Instrumentation layer early in the life cycle" do startup_sequence = sequence('startup') @app.expects(:initialize_app_defaults).in_sequence(startup_sequence) Puppet::Util::Instrumentation.expects(:init).in_sequence(startup_sequence) @app.expects(:preinit).in_sequence(startup_sequence) expect { @app.run }.to exit_with(1) 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', :'fails_on_ruby_1.9.2' => true 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 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.stubs(:puts) expect { @app.handle_help(nil) }.to exit_with 0 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) expect { @app.handle_version(nil) }.to exit_with 0 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 transform boolean option to normal form for Puppet.settings" do @app.expects(:handle_unknown).with("--option", true) @app.send(:handlearg, "--[no-]option", true) end it "should transform boolean option to no- form for Puppet.settings" do @app.expects(:handle_unknown).with("--no-option", false) @app.send(:handlearg, "--[no-]option", false) end end end describe "when calling default setup" do before :each do @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) @app.setup Puppet::Util::Log.level.should == (level == :verbose ? :info : :debug) end end it "should honor setdest option" do @app.options.stubs(:[]).with(:setdest).returns(false) Puppet::Util::Log.expects(:setup_default) @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 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 Puppet.expects(:err) expect { @app.run }.to exit_with 1 end it "should raise an error if dispatch returns no command" do @app.stubs(:get_command).returns(nil) Puppet.expects(:err) expect { @app.run }.to exit_with 1 end it "should raise an error if dispatch returns an invalid command" do @app.stubs(:get_command).returns(:this_function_doesnt_exist) Puppet.expects(:err) expect { @app.run }.to exit_with 1 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/indirector/facts/couch_spec.rb b/spec/unit/indirector/facts/couch_spec.rb index 7038a438d..d0862486c 100755 --- a/spec/unit/indirector/facts/couch_spec.rb +++ b/spec/unit/indirector/facts/couch_spec.rb @@ -1,102 +1,102 @@ #!/usr/bin/env rspec require 'spec_helper' require 'puppet/node/facts' require 'puppet/indirector/facts/couch' -describe "Puppet::Node::Facts::Couch", :'fails_on_ruby_1.9.2' => true do +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?, :'fails_on_ruby_1.9.2' => true do + 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/ldap_spec.rb b/spec/unit/indirector/ldap_spec.rb index d4c9ddcff..2b40325de 100755 --- a/spec/unit/indirector/ldap_spec.rb +++ b/spec/unit/indirector/ldap_spec.rb @@ -1,137 +1,137 @@ #!/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?, :'fails_on_ruby_1.9.2' => true do + 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/resource/ral_spec.rb b/spec/unit/indirector/resource/ral_spec.rb index 2a3fec0d3..0205db52e 100755 --- a/spec/unit/indirector/resource/ral_spec.rb +++ b/spec/unit/indirector/resource/ral_spec.rb @@ -1,130 +1,130 @@ #!/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", :'fails_on_ruby_1.9.2' => true do + 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' @report = stub 'report' @transaction = stub 'transaction', :report => @report Puppet::Resource::Catalog.stubs(:new).returns(@catalog) @catalog.stubs(:apply).returns(@transaction) @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).returns(@transaction) Puppet::Resource::Ral.new.save(@request).should end it "should return a regular resource that used to be the ral resource" do Puppet::Resource::Ral.new.save(@request).should == [@rebuilt_res, @report] end end end diff --git a/spec/unit/interface_spec.rb b/spec/unit/interface_spec.rb index bc433e9bf..1621b9ad8 100755 --- a/spec/unit/interface_spec.rb +++ b/spec/unit/interface_spec.rb @@ -1,233 +1,233 @@ require 'spec_helper' require 'puppet/face' require 'puppet/interface' describe Puppet::Interface do subject { Puppet::Interface } before :each do @faces = Puppet::Interface::FaceCollection. instance_variable_get("@faces").dup @dq = $".dup $".delete_if do |path| path =~ %r{/face/.*\.rb$} end Puppet::Interface::FaceCollection.instance_variable_get("@faces").clear end after :each do Puppet::Interface::FaceCollection.instance_variable_set("@faces", @faces) $".clear ; @dq.each do |item| $" << item end 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 describe "version matching" do { '1' => '1.1.1', '1.0' => '1.0.1', '1.0.1' => '1.0.1', '1.1' => '1.1.1', '1.1.1' => '1.1.1' }.each do |input, expect| it "should match #{input.inspect} to #{expect.inspect}" do face = subject[:version_matching, input] face.should be face.version.should == expect end end %w{1.0.2 1.2}.each do |input| it "should not match #{input.inspect} to any version" do expect { subject[:version_matching, input] }. to raise_error Puppet::Error, /Could not find version/ end end 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 # Required documentation methods... { :summary => "summary", :description => "This is the description of the stuff\n\nWhee", :examples => "This is my example", :short_description => "This is my custom short description", :notes => "These are my notes...", :author => "This is my authorship data", }.each do |attr, value| it "should support #{attr} in the builder" do face = subject.new(:builder, '1.0.0') do self.send(attr, value) end face.send(attr).should == value end 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", :'fails_on_ruby_1.9.2' => true do + 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 # 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 subject::FaceCollection.expects(:load_face).with(:foo, :current) subject::FaceCollection.expects(:load_face).with(:foo, '0.0.1') expect { subject[:foo, '0.0.1'] }.to raise_error Puppet::Error end 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", :'fails_on_ruby_1.9.2' => true do + 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 when_invoked {|_| true } 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 when_invoked {|_| true } 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 when_invoked {|_| true } ; option "--quux" end action :bar do when_invoked {|_| true } ; option "--quux" end end face.get_action(:foo).options.should =~ [:quux] face.get_action(:bar).options.should =~ [:quux] end it "should only list options and not aliases" do face = subject.new(:face_options, '0.0.1') do option "--bar", "-b", "--foo-bar" end face.options.should =~ [:bar] end end describe "with inherited options" do let :parent do parent = Class.new(subject) parent.option("--inherited") parent.action(:parent_action) do when_invoked {|_| true } end parent end let :face do face = parent.new(:example, '0.2.1') face.option("--local") face.action(:face_action) do when_invoked {|_| true } end face end - describe "#options", :'fails_on_ruby_1.9.2' => true do + describe "#options" do it "should list inherited options" do face.options.should =~ [:inherited, :local] end it "should see all options on face actions" do face.get_action(:face_action).options.should =~ [:inherited, :local] end it "should see all options on inherited actions accessed on the subclass" do face.get_action(:parent_action).options.should =~ [:inherited, :local] end it "should not see subclass actions on the parent class" do parent.options.should =~ [:inherited] end it "should not see subclass actions on actions accessed on the parent class" do parent.get_action(:parent_action).options.should =~ [:inherited] end end - describe "#get_option", :'fails_on_ruby_1.9.2' => true do + 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 it_should_behave_like "documentation on faces" do subject do Puppet::Interface.new(:face_documentation, '0.0.1') end end end diff --git a/spec/unit/network/http/mongrel/rest_spec.rb b/spec/unit/network/http/mongrel/rest_spec.rb index d87596f77..51ce3fccb 100755 --- a/spec/unit/network/http/mongrel/rest_spec.rb +++ b/spec/unit/network/http/mongrel/rest_spec.rb @@ -1,276 +1,276 @@ #!/usr/bin/env rspec require 'spec_helper' require 'puppet/network/http' -describe "Puppet::Network::HTTP::MongrelREST", :if => Puppet.features.mongrel?, :'fails_on_ruby_1.9.2' => true do +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.stubs(: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 @params = {'REQUEST_METHOD' => 'GET'} @request.stubs(:params).returns(@params) end it "should skip empty parameter values" do @params['QUERY_STRING'] = "&=" lambda { @handler.params(@request) }.should_not raise_error end it "should include the HTTP request parameters, with the keys as symbols" do @params['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 escaped = CGI.escape("foo bar") @params['QUERY_STRING'] = "foo=#{escaped}" result = @handler.params(@request) result[:foo].should == "foo bar" end it "should include parameters from the body of a POST request" do @params.merge!( 'QUERY_STRING' => nil, 'REQUEST_METHOD' => 'POST' ) body = StringIO.new('foo=bar&baz=qux') @request.stubs(:body).returns(body) @handler.params(@request).should include( :foo => 'bar', :baz => 'qux' ) end it "should convert the string 'true' to the boolean" do @params['QUERY_STRING'] = 'foo=true' result = @handler.params(@request) result[:foo].should be_true end it "should convert the string 'false' to the boolean" do @params['QUERY_STRING'] = 'foo=false' result = @handler.params(@request) result[:foo].should be_false end it "should convert integer arguments to Integers" do @params['QUERY_STRING'] = 'foo=15' result = @handler.params(@request) result[:foo].should == 15 end it "should convert floating point arguments to Floats" do @params['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})) @params['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 @params['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 @params['QUERY_STRING'] = "ip=foo" @handler.params(@request)[:ip].should be_nil end it "should pass the client's ip address to model find" do @params['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 @params["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 @params["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 @params.merge!( "REMOTE_ADDR" => "remote_addr", "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" @params["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" @params["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" @params.merge!( "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" @params.merge!( "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" @params.merge!( "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" @params.merge!( "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" @params["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 2e0ff04a0..b8e486d25 100755 --- a/spec/unit/network/http/mongrel_spec.rb +++ b/spec/unit/network/http/mongrel_spec.rb @@ -1,91 +1,91 @@ #!/usr/bin/env rspec require 'spec_helper' require 'puppet/network/http' -describe "Puppet::Network::HTTP::Mongrel", "after initializing", :if => Puppet.features.mongrel?, :'fails_on_ruby_1.9.2' => true do - it "should not be listening", :'fails_on_ruby_1.9.2' => true do +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?, :'fails_on_ruby_1.9.2' => true do +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) @listen_params = { :address => "127.0.0.1", :port => 31337 } 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 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 end end -describe "Puppet::Network::HTTP::Mongrel", "when turning off listening", :if => Puppet.features.mongrel?, :'fails_on_ruby_1.9.2' => true do +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 ]} 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/parser/ast/function_spec.rb b/spec/unit/parser/ast/function_spec.rb index 95dc1150c..4ad176dab 100755 --- a/spec/unit/parser/ast/function_spec.rb +++ b/spec/unit/parser/ast/function_spec.rb @@ -1,92 +1,92 @@ #!/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", :'fails_on_ruby_1.9.2' => true do + 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/selector_spec.rb b/spec/unit/parser/ast/selector_spec.rb index 76afec271..1bf5f6757 100755 --- a/spec/unit/parser/ast/selector_spec.rb +++ b/spec/unit/parser/ast/selector_spec.rb @@ -1,138 +1,138 @@ #!/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", :'fails_on_ruby_1.9.2' => true do + 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/functions/inline_template_spec.rb b/spec/unit/parser/functions/inline_template_spec.rb index 6357e2fea..1b1d1bdcd 100755 --- a/spec/unit/parser/functions/inline_template_spec.rb +++ b/spec/unit/parser/functions/inline_template_spec.rb @@ -1,61 +1,61 @@ #!/usr/bin/env rspec require 'spec_helper' -describe "the inline_template function", :'fails_on_ruby_1.9.2' => true do +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/resource_spec.rb b/spec/unit/parser/resource_spec.rb index 508159f45..59513a103 100755 --- a/spec/unit/parser/resource_spec.rb +++ b/spec/unit/parser/resource_spec.rb @@ -1,639 +1,640 @@ #!/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", :'fails_on_ruby_1.9.2' => true do - lambda { Puppet::Parser::Resource.new('file', '/my/file') }.should raise_error(ArgumentError) + it "should fail unless #{name.to_s} is specified" do + expect { 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 before do @node = Puppet::Node.new "test-node" @compiler = Puppet::Parser::Compiler.new @node @catalog = Puppet::Resource::Catalog.new source = stub('source') source.stubs(:module_name) @scope = Puppet::Parser::Scope.new(:compiler => @compiler, :source => source) @catalog.add_resource(Puppet::Parser::Resource.new("stage", :main, :scope => @scope)) end it "should evaluate the associated AST definition" do definition = newdefine "mydefine" res = Puppet::Parser::Resource.new("mydefine", "whatever", :scope => @scope, :source => @source, :catalog => @catalog) 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, :catalog => @catalog) @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, :catalog => @catalog) nodedef.expects(:evaluate_code).with(res) res.evaluate end - it "should add an edge to any specified stage for class resources", :'fails_on_ruby_1.9.2' => true do - @compiler.known_resource_types.add Puppet::Resource::Type.new(:hostclass, "foo", '') + it "should add an edge to any specified stage for class resources" do + @compiler.known_resource_types.add Puppet::Resource::Type.new(:hostclass, "foo", {}) other_stage = Puppet::Parser::Resource.new(:stage, "other", :scope => @scope, :catalog => @catalog) @compiler.add_resource(@scope, other_stage) resource = Puppet::Parser::Resource.new(:class, "foo", :scope => @scope, :catalog => @catalog) resource[:stage] = 'other' @compiler.add_resource(@scope, resource) resource.evaluate @compiler.catalog.edge?(other_stage, resource).should be_true end - it "should fail if an unknown stage is specified", :'fails_on_ruby_1.9.2' => true do - @compiler.known_resource_types.add Puppet::Resource::Type.new(:hostclass, "foo", '') + it "should fail if an unknown stage is specified" do + @compiler.known_resource_types.add Puppet::Resource::Type.new(:hostclass, "foo", {}) resource = Puppet::Parser::Resource.new(:class, "foo", :scope => @scope, :catalog => @catalog) resource[:stage] = 'other' lambda { resource.evaluate }.should raise_error(ArgumentError, /Could not find stage other specified by/) end - it "should add edges from the class resources to the parent's stage if no stage is specified", :'fails_on_ruby_1.9.2' => true do + 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 = Puppet::Parser::Resource.new(:stage, :foo_stage, :scope => @scope, :catalog => @catalog) @compiler.add_resource(@scope, foo_stage) - @compiler.known_resource_types.add Puppet::Resource::Type.new(:hostclass, "foo", '') + @compiler.known_resource_types.add Puppet::Resource::Type.new(:hostclass, "foo", {}) resource = Puppet::Parser::Resource.new(:class, "foo", :scope => @scope, :catalog => @catalog) resource[:stage] = 'foo_stage' @compiler.add_resource(@scope, resource) resource.evaluate @compiler.catalog.should be_edge(foo_stage, resource) end it "should allow edges to propagate multiple levels down the scope hierarchy" do Puppet[:code] = <<-MANIFEST stage { before: before => Stage[main] } class alpha { include beta } class beta { include gamma } class gamma { } class { alpha: stage => before } MANIFEST catalog = Puppet::Parser::Compiler.compile(Puppet::Node.new 'anyone') # Stringify them to make for easier lookup edges = catalog.edges.map {|e| [e.source.ref, e.target.ref]} edges.should include(["Stage[before]", "Class[Alpha]"]) edges.should include(["Stage[before]", "Class[Beta]"]) edges.should include(["Stage[before]", "Class[Gamma]"]) end it "should use the specified stage even if the parent scope specifies one" do Puppet[:code] = <<-MANIFEST stage { before: before => Stage[main], } stage { after: require => Stage[main], } class alpha { class { beta: stage => after } } class beta { } class { alpha: stage => before } MANIFEST catalog = Puppet::Parser::Compiler.compile(Puppet::Node.new 'anyone') edges = catalog.edges.map {|e| [e.source.ref, e.target.ref]} edges.should include(["Stage[before]", "Class[Alpha]"]) edges.should include(["Stage[after]", "Class[Beta]"]) end - it "should add edges from top-level class resources to the main stage if no stage is specified", :'fails_on_ruby_1.9.2' => true do + 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) - @compiler.known_resource_types.add Puppet::Resource::Type.new(:hostclass, "foo", '') + @compiler.known_resource_types.add Puppet::Resource::Type.new(:hostclass, "foo", {}) resource = Puppet::Parser::Resource.new(:class, "foo", :scope => @scope, :catalog => @catalog) @compiler.add_resource(@scope, resource) resource.evaluate @compiler.catalog.should be_edge(main, resource) 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['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['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['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 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/provider/mount/parsed_spec.rb b/spec/unit/provider/mount/parsed_spec.rb index 29c3cf020..8cb6efbc3 100755 --- a/spec/unit/provider/mount/parsed_spec.rb +++ b/spec/unit/provider/mount/parsed_spec.rb @@ -1,289 +1,289 @@ #!/usr/bin/env rspec require 'spec_helper' require 'shared_behaviours/all_parsedfile_providers' provider_class = Puppet::Type.type(:mount).provider(:parsed) describe provider_class, :unless => Puppet.features.microsoft_windows? 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', :'fails_on_ruby_1.9.2' => true do + 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 calling instances 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 @retrieve = @provider.instances.collect { |prov| {:name => prov.get(:name), :ensure => prov.get(:ensure)}} end # Following mountpoint are present in all fstabs/mountoutputs it "should include unmounted resources" do @retrieve.should include(:name => '/', :ensure => :mounted) end it "should include mounted resources" do @retrieve.should include(:name => '/boot', :ensure => :unmounted) end it "should include ghost resources" do @retrieve.should include(:name => '/ghost', :ensure => :ghost) end end 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/service/init_spec.rb b/spec/unit/provider/service/init_spec.rb index 24a17a42a..2b900ef8a 100755 --- a/spec/unit/provider/service/init_spec.rb +++ b/spec/unit/provider/service/init_spec.rb @@ -1,170 +1,170 @@ #!/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", :'fails_on_ruby_1.9.2' => true do + it "should omit a single service from the exclude list" do exclude = 'two' (@services - [exclude]).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/src_spec.rb b/spec/unit/provider/service/src_spec.rb index b45ca0c7c..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 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", :'fails_on_ruby_1.9.2' => true do + 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", :'fails_on_ruby_1.9.2' => true do + 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", :'fails_on_ruby_1.9.2' => true do + 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", :'fails_on_ruby_1.9.2' => true do + 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", :'fails_on_ruby_1.9.2' => true do + 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/user/user_role_add_spec.rb b/spec/unit/provider/user/user_role_add_spec.rb index 3d96f34bd..6d779642b 100755 --- a/spec/unit/provider/user/user_role_add_spec.rb +++ b/spec/unit/provider/user/user_role_add_spec.rb @@ -1,306 +1,306 @@ require 'spec_helper' require 'puppet_spec/files' require 'tempfile' provider_class = Puppet::Type.type(:user).provider(:user_role_add) describe provider_class, :unless => Puppet.features.microsoft_windows? do include PuppetSpec::Files before do @resource = stub("resource", :name => "myuser", :managehome? => nil) @resource.stubs(:should).returns "fakeval" @resource.stubs(:should).with(:keys).returns Hash.new @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", :'fails_on_ruby_1.9.2' => true do + 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", :'fails_on_ruby_1.9.2' => true do + 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 let(:path) { tmpfile('etc-shadow') } before :each do @provider.stubs(:target_file_path).returns(path) end def write_fixture(content) File.open(path, 'w') { |f| f.print(content) } end it "should update the target user" do write_fixture < "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", :'fails_on_ruby_1.9.2' => true do + 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/resource/status_spec.rb b/spec/unit/resource/status_spec.rb index 922f9edad..967708432 100755 --- a/spec/unit/resource/status_spec.rb +++ b/spec/unit/resource/status_spec.rb @@ -1,154 +1,154 @@ #!/usr/bin/env rspec require 'spec_helper' require 'puppet/resource/status' describe Puppet::Resource::Status do include PuppetSpec::Files before do @resource = Puppet::Type.type(:file).new :path => make_absolute("/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 == make_absolute("/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", :'fails_on_ruby_1.9.2' => true do + 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 end end end diff --git a/spec/unit/resource_spec.rb b/spec/unit/resource_spec.rb index 4a22fc499..548322fb0 100755 --- a/spec/unit/resource_spec.rb +++ b/spec/unit/resource_spec.rb @@ -1,826 +1,826 @@ #!/usr/bin/env rspec require 'spec_helper' require 'puppet/resource' describe Puppet::Resource do include PuppetSpec::Files let :basepath do make_absolute("/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 expect { Puppet::Resource.new("resource-spec-foo") }.should raise_error(ArgumentError) end it 'should fail if strict is set and type does not exist' do expect { Puppet::Resource.new('resource-spec-foo', 'title', {:strict=>true}) }.should raise_error(ArgumentError, 'Invalid resource type resource-spec-foo') end it 'should fail if strict is set and class does not exist' do expect { Puppet::Resource.new('Class', 'resource-spec-foo', {:strict=>true}) }.should raise_error(ArgumentError, 'Could not find declared class resource-spec-foo') end it "should fail if the title is a hash and the type is not a valid resource reference string" do expect { Puppet::Resource.new({:type => "resource-spec-foo", :title => "bar"}) }. to raise_error ArgumentError, /Puppet::Resource.new does not take a hash/ 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 setting default parameters" do before do @scope = Puppet::Parser::Scope.new end it "should fail when asked to set default values and it is not a parser resource" do Puppet::Node::Environment.new.known_resource_types.add( Puppet::Resource::Type.new(:definition, "default_param", :arguments => {"a" => Puppet::Parser::AST::String.new(:value => "default")}) ) resource = Puppet::Resource.new("default_param", "name") lambda { resource.set_default_parameters(@scope) }.should raise_error(Puppet::DevError) end it "should evaluate and set any default values when no value is provided" do Puppet::Node::Environment.new.known_resource_types.add( Puppet::Resource::Type.new(:definition, "default_param", :arguments => {"a" => Puppet::Parser::AST::String.new(:value => "a_default_value")}) ) resource = Puppet::Parser::Resource.new("default_param", "name", :scope => Puppet::Parser::Scope.new) resource.set_default_parameters(@scope) resource["a"].should == "a_default_value" end it "should skip attributes with no default value" do Puppet::Node::Environment.new.known_resource_types.add( Puppet::Resource::Type.new(:definition, "no_default_param", :arguments => {"a" => Puppet::Parser::AST::String.new(:value => "a_default_value")}) ) resource = Puppet::Parser::Resource.new("no_default_param", "name", :scope => Puppet::Parser::Scope.new) lambda { resource.set_default_parameters(@scope) }.should_not raise_error end it "should return the list of default parameters set" do Puppet::Node::Environment.new.known_resource_types.add( Puppet::Resource::Type.new(:definition, "default_param", :arguments => {"a" => Puppet::Parser::AST::String.new(:value => "a_default_value")}) ) resource = Puppet::Parser::Resource.new("default_param", "name", :scope => Puppet::Parser::Scope.new) resource.set_default_parameters(@scope).should == [:a] end end describe "when validating all required parameters are present" do it "should be able to validate that all required parameters are present" do Puppet::Node::Environment.new.known_resource_types.add( Puppet::Resource::Type.new(:definition, "required_param", :arguments => {"a" => nil}) ) lambda { Puppet::Resource.new("required_param", "name").validate_complete }.should raise_error(Puppet::ParseError) end it "should not fail when all required parameters are present" do Puppet::Node::Environment.new.known_resource_types.add( Puppet::Resource::Type.new(:definition, "no_required_param") ) resource = Puppet::Resource.new("no_required_param", "name") resource["a"] = "meh" lambda { resource.validate_complete }.should_not raise_error end it "should not validate against builtin types" do lambda { Puppet::Resource.new("file", "/bar").validate_complete }.should_not raise_error end 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 expect { 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 expect { 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" expect { 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 expect { 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 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", :'fails_on_ruby_1.9.2' => true do + 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 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') expect { Puppet::Resource.from_pson(@data) }.should raise_error(ArgumentError) end it "should fail if no type is provided" do @data.delete('type') expect { 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 be 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 describe "#prune_parameters" do before do Puppet.newtype('blond') do newproperty(:ensure) newproperty(:height) newproperty(:weight) newproperty(:sign) newproperty(:friends) newparam(:admits_to_dying_hair) newparam(:admits_to_age) newparam(:name) end end it "should strip all parameters and strip properties that are nil, empty or absent except for ensure" do resource = Puppet::Resource.new("blond", "Bambi", :parameters => { :ensure => 'absent', :height => '', :weight => 'absent', :friends => [], :admits_to_age => true, :admits_to_dying_hair => false }) pruned_resource = resource.prune_parameters pruned_resource.should == Puppet::Resource.new("blond", "Bambi", :parameters => {:ensure => 'absent'}) end it "should leave parameters alone if in parameters_to_include" do resource = Puppet::Resource.new("blond", "Bambi", :parameters => { :admits_to_age => true, :admits_to_dying_hair => false }) pruned_resource = resource.prune_parameters(:parameters_to_include => [:admits_to_dying_hair]) pruned_resource.should == Puppet::Resource.new("blond", "Bambi", :parameters => {:admits_to_dying_hair => false}) end it "should leave properties if not nil, absent or empty" do resource = Puppet::Resource.new("blond", "Bambi", :parameters => { :ensure => 'silly', :height => '7 ft 5 in', :friends => ['Oprah'], }) pruned_resource = resource.prune_parameters pruned_resource.should == resource = Puppet::Resource.new("blond", "Bambi", :parameters => { :ensure => 'silly', :height => '7 ft 5 in', :friends => ['Oprah'], }) end end end diff --git a/spec/unit/simple_graph_spec.rb b/spec/unit/simple_graph_spec.rb index f2fb5cd82..28f21bddd 100755 --- a/spec/unit/simple_graph_spec.rb +++ b/spec/unit/simple_graph_spec.rb @@ -1,933 +1,933 @@ #!/usr/bin/env rspec 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 # This works with `add_edges` to auto-vivify the resource instances. let :vertex do Hash.new do |hash, key| hash[key] = Puppet::Type.type(:notify).new(:name => key.to_s) end end def add_edges(hash) hash.each do |a,b| @graph.add_edge(vertex[a], vertex[b]) end end def simplify(cycles) cycles.map do |x| x.map do |y| y.to_s.match(/^Notify\[(.*)\]$/)[1] end 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\((Notify\[a\] => Notify\[b\] => Notify\[a\]|Notify\[b\] => Notify\[a\] => Notify\[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 }.should_not raise_error simplify(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 }.should_not raise_error simplify(cycles).should be == [["a1", "a"], ["b1", "b"]] 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 }.should_not raise_error simplify(cycles).should be == [%w{a1 a}, %w{c1 c2 c3 c}] 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 }.should_not raise_error simplify(cycles).should be == [%w{a b c1 c2 c}] 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 }.should_not raise_error simplify(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 paths = @graph.paths_in_cycle(cycles.first, 100) simplify(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 cycles.length.should be == 1 paths = @graph.paths_in_cycle(cycles.first, 100) simplify(paths).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 cycles.length.should be == 1 paths = @graph.paths_in_cycle(cycles.first, 100) simplify(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 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", :'fails_on_ruby_1.9.2' => true do + describe "when matching edges" do before do @graph = Puppet::SimpleGraph.new # The Ruby 1.8 semantics for String#[] are that treating it like an # array and asking for `"a"[:whatever]` returns `nil`. Ruby 1.9 # enforces that your index has to be numeric. # # Now, the real object here, a resource, implements [] and does # something sane, but we don't care about any of the things that get # asked for. Right now, anyway. # # So, in 1.8 we could just pass a string and it worked. For 1.9 we can # fake it well enough by stubbing out the operator to return nil no # matter what input we give. --daniel 2012-03-11 resource = "a" resource.stubs(:[]) @event = Puppet::Transaction::Event.new(:name => :yay, :resource => resource) @none = Puppet::Transaction::Event.new(:name => :NONE, :resource => resource) @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 def ref "Container[#{self}]" 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 =~ /#{Regexp.escape(name)}/ } x.should_not be_nil def x.to_s "Whit[#{name}]" end def x.inspect to_s end x end def admissible_sentinel_of(x) @depgraph.vertex?(x) ? x : whit_called("admissible_#{x.ref}") end def completed_sentinel_of(x) @depgraph.vertex?(x) ? x : whit_called("completed_#{x.ref}") 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 sentinel should depend on its admissible sentinel" do containers.each { |container| @depgraph.path_between(admissible_sentinel_of(container),completed_sentinel_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 sentinel" do containers.each { |container| contents_of(container).each { |leaf| @depgraph.should be_edge(admissible_sentinel_of(container),admissible_sentinel_of(leaf)) } } end # 2) completed_X depends on each on the contents of X # it "completed sentinels should depend on their container's contents" do containers.each { |container| contents_of(container).each { |leaf| @depgraph.should be_edge(completed_sentinel_of(leaf),completed_sentinel_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_sentinel_of(f),admissible_sentinel_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)", :if => (RUBY_VERSION[0,3] == '1.8' or YAML::ENGINE.syck?) 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/host_spec.rb b/spec/unit/ssl/host_spec.rb index 3f94407be..fda1baa37 100755 --- a/spec/unit/ssl/host_spec.rb +++ b/spec/unit/ssl/host_spec.rb @@ -1,863 +1,863 @@ #!/usr/bin/env rspec require 'spec_helper' require 'puppet/ssl/host' describe Puppet::SSL::Host do include PuppetSpec::Files before do Puppet::SSL::Host.indirection.terminus_class = :file # Get a safe temporary file dir = tmpdir("ssl_host_testing") Puppet.settings[:confdir] = dir Puppet.settings[:vardir] = dir Puppet.settings.use :main, :ssl @host = Puppet::SSL::Host.new("myname") end after do # Cleaned out any cached localhost instance. Puppet::SSL::Host.reset 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 allow to reset localhost" do previous_host = Puppet::SSL::Host.localhost Puppet::SSL::Host.reset Puppet::SSL::Host.localhost.should_not == previous_host 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 create a localhost cert if no cert is available and it is a CA with autosign and it is using DNS alt names", :unless => Puppet.features.microsoft_windows? do Puppet[:autosign] = true Puppet[:confdir] = tmpdir('conf') Puppet[:dns_alt_names] = "foo,bar,baz" ca = Puppet::SSL::CertificateAuthority.new Puppet::SSL::CertificateAuthority.stubs(:instance).returns ca localhost = Puppet::SSL::Host.localhost cert = localhost.certificate cert.should be_a(Puppet::SSL::Certificate) cert.subject_alt_names.should =~ %W[DNS:#{Puppet[:certname]} DNS:foo DNS:bar DNS:baz] end context "with dns_alt_names" do before :each do @key = stub('key content') key = stub('key', :generate => true, :content => @key) Puppet::SSL::Key.stubs(:new).returns key Puppet::SSL::Key.indirection.stubs(:save).with(key) @cr = stub('certificate request') Puppet::SSL::CertificateRequest.stubs(:new).returns @cr Puppet::SSL::CertificateRequest.indirection.stubs(:save).with(@cr) end describe "explicitly specified" do before :each do Puppet[:dns_alt_names] = 'one, two' end it "should not include subjectAltName if not the local node" do @cr.expects(:generate).with(@key, {}) Puppet::SSL::Host.new('not-the-' + Puppet[:certname]).generate end it "should include subjectAltName if I am a CA" do @cr.expects(:generate). with(@key, { :dns_alt_names => Puppet[:dns_alt_names] }) Puppet::SSL::Host.localhost end end describe "implicitly defaulted" do let(:ca) { stub('ca', :sign => nil) } before :each do Puppet[:dns_alt_names] = '' Puppet::SSL::CertificateAuthority.stubs(:instance).returns ca end it "should not include defaults if we're not the CA" do Puppet::SSL::CertificateAuthority.stubs(:ca?).returns false @cr.expects(:generate).with(@key, {}) Puppet::SSL::Host.localhost end it "should not include defaults if not the local node" do Puppet::SSL::CertificateAuthority.stubs(:ca?).returns true @cr.expects(:generate).with(@key, {}) Puppet::SSL::Host.new('not-the-' + Puppet[:certname]).generate end it "should not include defaults if we can't resolve our fqdn" do Puppet::SSL::CertificateAuthority.stubs(:ca?).returns true Facter.stubs(:value).with(:fqdn).returns nil @cr.expects(:generate).with(@key, {}) Puppet::SSL::Host.localhost end it "should provide defaults if we're bootstrapping the local master" do Puppet::SSL::CertificateAuthority.stubs(:ca?).returns true Facter.stubs(:value).with(:fqdn).returns 'web.foo.com' Facter.stubs(:value).with(:domain).returns 'foo.com' @cr.expects(:generate).with(@key, {:dns_alt_names => "puppet, web.foo.com, puppet.foo.com"}) Puppet::SSL::Host.localhost end end 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 verify its certificate matches its key" do Puppet::SSL::Host.new("foo").should respond_to(:validate_certificate_with_key) end it "should consider the certificate invalid if it cannot find a key" do host = Puppet::SSL::Host.new("foo") certificate = mock('cert', :fingerprint => 'DEADBEEF') host.expects(:certificate).twice.returns certificate host.expects(:key).returns nil lambda { host.validate_certificate_with_key }.should raise_error(Puppet::Error, "No private key with which to validate certificate with fingerprint: DEADBEEF") end it "should consider the certificate invalid if it cannot find a certificate" do host = Puppet::SSL::Host.new("foo") host.expects(:key).never host.expects(:certificate).returns nil lambda { host.validate_certificate_with_key }.should raise_error(Puppet::Error, "No certificate to validate.") 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, :fingerprint => 'DEADBEEF'} host.stubs(:key).returns key host.stubs(:certificate).returns certificate sslcert.expects(:check_private_key).with("private_key").returns false lambda { host.validate_certificate_with_key }.should raise_error(Puppet::Error, /DEADBEEF/) 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 lambda{ host.validate_certificate_with_key }.should_not raise_error 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(:validate_certificate_with_key) 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 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", :'fails_on_ruby_1.9.2' => true do + 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, true) @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) expect { @host.wait_for_cert(0) }.to exit_with 1 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) expect { @host.wait_for_cert(0) }.to exit_with 1 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", :unless => Puppet.features.microsoft_windows? do include PuppetSpec::Files before do Puppet[:vardir] = tmpdir("ssl_test_vardir") Puppet[:ssldir] = tmpdir("ssl_test_ssldir") # 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/transaction/event_spec.rb b/spec/unit/transaction/event_spec.rb index 5f7f367b4..ad5c00d76 100755 --- a/spec/unit/transaction/event_spec.rb +++ b/spec/unit/transaction/event_spec.rb @@ -1,128 +1,128 @@ #!/usr/bin/env rspec require 'spec_helper' require 'puppet/transaction/event' describe Puppet::Transaction::Event do include PuppetSpec::Files [:previous_value, :desired_value, :property, :resource, :name, :message, :file, :line, :tags, :audited].each do |attr| - it "should support #{attr}", :'fails_on_ruby_1.9.2' => true do + 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", :'fails_on_ruby_1.9.2' => true do + 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", :'fails_on_ruby_1.9.2' => true do + 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", :'fails_on_ruby_1.9.2' => true do + 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", :'fails_on_ruby_1.9.2' => true do + 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 => make_absolute("/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/type/augeas_spec.rb b/spec/unit/type/augeas_spec.rb index e80da9559..c8dc207f9 100755 --- a/spec/unit/type/augeas_spec.rb +++ b/spec/unit/type/augeas_spec.rb @@ -1,119 +1,119 @@ #!/usr/bin/env rspec require 'spec_helper' augeas = Puppet::Type.type(:augeas) describe augeas do - describe "when augeas is present", :if => Puppet.features.augeas?, :'fails_on_ruby_1.9.2' => true 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/file_spec.rb b/spec/unit/type/file_spec.rb index 5a2d07e69..97b49c37b 100755 --- a/spec/unit/type/file_spec.rb +++ b/spec/unit/type/file_spec.rb @@ -1,1522 +1,1522 @@ #!/usr/bin/env rspec require 'spec_helper' describe Puppet::Type.type(:file) do include PuppetSpec::Files let(:path) { tmpfile('file_testing') } let(:file) { described_class.new(:path => path, :catalog => catalog) } let(:provider) { file.provider } let(:catalog) { Puppet::Resource::Catalog.new } before do @real_posix = Puppet.features.posix? Puppet.features.stubs("posix?").returns(true) end describe "the path parameter" do describe "on POSIX systems", :if => Puppet.features.posix? do it "should remove trailing slashes" do file[:path] = "/foo/bar/baz/" file[:path].should == "/foo/bar/baz" end it "should remove double slashes" do file[:path] = "/foo/bar//baz" file[:path].should == "/foo/bar/baz" end it "should remove trailing double slashes" do file[:path] = "/foo/bar/baz//" file[:path].should == "/foo/bar/baz" end it "should leave a single slash alone" do file[:path] = "/" file[:path].should == "/" end it "should accept a double-slash at the start of the path" do expect { file[: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 Windows systems", :if => Puppet.features.microsoft_windows? do it "should remove trailing slashes" do file[:path] = "X:/foo/bar/baz/" file[:path].should == "X:/foo/bar/baz" end it "should remove double slashes" do file[:path] = "X:/foo/bar//baz" file[:path].should == "X:/foo/bar/baz" end it "should remove trailing double slashes" do file[:path] = "X:/foo/bar/baz//" file[:path].should == "X:/foo/bar/baz" end - it "should leave a drive letter with a slash alone", :'fails_on_ruby_1.9.2' => true do + it "should leave a drive letter with a slash alone" do file[:path] = "X:/" file[:path].should == "X:/" end - it "should not accept a drive letter without a slash", :'fails_on_ruby_1.9.2' => true do + it "should not accept a drive letter without a slash" do lambda { file[:path] = "X:" }.should raise_error(/File paths must be fully qualified/) end - describe "when using UNC filenames", :if => Puppet.features.microsoft_windows?, :'fails_on_ruby_1.9.2' => true do + describe "when using UNC filenames", :if => Puppet.features.microsoft_windows? do before :each do pending("UNC file paths not yet supported") end it "should remove trailing slashes" do file[:path] = "//server/foo/bar/baz/" file[:path].should == "//server/foo/bar/baz" end it "should remove double slashes" do file[:path] = "//server/foo/bar//baz" file[:path].should == "//server/foo/bar/baz" end it "should remove trailing double slashes" do file[:path] = "//server/foo/bar/baz//" file[:path].should == "//server/foo/bar/baz" end it "should remove a trailing slash from a sharename" do file[:path] = "//server/foo/" file[:path].should == "//server/foo" end it "should not modify a sharename" do file[:path] = "//server/foo" file[:path].should == "//server/foo" end end end end describe "the backup parameter" do [false, 'false', :false].each do |value| it "should disable backup if the value is #{value.inspect}" do file[:backup] = value file[:backup].should == false end end [true, 'true', '.puppet-bak'].each do |value| it "should use .puppet-bak if the value is #{value.inspect}" do file[:backup] = value file[:backup].should == '.puppet-bak' end end it "should use the provided value if it's any other string" do file[:backup] = "over there" file[:backup].should == "over there" end it "should fail if backup is set to anything else" do expect do file[:backup] = 97 end.to raise_error(Puppet::Error, /Invalid backup type 97/) end end describe "the recurse parameter" do it "should default to recursion being disabled" do file[:recurse].should be_false end [true, "true", 10, "inf", "remote"].each do |value| it "should consider #{value} to enable recursion" do file[:recurse] = value file[:recurse].should be_true end end [false, "false", 0].each do |value| it "should consider #{value} to disable recursion" do file[:recurse] = value file[:recurse].should be_false end end it "should warn if recurse is specified as a number" do Puppet.expects(:deprecation_warning).with("Setting recursion depth with the recurse parameter is now deprecated, please use recurselimit") file[:recurse] = 3 end end describe "the recurselimit parameter" do it "should accept integers" do file[:recurselimit] = 12 file[:recurselimit].should == 12 end it "should munge string numbers to number numbers" do file[:recurselimit] = '12' file[:recurselimit].should == 12 end it "should fail if given a non-number" do expect do file[:recurselimit] = 'twelve' end.to raise_error(Puppet::Error, /Invalid value "twelve"/) end end describe "the replace parameter" do [true, :true, :yes].each do |value| it "should consider #{value} to be true" do file[:replace] = value file[:replace].should == :true end end [false, :false, :no].each do |value| it "should consider #{value} to be false" do file[:replace] = value file[:replace].should == :false end end end describe "#[]" do it "should raise an exception" do expect do described_class['anything'] end.to raise_error("Global resource access is deprecated") end end describe ".instances" do it "should return an empty array" do described_class.instances.should == [] end end describe "#asuser" do before :each do # Mocha won't let me just stub SUIDManager.asuser to yield and return, # but it will do exactly that if we're not root. Puppet.features.stubs(:root?).returns false end it "should return the desired owner if they can write to the parent directory" do file[:owner] = 1001 FileTest.stubs(:writable?).with(File.dirname file[:path]).returns true file.asuser.should == 1001 end it "should return nil if the desired owner can't write to the parent directory" do file[:owner] = 1001 FileTest.stubs(:writable?).with(File.dirname file[:path]).returns false file.asuser.should == nil end it "should return nil if not managing owner" do file.asuser.should == nil end end describe "#bucket" do it "should return nil if backup is off" do file[:backup] = false file.bucket.should == nil end it "should not return a bucket if using a file extension for backup" do file[:backup] = '.backup' file.bucket.should == nil end it "should return the default filebucket if using the 'puppet' filebucket" do file[:backup] = 'puppet' bucket = stub('bucket') file.stubs(:default_bucket).returns bucket file.bucket.should == bucket end it "should fail if using a remote filebucket and no catalog exists" do file.catalog = nil file[:backup] = 'my_bucket' expect { file.bucket }.to raise_error(Puppet::Error, "Can not find filebucket for backups without a catalog") end it "should fail if the specified filebucket isn't in the catalog" do file[:backup] = 'my_bucket' expect { file.bucket }.to raise_error(Puppet::Error, "Could not find filebucket my_bucket specified in backup") end it "should use the specified filebucket if it is in the catalog" do file[:backup] = 'my_bucket' filebucket = Puppet::Type.type(:filebucket).new(:name => 'my_bucket') catalog.add_resource(filebucket) file.bucket.should == filebucket.bucket end end describe "#asuser" do before :each do # Mocha won't let me just stub SUIDManager.asuser to yield and return, # but it will do exactly that if we're not root. Puppet.features.stubs(:root?).returns false end it "should return the desired owner if they can write to the parent directory" do file[:owner] = 1001 FileTest.stubs(:writable?).with(File.dirname file[:path]).returns true file.asuser.should == 1001 end it "should return nil if the desired owner can't write to the parent directory" do file[:owner] = 1001 FileTest.stubs(:writable?).with(File.dirname file[:path]).returns false file.asuser.should == nil end it "should return nil if not managing owner" do file.asuser.should == nil end end describe "#bucket" do it "should return nil if backup is off" do file[:backup] = false file.bucket.should == nil end it "should return nil if using a file extension for backup" do file[:backup] = '.backup' file.bucket.should == nil end it "should return the default filebucket if using the 'puppet' filebucket" do file[:backup] = 'puppet' bucket = stub('bucket') file.stubs(:default_bucket).returns bucket file.bucket.should == bucket end it "should fail if using a remote filebucket and no catalog exists" do file.catalog = nil file[:backup] = 'my_bucket' expect { file.bucket }.to raise_error(Puppet::Error, "Can not find filebucket for backups without a catalog") end it "should fail if the specified filebucket isn't in the catalog" do file[:backup] = 'my_bucket' expect { file.bucket }.to raise_error(Puppet::Error, "Could not find filebucket my_bucket specified in backup") end it "should use the specified filebucket if it is in the catalog" do file[:backup] = 'my_bucket' filebucket = Puppet::Type.type(:filebucket).new(:name => 'my_bucket') catalog.add_resource(filebucket) file.bucket.should == filebucket.bucket end end describe "#exist?" do 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 end describe "#eval_generate" do before do @graph = stub 'graph', :add_edge => nil catalog.stubs(:relationship_graph).returns @graph end it "should recurse if recursion is enabled" do resource = stub('resource', :[] => 'resource') file.expects(:recurse).returns [resource] file[:recurse] = true file.eval_generate.should == [resource] end it "should not recurse if recursion is disabled" do file.expects(:recurse).never file[:recurse] = false file.eval_generate.should == [] end end describe "#ancestors" do it "should return the ancestors of the file, in ascending order" do file = described_class.new(:path => make_absolute("/tmp/foo/bar/baz/qux")) pieces = %W[#{make_absolute('/')} tmp foo bar baz] ancestors = file.ancestors ancestors.should_not be_empty ancestors.reverse.each_with_index do |path,i| path.should == File.join(*pieces[0..i]) end end end describe "#flush" do it "should flush all properties that respond to :flush" do file[:source] = File.expand_path(__FILE__) file.parameter(:source).expects(:flush) file.flush end it "should reset its stat reference" do FileUtils.touch(path) stat1 = file.stat file.stat.should equal(stat1) file.flush file.stat.should_not equal(stat1) end end describe "#initialize" do it "should remove a trailing slash from the title to create the path" do title = File.expand_path("/abc/\n\tdef/") file = described_class.new(:title => title) file[:path].should == title end it "should set a desired 'ensure' value if none is set and 'content' is set" do file = described_class.new(:path => path, :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 = described_class.new(:path => path, :target => File.expand_path(__FILE__)) file[:ensure].should == :symlink end end describe "#mark_children_for_purging" do it "should set each child's ensure to absent" do paths = %w[foo bar baz] children = paths.inject({}) do |children,child| children.merge child => described_class.new(:path => File.join(path, child), :ensure => :present) end file.mark_children_for_purging(children) children.length.should == 3 children.values.each do |child| child[:ensure].should == :absent end end it "should skip children which have a source" do child = described_class.new(:path => path, :ensure => :present, :source => File.expand_path(__FILE__)) file.mark_children_for_purging('foo' => child) child[:ensure].should == :present end end describe "#newchild" do it "should create a new resource relative to the parent" do child = file.newchild('bar') child.should be_a(described_class) child[:path].should == File.join(file[:path], 'bar') end { :ensure => :present, :recurse => true, :recurselimit => 5, :target => "some_target", :source => File.expand_path("some_source"), }.each do |param, value| it "should omit the #{param} parameter" do # Make a new file, because we have to set the param at initialization # or it wouldn't be copied regardless. file = described_class.new(:path => path, param => value) child = file.newchild('bar') child[param].should_not == value end end it "should copy all of the parent resource's 'should' values that were set at initialization" do parent = described_class.new(:path => path, :owner => 'root', :group => 'wheel') child = parent.newchild("my/path") child[:owner].should == 'root' child[:group].should == 'wheel' end it "should not copy default values to the new child" do child = file.newchild("my/path") child.original_parameters.should_not include(:backup) end it "should not copy values to the child which were set by the source" do source = File.expand_path(__FILE__) file[:source] = source metadata = stub 'metadata', :owner => "root", :group => "root", :mode => 0755, :ftype => "file", :checksum => "{md5}whatever", :source => source 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 describe "#purge?" do it "should return false if purge is not set" do file.must_not be_purge end it "should return true if purge is set to true" do file[:purge] = true file.must be_purge end it "should return false if purge is set to false" do file[:purge] = false file.must_not be_purge end end describe "#recurse" do before do file[:recurse] = true @metadata = Puppet::FileServing::Metadata end describe "and a source is set" do it "should pass the already-discovered resources to recurse_remote" do file[:source] = File.expand_path(__FILE__) 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 it "should use recurse_link" do file[:target] = File.expand_path(__FILE__) 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 is 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 mark each file for removal" do local = described_class.new(:path => path, :ensure => :present) file.expects(:recurse_local).returns("local" => local) file.recurse local[:ensure].should == :absent end it "should not remove files that exist in the remote repository" do file[:source] = File.expand_path(__FILE__) file.expects(:recurse_local).returns({}) remote = described_class.new(:path => path, :source => File.expand_path(__FILE__), :ensure => :present) file.expects(:recurse_remote).with { |hash| hash["remote"] = remote } file.recurse remote[:ensure].should_not == :absent end end end describe "#remove_less_specific_files" do it "should remove any nested files that are already in the catalog" do foo = described_class.new :path => File.join(file[:path], 'foo') bar = described_class.new :path => File.join(file[:path], 'bar') baz = described_class.new :path => File.join(file[:path], 'baz') catalog.add_resource(foo) catalog.add_resource(bar) file.remove_less_specific_files([foo, bar, baz]).should == [baz] end end describe "#remove_less_specific_files" do it "should remove any nested files that are already in the catalog" do foo = described_class.new :path => File.join(file[:path], 'foo') bar = described_class.new :path => File.join(file[:path], 'bar') baz = described_class.new :path => File.join(file[:path], 'baz') catalog.add_resource(foo) catalog.add_resource(bar) file.remove_less_specific_files([foo, bar, baz]).should == [baz] end end describe "#recurse?" do it "should be true if recurse is true" do file[:recurse] = true file.must be_recurse end it "should be true if recurse is remote" do file[:recurse] = :remote file.must be_recurse end it "should be false if recurse is false" do file[:recurse] = false file.must_not be_recurse end end describe "#recurse_link" 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.stubs(:perform_recursion).returns [@first, @second] file.recurse_link("first" => @resource, "second" => file) file[:ensure].should == :link file[:target].should == "/my/second" end it "should :ensure to :directory if the file is a directory" do file.stubs(:perform_recursion).returns [@first, @second] file.recurse_link("first" => file, "second" => @resource) file[:ensure].should == :directory end it "should return a hash with both created and existing resources with the relative paths as the hash keys" do file.expects(:perform_recursion).returns [@first, @second] file.stubs(:newchild).returns file file.recurse_link("second" => @resource).should == {"second" => @resource, "first" => file} end end describe "#recurse_local" 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 describe "#recurse_remote" do let(:my) { File.expand_path('/my') } 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(File.expand_path("/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(File.expand_path("/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 let(:sources) do h = {} %w{/a /b /c /d}.each do |key| h[key] = URI.unescape(Puppet::Util.path_to_uri(File.expand_path(key)).to_s) end h end 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(File.expand_path("/whatever"), :relative_path => "foobar") file[:source] = sources.keys.sort.map { |key| File.expand_path(key) } file.expects(:perform_recursion).with(sources['/a']).returns nil file.expects(:perform_recursion).with(sources['/b']).returns [] file.expects(:perform_recursion).with(sources['/c']).returns [data] file.expects(:perform_recursion).with(sources['/d']).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] = abs_path = %w{/a /b /c /d}.map {|f| File.expand_path(f) } file.stubs(:newchild).returns @resource one = [klass.new(abs_path[0], :relative_path => "a")] file.expects(:perform_recursion).with(sources['/a']).returns one file.expects(:newchild).with("a").returns @resource two = [klass.new(abs_path[1], :relative_path => "a"), klass.new(abs_path[1], :relative_path => "b")] file.expects(:perform_recursion).with(sources['/b']).returns two file.expects(:newchild).with("b").returns @resource three = [klass.new(abs_path[2], :relative_path => "a"), klass.new(abs_path[2], :relative_path => "c")] file.expects(:perform_recursion).with(sources['/c']).returns three file.expects(:newchild).with("c").returns @resource file.expects(:perform_recursion).with(sources['/d']).returns [] file.recurse_remote({}) end end end end describe "#perform_recursion" 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 describe "#remove_existing" do it "should do nothing if the file doesn't exist" do file.remove_existing(:file).should == nil end it "should fail if it can't backup the file" do file.stubs(:stat).returns stub('stat') file.stubs(:perform_backup).returns false expect { file.remove_existing(:file) }.to raise_error(Puppet::Error, /Could not back up; will not replace/) end it "should not do anything if the file is already the right type and not a link" do file.stubs(:stat).returns stub('stat', :ftype => 'file') file.remove_existing(:file).should == nil end it "should not remove directories and should not invalidate the stat unless force is set" do # Actually call stat to set @needs_stat to nil file.stat file.stubs(:stat).returns stub('stat', :ftype => 'directory') file.remove_existing(:file) file.instance_variable_get(:@stat).should == nil @logs.should be_any {|log| log.level == :notice and log.message =~ /Not removing directory; use 'force' to override/} end it "should remove a directory if force is set" do file[:force] = true file.stubs(:stat).returns stub('stat', :ftype => 'directory') FileUtils.expects(:rmtree).with(file[:path]) file.remove_existing(:file).should == true end it "should remove an existing file" do file.stubs(:perform_backup).returns true FileUtils.touch(path) file.remove_existing(:directory).should == true File.exists?(file[:path]).should == false end it "should remove an existing link", :unless => Puppet.features.microsoft_windows? do file.stubs(:perform_backup).returns true target = tmpfile('link_target') FileUtils.touch(target) FileUtils.symlink(target, path) file[:target] = target file.remove_existing(:directory).should == true File.exists?(file[:path]).should == false end it "should fail if the file is not a file, link, or directory" do file.stubs(:stat).returns stub('stat', :ftype => 'socket') expect { file.remove_existing(:file) }.to raise_error(Puppet::Error, /Could not back up files of type socket/) end it "should invalidate the existing stat of the file" do # Actually call stat to set @needs_stat to nil file.stat file.stubs(:stat).returns stub('stat', :ftype => 'file') File.stubs(:unlink) file.remove_existing(:directory).should == true file.instance_variable_get(:@stat).should == :needs_stat end end describe "#retrieve" do it "should copy the source values if the 'source' parameter is set" do file[:source] = File.expand_path('/foo/bar') file.parameter(:source).expects(:copy_source_values) file.retrieve end end describe "#should_be_file?" do 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 end describe "#stat", :unless => Puppet.features.microsoft_windows? do before do target = tmpfile('link_target') FileUtils.touch(target) FileUtils.symlink(target, path) file[:target] = target file[:links] = :manage # so we always use :lstat end it "should stat the target if it is following links" do file[:links] = :follow file.stat.ftype.should == 'file' end it "should stat the link if is it not following links" do file[:links] = :manage file.stat.ftype.should == 'link' end it "should return nil if the file does not exist" do file[:path] = '/foo/bar/baz/non-existent' file.stat.should be_nil end it "should return nil if the file cannot be stat'ed" do dir = tmpfile('link_test_dir') child = File.join(dir, 'some_file') Dir.mkdir(dir) File.chmod(0, dir) file[:path] = child file.stat.should be_nil # chmod it back so we can clean it up File.chmod(0777, dir) end it "should return the stat instance" do file.stat.should be_a(File::Stat) end it "should cache the stat instance" do file.stat.should equal(file.stat) 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[: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[: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 describe "#fail_if_checksum_is_wrong" do it "should fail if the checksum of the file doesn't match the expected one" do expect do file.instance_eval do parameter(:checksum).stubs(:sum_file).returns('wrong!!') fail_if_checksum_is_wrong(self[:path], 'anything!') end end.to raise_error(Puppet::Error, /File written to disk did not match checksum/) end it "should not fail if the checksum is correct" do file.instance_eval do parameter(:checksum).stubs(:sum_file).returns('anything!') fail_if_checksum_is_wrong(self[:path], 'anything!').should == nil end end it "should not fail if the checksum is absent" do file.instance_eval do parameter(:checksum).stubs(:sum_file).returns(nil) fail_if_checksum_is_wrong(self[:path], 'anything!').should == nil end end end describe "#write_content" do it "should delegate writing the file to the content property" do io = stub('io') file[:content] = "some content here" file.property(:content).expects(:write).with(io) file.send(:write_content, io) end end describe "#write_temporary_file?" do it "should be true if the file has specified content" do file[:content] = 'some content' file.send(:write_temporary_file?).should be_true end it "should be true if the file has specified source" do file[:source] = File.expand_path('/tmp/foo') file.send(:write_temporary_file?).should be_true end it "should be false if the file has neither content nor source" do file.send(:write_temporary_file?).should be_false end end describe "#property_fix" do { :mode => 0777, :owner => 'joeuser', :group => 'joeusers', :seluser => 'seluser', :selrole => 'selrole', :seltype => 'seltype', :selrange => 'selrange' }.each do |name,value| it "should sync the #{name} property if it's not in sync" do file[name] = value prop = file.property(name) prop.expects(:retrieve) prop.expects(:safe_insync?).returns false prop.expects(:sync) file.send(:property_fix) end end end describe "when autorequiring" do describe "target" do it "should require file resource when specified with the target property" do file = described_class.new(:path => File.expand_path("/foo"), :ensure => :directory) link = described_class.new(:path => File.expand_path("/bar"), :ensure => :symlink, :target => File.expand_path("/foo")) catalog.add_resource file catalog.add_resource link reqs = link.autorequire reqs.size.must == 1 reqs[0].source.must == file reqs[0].target.must == link end it "should require file resource when specified with the ensure property" do file = described_class.new(:path => File.expand_path("/foo"), :ensure => :directory) link = described_class.new(:path => File.expand_path("/bar"), :ensure => File.expand_path("/foo")) catalog.add_resource file catalog.add_resource link reqs = link.autorequire reqs.size.must == 1 reqs[0].source.must == file reqs[0].target.must == link end it "should not require target if target is not managed" do link = described_class.new(:path => File.expand_path('/foo'), :ensure => :symlink, :target => '/bar') catalog.add_resource link link.autorequire.size.should == 0 end end describe "directories" do it "should autorequire its parent directory" do dir = described_class.new(:path => File.dirname(path)) catalog.add_resource file catalog.add_resource dir reqs = file.autorequire reqs[0].source.must == dir reqs[0].target.must == file end it "should autorequire its nearest ancestor directory" do dir = described_class.new(:path => File.dirname(path)) grandparent = described_class.new(:path => File.dirname(File.dirname(path))) catalog.add_resource file catalog.add_resource dir catalog.add_resource grandparent reqs = file.autorequire reqs.length.must == 1 reqs[0].source.must == dir reqs[0].target.must == file end it "should not autorequire anything when there is no nearest ancestor directory" do catalog.add_resource file file.autorequire.should be_empty end it "should not autorequire its parent dir if its parent dir is itself" do file[:path] = File.expand_path('/') catalog.add_resource file file.autorequire.should be_empty end describe "on Windows systems", :if => Puppet.features.microsoft_windows? do describe "when using UNC filenames" do it "should autorequire its parent directory" do file[:path] = '//server/foo/bar/baz' dir = described_class.new(:path => "//server/foo/bar") catalog.add_resource file catalog.add_resource dir reqs = file.autorequire reqs[0].source.must == dir reqs[0].target.must == file end it "should autorequire its nearest ancestor directory" do file = described_class.new(:path => "//server/foo/bar/baz/qux") dir = described_class.new(:path => "//server/foo/bar/baz") grandparent = described_class.new(:path => "//server/foo/bar") catalog.add_resource file catalog.add_resource dir catalog.add_resource grandparent reqs = file.autorequire reqs.length.must == 1 reqs[0].source.must == dir reqs[0].target.must == file end it "should not autorequire anything when there is no nearest ancestor directory" do file = described_class.new(:path => "//server/foo/bar/baz/qux") catalog.add_resource file file.autorequire.should be_empty end it "should not autorequire its parent dir if its parent dir is itself" do file = described_class.new(:path => "//server/foo") catalog.add_resource file puts file.autorequire file.autorequire.should be_empty end end end end end describe "when managing links" do require 'tempfile' if @real_posix describe "on POSIX systems" do before do Dir.mkdir(path) @target = File.join(path, "target") @link = File.join(path, "link") File.open(@target, "w", 0644) { |f| f.puts "yayness" } File.symlink(@target, @link) file[:path] = @link file[:mode] = 0755 catalog.add_resource file 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. (File.stat(@target).mode & 007777).to_s(8).should == '644' end it "should be able to follow links" do file[:links] = :follow catalog.apply (File.stat(@target).mode & 007777).to_s(8).should == '755' 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 describe "when using source" do before do file[:source] = File.expand_path('/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 auditing" do before :each do # to prevent the catalog from trying to write state.yaml Puppet::Util::Storage.stubs(:store) end it "should not fail if creating a new file if group is not set" do file = described_class.new(:path => path, :audit => 'all', :content => 'content') catalog.add_resource(file) report = catalog.apply.report report.resource_statuses["File[#{path}]"].should_not be_failed File.read(path).should == 'content' end it "should not log errors if creating a new file with ensure present and no content" do file[:audit] = 'content' file[:ensure] = 'present' catalog.add_resource(file) catalog.apply File.should be_exist(path) @logs.should_not be_any {|l| l.level != :notice } end end describe "when specifying both source and checksum" do it 'should use the specified checksum when source is first' do file[:source] = File.expand_path('/foo') file[:checksum] = :md5lite file[:checksum].should == :md5lite end it 'should use the specified checksum when source is last' do file[:checksum] = :md5lite file[:source] = File.expand_path('/foo') file[:checksum].should == :md5lite end end describe "when validating" do [[:source, :target], [:source, :content], [:target, :content]].each do |prop1,prop2| it "should fail if both #{prop1} and #{prop2} are specified" do file[prop1] = prop1 == :source ? File.expand_path("prop1 value") : "prop1 value" file[prop2] = "prop2 value" expect do file.validate end.to raise_error(Puppet::Error, /You cannot specify more than one of/) end end end end diff --git a/spec/unit/type/group_spec.rb b/spec/unit/type/group_spec.rb index a5486dd84..e7da6abf6 100755 --- a/spec/unit/type/group_spec.rb +++ b/spec/unit/type/group_spec.rb @@ -1,63 +1,63 @@ #!/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 it "should have a system_groups feature" do @class.provider_feature(:system_groups).should_not be_nil 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 - it "should have a boolean method for determining if duplicates are allowed", :'fails_on_ruby_1.9.2' => true do + it "should have a boolean method for determining if duplicates are allowed" do @class.new(:name => "foo").should respond_to "allowdupe?" end - it "should have a boolean method for determining if system groups are allowed", :'fails_on_ruby_1.9.2' => true do + it "should have a boolean method for determining if system groups are allowed" do @class.new(:name => "foo").should respond_to "system?" 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/resources_spec.rb b/spec/unit/type/resources_spec.rb index 652a6e8b7..ca2ffdd1f 100755 --- a/spec/unit/type/resources_spec.rb +++ b/spec/unit/type/resources_spec.rb @@ -1,101 +1,101 @@ #!/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", :'fails_on_ruby_1.9.2' => true do + 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 => "#{File.expand_path('/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 151c5cc19..c945b4b3a 100755 --- a/spec/unit/type/schedule_spec.rb +++ b/spec/unit/type/schedule_spec.rb @@ -1,425 +1,425 @@ #!/usr/bin/env rspec require 'spec_helper' module ScheduleTesting 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 apply to device" do @schedule.must be_appliable_to_device end it "should apply to host" do @schedule.must be_appliable_to_host end it "should default to :distance for period-matching" do @schedule[:periodmatch].must == :distance end it "should default to a :repeat of 1" do @schedule[:repeat].must == 1 end it "should never match when the period is :never" do @schedule[:period] = :never @schedule.must_not be_match 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 }.must 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 }.must be_instance_of(Puppet::Type.type(:schedule)) end end describe Puppet::Type.type(:schedule), "when matching ranges" do include ScheduleTesting before do Time.stubs(:now).returns(Time.local(2011, "may", 23, 11, 0, 0)) end it "should match when the start time is before the current time and the end time is after the current time" do @schedule[:range] = "10:59:50 - 11:00:10" @schedule.must be_match end it "should not match when the start time is after the current time" do @schedule[:range] = "11:00:05 - 11:00:10" @schedule.must_not be_match end it "should not match when the end time is previous to the current time" do @schedule[:range] = "10:59:50 - 10:59:55" @schedule.must_not be_match end it "should throw an error if the upper limit is less than the lower limit" do pending "bug #7639" @schedule[:range] = "01:02:03 - 01:00:00" @schedule.must_throw Puppet::Error end it "should not match the current time fails between an array of ranges" do @schedule[:range] = ["4-6", "20-23"] @schedule.must_not be_match end it "should match the lower array of ranges" do @schedule[:range] = ["9-11", "14-16"] @schedule.must be_match end it "should match the upper array of ranges" do @schedule[:range] = ["4-6", "11-12"] @schedule.must be_match end end - describe Puppet::Type.type(:schedule), "when matching hourly by distance", :'fails_on_ruby_1.9.2' => true do + describe Puppet::Type.type(:schedule), "when matching hourly by distance" do include ScheduleTesting before do @schedule[:period] = :hourly @schedule[:periodmatch] = :distance Time.stubs(:now).returns(Time.local(2011, "may", 23, 11, 0, 0)) end it "should match when the previous time was an hour ago" do @schedule.must be_match(hour("-", 1)) end it "should not match when the previous time was now" do @schedule.must_not be_match(Time.now) end it "should not match when the previous time was 59 minutes ago" do @schedule.must_not be_match(min("-", 59)) end end - describe Puppet::Type.type(:schedule), "when matching daily by distance", :'fails_on_ruby_1.9.2' => true do + describe Puppet::Type.type(:schedule), "when matching daily by distance" do include ScheduleTesting before do @schedule[:period] = :daily @schedule[:periodmatch] = :distance Time.stubs(:now).returns(Time.local(2011, "may", 23, 11, 0, 0)) end it "should match when the previous time was one day ago" do @schedule.must be_match(day("-", 1)) end it "should not match when the previous time is now" do @schedule.must_not be_match(Time.now) end it "should not match when the previous time was 23 hours ago" do @schedule.must_not be_match(hour("-", 23)) end end - describe Puppet::Type.type(:schedule), "when matching weekly by distance", :'fails_on_ruby_1.9.2' => true do + describe Puppet::Type.type(:schedule), "when matching weekly by distance" do include ScheduleTesting before do @schedule[:period] = :weekly @schedule[:periodmatch] = :distance Time.stubs(:now).returns(Time.local(2011, "may", 23, 11, 0, 0)) end it "should match when the previous time was seven days ago" do @schedule.must be_match(day("-", 7)) end it "should not match when the previous time was now" do @schedule.must_not be_match(Time.now) end it "should not match when the previous time was six days ago" do @schedule.must_not be_match(day("-", 6)) end end - describe Puppet::Type.type(:schedule), "when matching monthly by distance", :'fails_on_ruby_1.9.2' => true do + describe Puppet::Type.type(:schedule), "when matching monthly by distance" do include ScheduleTesting before do @schedule[:period] = :monthly @schedule[:periodmatch] = :distance Time.stubs(:now).returns(Time.local(2011, "may", 23, 11, 0, 0)) end it "should match when the previous time was 32 days ago" do @schedule.must be_match(day("-", 32)) end it "should not match when the previous time was now" do @schedule.must_not be_match(Time.now) end it "should not match when the previous time was 27 days ago" do @schedule.must_not be_match(day("-", 27)) end end - describe Puppet::Type.type(:schedule), "when matching hourly by number", :'fails_on_ruby_1.9.2' => true do + 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.must be_match(previous) 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.must_not be_match(previous) end end - describe Puppet::Type.type(:schedule), "when matching daily by number", :'fails_on_ruby_1.9.2' => true do + 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.must be_match(previous) 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.must_not be_match(previous) end end - describe Puppet::Type.type(:schedule), "when matching weekly by number", :'fails_on_ruby_1.9.2' => true do + 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.must be_match(previous) 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.must_not be_match(previous) end end - describe Puppet::Type.type(:schedule), "when matching monthly by number", :'fails_on_ruby_1.9.2' => true do + 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.must be_match(previous) 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.must_not be_match(previous) end end - describe Puppet::Type.type(:schedule), "when matching with a repeat greater than one", :'fails_on_ruby_1.9.2' => true do + describe Puppet::Type.type(:schedule), "when matching with a repeat greater than one" do include ScheduleTesting before do @schedule[:period] = :daily @schedule[:repeat] = 2 Time.stubs(:now).returns(Time.local(2011, "may", 23, 11, 0, 0)) end it "should fail if the periodmatch is 'number'" do @schedule[:periodmatch] = :number proc { @schedule[:repeat] = 2 }.must 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.must be_match(previous) 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.must_not be_match(previous) end end describe Puppet::Type.type(:schedule), "when matching days of the week" do include ScheduleTesting before do # 2011-05-23 is a Monday Time.stubs(:now).returns(Time.local(2011, "may", 23, 11, 0, 0)) end it "should raise an error if the weekday is 'Someday'" do proc { @schedule[:weekday] = "Someday" }.should raise_error(Puppet::Error) end it "should raise an error if the weekday is '7'" do proc { @schedule[:weekday] = "7" }.should raise_error(Puppet::Error) end it "should accept all full weekday names as valid values" do proc { @schedule[:weekday] = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'] }.should_not raise_error end it "should accept all short weekday names as valid values" do proc { @schedule[:weekday] = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'] }.should_not raise_error end it "should match if the weekday is 'Monday'" do @schedule[:weekday] = "Monday" @schedule.match?.should be_true end it "should match if the weekday is 'Mon'" do @schedule[:weekday] = "Mon" @schedule.match?.should be_true end it "should match if the weekday is '1'" do @schedule[:weekday] = "1" @schedule.match?.should be_true end it "should not match if the weekday is Tuesday" do @schedule[:weekday] = "Tuesday" @schedule.should_not be_match end it "should match if weekday is ['Sun', 'Mon']" do @schedule[:weekday] = ["Sun", "Mon"] @schedule.match?.should be_true end it "should not match if weekday is ['Sun', 'Tue']" do @schedule[:weekday] = ["Sun", "Tue"] @schedule.should_not be_match end it "should match if the weekday is 'Monday'" do @schedule[:weekday] = "Monday" @schedule.match?.should be_true end it "should match if the weekday is 'Mon'" do @schedule[:weekday] = "Mon" @schedule.match?.should be_true end it "should match if the weekday is '1'" do @schedule[:weekday] = "1" @schedule.match?.should be_true end it "should not match if the weekday is Tuesday" do @schedule[:weekday] = "Tuesday" @schedule.should_not be_match end it "should match if weekday is ['Sun', 'Mon']" do @schedule[:weekday] = ["Sun", "Mon"] @schedule.match?.should be_true end end end diff --git a/spec/unit/util/autoload_spec.rb b/spec/unit/util/autoload_spec.rb index 98b137995..8fbdfadb5 100755 --- a/spec/unit/util/autoload_spec.rb +++ b/spec/unit/util/autoload_spec.rb @@ -1,222 +1,222 @@ #!/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" @loaded = {} @autoload.class.stubs(:loaded).returns(@loaded) end describe "when building the search path" do before :each do ## modulepath/libdir can't be used until after app settings are initialized, so we need to simulate that: Puppet.settings.expects(:app_defaults_initialized?).returns(true).at_least_once @dira = File.expand_path('/a') @dirb = File.expand_path('/b') @dirc = File.expand_path('/c') end 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 "#{@dira}#{File::PATH_SEPARATOR}#{@dirb}#{File::PATH_SEPARATOR}#{@dirc}" Dir.expects(:entries).with(@dira).returns %w{one two} Dir.expects(:entries).with(@dirb).returns %w{one two} FileTest.stubs(:directory?).returns false FileTest.expects(:directory?).with(@dira).returns true FileTest.expects(:directory?).with(@dirb).returns true ["#{@dira}/one/plugins", "#{@dira}/two/lib", "#{@dirb}/one/plugins", "#{@dirb}/two/lib"].each do |d| FileTest.expects(:directory?).with(d).returns true end @autoload.class.module_directories.should == ["#{@dira}/one/plugins", "#{@dira}/two/lib", "#{@dirb}/one/plugins", "#{@dirb}/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 @dira Dir.expects(:entries).with(@dira).returns %w{. ..} FileTest.expects(:directory?).with(@dira).returns true FileTest.expects(:directory?).with("#{@dira}/./lib").never FileTest.expects(:directory?).with("#{@dira}/./plugins").never FileTest.expects(:directory?).with("#{@dira}/../lib").never FileTest.expects(:directory?).with("#{@dira}/../plugins").never @autoload.class.module_directories end it "should include the module directories, the Puppet libdir, and all of the Ruby load directories" do Puppet[:libdir] = %w{/libdir1 /lib/dir/two /third/lib/dir}.join(File::PATH_SEPARATOR) @autoload.class.expects(:module_directories).returns %w{/one /two} @autoload.class.search_directories.should == %w{/one /two} + Puppet[:libdir].split(File::PATH_SEPARATOR) + $LOAD_PATH end end describe "when loading a file" do before do @autoload.class.stubs(:search_directories).returns %w{/a} FileTest.stubs(:directory?).returns true @time_a = Time.utc(2010, 'jan', 1, 6, 30) File.stubs(:mtime).returns @time_a end [RuntimeError, LoadError, SyntaxError].each do |error| it "should die with Puppet::Error if a #{error.to_s} exception is thrown" do File.stubs(: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 autoloader" do File.stubs(:exist?).returns true Kernel.stubs(:load) @autoload.load("myfile") @autoload.class.loaded?("tmp/myfile.rb").should be $LOADED_FEATURES.delete("tmp/myfile.rb") end it "should register loaded files with the main loaded file list so they are not reloaded by ruby" do File.stubs(:exist?).returns true Kernel.stubs(:load) @autoload.load("myfile") $LOADED_FEATURES.should be_include("tmp/myfile.rb") $LOADED_FEATURES.delete("tmp/myfile.rb") end it "should load the first file in the searchpath" do @autoload.stubs(:search_directories).returns %w{/a /b} FileTest.stubs(:directory?).returns true File.stubs(:exist?).returns true Kernel.expects(:load).with("/a/tmp/myfile.rb", optionally(anything)) @autoload.load("myfile") $LOADED_FEATURES.delete("tmp/myfile.rb") end it "should treat equivalent paths to a loaded file as loaded" do File.stubs(:exist?).returns true Kernel.stubs(:load) @autoload.load("myfile") @autoload.class.loaded?("tmp/myfile").should be @autoload.class.loaded?("tmp/./myfile.rb").should be @autoload.class.loaded?("./tmp/myfile.rb").should be @autoload.class.loaded?("tmp/../tmp/myfile.rb").should be $LOADED_FEATURES.delete("tmp/myfile.rb") end end describe "when loading all files" do before do @autoload.class.stubs(:search_directories).returns %w{/a} FileTest.stubs(:directory?).returns true Dir.stubs(:glob).returns ["/a/foo/file.rb"] File.stubs(:exist?).returns true @time_a = Time.utc(2010, 'jan', 1, 6, 30) File.stubs(:mtime).returns @time_a @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", :'fails_on_ruby_1.9.2' => true do + it "should die an if a #{error.to_s} exception is thrown" do Kernel.expects(:load).raises error lambda { @autoload.loadall }.should raise_error(Puppet::Error) end end - it "should require the full path to the file", :'fails_on_ruby_1.9.2' => true do + it "should require the full path to the file" do Kernel.expects(:load).with("/a/foo/file.rb", optionally(anything)) @autoload.loadall end end describe "when reloading files" do before :each do @file_a = "/a/file.rb" @file_b = "/b/file.rb" @first_time = Time.utc(2010, 'jan', 1, 6, 30) @second_time = @first_time + 60 end after :each do $LOADED_FEATURES.delete("a/file.rb") $LOADED_FEATURES.delete("b/file.rb") end describe "in one directory" do before :each do @autoload.class.stubs(:search_directories).returns %w{/a} File.expects(:mtime).with(@file_a).returns(@first_time) @autoload.class.mark_loaded("file", @file_a) end it "should reload if mtime changes" do File.stubs(:mtime).with(@file_a).returns(@first_time + 60) File.stubs(:exist?).with(@file_a).returns true Kernel.expects(:load).with(@file_a, optionally(anything)) @autoload.class.reload_changed end it "should do nothing if the file is deleted" do File.stubs(:mtime).with(@file_a).raises(Errno::ENOENT) File.stubs(:exist?).with(@file_a).returns false Kernel.expects(:load).never @autoload.class.reload_changed end end describe "in two directories" do before :each do @autoload.class.stubs(:search_directories).returns %w{/a /b} end it "should load b/file when a/file is deleted" do File.expects(:mtime).with(@file_a).returns(@first_time) @autoload.class.mark_loaded("file", @file_a) File.stubs(:mtime).with(@file_a).raises(Errno::ENOENT) File.stubs(:exist?).with(@file_a).returns false File.stubs(:exist?).with(@file_b).returns true File.stubs(:mtime).with(@file_b).returns @first_time Kernel.expects(:load).with(@file_b, optionally(anything)) @autoload.class.reload_changed @autoload.class.send(:loaded)["file"].should == [@file_b, @first_time] end it "should load a/file when b/file is loaded and a/file is created" do File.stubs(:mtime).with(@file_b).returns @first_time File.stubs(:exist?).with(@file_b).returns true @autoload.class.mark_loaded("file", @file_b) File.stubs(:mtime).with(@file_a).returns @first_time File.stubs(:exist?).with(@file_a).returns true Kernel.expects(:load).with(@file_a, optionally(anything)) @autoload.class.reload_changed @autoload.class.send(:loaded)["file"].should == [@file_a, @first_time] end end end end diff --git a/spec/unit/util/log_spec.rb b/spec/unit/util/log_spec.rb index 77f1aa342..a74f768b2 100755 --- a/spec/unit/util/log_spec.rb +++ b/spec/unit/util/log_spec.rb @@ -1,259 +1,259 @@ #!/usr/bin/env rspec require 'spec_helper' require 'puppet/util/log' describe Puppet::Util::Log do include PuppetSpec::Files 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 ".setup_default" do it "should default to :syslog" do Puppet.features.stubs(:syslog?).returns(true) Puppet::Util::Log.expects(:newdestination).with(:syslog) Puppet::Util::Log.setup_default end it "should fall back to :file" do Puppet.features.stubs(:syslog?).returns(false) Puppet::Util::Log.expects(:newdestination).with(Puppet[:puppetdlog]) Puppet::Util::Log.setup_default end 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 Puppet::Util::Log::DestSyslog do before do @syslog = Puppet::Util::Log::DestSyslog.new 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 it "should not create unsuitable log destinations" do Puppet.features.stubs(:syslog?).returns(false) Puppet::Util::Log::DestSyslog.expects(:suitable?) Puppet::Util::Log::DestSyslog.expects(:new).never Puppet::Util::Log.newdestination(:syslog) 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 => make_absolute("/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 => make_absolute("/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", :'fails_on_ruby_1.9.2' => true do + 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 == [:@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/network_device/cisco/device_spec.rb b/spec/unit/util/network_device/cisco/device_spec.rb index 182d9ee71..cb2d161e3 100755 --- a/spec/unit/util/network_device/cisco/device_spec.rb +++ b/spec/unit/util/network_device/cisco/device_spec.rb @@ -1,408 +1,408 @@ #!/usr/bin/env rspec require '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" => "GigabitEthernet1", "Te2" => "TenGigabitEthernet2", "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}", :'fails_on_ruby_1.9.2' => true do + 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", :'fails_on_ruby_1.9.2' => true do + 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 describe "when finding device facts" do it "should delegate to the cisco facts entity" do facts = stub 'facts' Puppet::Util::NetworkDevice::Cisco::Facts.expects(:new).returns(facts) facts.expects(:retrieve).returns(:facts) @cisco.facts.should == :facts end end end diff --git a/spec/unit/util/network_device/transport/ssh_spec.rb b/spec/unit/util/network_device/transport/ssh_spec.rb index 04a86ba3f..d3e6b643b 100755 --- a/spec/unit/util/network_device/transport/ssh_spec.rb +++ b/spec/unit/util/network_device/transport/ssh_spec.rb @@ -1,218 +1,218 @@ #!/usr/bin/env rspec require 'spec_helper' require 'puppet/util/network_device/transport/ssh' -describe Puppet::Util::NetworkDevice::Transport::Ssh, :if => Puppet.features.ssh?, :'fails_on_ruby_1.9.2' => true do +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 it "should raise a Puppet::Error when encountering an authentication failure" do Net::SSH.expects(:start).raises Net::SSH::AuthenticationFailed @transport.host = "localhost" @transport.user = "user" lambda { @transport.connect }.should raise_error Puppet::Error 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/queue/stomp_spec.rb b/spec/unit/util/queue/stomp_spec.rb index 7730ab7cb..c4dc525ca 100755 --- a/spec/unit/util/queue/stomp_spec.rb +++ b/spec/unit/util/queue/stomp_spec.rb @@ -1,140 +1,140 @@ #!/usr/bin/env rspec require 'spec_helper' require 'puppet/util/queue' -describe Puppet::Util::Queue, :if => Puppet.features.stomp?, :'fails_on_ruby_1.9.2' => true do +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?, :'fails_on_ruby_1.9.2' => true do +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", :publish => true) 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", :publish => true) 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 publishing a message" do before do @client = stub 'client', :publish => true Stomp::Client.stubs(:new).returns @client @queue = Puppet::Util::Queue::Stomp.new end it "should publish it to the queue client instance" do @client.expects(:publish).with { |queue, msg, options| msg == "Smite!" } @queue.publish_message('fooqueue', 'Smite!') end it "should publish it to the transformed queue name" do @client.expects(:publish).with { |queue, msg, options| queue == "/queue/fooqueue" } @queue.publish_message('fooqueue', 'Smite!') end it "should publish it as a persistent message" do @client.expects(:publish).with { |queue, msg, options| options[:persistent] == true } @queue.publish_message('fooqueue', 'Smite!') end it "should use send when the gem does not support publish" do Stomp::Client.stubs(:new).returns(stub('client', :send => true)) Puppet::Util::Queue::Stomp.new.publish_message('fooqueue', 'Smite!') end end describe "when subscribing to a queue" do before do @client = stub 'client', :acknowledge => true, :publish => 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