Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use a logger for better output control #28

Merged
merged 3 commits into from
Oct 9, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
32 changes: 32 additions & 0 deletions lib/ruby_dep/logger.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,40 @@
require 'logger'

module RubyDep
def self.logger
@logger ||= stderr_logger
end

def self.logger=(new_logger)
@logger = new_logger.nil? ? NullLogger.new : new_logger
end

def self.stderr_logger
::Logger.new(STDERR).tap do |logger|
logger.formatter = proc { |_,_,_,msg| "#{msg}\n" }
end
end

# Shamelessly stolen from https://github.com/karafka/null-logger
class NullLogger
LOG_LEVELS = %w(unknown fatal error warn info debug).freeze

def respond_to_missing?(method_name, include_private = false)
LOG_LEVELS.include?(method_name.to_s) || super
end

def method_missing(method_name, *args, &block)
LOG_LEVELS.include?(method_name.to_s) ? nil : super
end
end

# TODO: not used, but kept for the sake of SemVer
# TODO: remove in next major version
class Logger
def initialize(device, prefix)
@device = device
@prefix = prefix
::RubyDep.logger.warn("The RubyDep::Logger class is deprecated")
end

def warning(msg)
Expand Down
9 changes: 5 additions & 4 deletions lib/ruby_dep/warning.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ class Warning

def initialize
@version = RubyVersion.new(RUBY_VERSION, RUBY_ENGINE)
@logger = Logger.new(STDERR, PREFIX)
end

def show_warnings
Expand All @@ -53,9 +52,11 @@ def status
end

def warn_ruby(msg)
@logger.warning(msg)
@logger.notice(recommendation)
@logger.notice(NOTICE_HOW_TO_DISABLE)
RubyDep.logger.tap do |logger|
logger.warn(PREFIX + msg)
logger.info(PREFIX + recommendation)
logger.info(PREFIX + NOTICE_HOW_TO_DISABLE)
end
end

def recommendation
Expand Down
13 changes: 13 additions & 0 deletions spec/acceptance/fixtures/nil_logger.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
require 'ruby_dep/warning'

# Monkey patch so warning happens on every tested Ruby version
module RubyDep
class RubyVersion
def status
:insecure
end
end
end

RubyDep.logger = nil
RubyDep::Warning.new.show_warnings
17 changes: 17 additions & 0 deletions spec/acceptance/fixtures/stdout_logger.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
require 'ruby_dep/warning'

# Monkey patch so warning happens on every tested Ruby version
module RubyDep
class RubyVersion
def status
:insecure
end
end
end

RubyDep.logger = Logger.new(STDOUT).tap do |logger|
logger.formatter = proc do |severity,_,_,msg|
"#{severity};"
end
end
RubyDep::Warning.new.show_warnings
21 changes: 21 additions & 0 deletions spec/acceptance/warnings_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,25 @@ def run_isolated(cmd)
end
end
end

context 'when a logger is set manually' do
context 'with logger instance' do
let!(:spec) { 'stdout_logger.rb' }
let(:code) do
"o=`#{subcmd}`;"\
"expected = \"WARN;INFO;INFO;\";" \
"raise \"Unexpected output: \#{o.inspect}\" unless o == expected"
end
it 'uses the given logger' do
run_isolated(cmd)
end
end

context 'with nil' do
let!(:spec) { 'nil_logger.rb' }
it 'produces no output' do
run_isolated(cmd)
end
end
end
end
77 changes: 61 additions & 16 deletions spec/lib/ruby_dep/logger_spec.rb
Original file line number Diff line number Diff line change
@@ -1,24 +1,69 @@
require 'ruby_dep/logger'

RSpec.describe RubyDep::Logger do
let(:device) { instance_double(IO) }

describe '#warning' do
context 'with a prefix' do
subject { described_class.new(device, 'foo: ') }
it 'outputs message with prefix' do
expect(device).to receive(:puts).with('foo: bar')
subject.warning('bar')
RSpec.describe RubyDep do
around do |example|
example.run
RubyDep.instance_variable_set(:@logger, nil)
end

let(:stderr_logger) { instance_double(Logger, 'stderr logger') }
let(:null_logger) { instance_double(RubyDep::NullLogger, 'null logger') }

let(:string_io) { instance_double(StringIO) }

before do
allow(StringIO).to receive(:new).and_return(string_io)
allow(RubyDep::NullLogger).to receive(:new).and_return(null_logger)
allow(Logger).to receive(:new).with(STDERR).and_return(stderr_logger)
end

describe '.logger' do
context 'when not set yet' do
before do
allow(stderr_logger).to receive(:formatter=)
end

it 'returns stderr_logger' do
expect(described_class.logger).to be(stderr_logger)
end

it 'sets up a simple formatter' do
expect(stderr_logger).to receive(:formatter=) do |callback|
expect( callback.call('a', 'b', 'c', 'd')).to eq("d\n")
end
described_class.logger
end

context 'when reset to nil' do
before { described_class.logger = nil }

it 'returns null logger' do
expect(described_class.logger).to be(null_logger)
end
end

context 'when set to a logger' do
let(:logger) { instance_double(Logger) }
before { described_class.logger = logger }

it 'returns given logger' do
expect(described_class.logger).to be(logger)
end
end
end
end

