diff --git a/ext/project_data.yaml b/ext/project_data.yaml index 5aff6ab4b..a4d1f81fc 100644 --- a/ext/project_data.yaml +++ b/ext/project_data.yaml @@ -1,50 +1,50 @@ --- project: 'puppet' author: 'Puppet Labs' email: 'info@puppetlabs.com' homepage: 'https://github.com/puppetlabs/puppet' summary: 'Puppet, an automated configuration management tool' description: 'Puppet, an automated configuration management tool' version_file: 'lib/puppet/version.rb' # files and gem_files are space separated lists files: '[A-Z]* install.rb bin lib conf man examples ext tasks spec' # The gem specification bits only work on Puppet >= 3.0rc, NOT 2.7.x and earlier gem_files: '[A-Z]* install.rb bin lib conf man examples ext tasks spec' gem_test_files: 'spec/**/*' gem_executables: 'puppet' gem_default_executables: 'puppet' gem_forge_project: 'puppet' gem_runtime_dependencies: facter: ['> 1.6', '< 3'] hiera: '~> 1.0' json_pure: gem_rdoc_options: - --title - "Puppet - Configuration Management" - --main - README.md - --line-numbers gem_platform_dependencies: x86-mingw32: gem_runtime_dependencies: # Pinning versions that require native extensions ffi: '~> 1.9.5' win32-dir: '~> 0.4.9' - win32-eventlog: '~> 0.6.1' + win32-eventlog: '~> 0.6.2' win32-process: '~> 0.7.4' win32-security: '~> 0.2.5' win32-service: '~> 0.8.6' win32console: '1.3.2' minitar: '~> 0.5.4' x64-mingw32: gem_runtime_dependencies: ffi: '~> 1.9.5' win32-dir: '~> 0.4.9' - win32-eventlog: '~> 0.6.1' + win32-eventlog: '~> 0.6.2' win32-process: '~> 0.7.4' win32-security: '~> 0.2.5' win32-service: '~> 0.8.6' minitar: '~> 0.5.4' bundle_platforms: x86-mingw32: mingw x64-mingw32: x64_mingw diff --git a/spec/integration/agent/logging_spec.rb b/spec/integration/agent/logging_spec.rb index 1c4394a6e..c686397c8 100755 --- a/spec/integration/agent/logging_spec.rb +++ b/spec/integration/agent/logging_spec.rb @@ -1,182 +1,178 @@ #! /usr/bin/env ruby require 'spec_helper' require 'puppet' require 'puppet/daemon' require 'puppet/application/agent' # The command line flags affecting #20900 and #20919: # # --onetime # --daemonize # --no-daemonize # --logdest # --verbose # --debug # (no flags) (-) # # d and nd are mutally exclusive # # Combinations without logdest, verbose or debug: # # --onetime --daemonize # --onetime --no-daemonize # --onetime # --daemonize # --no-daemonize # - # # 6 cases X [--logdest=console, --logdest=syslog, --logdest=/some/file, ] # = 24 cases to test # # X [--verbose, --debug, ] # = 72 cases to test # # Expectations of behavior are defined in the expected_loggers, expected_level methods, # so adapting to a change in logging behavior should hopefully be mostly a matter of # adjusting the logic in those methods to define new behavior. # # Note that this test does not have anything to say about what happens to logging after # daemonizing. describe 'agent logging' do ONETIME = '--onetime' DAEMONIZE = '--daemonize' NO_DAEMONIZE = '--no-daemonize' LOGDEST_FILE = '--logdest=/dev/null/foo' LOGDEST_SYSLOG = '--logdest=syslog' LOGDEST_CONSOLE = '--logdest=console' VERBOSE = '--verbose' DEBUG = '--debug' DEFAULT_LOG_LEVEL = :notice INFO_LEVEL = :info DEBUG_LEVEL = :debug CONSOLE = :console SYSLOG = :syslog EVENTLOG = :eventlog FILE = :file ONETIME_DAEMONIZE_ARGS = [ [ONETIME], [ONETIME, DAEMONIZE], [ONETIME, NO_DAEMONIZE], [DAEMONIZE], [NO_DAEMONIZE], [], ] LOG_DEST_ARGS = [LOGDEST_FILE, LOGDEST_SYSLOG, LOGDEST_CONSOLE, nil] LOG_LEVEL_ARGS = [VERBOSE, DEBUG, nil] shared_examples "an agent" do |argv, expected| before(:each) do # Don't actually run the agent, bypassing cert checks, forking and the puppet run itself Puppet::Application::Agent.any_instance.stubs(:run_command) end def double_of_bin_puppet_agent_call(argv) argv.unshift('agent') command_line = Puppet::Util::CommandLine.new('puppet', argv) command_line.execute end if Puppet.features.microsoft_windows? && argv.include?(DAEMONIZE) it "should exit on a platform which cannot daemonize if the --daemonize flag is set" do expect { double_of_bin_puppet_agent_call(argv) }.to raise_error(SystemExit) end else it "when evoked with #{argv}, logs to #{expected[:loggers].inspect} at level #{expected[:level]}" do - if Facter.value(:kernelmajversion).to_f < 6.0 - pending("requires win32-eventlog gem upgrade to 0.6.2 on Windows 2003") - end - # This logger is created by the Puppet::Settings object which creates and # applies a catalog to ensure that configuration files and users are in # place. # # It's not something we are specifically testing here since it occurs # regardless of user flags. Puppet::Util::Log.expects(:newdestination).with(instance_of(Puppet::Transaction::Report)).at_least_once expected[:loggers].each do |logclass| Puppet::Util::Log.expects(:newdestination).with(logclass).at_least_once end double_of_bin_puppet_agent_call(argv) Puppet::Util::Log.level.should == expected[:level] end end end def self.no_log_dest_set_in(argv) ([LOGDEST_SYSLOG, LOGDEST_CONSOLE, LOGDEST_FILE] & argv).empty? end def self.verbose_or_debug_set_in_argv(argv) !([VERBOSE, DEBUG] & argv).empty? end def self.log_dest_is_set_to(argv, log_dest) argv.include?(log_dest) end # @param argv Array of commandline flags # @return Set of expected loggers def self.expected_loggers(argv) loggers = Set.new loggers << CONSOLE if verbose_or_debug_set_in_argv(argv) loggers << 'console' if log_dest_is_set_to(argv, LOGDEST_CONSOLE) loggers << '/dev/null/foo' if log_dest_is_set_to(argv, LOGDEST_FILE) if Puppet.features.microsoft_windows? # an explicit call to --logdest syslog on windows is swallowed silently with no # logger created (see #suitable() of the syslog Puppet::Util::Log::Destination subclass) # however Puppet::Util::Log.newdestination('syslog') does get called...so we have # to set an expectation loggers << 'syslog' if log_dest_is_set_to(argv, LOGDEST_SYSLOG) loggers << EVENTLOG if no_log_dest_set_in(argv) else # posix loggers << 'syslog' if log_dest_is_set_to(argv, LOGDEST_SYSLOG) loggers << SYSLOG if no_log_dest_set_in(argv) end return loggers end # @param argv Array of commandline flags # @return Symbol of the expected log level def self.expected_level(argv) case when argv.include?(VERBOSE) then INFO_LEVEL when argv.include?(DEBUG) then DEBUG_LEVEL else DEFAULT_LOG_LEVEL end end # @param argv Array of commandline flags # @return Hash of expected loggers and the expected log level def self.with_expectations_based_on(argv) { :loggers => expected_loggers(argv), :level => expected_level(argv), } end # For running a single spec (by line number): rspec -l150 spec/integration/agent/logging_spec.rb # debug_argv = [] # it_should_behave_like( "an agent", [debug_argv], with_expectations_based_on([debug_argv])) ONETIME_DAEMONIZE_ARGS.each do |onetime_daemonize_args| LOG_LEVEL_ARGS.each do |log_level_args| LOG_DEST_ARGS.each do |log_dest_args| argv = (onetime_daemonize_args + [log_level_args, log_dest_args]).flatten.compact describe "for #{argv}" do it_should_behave_like( "an agent", argv, with_expectations_based_on(argv)) end end end end end diff --git a/spec/unit/util/log/destinations_spec.rb b/spec/unit/util/log/destinations_spec.rb index a9587addd..0e95566a3 100755 --- a/spec/unit/util/log/destinations_spec.rb +++ b/spec/unit/util/log/destinations_spec.rb @@ -1,242 +1,236 @@ #! /usr/bin/env ruby require 'spec_helper' require 'json' require 'puppet/util/log' describe Puppet::Util::Log.desttypes[:report] do before do @dest = Puppet::Util::Log.desttypes[:report] end it "should require a report at initialization" do @dest.new("foo").report.should == "foo" end it "should send new messages to the report" do report = mock 'report' dest = @dest.new(report) report.expects(:<<).with("my log") dest.handle "my log" end end describe Puppet::Util::Log.desttypes[:file] do include PuppetSpec::Files before do File.stubs(:open) # prevent actually creating the file File.stubs(:chown) # prevent chown on non existing file from failing @class = Puppet::Util::Log.desttypes[:file] end it "should default to autoflush false" do @class.new(tmpfile('log')).autoflush.should == true end describe "when matching" do shared_examples_for "file destination" do it "should match an absolute path" do @class.match?(abspath).should be_true end it "should not match a relative path" do @class.match?(relpath).should be_false end end describe "on POSIX systems", :as_platform => :posix do let (:abspath) { '/tmp/log' } let (:relpath) { 'log' } it_behaves_like "file destination" it "logs an error if it can't chown the file owner & group" do FileUtils.expects(:chown).with(Puppet[:user], Puppet[:group], abspath).raises(Errno::EPERM) Puppet.features.expects(:root?).returns(true) Puppet.expects(:err).with("Unable to set ownership to #{Puppet[:user]}:#{Puppet[:group]} for log file: #{abspath}") @class.new(abspath) end it "doesn't attempt to chown when running as non-root" do FileUtils.expects(:chown).with(Puppet[:user], Puppet[:group], abspath).never Puppet.features.expects(:root?).returns(false) @class.new(abspath) end end describe "on Windows systems", :as_platform => :windows do let (:abspath) { 'C:\\temp\\log.txt' } let (:relpath) { 'log.txt' } it_behaves_like "file destination" end end end describe Puppet::Util::Log.desttypes[:syslog] do let (:klass) { Puppet::Util::Log.desttypes[:syslog] } # these tests can only be run when syslog is present, because # we can't stub the top-level Syslog module describe "when syslog is available", :if => Puppet.features.syslog? do before :each do Syslog.stubs(:opened?).returns(false) Syslog.stubs(:const_get).returns("LOG_KERN").returns(0) Syslog.stubs(:open) end it "should open syslog" do Syslog.expects(:open) klass.new end it "should close syslog" do Syslog.expects(:close) dest = klass.new dest.close end it "should send messages to syslog" do syslog = mock 'syslog' syslog.expects(:info).with("don't panic") Syslog.stubs(:open).returns(syslog) msg = Puppet::Util::Log.new(:level => :info, :message => "don't panic") dest = klass.new dest.handle(msg) end end describe "when syslog is unavailable" do it "should not be a suitable log destination" do Puppet.features.stubs(:syslog?).returns(false) klass.suitable?(:syslog).should be_false end end end describe Puppet::Util::Log.desttypes[:logstash_event] do describe "when using structured log format with logstash_event schema" do before :each do @msg = Puppet::Util::Log.new(:level => :info, :message => "So long, and thanks for all the fish.", :source => "a dolphin") end it "format should fix the hash to have the correct structure" do dest = described_class.new result = dest.format(@msg) result["version"].should == 1 result["level"].should == :info result["message"].should == "So long, and thanks for all the fish." result["source"].should == "a dolphin" # timestamp should be within 10 seconds Time.parse(result["@timestamp"]).should >= ( Time.now - 10 ) end it "format returns a structure that can be converted to json" do dest = described_class.new hash = dest.format(@msg) JSON.parse(hash.to_json) end it "handle should send the output to stdout" do $stdout.expects(:puts).once dest = described_class.new dest.handle(@msg) end end end describe Puppet::Util::Log.desttypes[:console] do let (:klass) { Puppet::Util::Log.desttypes[:console] } describe "when color is available" do before :each do subject.stubs(:console_has_color?).returns(true) end it "should support color output" do Puppet[:color] = true subject.colorize(:red, 'version').should == "\e[0;31mversion\e[0m" end it "should withhold color output when not appropriate" do Puppet[:color] = false subject.colorize(:red, 'version').should == "version" end it "should handle multiple overlapping colors in a stack-like way" do Puppet[:color] = true vstring = subject.colorize(:red, 'version') subject.colorize(:green, "(#{vstring})").should == "\e[0;32m(\e[0;31mversion\e[0;32m)\e[0m" end it "should handle resets in a stack-like way" do Puppet[:color] = true vstring = subject.colorize(:reset, 'version') subject.colorize(:green, "(#{vstring})").should == "\e[0;32m(\e[mversion\e[0;32m)\e[0m" end it "should include the log message's source/context in the output when available" do Puppet[:color] = false $stdout.expects(:puts).with("Info: a hitchhiker: don't panic") msg = Puppet::Util::Log.new(:level => :info, :message => "don't panic", :source => "a hitchhiker") dest = klass.new dest.handle(msg) end end end describe ":eventlog", :if => Puppet::Util::Platform.windows? do - before do - if Facter.value(:kernelmajversion).to_f < 6.0 - pending("requires win32-eventlog gem upgrade to 0.6.2 on Windows 2003") - end - end - let(:klass) { Puppet::Util::Log.desttypes[:eventlog] } def expects_message_with_type(klass, level, eventlog_type, eventlog_id) eventlog = stub('eventlog') eventlog.expects(:report_event).with(has_entries(:source => "Puppet", :event_type => eventlog_type, :event_id => eventlog_id, :data => "a hitchhiker: don't panic")) Win32::EventLog.stubs(:open).returns(eventlog) msg = Puppet::Util::Log.new(:level => level, :message => "don't panic", :source => "a hitchhiker") dest = klass.new dest.handle(msg) end it "supports the eventlog feature" do expect(Puppet.features.eventlog?).to be_true end it "logs to the Application event log" do eventlog = stub('eventlog') Win32::EventLog.expects(:open).with('Application').returns(stub('eventlog')) klass.new end it "logs :debug level as an information type event" do expects_message_with_type(klass, :debug, klass::EVENTLOG_INFORMATION_TYPE, 0x1) end it "logs :warning level as an warning type event" do expects_message_with_type(klass, :warning, klass::EVENTLOG_WARNING_TYPE, 0x2) end it "logs :err level as an error type event" do expects_message_with_type(klass, :err, klass::EVENTLOG_ERROR_TYPE, 0x3) end end