diff --git a/spec/unit/daemon_spec.rb b/spec/unit/daemon_spec.rb index a025be43a..36ec0adc7 100755 --- a/spec/unit/daemon_spec.rb +++ b/spec/unit/daemon_spec.rb @@ -1,255 +1,253 @@ #! /usr/bin/env ruby require 'spec_helper' require 'puppet/daemon' require 'puppet/agent' def without_warnings flag = $VERBOSE $VERBOSE = nil yield $VERBOSE = flag end class TestClient def lockfile_path "/dev/null" end end describe Puppet::Daemon, :unless => Puppet.features.microsoft_windows? do include PuppetSpec::Files class RecordingScheduler attr_reader :jobs def run_loop(jobs) @jobs = jobs end end - let(:server) { double("Server", :start => nil, :wait_for_shutdown => nil) } let(:agent) { Puppet::Agent.new(TestClient.new, false) } + let(:server) { stub("Server", :start => nil, :wait_for_shutdown => nil) } let(:pidfile) { stub("PidFile", :lock => true, :unlock => true, :file_path => 'fake.pid') } let(:scheduler) { RecordingScheduler.new } let(:daemon) { Puppet::Daemon.new(pidfile, scheduler) } before do daemon.stubs(:close_streams).returns nil end it "should reopen the Log logs when told to reopen logs" do Puppet::Util::Log.expects(:reopen) daemon.reopen_logs end - let(:server) { stub("Server", :start => nil, :wait_for_shutdown => nil) } - describe "when setting signal traps" do signals = {:INT => :stop, :TERM => :stop } signals.update({:HUP => :restart, :USR1 => :reload, :USR2 => :reopen_logs}) unless Puppet.features.microsoft_windows? signals.each do |signal, method| it "should log and call #{method} when it receives #{signal}" do Signal.expects(:trap).with(signal).yields Puppet.expects(:notice) daemon.expects(method) daemon.set_signal_traps end end end describe "when starting" do before do daemon.stubs(:set_signal_traps) end it "should fail if it has neither agent nor server" do expect { daemon.start }.to raise_error(Puppet::DevError) end it "should create its pidfile" do pidfile.expects(:lock).returns(true) daemon.agent = agent daemon.start end it "should fail if it cannot lock" do pidfile.expects(:lock).returns(false) daemon.agent = agent expect { daemon.start }.to raise_error(RuntimeError, "Could not create PID file: #{pidfile.file_path}") end it "should start its server if one is configured" do daemon.server = server server.expects(:start) daemon.start end it "disables the reparse of configs if the filetimeout is 0" do Puppet[:filetimeout] = 0 daemon.agent = agent daemon.start expect(scheduler.jobs[0]).not_to be_enabled end it "disables the agent run when there is no agent" do Puppet[:filetimeout] = 0 daemon.server = server daemon.start expect(scheduler.jobs[1]).not_to be_enabled end it "waits for the server to shutdown when there is one" do daemon.server = server server.expects(:wait_for_shutdown) daemon.start end it "waits for the server to shutdown when there is one" do daemon.server = server server.expects(:wait_for_shutdown) daemon.start end end describe "when stopping" do before do Puppet::Util::Log.stubs(:close_all) # to make the global safe to mock, set it to a subclass of itself, # then restore it in an after pass without_warnings { Puppet::Application = Class.new(Puppet::Application) } end after do # restore from the superclass so we lose the stub garbage without_warnings { Puppet::Application = Puppet::Application.superclass } end it "should stop its server if one is configured" do server.expects(:stop) daemon.server = server expect { daemon.stop }.to exit_with 0 end it 'should request a stop from Puppet::Application' do Puppet::Application.expects(:stop!) expect { daemon.stop }.to exit_with 0 end it "should remove its pidfile" do pidfile.expects(:unlock) expect { daemon.stop }.to exit_with 0 end it "should close all logs" do Puppet::Util::Log.expects(:close_all) expect { daemon.stop }.to exit_with 0 end it "should exit unless called with ':exit => false'" do expect { daemon.stop }.to exit_with 0 end it "should not exit if called with ':exit => false'" do daemon.stop :exit => false end end describe "when reloading" do it "should do nothing if no agent is configured" do daemon.reload end it "should do nothing if the agent is running" do agent.expects(:running?).returns true daemon.agent = agent daemon.reload end it "should run the agent if one is available and it is not running" do agent.expects(:running?).returns false agent.expects(:run).with({:splay => false}) daemon.agent = agent daemon.reload end end describe "when restarting" do before do without_warnings { Puppet::Application = Class.new(Puppet::Application) } end after do without_warnings { Puppet::Application = Puppet::Application.superclass } end it 'should set Puppet::Application.restart!' do Puppet::Application.expects(:restart!) daemon.stubs(:reexec) daemon.restart end it "should reexec itself if no agent is available" do daemon.expects(:reexec) daemon.restart end it "should reexec itself if the agent is not running" do agent.expects(:running?).returns false daemon.agent = agent daemon.expects(:reexec) daemon.restart end end describe "when reexecing it self" do before do daemon.stubs(:exec) daemon.stubs(:stop) end it "should fail if no argv values are available" do daemon.expects(:argv).returns nil expect { daemon.reexec }.to raise_error(Puppet::DevError) end it "should shut down without exiting" do daemon.argv = %w{foo} daemon.expects(:stop).with(:exit => false) daemon.reexec end it "should call 'exec' with the original executable and arguments" do daemon.argv = %w{foo} daemon.expects(:exec).with($0 + " foo") daemon.reexec end end end diff --git a/spec/unit/file_serving/fileset_spec.rb b/spec/unit/file_serving/fileset_spec.rb index 57a87ce8f..bd5809604 100755 --- a/spec/unit/file_serving/fileset_spec.rb +++ b/spec/unit/file_serving/fileset_spec.rb @@ -1,354 +1,353 @@ #! /usr/bin/env ruby require 'spec_helper' require 'puppet/file_serving/fileset' describe Puppet::FileServing::Fileset do include PuppetSpec::Files let(:somefile) { make_absolute("/some/file") } context "when initializing" do it "requires a path" do expect { Puppet::FileServing::Fileset.new }.to raise_error(ArgumentError) end it "fails if its path is not fully qualified" do expect { Puppet::FileServing::Fileset.new("some/file") }.to raise_error(ArgumentError, "Fileset paths must be fully qualified: some/file") end it "removes a trailing file path separator" do path_with_separator = "#{somefile}#{File::SEPARATOR}" Puppet::FileSystem.expects(:lstat).with(somefile).returns stub('stat') fileset = Puppet::FileServing::Fileset.new(path_with_separator) expect(fileset.path).to eq(somefile) end it "can be created from the root directory" do path = File.expand_path(File::SEPARATOR) Puppet::FileSystem.expects(:lstat).with(path).returns stub('stat') fileset = Puppet::FileServing::Fileset.new(path) expect(fileset.path).to eq(path) end it "fails if its path does not exist" do Puppet::FileSystem.expects(:lstat).with(somefile).raises(Errno::ENOENT) expect { Puppet::FileServing::Fileset.new(somefile) }.to raise_error(ArgumentError, "Fileset paths must exist") end it "accepts a 'recurse' option" do Puppet::FileSystem.expects(:lstat).with(somefile).returns stub('stat') set = Puppet::FileServing::Fileset.new(somefile, :recurse => true) expect(set.recurse).to be_truthy end it "accepts a 'recurselimit' option" do Puppet::FileSystem.expects(:lstat).with(somefile).returns stub('stat') set = Puppet::FileServing::Fileset.new(somefile, :recurselimit => 3) expect(set.recurselimit).to eq(3) end it "accepts an 'ignore' option" do Puppet::FileSystem.expects(:lstat).with(somefile).returns stub('stat') set = Puppet::FileServing::Fileset.new(somefile, :ignore => ".svn") expect(set.ignore).to eq([".svn"]) end it "accepts a 'links' option" do Puppet::FileSystem.expects(:lstat).with(somefile).returns stub('stat') set = Puppet::FileServing::Fileset.new(somefile, :links => :manage) expect(set.links).to eq(:manage) end it "accepts a 'checksum_type' option" do Puppet::FileSystem.expects(:lstat).with(somefile).returns stub('stat') set = Puppet::FileServing::Fileset.new(somefile, :checksum_type => :test) expect(set.checksum_type).to eq(:test) end it "fails if 'links' is set to anything other than :manage or :follow" do expect { Puppet::FileServing::Fileset.new(somefile, :links => :whatever) }.to raise_error(ArgumentError, "Invalid :links value 'whatever'") end it "defaults to 'false' for recurse" do Puppet::FileSystem.expects(:lstat).with(somefile).returns stub('stat') expect(Puppet::FileServing::Fileset.new(somefile).recurse).to eq(false) end it "defaults to :infinite for recurselimit" do Puppet::FileSystem.expects(:lstat).with(somefile).returns stub('stat') expect(Puppet::FileServing::Fileset.new(somefile).recurselimit).to eq(:infinite) end it "defaults to an empty ignore list" do Puppet::FileSystem.expects(:lstat).with(somefile).returns stub('stat') expect(Puppet::FileServing::Fileset.new(somefile).ignore).to eq([]) end it "defaults to :manage for links" do Puppet::FileSystem.expects(:lstat).with(somefile).returns stub('stat') expect(Puppet::FileServing::Fileset.new(somefile).links).to eq(:manage) end describe "using an indirector request" do let(:values) { { :links => :manage, :ignore => %w{a b}, :recurse => true, :recurselimit => 1234 } } - let(:stub_file) { double(somefile, :lstat => double('stat')) } before :each do Puppet::FileSystem.expects(:lstat).with(somefile).returns stub('stat') end [:recurse, :recurselimit, :ignore, :links].each do |option| it "passes the #{option} option on to the fileset if present" do request = Puppet::Indirector::Request.new(:file_serving, :find, "foo", nil, {option => values[option]}) expect(Puppet::FileServing::Fileset.new(somefile, request).send(option)).to eq(values[option]) end end it "converts the integer as a string to their integer counterpart when setting options" do request = Puppet::Indirector::Request.new(:file_serving, :find, "foo", nil, {:recurselimit => "1234"}) expect(Puppet::FileServing::Fileset.new(somefile, request).recurselimit).to eq(1234) end it "converts the string 'true' to the boolean true when setting options" do request = Puppet::Indirector::Request.new(:file_serving, :find, "foo", nil, {:recurse => "true"}) expect(Puppet::FileServing::Fileset.new(somefile, request).recurse).to eq(true) end it "converts the string 'false' to the boolean false when setting options" do request = Puppet::Indirector::Request.new(:file_serving, :find, "foo", nil, {:recurse => "false"}) expect(Puppet::FileServing::Fileset.new(somefile, request).recurse).to eq(false) end end end context "when recursing" do before do @path = make_absolute("/my/path") Puppet::FileSystem.stubs(:lstat).with(@path).returns stub('stat', :directory? => true) @fileset = Puppet::FileServing::Fileset.new(@path) @dirstat = stub 'dirstat', :directory? => true @filestat = stub 'filestat', :directory? => false end def mock_dir_structure(path, stat_method = :lstat) Puppet::FileSystem.stubs(stat_method).with(path).returns @dirstat # Keep track of the files we're stubbing. @files = %w{.} top_names = %w{one two .svn CVS} sub_names = %w{file1 file2 .svn CVS 0 false} Dir.stubs(:entries).with(path).returns(top_names) top_names.each do |subdir| @files << subdir # relative path subpath = File.join(path, subdir) Puppet::FileSystem.stubs(stat_method).with(subpath).returns @dirstat Dir.stubs(:entries).with(subpath).returns(sub_names) sub_names.each do |file| @files << File.join(subdir, file) # relative path subfile_path = File.join(subpath, file) Puppet::FileSystem.stubs(stat_method).with(subfile_path).returns(@filestat) end end end MockStat = Struct.new(:path, :directory) do # struct doesn't support thing ending in ? def directory? directory end end MockDirectory = Struct.new(:name, :entries) do def mock(base_path) extend Mocha::API path = File.join(base_path, name) Puppet::FileSystem.stubs(:lstat).with(path).returns MockStat.new(path, true) Dir.stubs(:entries).with(path).returns(['.', '..'] + entries.map(&:name)) entries.each do |entry| entry.mock(path) end end end MockFile = Struct.new(:name) do def mock(base_path) extend Mocha::API path = File.join(base_path, name) Puppet::FileSystem.stubs(:lstat).with(path).returns MockStat.new(path, false) end end it "doesn't ignore pending directories when the last entry at the top level is a file" do structure = MockDirectory.new('path', [MockDirectory.new('dir1', [MockDirectory.new('a', [MockFile.new('f')])]), MockFile.new('file')]) structure.mock(make_absolute('/your')) fileset = Puppet::FileServing::Fileset.new(make_absolute('/your/path')) fileset.recurse = true fileset.links = :manage expect(fileset.files).to eq([".", "dir1", "file", "dir1/a", "dir1/a/f"]) end it "recurses through the whole file tree if :recurse is set to 'true'" do mock_dir_structure(@path) @fileset.recurse = true expect(@fileset.files.sort).to eq(@files.sort) end it "does not recurse if :recurse is set to 'false'" do mock_dir_structure(@path) @fileset.recurse = false expect(@fileset.files).to eq(%w{.}) end it "recurses to the level set by :recurselimit" do mock_dir_structure(@path) @fileset.recurse = true @fileset.recurselimit = 1 expect(@fileset.files).to eq(%w{. one two .svn CVS}) end it "ignores the '.' and '..' directories in subdirectories" do mock_dir_structure(@path) @fileset.recurse = true expect(@fileset.files.sort).to eq(@files.sort) end it "does not fail if the :ignore value provided is nil" do mock_dir_structure(@path) @fileset.recurse = true @fileset.ignore = nil expect { @fileset.files }.to_not raise_error end it "ignores files that match a single pattern in the ignore list" do mock_dir_structure(@path) @fileset.recurse = true @fileset.ignore = ".svn" expect(@fileset.files.find { |file| file.include?(".svn") }).to be_nil end it "ignores files that match any of multiple patterns in the ignore list" do mock_dir_structure(@path) @fileset.recurse = true @fileset.ignore = %w{.svn CVS} expect(@fileset.files.find { |file| file.include?(".svn") or file.include?("CVS") }).to be_nil end it "ignores files that match a pattern given as a number" do mock_dir_structure(@path) @fileset.recurse = true @fileset.ignore = [0] expect(@fileset.files.find { |file| file.include?("0") }).to be_nil end it "ignores files that match a pattern given as a boolean" do mock_dir_structure(@path) @fileset.recurse = true @fileset.ignore = [false] expect(@fileset.files.find { |file| file.include?("false") }).to be_nil end it "uses Puppet::FileSystem#stat if :links is set to :follow" do mock_dir_structure(@path, :stat) @fileset.recurse = true @fileset.links = :follow expect(@fileset.files.sort).to eq(@files.sort) end it "uses Puppet::FileSystem#lstat if :links is set to :manage" do mock_dir_structure(@path, :lstat) @fileset.recurse = true @fileset.links = :manage expect(@fileset.files.sort).to eq(@files.sort) end it "works when paths have regexp significant characters" do @path = make_absolute("/my/path/rV1x2DafFr0R6tGG+1bbk++++TM") stat = stub('dir_stat', :directory? => true) stub_file = stub(@path, :stat => stat, :lstat => stat) Puppet::FileSystem.expects(:lstat).with(@path).returns stub(@path, :stat => stat, :lstat => stat) @fileset = Puppet::FileServing::Fileset.new(@path) mock_dir_structure(@path) @fileset.recurse = true expect(@fileset.files.sort).to eq(@files.sort) end end it "manages the links to missing files" do path = make_absolute("/my/path") stat = stub 'stat', :directory? => true Puppet::FileSystem.expects(:stat).with(path).returns stat Puppet::FileSystem.expects(:lstat).with(path).returns stat link_path = File.join(path, "mylink") Puppet::FileSystem.expects(:stat).with(link_path).raises(Errno::ENOENT) Dir.stubs(:entries).with(path).returns(["mylink"]) fileset = Puppet::FileServing::Fileset.new(path) fileset.links = :follow fileset.recurse = true expect(fileset.files.sort).to eq(%w{. mylink}.sort) end context "when merging other filesets" do before do @paths = [make_absolute("/first/path"), make_absolute("/second/path"), make_absolute("/third/path")] Puppet::FileSystem.stubs(:lstat).returns stub('stat', :directory? => false) @filesets = @paths.collect do |path| Puppet::FileSystem.stubs(:lstat).with(path).returns stub('stat', :directory? => true) Puppet::FileServing::Fileset.new(path, :recurse => true) end Dir.stubs(:entries).returns [] end it "returns a hash of all files in each fileset with the value being the base path" do Dir.expects(:entries).with(make_absolute("/first/path")).returns(%w{one uno}) Dir.expects(:entries).with(make_absolute("/second/path")).returns(%w{two dos}) Dir.expects(:entries).with(make_absolute("/third/path")).returns(%w{three tres}) expect(Puppet::FileServing::Fileset.merge(*@filesets)).to eq({ "." => make_absolute("/first/path"), "one" => make_absolute("/first/path"), "uno" => make_absolute("/first/path"), "two" => make_absolute("/second/path"), "dos" => make_absolute("/second/path"), "three" => make_absolute("/third/path"), "tres" => make_absolute("/third/path"), }) end it "includes the base directory from the first fileset" do Dir.expects(:entries).with(make_absolute("/first/path")).returns(%w{one}) Dir.expects(:entries).with(make_absolute("/second/path")).returns(%w{two}) expect(Puppet::FileServing::Fileset.merge(*@filesets)["."]).to eq(make_absolute("/first/path")) end it "uses the base path of the first found file when relative file paths conflict" do Dir.expects(:entries).with(make_absolute("/first/path")).returns(%w{one}) Dir.expects(:entries).with(make_absolute("/second/path")).returns(%w{one}) expect(Puppet::FileServing::Fileset.merge(*@filesets)["one"]).to eq(make_absolute("/first/path")) end end end