describe '#notice' do
context 'with a prefix' do
subject { described_class.new(device, 'foo: ') }
it 'outputs message with prefix' do
expect(device).to receive(:puts).with('foo: bar')
subject.notice('bar')
context 'when already set' do
context 'with a custom logger' do
let(:logger) { instance_double(Logger) }
before { described_class.logger = logger }

context 'when reset' do
before { described_class.logger = nil }

it 'outputs to null logger' do
expect(described_class.logger).to be(null_logger)
end
end
end
end
end
Expand Down
2 changes: 2 additions & 0 deletions spec/lib/ruby_dep/travis/ruby_version_spec.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
require 'ruby_dep/travis'

RSpec.describe RubyDep::Travis::RubyVersion do
subject { described_class.new(travis_version_string) }

Expand Down
37 changes: 18 additions & 19 deletions spec/lib/ruby_dep/warning_spec.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
require 'ruby_dep/warning'

RSpec.describe RubyDep::Warning do
let(:logger) { instance_double(RubyDep::Logger) }
let(:logger) { instance_double(Logger) }

let(:outdated_ruby) { instance_double(RubyDep::RubyVersion) }
let(:up_to_date_ruby) { instance_double(RubyDep::RubyVersion) }
Expand All @@ -11,10 +11,9 @@
let(:untracked_engine_ruby) { instance_double(RubyDep::RubyVersion) }

before do
allow(RubyDep::Logger).to receive(:new)
.with(STDERR, 'RubyDep: WARNING: ').and_return(logger)
allow(logger).to receive(:warning)
allow(logger).to receive(:notice)
allow(RubyDep).to receive(:logger).and_return(logger)
allow(logger).to receive(:warn)
allow(logger).to receive(:info)

allow(RubyDep::RubyVersion).to receive(:new)
.with(RUBY_VERSION, RUBY_ENGINE).and_return(ruby_version)
Expand Down Expand Up @@ -74,8 +73,8 @@ def rquote(str)
context 'with any outdated Ruby' do
let(:ruby_version) { outdated_ruby }
it 'does not show anything' do
expect(logger).to_not have_received(:warning)
expect(logger).to_not have_received(:notice)
expect(logger).to_not have_received(:warn)
expect(logger).to_not have_received(:info)
end
end
end
Expand All @@ -91,8 +90,8 @@ def rquote(str)
context 'with any outdated Ruby' do
let(:ruby_version) { outdated_ruby }
it 'does not show anything' do
expect(logger).to_not have_received(:warning)
expect(logger).to_not have_received(:notice)
expect(logger).to_not have_received(:warn)
expect(logger).to_not have_received(:info)
end
end
end
Expand All @@ -102,61 +101,61 @@ def rquote(str)
context 'with an up-to-date Ruby' do
let(:ruby_version) { up_to_date_ruby }
it 'does not show anything' do
expect(logger).to_not have_received(:warning)
expect(logger).to_not have_received(:notice)
expect(logger).to_not have_received(:warn)
expect(logger).to_not have_received(:info)
end
end

context 'with a secure but buggy Ruby' do
let(:ruby_version) { buggy_ruby }
it 'shows warning about bugs' do
expect(logger).to have_received(:warning).with(
expect(logger).to have_received(:warn).with(
%r{Your Ruby is outdated\/buggy.})
end

it 'shows recommended action' do
expected = rquote(
'Your Ruby is: 2.2.4 (buggy). Recommendation: upgrade to'\
' 2.2.5 or 2.3.1')
expect(logger).to have_received(:notice).with(expected)
expect(logger).to have_received(:info).with(expected)
end
end

context 'with an insecure Ruby' do
let(:ruby_version) { insecure_ruby }
it 'shows warning about vulnerability' do
expect(logger).to have_received(:warning).with(
expect(logger).to have_received(:warn).with(
/Your Ruby has security vulnerabilities!/)
end

it 'shows recommended action' do
expected = rquote(
'Your Ruby is: 2.2.3 (insecure). Recommendation:'\
' upgrade to 2.2.5 or 2.3.1. (Or, at least to 2.2.4 or 2.3.0)')
expect(logger).to have_received(:notice).with(expected)
expect(logger).to have_received(:info).with(expected)
end
end

context 'with an unsupported Ruby' do
let(:ruby_version) { unsupported_ruby }
it 'shows warning about vulnerability' do
expect(logger).to have_received(:warning).with(
expect(logger).to have_received(:warn).with(
/Your Ruby has security vulnerabilities!/)
end

it 'shows recommended action' do
expected = rquote(
'Your Ruby is: 1.9.3 (insecure). Recommendation: upgrade to 2.2.5'\
' or 2.3.1. (Or, at least to 2.1.9 or 2.2.4 or 2.3.0)')
expect(logger).to have_received(:notice).with(expected)
expect(logger).to have_received(:info).with(expected)
end
end

context 'with an untracked ruby engine' do
context 'when the Ruby is not listed' do
let(:ruby_version) { untracked_engine_ruby }
it 'shows warning about lack of support' do
expect(logger).to have_received(:warning).with(
expect(logger).to have_received(:warn).with(
/Your Ruby may not be supported./)
end

Expand All @@ -165,7 +164,7 @@ def rquote(str)
"Your Ruby is: 1.2.3 'ironruby' (unrecognized). If you need"\
' this version supported, please open an issue at'\
' http://github.com/e2/ruby_dep')
expect(logger).to have_received(:notice).with(expected)
expect(logger).to have_received(:info).with(expected)
end
end
end
Expand Down