diff --git a/lib/puppet/provider/service/gentoo.rb b/lib/puppet/provider/service/gentoo.rb index 8928d4459..4beb9ea6c 100644 --- a/lib/puppet/provider/service/gentoo.rb +++ b/lib/puppet/provider/service/gentoo.rb @@ -1,51 +1,56 @@ # Manage gentoo services. Start/stop is the same as InitSvc, but enable/disable # is special. Puppet::Type.type(:service).provide :gentoo, :parent => :init do desc <<-EOT Gentoo's form of `init`-style service management. Uses `rc-update` for service enabling and disabling. EOT commands :update => "/sbin/rc-update" confine :operatingsystem => :gentoo defaultfor :operatingsystem => :gentoo def self.defpath superclass.defpath end + def self.instances + # this exclude list was found with grep -L '\/sbin\/runscript' /etc/init.d/* + self.get_services(self.defpath, ['functions.sh', 'reboot.sh', 'shutdown.sh']) + end + def disable output = update :del, @resource[:name], :default rescue Puppet::ExecutionFailure raise Puppet::Error, "Could not disable #{self.name}: #{output}" end def enabled? begin output = update :show rescue Puppet::ExecutionFailure return :false end line = output.split(/\n/).find { |l| l.include?(@resource[:name]) } return :false unless line # If it's enabled then it will print output showing service | runlevel if output =~ /^\s*#{@resource[:name]}\s*\|\s*(boot|default)/ return :true else return :false end end def enable output = update :add, @resource[:name], :default rescue Puppet::ExecutionFailure raise Puppet::Error, "Could not enable #{self.name}: #{output}" end end diff --git a/lib/puppet/provider/service/init.rb b/lib/puppet/provider/service/init.rb index 2a54db24f..902cb18c6 100755 --- a/lib/puppet/provider/service/init.rb +++ b/lib/puppet/provider/service/init.rb @@ -1,136 +1,134 @@ # The standard init-based service type. Many other service types are # customizations of this module. Puppet::Type.type(:service).provide :init, :parent => :base do desc "Standard `init`-style service management." - class << self - attr_accessor :defpath - end - - case Facter["operatingsystem"].value - when "FreeBSD" - @defpath = ["/etc/rc.d", "/usr/local/etc/rc.d"] - when "HP-UX" - @defpath = "/sbin/init.d" - when "Archlinux" - @defpath = "/etc/rc.d" - else - @defpath = "/etc/init.d" + def self.defpath + case Facter.value(:operatingsystem) + when "FreeBSD" + ["/etc/rc.d", "/usr/local/etc/rc.d"] + when "HP-UX" + "/sbin/init.d" + when "Archlinux" + "/etc/rc.d" + else + "/etc/init.d" + end end # We can't confine this here, because the init path can be overridden. - #confine :exists => @defpath + #confine :exists => defpath # List all services of this type. def self.instances get_services(self.defpath) end def self.get_services(defpath, exclude=[]) defpath = [defpath] unless defpath.is_a? Array instances = [] defpath.each do |path| unless FileTest.directory?(path) Puppet.debug "Service path #{path} does not exist" next end check = [:ensure] check << :enable if public_method_defined? :enabled? Dir.entries(path).each do |name| fullpath = File.join(path, name) next if name =~ /^\./ next if exclude.include? name next if not FileTest.executable?(fullpath) instances << new(:name => name, :path => path, :hasstatus => true) end end instances end # Mark that our init script supports 'status' commands. def hasstatus=(value) case value when true, "true"; @parameters[:hasstatus] = true when false, "false"; @parameters[:hasstatus] = false else raise Puppet::Error, "Invalid 'hasstatus' value #{value.inspect}" end end # Where is our init script? def initscript @initscript ||= self.search(@resource[:name]) end def paths @paths ||= @resource[:path].find_all do |path| if File.directory?(path) true else if File.exist?(path) and ! File.directory?(path) self.debug "Search path #{path} is not a directory" else self.debug "Search path #{path} does not exist" end false end end end def search(name) paths.each { |path| fqname = File.join(path,name) begin stat = File.stat(fqname) rescue # should probably rescue specific errors... self.debug("Could not find #{name} in #{path}") next end # if we've gotten this far, we found a valid script return fqname } paths.each { |path| fqname_sh = File.join(path,"#{name}.sh") begin stat = File.stat(fqname_sh) rescue # should probably rescue specific errors... self.debug("Could not find #{name}.sh in #{path}") next end # if we've gotten this far, we found a valid script return fqname_sh } raise Puppet::Error, "Could not find init script for '#{name}'" end # The start command is just the init scriptwith 'start'. def startcmd [initscript, :start] end # The stop command is just the init script with 'stop'. def stopcmd [initscript, :stop] end def restartcmd (@resource[:hasrestart] == :true) && [initscript, :restart] end # If it was specified that the init script has a 'status' command, then # we just return that; otherwise, we return false, which causes it to # fallback to other mechanisms. def statuscmd (@resource[:hasstatus] == :true) && [initscript, :status] end end diff --git a/spec/fixtures/unit/provider/service/gentoo/rc_update_show b/spec/fixtures/unit/provider/service/gentoo/rc_update_show new file mode 100644 index 000000000..6dcca3518 --- /dev/null +++ b/spec/fixtures/unit/provider/service/gentoo/rc_update_show @@ -0,0 +1,30 @@ + alsasound | default + bootmisc | boot + devfs | sysinit + dmcrypt | boot + dmesg | sysinit + fsck | boot + hostname | boot + hwclock | boot + keymaps | boot + killprocs | shutdown + local | default + localmount | boot + lvm | boot + modules | boot + mount-ro | shutdown + mtab | boot + net.lo | boot + netmount | default + procfs | boot + root | boot + rsyslog | boot + savecache | shutdown + swap | boot + swapfiles | boot + sysctl | boot + termencoding | boot + udev | sysinit + udev-postmount | default + urandom | boot + xdm | default diff --git a/spec/integration/network/server/mongrel_spec.rb b/spec/integration/network/server/mongrel_spec.rb index 0c6bd5b00..a92ba83a1 100755 --- a/spec/integration/network/server/mongrel_spec.rb +++ b/spec/integration/network/server/mongrel_spec.rb @@ -1,58 +1,70 @@ #!/usr/bin/env rspec require 'spec_helper' require 'puppet/network/server' -require 'socket' +require 'net/http' describe Puppet::Network::Server, :'fails_on_ruby_1.9.2' => true 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 => 34346, :handlers => [ :node ] } + @params = { :port => port, :handlers => [ :node ] } @server = Puppet::Network::Server.new(@params) end - after { Puppet.settings.clear } + 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 - lambda { TCPSocket.new('127.0.0.1', 34346) }.should_not raise_error + 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 - lambda { TCPSocket.new('127.0.0.1', 34346) }.should raise_error(Errno::ECONNREFUSED) + expect { Net::HTTP.get('127.0.0.1', '/', port) }. + should raise_error Errno::ECONNREFUSED end end - - after :each do - @server.unlisten if @server.listening? - end end end diff --git a/spec/integration/network/server/webrick_spec.rb b/spec/integration/network/server/webrick_spec.rb index 7365462d3..0f31855b2 100755 --- a/spec/integration/network/server/webrick_spec.rb +++ b/spec/integration/network/server/webrick_spec.rb @@ -1,83 +1,90 @@ #!/usr/bin/env rspec require 'spec_helper' require 'puppet/network/server' require 'puppet/ssl/certificate_authority' require 'socket' describe Puppet::Network::Server, :unless => Puppet.features.microsoft_windows? do include PuppetSpec::Files + # This reduces the odds of conflicting port numbers between concurrent runs + # of the suite on the same machine dramatically. + def port + 20000 + ($$ % 40000) + end + describe "when using webrick" do before :each do Puppet[:servertype] = 'webrick' Puppet[:server] = '127.0.0.1' - @params = { :port => 34343, :handlers => [ :node ], :xmlrpc_handlers => [ :status ] } + @params = { :port => port, :handlers => [ :node ] } # Get a safe temporary file dir = tmpdir("webrick_integration_testing") Puppet.settings[:confdir] = dir Puppet.settings[:vardir] = dir + Puppet.settings[:logdir] = dir Puppet.settings[:group] = Process.gid Puppet::SSL::Host.ca_location = :local ca = Puppet::SSL::CertificateAuthority.new ca.generate(Puppet[:certname]) unless Puppet::SSL::Certificate.indirection.find(Puppet[:certname]) end after do Puppet.settings.clear Puppet::SSL::Host.ca_location = :none end describe "before listening" do it "should not be reachable at the specified address and port" do - lambda { TCPSocket.new('127.0.0.1', 34343) }.should raise_error + lambda { TCPSocket.new('127.0.0.1', port) }.should raise_error end end describe "when listening" do it "should be reachable on the specified address and port" do - @server = Puppet::Network::Server.new(@params.merge(:port => 34343)) + @server = Puppet::Network::Server.new(@params.merge(:port => port)) @server.listen - lambda { TCPSocket.new('127.0.0.1', 34343) }.should_not raise_error + lambda { TCPSocket.new('127.0.0.1', port) }.should_not raise_error end it "should default to '0.0.0.0' as its bind address" do Puppet.settings.clear Puppet[:servertype] = 'webrick' Puppet[:bindaddress].should == '0.0.0.0' end it "should use any specified bind address" do Puppet[:bindaddress] = "127.0.0.1" - @server = Puppet::Network::Server.new(@params.merge(:port => 34343)) + @server = Puppet::Network::Server.new(@params.merge(:port => port)) @server.stubs(:unlisten) # we're breaking listening internally, so we have to keep it from unlistening @server.send(:http_server).expects(:listen).with { |args| args[:address] == "127.0.0.1" } @server.listen end it "should not allow multiple servers to listen on the same address and port" do - @server = Puppet::Network::Server.new(@params.merge(:port => 34343)) + @server = Puppet::Network::Server.new(@params.merge(:port => port)) @server.listen - @server2 = Puppet::Network::Server.new(@params.merge(:port => 34343)) + @server2 = Puppet::Network::Server.new(@params.merge(:port => port)) lambda { @server2.listen }.should raise_error end after :each do @server.unlisten if @server && @server.listening? end end describe "after unlistening" do it "should not be reachable on the port and address assigned" do - @server = Puppet::Network::Server.new(@params.merge(:port => 34343)) + @server = Puppet::Network::Server.new(@params.merge(:port => port)) @server.listen @server.unlisten - lambda { TCPSocket.new('127.0.0.1', 34343) }.should raise_error(Errno::ECONNREFUSED) + lambda { TCPSocket.new('127.0.0.1', port) }.should raise_error(Errno::ECONNREFUSED) end end end end diff --git a/spec/integration/provider/service/init_spec.rb b/spec/integration/provider/service/init_spec.rb index 483507d5f..877c01171 100755 --- a/spec/integration/provider/service/init_spec.rb +++ b/spec/integration/provider/service/init_spec.rb @@ -1,30 +1,46 @@ #!/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 "when running on FreeBSD", :if => (Facter.value(:operatingsystem) == "FreeBSD") do + describe "when running on FreeBSD" do + before :each do + Facter.stubs(:value).with(:operatingsystem).returns 'FreeBSD' + end + 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 + describe "when running on HP-UX" do + before :each do + Facter.stubs(:value).with(:operatingsystem).returns 'HP-UX' + end + 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 + describe "when running on Archlinux" do + before :each do + Facter.stubs(:value).with(:operatingsystem).returns 'Archlinux' + end + 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 + describe "when not running on FreeBSD, HP-UX or Archlinux" do + before :each do + Facter.stubs(:value).with(:operatingsystem).returns 'RedHat' + end + 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/unit/provider/service/gentoo_spec.rb b/spec/unit/provider/service/gentoo_spec.rb new file mode 100755 index 000000000..78d19f25f --- /dev/null +++ b/spec/unit/provider/service/gentoo_spec.rb @@ -0,0 +1,230 @@ +#!/usr/bin/env rspec + +require 'spec_helper' + +describe Puppet::Type.type(:service).provider(:gentoo) do + + before :each do + Puppet::Type.type(:service).stubs(:defaultprovider).returns described_class + FileTest.stubs(:file?).with('/sbin/rc-update').returns true + FileTest.stubs(:executable?).with('/sbin/rc-update').returns true + Facter.stubs(:value).with(:operatingsystem).returns 'Gentoo' + + # The initprovider (parent of the gentoo provider) does a stat call + # before it even tries to execute an initscript. We use sshd in all the + # tests so make sure it is considered present. + File.stubs(:stat).with('/etc/init.d/sshd') + end + + let :initscripts do + [ + 'alsasound', + 'bootmisc', + 'functions.sh', + 'hwclock', + 'reboot.sh', + 'rsyncd', + 'shutdown.sh', + 'sshd', + 'vixie-cron', + 'wpa_supplicant', + 'xdm-setup' + ] + end + + let :helperscripts do + [ + 'functions.sh', + 'reboot.sh', + 'shutdown.sh' + ] + end + + describe ".instances" do + + it "should have an instances method" do + described_class.should respond_to :instances + end + + it "should get a list of services from /etc/init.d but exclude helper scripts" do + Dir.expects(:entries).with('/etc/init.d').returns initscripts + (initscripts - helperscripts).each do |script| + FileTest.expects(:executable?).with("/etc/init.d/#{script}").returns true + end + helperscripts.each do |script| + FileTest.expects(:executable?).with("/etc/init.d/#{script}").never + end + described_class.instances.map(&:name).should == [ + 'alsasound', + 'bootmisc', + 'hwclock', + 'rsyncd', + 'sshd', + 'vixie-cron', + 'wpa_supplicant', + 'xdm-setup' + ] + end + end + + describe "#start" do + it "should use the supplied start command if specified" do + provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd', :start => '/bin/foo')) + provider.expects(:execute).with(['/bin/foo'], :failonfail => true, :squelch => true) + provider.start + end + it "should start the service with start otherwise" do + provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd')) + provider.expects(:execute).with(['/etc/init.d/sshd',:start], :failonfail => true, :squelch => true) + provider.start + end + end + + describe "#stop" do + it "should use the supplied stop command if specified" do + provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd', :stop => '/bin/foo')) + provider.expects(:execute).with(['/bin/foo'], :failonfail => true, :squelch => true) + provider.stop + end + it "should stop the service with stop otherwise" do + provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd')) + provider.expects(:execute).with(['/etc/init.d/sshd',:stop], :failonfail => true, :squelch => true) + provider.stop + end + end + + describe "#enabled?" do + + before :each do + described_class.any_instance.stubs(:update).with(:show).returns File.read(my_fixture('rc_update_show')) + end + + it "should run rc-update show to get a list of enabled services" do + provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd')) + provider.expects(:update).with(:show).returns "\n" + provider.enabled? + end + + ['hostname', 'net.lo', 'procfs'].each do |service| + it "should consider service #{service} in runlevel boot as enabled" do + provider = described_class.new(Puppet::Type.type(:service).new(:name => service)) + provider.enabled?.should == :true + end + end + + ['alsasound', 'xdm', 'netmount'].each do |service| + it "should consider service #{service} in runlevel default as enabled" do + provider = described_class.new(Puppet::Type.type(:service).new(:name => service)) + provider.enabled?.should == :true + end + end + + ['rsyncd', 'lighttpd', 'mysql'].each do |service| + it "should consider unused service #{service} as disabled" do + provider = described_class.new(Puppet::Type.type(:service).new(:name => service)) + provider.enabled?.should == :false + end + end + + end + + describe "#enable" do + it "should run rc-update add to enable a service" do + provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd')) + provider.expects(:update).with(:add, 'sshd', :default) + provider.enable + end + end + + describe "#disable" do + it "should run rc-update del to disable a service" do + provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd')) + provider.expects(:update).with(:del, 'sshd', :default) + provider.disable + end + end + + describe "#status" do + + describe "when a special status command is specified" do + it "should use the status command from the resource" do + provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd', :status => '/bin/foo')) + provider.expects(:execute).with(['/etc/init.d/sshd',:status], :failonfail => false, :squelch => true).never + provider.expects(:execute).with(['/bin/foo'], :failonfail => false, :squelch => true) + provider.status + end + + it "should return :stopped when the status command returns with a non-zero exitcode" do + provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd', :status => '/bin/foo')) + provider.expects(:execute).with(['/etc/init.d/sshd',:status], :failonfail => false, :squelch => true).never + provider.expects(:execute).with(['/bin/foo'], :failonfail => false, :squelch => true) + $CHILD_STATUS.stubs(:exitstatus).returns 3 + provider.status.should == :stopped + end + + it "should return :running when the status command returns with a zero exitcode" do + provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd', :status => '/bin/foo')) + provider.expects(:execute).with(['/etc/init.d/sshd',:status], :failonfail => false, :squelch => true).never + provider.expects(:execute).with(['/bin/foo'], :failonfail => false, :squelch => true) + $CHILD_STATUS.stubs(:exitstatus).returns 0 + provider.status.should == :running + end + end + + describe "when hasstatus is false" do + it "should return running if a pid can be found" do + provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd', :hasstatus => false)) + provider.expects(:execute).with(['/etc/init.d/sshd',:status], :failonfail => false, :squelch => true).never + provider.expects(:getpid).returns 1000 + provider.status.should == :running + end + + it "should return stopped if no pid can be found" do + provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd', :hasstatus => false)) + provider.expects(:execute).with(['/etc/init.d/sshd',:status], :failonfail => false, :squelch => true).never + provider.expects(:getpid).returns nil + provider.status.should == :stopped + end + end + + describe "when hasstatus is true" do + it "should return running if status exits with a zero exitcode" do + provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd', :hasstatus => true)) + provider.expects(:execute).with(['/etc/init.d/sshd',:status], :failonfail => false, :squelch => true) + $CHILD_STATUS.stubs(:exitstatus).returns 0 + provider.status.should == :running + end + + it "should return stopped if status exits with a non-zero exitcode" do + provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd', :hasstatus => true)) + provider.expects(:execute).with(['/etc/init.d/sshd',:status], :failonfail => false, :squelch => true) + $CHILD_STATUS.stubs(:exitstatus).returns 3 + provider.status.should == :stopped + end + end + end + + describe "#restart" do + it "should use the supplied restart command if specified" do + provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd', :restart => '/bin/foo')) + provider.expects(:execute).with(['/etc/init.d/sshd',:restart], :failonfail => true, :squelch => true).never + provider.expects(:execute).with(['/bin/foo'], :failonfail => true, :squelch => true) + provider.restart + end + + it "should restart the service with restart if hasrestart is true" do + provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd', :hasrestart => true)) + provider.expects(:execute).with(['/etc/init.d/sshd',:restart], :failonfail => true, :squelch => true) + provider.restart + end + + it "should restart the service with stop/start if hasrestart is false" do + provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd', :hasrestart => false)) + provider.expects(:execute).with(['/etc/init.d/sshd',:restart], :failonfail => true, :squelch => true).never + provider.expects(:execute).with(['/etc/init.d/sshd',:stop], :failonfail => true, :squelch => true) + provider.expects(:execute).with(['/etc/init.d/sshd',:start], :failonfail => true, :squelch => true) + provider.restart + end + end + +end diff --git a/spec/unit/provider/service/init_spec.rb b/spec/unit/provider/service/init_spec.rb index 8374594e7..173fb8515 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.to_a).each do |inst| + (@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